--- a/DoWhatIMeanSupport.st Sat May 07 12:30:34 2016 +0200
+++ b/DoWhatIMeanSupport.st Sat May 07 12:37:59 2016 +0200
@@ -1508,7 +1508,7 @@
If nonNil, we can make better guesses, because we actually know what a variable's type is"
|crsrPos char interval i source partialSource cursorLineSource
- suggestions actions title|
+ suggestions actions title suggestionCollector|
languageOrNil := SmalltalkLanguage instance.
methodOrNil := methodOrNilArg.
@@ -1527,13 +1527,36 @@
crsrPos := crsrPos - 1.
char := codeView characterAtCharacterPosition:crsrPos.
].
-
char == $. ifTrue:[
"/ either at end of statement or after a character constant
crsrPos == 1 ifTrue:[^ self].
(codeView characterAtCharacterPosition:crsrPos-1) == $$ ifFalse:[^ self].
].
+ suggestionCollector :=
+ [:listOfSuggestions :listOfActionsOrBlock :titleWhenAsking |
+ "/ may be called multiple times!!
+ suggestions isNil ifTrue:[
+ suggestions := listOfSuggestions.
+ actions := listOfActionsOrBlock.
+ title := titleWhenAsking.
+ ] ifFalse:[
+ suggestions := suggestions asOrderedCollection.
+ actions isBlock ifTrue:[
+ actions := Array new:suggestions size withAll:actions.
+ ].
+ actions := actions asOrderedCollection.
+
+ suggestions addAll:listOfSuggestions.
+ listOfActionsOrBlock isBlock ifTrue:[
+ actions addAll:(Array new:listOfSuggestions size withAll:listOfActionsOrBlock).
+ ] ifFalse:[
+ actions addAll:listOfActionsOrBlock.
+ ].
+ title := titleWhenAsking.
+ ].
+ ].
+
interval := crsrPos-1 to:crsrPos.
source := codeView contentsAsString string.
@@ -1560,11 +1583,7 @@
self
tryCodeCompletionWithSource:cursorLineSource nodeInterval:interval
at:crsrPos mustBeExpression:true
- into:[:listOfSuggestions :listOfActions :titleWhenAsking |
- suggestions := listOfSuggestions.
- actions := listOfActions.
- title := titleWhenAsking.
- ].
+ into:suggestionCollector.
].
].
@@ -1573,12 +1592,7 @@
"/ self
"/ tryCodeCompletionWithSource:partialSource nodeInterval:interval
"/ at:crsrPos mustBeExpression:(classOrNilArg isNil and:[methodOrNilArg isNil])
-"/ into:[:listOfSuggestions :listOfActions :titleWhenAsking |
-"/ suggestions := listOfSuggestions.
-"/ actions := listOfActions.
-"/ title := titleWhenAsking.
-"/ "/ suggestions1 size>100 ifTrue:[ self halt].
-"/ ].
+"/ into:suggestionCollector.
"/ ].
suggestions isEmptyOrNil ifTrue:[
@@ -1586,11 +1600,7 @@
self
tryCodeCompletionWithSource:source nodeInterval:interval
at:crsrPos mustBeExpression:false
- into:[:listOfSuggestions :listOfActions :titleWhenAsking |
- suggestions := listOfSuggestions.
- actions := listOfActions.
- title := titleWhenAsking.
- ].
+ into:suggestionCollector
].
suggestions isNil ifTrue:[
@@ -1598,12 +1608,7 @@
self
tryCodeCompletionWithSource:partialSource nodeInterval:interval
at:crsrPos mustBeExpression:(classOrNilArg isNil and:[methodOrNilArg isNil])
- into:[:listOfSuggestions :listOfActions :titleWhenAsking |
- suggestions := listOfSuggestions.
- actions := listOfActions.
- title := titleWhenAsking.
- "/ suggestions1 size>100 ifTrue:[ self halt].
- ].
+ into:suggestionCollector.
].
suggestions isEmptyOrNil ifTrue:[
@@ -2036,10 +2041,11 @@
codeView characterBeforeCursor == $: ifTrue:[
(bestSelectors select:[:sel | sel asLowercase startsWith:lcSelector]) isEmpty ifTrue:[
"/ nothing better around
- |argIndex argNames impls|
+ |argIndex argNames argNameStrings impls|
argIndex := node selectorParts size.
argNames := Set new.
+ argNameStrings := OrderedCollection new.
impls := Smalltalk allImplementorsOf:selector.
impls size < 10 ifTrue:[
impls do:[:eachImplClass |
@@ -2048,12 +2054,15 @@
mthd := (eachImplClass compiledMethodAt:selector).
argName := (mthd methodArgNames ? #()) at:argIndex ifAbsent:nil.
argName notNil ifTrue:[
- argNames add:(argName,' in (' ,mthd mclass name allBold,' ',mthd methodDefinitionTemplate).
+ (argNames includes:argName) ifFalse:[
+ argNames add:argName.
+ argNameStrings add:(argName allItalic,' hint only: argName in (' ,mthd mclass name allBold,' ',mthd methodDefinitionTemplate).
+ ].
].
].
- argNames notEmptyOrNil ifTrue: [
- argNames := argNames asOrderedCollection sort.
- actionBlock value:argNames value:[:selIndex | ] value: 'argument name hint'.
+ argNameStrings notEmptyOrNil ifTrue: [
+ argNameStrings := argNameStrings asOrderedCollection sort.
+ actionBlock value:argNameStrings value:[:selIndex | ] value: 'argument name hint'.
^ self.
]
]
@@ -2061,9 +2070,12 @@
].
] ifFalse:[
"/ when completing a non-keyword AND the parent is a keyword message,
- "/ only consider longer keyword messages or unary messages
- (parentNode notNil and:[ parentNode isKeywordMessage ]) ifTrue:[
- bestSelectors := bestSelectors select:[:sel | sel isUnarySelector ]
+ "/ only consider longer keyword messages or unary messages.
+ "/ unless the node is parenthesized
+ node hasParentheses ifFalse:[
+ (parentNode notNil and:[ parentNode isKeywordMessage ]) ifTrue:[
+ bestSelectors := bestSelectors select:[:sel | sel isUnarySelector or:[ sel startsWith:sel]]
+ ]
]
].
@@ -2588,7 +2600,7 @@
codeCompletionForMessageTo:node into:actionBlock
"find good suggestions for a message send to node, with no input yet"
- |knownClass suggestions selectorsImplementedInClass mostUseful editAction pos|
+ |knownClass suggestions selectorsImplementedInClass mostUseful editActions pos|
(knownClass := self classOfNode:node) isNil ifTrue:[^ self].
@@ -2645,8 +2657,10 @@
self sortUsefulSelectorsIn:suggestions. "/cosmetics
pos := codeView characterPositionOfCursor.
- editAction := self editActionToReplaceCodeFrom:pos to:pos-1 byWordIn:suggestions.
- actionBlock value:suggestions value:editAction value:nil.
+ editActions := suggestions collect:[:word |
+ self editActionToReplaceCodeFrom:pos to:pos-1 by:word.
+ ].
+ actionBlock value:suggestions value:editActions value:nil.
"Created: / 01-05-2016 / 17:01:21 / cg"
"Modified: / 01-05-2016 / 18:54:03 / cg"
@@ -3043,7 +3057,7 @@
char oldLen newLen
getDistanceComputeBlockWithWeight addWithFactorBlock allTheBest bestAssoc
globalFactor localFactor selectorOfMessageToNode implementors argIdx namesUsed kwPart
- editAction suggestions nameIsOK longerNames setOfNames otherArgNames
+ editAction editActions suggestions nameIsOK longerNames setOfNames otherArgNames
suggestionsWithInfo isLeftSideOfAssignment|
"/ Transcript show:'var in '; show:methodOrNil; show:' / '; showCR:classOrNil.
@@ -3103,18 +3117,20 @@
].
selectors := selectors1 order sort , #('-') , selectors2 order sort.
- editAction :=
- [:answer |
- |s|
- s := answer isInteger ifTrue:[selectors at:answer] ifFalse:[answer].
- codeView
- undoableDo:[
- codeView insertString:s atCharacterPosition:crsrPos.
- codeView cursorToCharacterPosition:crsrPos+s size.
- ]
- info:'completion'.
- ].
- actionBlock value:selectors value:editAction value:nil.
+ editActions := selectors collect:[:word | self editActionToInsert:word].
+ actionBlock value:selectors value:editActions value:nil.
+"/ editAction :=
+"/ [:answer |
+"/ |s|
+"/ s := answer isInteger ifTrue:[selectors at:answer] ifFalse:[answer].
+"/ codeView
+"/ undoableDo:[
+"/ codeView insertString:s atCharacterPosition:crsrPos.
+"/ codeView cursorToCharacterPosition:crsrPos+s size.
+"/ ]
+"/ info:'completion'.
+"/ ].
+"/ actionBlock value:selectors value:editAction value:nil.
^ self.
].
].
@@ -3601,14 +3617,80 @@
].
].
- editAction := self editActionToReplaceNode:node byWordIn:suggestions.
- actionBlock value:suggestionsWithInfo value:editAction value:nil.
+ editActions := suggestionsWithInfo collect:[:word |
+ self editActionToReplaceNode:node by:word.
+ ].
+ actionBlock value:suggestionsWithInfo value:editActions value:nil.
"Created: / 10-11-2006 / 13:16:33 / cg"
"Modified: / 16-02-2010 / 10:13:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 01-05-2016 / 18:45:07 / cg"
!
+editActionToInsert:aString
+ ^ [:index |
+ codeView
+ undoableDo:[
+ codeView insertSelectedStringAtCursor:aString.
+ codeView dontReplaceSelectionOnInput
+ ]
+ info:'Completion'.
+ ].
+!
+
+editActionToInsertFromSuggestions:suggestions
+ ^ [:index |
+ |answer|
+
+ answer := suggestions at:index.
+ codeView
+ undoableDo:[
+ codeView insertSelectedStringAtCursor:answer.
+ codeView dontReplaceSelectionOnInput
+ ]
+ info:'Completion'.
+ ].
+!
+
+editActionToReplaceCodeFrom:start to:stop by:aString
+ ^ [:index |
+ |oldVar oldLen newLen insertWithSpace|
+
+ insertWithSpace := false.
+
+ start <= stop ifTrue:[
+ oldVar := (codeView textFromCharacterPosition:start to:stop) asString string withoutSeparators.
+ ] ifFalse:[
+ codeView characterBeforeCursor == Character space ifTrue:[
+ insertWithSpace := true.
+ ].
+ ].
+
+ oldLen := stop - start + 1.
+ newLen := aString size.
+
+ codeView
+ undoableDo:[
+ insertWithSpace ifTrue:[
+ codeView insertSelectedStringAtCursor:aString
+ ] ifFalse:[
+ codeView replaceFromCharacterPosition:start to:stop with:aString.
+
+ (aString startsWith:oldVar) ifTrue:[
+ codeView selectFromCharacterPosition:start+oldLen to:start+newLen-1.
+ ] ifFalse:[
+ codeView selectFromCharacterPosition:start to:start+newLen-1.
+ ].
+ ].
+ codeView dontReplaceSelectionOnInput
+ ]
+ info:'Completion'.
+
+ ].
+
+ "Created: / 01-05-2016 / 18:47:40 / cg"
+!
+
editActionToReplaceCodeFrom:start to:stop byWordIn:suggestions
^ [:index |
|answer oldVar oldLen newLen insertWithSpace|
@@ -3649,6 +3731,12 @@
"Created: / 01-05-2016 / 18:47:40 / cg"
!
+editActionToReplaceNode:node by:word
+ ^ self editActionToReplaceCodeFrom:node start to:node stop by:word
+
+ "Created: / 01-05-2016 / 18:44:09 / cg"
+!
+
editActionToReplaceNode:node byWordIn:suggestions
^ self editActionToReplaceCodeFrom:node start to:node stop byWordIn:suggestions
@@ -3965,66 +4053,63 @@
|optionalExtraSpace|
optionalExtraSpace := (codeView characterAfterCursor isSeparator)
- ifTrue:['']
- ifFalse:[' '].
+ ifTrue:['']
+ ifFalse:[' '].
(
- #(
- 'ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:'
- 'and:' 'or:' 'timesRepeat:' 'whileTrue:' 'whileFalse:'
- ) includes:chosenCompletion
+ #(
+ 'ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:'
+ 'and:' 'or:' 'timesRepeat:' 'whileTrue:' 'whileFalse:'
+ ) includes:chosenCompletion
) ifTrue:[
- codeView insertStringAtCursor:('[',optionalExtraSpace).
- "/ codeView cursorLeft:1+extra size.
+ codeView insertStringAtCursor:('[',optionalExtraSpace,']').
+ "/ codeView cursorLeft:1+extra size.
].
(
- #(
- 'collect:' 'select:' 'reject:' 'do:'
- ) includes:chosenCompletion
+ #(
+ 'collect:' 'select:' 'reject:' 'do:'
+ ) includes:chosenCompletion
) ifTrue:[
- codeView insertStringAtCursor:('[:each | ]',optionalExtraSpace).
- codeView cursorLeft:1+optionalExtraSpace size.
+ codeView insertStringAtCursor:('[:each | ]',optionalExtraSpace).
+ codeView cursorLeft:1+optionalExtraSpace size.
].
(
- #(
- 'contains:' 'findFirst:' 'detect:'
- ) includes:chosenCompletion
+ #(
+ 'contains:' 'findFirst:' 'detect:'
+ ) includes:chosenCompletion
) ifTrue:[
- codeView insertStringAtCursor:('[:some | ]',optionalExtraSpace).
- codeView cursorLeft:1+optionalExtraSpace size.
+ codeView insertStringAtCursor:('[:some | ]',optionalExtraSpace).
+ codeView cursorLeft:1+optionalExtraSpace size.
].
(
- #(
- 'remove:ifAbsent:' 'detect:ifNone:'
- ) includes:chosenCompletion
+ #(
+ 'remove:ifAbsent:' 'detect:ifNone:'
+ ) includes:chosenCompletion
) ifTrue:[
- codeView insertStringAtCursor:('[]',optionalExtraSpace).
- codeView cursorLeft:1+optionalExtraSpace size.
+ codeView insertStringAtCursor:('[]',optionalExtraSpace).
+ codeView cursorLeft:1+optionalExtraSpace size.
].
!
messagesSentTo:varName in:aTree
- |messagesToReceiver|
-
- "/ collect messages sent
- messagesToReceiver := Set new.
- "/ remembered nodes is nonNil if parser aborte with error
- rememberedNodes notNil ifTrue:[
- rememberedNodes do:[:node |
+ |messagesToReceiver collector|
+
+ collector :=
+ [:node |
(node isMessage
and:[node receiver isVariable
and:[node receiver name = varName]]) ifTrue:[
messagesToReceiver add:(node selector)
].
].
+
+ "/ collect messages sent
+ messagesToReceiver := Set new.
+ "/ remembered nodes is nonNil if parser aborted with error
+ rememberedNodes notNil ifTrue:[
+ rememberedNodes do:collector.
] ifFalse:[
- tree allMessageNodesDo:[:node |
- (node isMessage
- and:[node receiver isVariable
- and:[node receiver name = varName]]) ifTrue:[
- messagesToReceiver add:node selector
- ]
- ].
+ tree allMessageNodesDo:collector.
].
^ messagesToReceiver
!
@@ -4363,6 +4448,64 @@
Transcript cr.
].
+ "/ if in a keyword-argument position...
+ node isMessage ifTrue:[
+ "/ where are we?
+ node selector isKeyword ifTrue:[
+ characterBeforeCursor == $: ifTrue:[
+ |argIdx senders implementors receiverClasses selectorUpToCursor implementorOfSelectorUpToCursor|
+ "/ about to enter an argument?
+ argIdx := node selectorParts keysAndValuesDetectKey:[:idx :part |
+ part stop == (codeView characterPositionOfCursor-1).
+ ] ifNone:nil.
+ argIdx notNil ifTrue:[
+ selectorUpToCursor := ((node selectorParts collect:#value) copyTo:argIdx) asStringWith:''.
+ implementors := Set new.
+ "/ find senders of this message, and see if they call it with a block argument
+ "/ this takes too long for a completion;
+ "/ Smalltalk allClassesDo:[:cls |
+ "/ cls instAndClassMethodsDo:[:m |
+ "/ (m sendsMessageForWhich:[:sel | sel startsWith:node selector]) ifTrue:[
+ "/ senders add:m
+ "/ ].
+ "/ ]
+ "/ ].
+ "/ therefore, restrict to a max. of 5 classes
+ receiverClasses := self classesOfNode:node receiver.
+ (receiverClasses notEmptyOrNil and:[receiverClasses size <= 5]) ifTrue:[
+ receiverClasses do:[:eachPossibleReceiverClass |
+ eachPossibleReceiverClass withAllSuperclassesDo:[:cls |
+ cls methodDictionary keysAndValuesDo:[:sel :mthd |
+ (sel startsWith:selectorUpToCursor) ifTrue:[
+ implementors add:mthd.
+ (sel = selectorUpToCursor) ifTrue:[
+ implementorOfSelectorUpToCursor := implementorOfSelectorUpToCursor ? mthd
+ ].
+ ].
+ ].
+ ]
+ ]
+ ].
+ implementorOfSelectorUpToCursor notNil ifTrue:[
+ |tree argName|
+
+ tree := implementorOfSelectorUpToCursor parseTree.
+ argName := tree argumentNames at:argIdx.
+ (argName includesString:'block' caseSensitive:false) ifTrue:[
+ actionBlock value:{'[ "',argName,'" ]'}
+ value:{ self editActionToInsert:('[ "',argName,'" ]') }
+ value:'block argument'
+ ].
+ ] ifFalse:[
+ implementors notEmpty ifTrue:[
+ self halt.
+ ].
+ ].
+ ].
+ ].
+ ].
+ ].
+
(node isVariable or:[node isBlock and:[node stop notNil]]) ifTrue:[
(characterPositionOfCursor == (node stop + 1)
"/ hack (spaces at end of line)
@@ -4515,8 +4658,50 @@
!DoWhatIMeanSupport methodsFor:'code completion-helpers-naive type inference'!
+addClassesFromAssignmentTo:varName in:aTree to:setOfTypes
+ "/ assignments...
+ aTree allAssignmentNodesDo:[:eachAssignmentNode |
+ |exprCls leftSide|
+
+ leftSide := eachAssignmentNode variable.
+ leftSide name = varName ifTrue:[
+ exprCls := self classOfNode:eachAssignmentNode value.
+ exprCls notNil ifTrue:[
+ setOfTypes add:exprCls
+ ]
+ ]
+ ].
+ ^ setOfTypes.
+!
+
+addClassesOfBlockVar:variableNode inScope:blockScope to:setOfTypes
+ |blockParent|
+
+ blockParent := blockScope parent.
+ (blockParent notNil and:[blockParent isMessage]) ifFalse:[^ setOfTypes].
+
+ "/ if the parent of the block is an enumeration message, and the receiver is known,
+ "/ we know the type of argument.
+ ( #(do: keysAndValuesDo: select: collect:) includes:blockParent selector) ifTrue:[
+ |collection|
+
+ collection := self valueOfNode:blockParent receiver.
+ collection notNil ifTrue:[
+ (collection isKindOf:Collection) ifTrue:[
+ collection notEmpty ifTrue:[
+ |someElement|
+ someElement := collection anElement.
+ setOfTypes add:someElement class.
+ ^ setOfTypes
+ ].
+ ].
+ ].
+ ].
+ ^ setOfTypes
+!
+
addClassesOfExpression:expr inClass:classOrNil to:setOfTypes
- |cls exprSelector exprVal varName instVarClass valClass
+ |cls exprSelector exprVal varName varScope instVarClass valClass
msgSelector msgReceiver msgArg1
receiverClasses receiverClass
arg1Classes mthd|
@@ -4527,47 +4712,59 @@
(exprVal isArray or:[ exprVal isByteArray or:[ exprVal isString ]]) ifTrue:[
exprVal isImmutable ifTrue:[
setOfTypes add:cls mutableClass.
- ^ self.
+ ^ setOfTypes.
]
].
setOfTypes add:cls.
- ^ self.
+ ^ setOfTypes.
].
expr isBlock ifTrue:[
setOfTypes add:Block.
- ^ self.
+ ^ setOfTypes.
].
(exprVal := self valueOfNode:expr) notNil ifTrue:[
"/ knowing the value is always great!!
setOfTypes add:exprVal class.
- ^ self.
+ ^ setOfTypes.
].
expr isVariable ifTrue:[
varName := expr name.
varName = 'self' ifTrue:[
setOfTypes add:(classOrNil ? UndefinedObject).
- ^ self
+ ^ setOfTypes
].
varName = 'super' ifTrue:[
classOrNil isNil
ifTrue:[setOfTypes add:Object]
ifFalse:[setOfTypes add:classOrNil superclass].
- ^ self.
+ ^ setOfTypes.
].
varName = 'thisContext' ifTrue:[
setOfTypes add:Context.
- ^ self
+ ^ setOfTypes
].
-
+
+ varScope := expr whoDefines: varName.
+ (varScope notNil) ifTrue:[
+ (varScope isBlock) ifTrue:[
+ self addClassesOfBlockVar:expr inScope:varScope to:setOfTypes.
+ ^ setOfTypes
+ ].
+ (varScope isMethod) ifTrue:[
+ setOfTypes addAll:( self classesFromAssignmentTo:varName in:varScope ).
+ ^ setOfTypes
+ ].
+ ].
+
classOrNil notNil ifTrue:[
instVarClass := classOrNil whichClassDefinesInstVar:varName.
instVarClass notNil ifTrue:[
setOfTypes addAll:(self classesOfInstVarNamed:varName inClass:instVarClass).
].
].
- ^ self
+ ^ setOfTypes
].
expr isMessage ifTrue:[
@@ -4586,7 +4783,7 @@
) includes:msgSelector
) ifTrue:[
setOfTypes add:True. "/ use True, because boolean does not include the full protocol
- ^ self
+ ^ setOfTypes
].
msgReceiver := expr receiver.
@@ -4598,20 +4795,20 @@
receiverClass notNil ifTrue:[
( #(copy shallowCopy) includes:exprSelector ) ifTrue:[
setOfTypes addAll:receiverClasses.
- ^ self.
+ ^ setOfTypes.
].
msgSelector == #theNonMetaclass ifTrue:[
setOfTypes add:receiverClass theNonMetaclass class.
- ^ self
+ ^ setOfTypes
].
msgSelector == #theMetaclass ifTrue:[
setOfTypes add:receiverClass theMetaclass class.
- ^ self
+ ^ setOfTypes
].
msgSelector == #class ifTrue:[
setOfTypes add:receiverClass class.
- ^ self.
+ ^ setOfTypes.
].
receiverClass isBehavior ifTrue:[
@@ -4619,20 +4816,20 @@
receiverClass isMeta ifTrue:[
( #( #'new' #'basicNew' #'new:' #'basicNew:' #'with:' #'with:with:') includes: msgSelector ) ifTrue:[
setOfTypes add:receiverClass theNonMetaclass.
- ^ self.
+ ^ setOfTypes.
].
"/ if that method sends one of new/basicNew/new:/basicNew:, assume it returns an instance of itself
mthd notNil ifTrue:[
( mthd sendsAny:#( #'new' #'basicNew' #'new:' #'basicNew:' )) ifTrue:[
setOfTypes add:receiverClass theNonMetaclass.
- ^ self
+ ^ setOfTypes
].
].
] ifFalse:[
mthd notNil ifTrue:[
(ParseTreeSearcher methodIsSetterMethod:mthd) ifTrue:[
setOfTypes add:receiverClass.
- ^ self
+ ^ setOfTypes
]
]
]
@@ -4643,14 +4840,14 @@
and:[ (valClass := Smalltalk classNamed:(msgSelector copyFrom:3)) notNil ]
) ifTrue:[
setOfTypes add:valClass.
- ^ self
+ ^ setOfTypes
].
((msgSelector startsWith:'is')
and:[ (valClass := Smalltalk classNamed:(msgSelector copyFrom:3)) notNil ]
) ifTrue:[
setOfTypes add:True. "/ Boolean - not boolean; it does not contain the full protocol (would not find ifTrue:)
- ^ self.
+ ^ setOfTypes.
].
#(
@@ -4665,7 +4862,7 @@
) pairWiseDo:[:sel :clsName |
msgSelector == sel ifTrue:[
setOfTypes add:(Smalltalk at:clsName).
- ^ self.
+ ^ setOfTypes.
].
].
@@ -4673,74 +4870,39 @@
"/ assume integer
setOfTypes add:Integer.
- ^ self
+ ^ setOfTypes
].
( #( + - * // \\ ) includes:msgSelector) ifTrue:[
"/ assume numeric
setOfTypes add:Number.
- ^ self
+ ^ setOfTypes
].
msgSelector == #/ ifTrue:[
((receiverClasses ? #()) contains:[:cls | cls includesBehavior:Number]) ifTrue:[
setOfTypes add:Number.
- ^ self.
+ ^ setOfTypes.
].
msgArg1 := expr arg1.
arg1Classes := ((self classesOfNode:msgArg1) ? #()).
(arg1Classes contains:[:cls | cls includesBehavior:Number]) ifTrue:[
setOfTypes add:Number.
- ^ self
+ ^ setOfTypes
].
].
( #( construct: / ) includes:msgSelector) ifTrue:[
((receiverClasses ? #()) contains:[:cls | cls includesBehavior:Filename]) ifTrue:[
setOfTypes add:Filename.
- ^ self
+ ^ setOfTypes
].
].
].
- ^ nil
+ ^ setOfTypes
!
-classOfNode:aNode
- "returns the class of a receiver, if it is well-known.
- Otherwise nil (either unknown, or multiple possibilities)
- When showing possible completions for a message,
- it is a good idea to know what the kind receiver is."
-
- | classes |
-
- classes := self classesOfNode:aNode.
- classes size == 1 ifTrue:[
- ^ classes anElement
- ].
- ^ nil
-!
-
-classesFromAssignmentTo:varName in:aTree
- |classesFromAssignments|
+addClassesOfInstVarNamed:varName inClass:aClass to:setOfTypes
+ |instIndex|
- classesFromAssignments := Set new.
- "/ assignments...
- aTree allAssignmentNodesDo:[:eachAssignmentNode |
- |exprCls leftSide|
-
- leftSide := eachAssignmentNode variable.
- leftSide name = varName ifTrue:[
- exprCls := self classOfNode:eachAssignmentNode value.
- exprCls notNil ifTrue:[
- classesFromAssignments add:exprCls
- ]
- ]
- ].
- ^ classesFromAssignments.
-!
-
-classesOfInstVarNamed:varName inClass:aClass
- |setOfTypes instIndex|
-
- setOfTypes := IdentitySet new.
instIndex := aClass instVarIndexFor:varName.
"/ look for instances
@@ -4810,23 +4972,42 @@
^ setOfTypes
!
+classOfNode:aNode
+ "returns the class of a receiver, if it is well-known.
+ Otherwise nil (either unknown, or multiple possibilities)
+ When showing possible completions for a message,
+ it is a good idea to know what the kind receiver is."
+
+ | classes |
+
+ classes := self classesOfNode:aNode.
+ classes size == 1 ifTrue:[
+ ^ classes anElement
+ ].
+ ^ nil
+!
+
+classesFromAssignmentTo:varName in:aTree
+ ^ self addClassesFromAssignmentTo:varName in:aTree to:IdentitySet new
+!
+
+classesOfInstVarNamed:varName inClass:aClass
+ ^ self addClassesOfInstVarNamed:varName inClass:aClass to:(IdentitySet new)
+!
+
classesOfNode:aNode
- "returns the set of possible classes of a receiver.
+ "returns the set of possible classes of a parsenode.
or nil if unknown.
When showing possible completions for a message,
it is a good idea to know what the kind receiver is."
- | setOfTypes|
-
- setOfTypes := Set new.
- self addClassesOfExpression:aNode inClass:classOrNil to:setOfTypes.
- ^ setOfTypes
+ ^ self addClassesOfExpression:aNode inClass:classOrNil to:(IdentitySet new).
!
valueAndKindOfVariable:aVariableName
"when showing possible completions for a variable,
it is a good idea to know what the reveiver's value is.
- Sigh - returns nil both if unknown AND if a real nil is there."
+ Sigh - returns nil as value both if unknown AND if a real nil is there"
|nodeVal con privateClass pool|
@@ -4868,7 +5049,8 @@
aVariableName = 'self' ifTrue:[
(classOrNil notNil and:[classOrNil isMeta]) ifTrue:[
- ^ { classOrNil theNonMetaclass . #pseudoVar }
+ ^ { classOrNil "theNonMetaclass" . #pseudoVar }
+ "/ ^ { classOrNil . #pseudoVar }
].
contextOrNil notNil ifTrue:[
^ { contextOrNil receiver . #pseudoVar }
@@ -4877,6 +5059,7 @@
].
contextOrNil notNil ifTrue:[
+ "/ in the debugger, we know more
con := contextOrNil.
[ con notNil ] whileTrue:[
"/ a local in the context?