--- a/.hgtags Fri Apr 29 06:55:47 2016 +0200
+++ b/.hgtags Sat Apr 30 06:46:08 2016 +0200
@@ -14,6 +14,7 @@
51c444bfe5aeba5196e667b3c3834a96c27ca1f1 rel3_6_1
532a328a9e0ec5da47acb16cdfeebebeed480c14 expecco_1_9_1_iX
58b910fe451351b6f40e4ef2e5706a1f4ac486d7 expeccoALM_1_9_0_1
+5afe663f6f8d96274ec7809078c755d184e8125a expecco_2_9_0
5cbf651bb214a2028e31d36a9d89eb2ed18e6f18 expecco_1_5_0
5ea9411aaac82ef8a744a3dcdacb10d47f5523a2 expecco_1_7_1rc1
5ea9411aaac82ef8a744a3dcdacb10d47f5523a2 expecco_1_7_1rc2
--- a/DoWhatIMeanSupport.st Fri Apr 29 06:55:47 2016 +0200
+++ b/DoWhatIMeanSupport.st Sat Apr 30 06:46:08 2016 +0200
@@ -1702,40 +1702,131 @@
!
classOfNode:aNode
- "when showing possible completions for a message,
+ "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."
- | nm nodeVal receiverClass nodeSelector nodeReceiver mthd|
+ | classes |
+
+ classes := self classesOfNode:aNode.
+ classes size == 1 ifTrue:[
+ ^ classes anElement
+ ].
+ ^ nil
+!
+
+classesOfInstVarNamed:varName inClass:aClass
+ |setOfTypes instIndex|
+
+ setOfTypes := IdentitySet new.
+ instIndex := aClass instVarIndexFor:varName.
+
+ "/ look for instances
+ aClass allSubInstancesDo:[:i |
+ |varClass|
+ varClass := (i instVarAt:instIndex) class.
+ setOfTypes add:varClass.
+ ].
+
+ "/ look for assignments in code
+ aClass withAllSubclassesDo:[:eachClass |
+ eachClass methodDictionary do:[:m |
+ |tree code visitor|
+
+ "/ quick check
+ code := m source.
+ (code notNil and:[code includesString:varName]) ifTrue:[
+ tree := Parser parse:code class:eachClass.
+ (tree notNil and:[tree ~~ #Error]) ifTrue:[
+ visitor := PluggableParseNodeVisitor new.
+ visitor
+ actionForNodeClass:AssignmentNode
+ put:[:node |
+ |val|
+
+ node variable name = varName ifTrue:[
+ "/ only look for wellknown types on the right side.
+ node expression isConstant ifTrue:[
+ val := node expression evaluate.
+ val isArray ifTrue:[
+ setOfTypes add:Array
+ ] ifFalse:[
+ setOfTypes add:val class
+ ].
+ ] ifFalse:[
+ node expression isMessage ifTrue:[
+ ( #(+ - * /) includes:node expression selector ) ifTrue:[
+ setOfTypes add:Number
+ ] ifFalse:[
+ ( #(// size) includes:node expression selector ) ifTrue:[
+ setOfTypes add:Integer
+ ] ifFalse:[
+ ( #(copy shallowCopy) includes:node expression selector ) ifTrue:[
+ ] ifFalse:[
+ ( #(new new: basicNew basicNew:) includes:node expression selector ) ifTrue:[
+ node expression receiver isGlobal ifTrue:[
+ setOfTypes add:node expression receiver evaluate
+ ].
+ ] ifFalse:[
+self breakPoint:#cg.
+ ]
+ ]
+ ]
+ ]
+ ].
+ ].
+ ].
+ true "/ yes - visit subnodes
+ ].
+ visitor visit:tree.
+ ].
+ ]
+ ]
+ ].
+ ^ setOfTypes
+!
+
+classesOfNode:aNode
+ "returns the set of possible classes of a receiver.
+ or nil if unknown.
+ When showing possible completions for a message,
+ it is a good idea to know what the kind receiver is."
+
+ | nm nodeVal receiverClass nodeSelector nodeReceiver mthd instVarClass|
aNode isBlock ifTrue:[
- ^ Block
+ ^ { Block }
].
-
(nodeVal := self valueOfNode:aNode) notNil ifTrue:[
"/ knowing the value is always great!!
- ^ nodeVal class
+ ^ { nodeVal class }
].
aNode isVariable ifTrue:[
nm := aNode name.
nm = 'self' ifTrue:[
- classOrNil isNil ifTrue:[^ UndefinedObject].
- ^ classOrNil
+ classOrNil isNil ifTrue:[^ { UndefinedObject } ].
+ ^ { classOrNil }
].
nm = 'super' ifTrue:[
classOrNil isNil ifTrue:[^ Object].
- ^ classOrNil superclass
+ ^ { classOrNil superclass }
].
nm = 'thisContext' ifTrue:[
- ^ Context
+ ^ { Context }
].
-"/ classOrNil notNil ifTrue:[
+ classOrNil notNil ifTrue:[
+ instVarClass := classOrNil whichClassDefinesInstVar:nm.
+ instVarClass notNil ifTrue:[
+ ^ self classesOfInstVarNamed:nm inClass:instVarClass.
+ ].
"/ (classOrNil allInstVarNames includes:nm) ifTrue:[
"/ "/ could look at existing instances here...
"/ self breakPoint:#cg.
"/ ].
-"/ ].
+ ].
^ nil
].
@@ -1747,25 +1838,25 @@
receiverClass := self classOfNode:nodeReceiver.
receiverClass notNil ifTrue:[
nodeSelector == #class ifTrue:[
- ^ receiverClass class
+ ^ { receiverClass class }
].
receiverClass isBehavior ifTrue:[
mthd := receiverClass lookupMethodFor:nodeSelector.
receiverClass isMeta ifTrue:[
( #( #'new' #'basicNew' #'new:' #'basicNew:' #'with:' #'with:with:') includes: nodeSelector ) ifTrue:[
- ^ receiverClass theNonMetaclass
+ ^ { receiverClass theNonMetaclass }
].
"/ 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:[
- ^ receiverClass theNonMetaclass
+ ^ { receiverClass theNonMetaclass }
].
].
] ifFalse:[
mthd notNil ifTrue:[
(ParseTreeSearcher methodIsSetterMethod:mthd) ifTrue:[
- ^ receiverClass.
+ ^ { receiverClass }.
]
]
]
@@ -1773,24 +1864,24 @@
].
classOrNil notNil ifTrue:[
(nodeReceiver isSelf and:[nodeSelector = #'class']) ifTrue:[
- ^ classOrNil class
+ ^ { classOrNil class }
].
].
(nodeSelector = #'asFilename') ifTrue:[
- ^ Filename
+ ^ { Filename }
].
(nodeSelector = #'asOrderedCollection') ifTrue:[
- ^ OrderedCollection
+ ^ { OrderedCollection }
].
(nodeSelector = #'asArray') ifTrue:[
- ^ Array
+ ^ { Array }
].
(nodeSelector = #'asSet') ifTrue:[
- ^ Set
+ ^ { Set }
].
(nodeSelector = #'size') ifTrue:[
- ^ SmallInteger
+ ^ { SmallInteger }
].
"/ some wellknown boolean returners (need better type inference here)
@@ -1801,22 +1892,20 @@
and: or:
exists atEnd
) includes:nodeSelector ) ifTrue:[
- ^ True "/ Boolean - not boolean; it does not contain the full protocol (would not find ifTrue:)
+ ^ { True } "/ Boolean - not boolean; it does not contain the full protocol (would not find ifTrue:)
].
( #( + - * / // \\ ) includes:nodeSelector) ifTrue:[
"/ assume numeric
- ^ Number
+ ^ { Number }
].
( #( class theMetaclass theNonMetaclass ) includes:nodeSelector) ifTrue:[
"/ assume behavior
- ^ Behavior
+ ^ { Behavior }
].
].
^ nil
-
- "Created: / 28-08-2013 / 16:34:53 / cg"
!
codeCompletionForLiteralSymbol:nodeOrNil element:tokenOrNil considerAll:considerAll into:actionBlock
@@ -1957,12 +2046,12 @@
findBest :=
[:node :selector |
- |srchClass srchClasses bestSelectors bestPrefixes
+ |srchClasses bestSelectors bestPrefixes
allMessagesSentToVariable classesImplementingAllMessages|
- srchClass := self classOfNode:node.
-
- srchClass isNil ifTrue:[
+ srchClasses := self classesOfNode:node.
+
+ srchClasses isEmptyOrNil ifTrue:[
node isVariable ifTrue:[
allMessagesSentToVariable := Set new.
rememberedNodes do:[:eachNode |
@@ -1990,16 +2079,19 @@
].
].
bestSelectors := Set new.
- srchClasses isEmptyOrNil ifTrue:[ srchClasses := Array with:srchClass ].
- srchClasses do:[:srchClass |
- |bestForThisClass|
-
- bestForThisClass := Parser findBest:50 selectorsFor:selector in:srchClass forCompletion:true.
- bestForThisClass := self
- withoutSelectorsUnlikelyFor:srchClass
- from:bestForThisClass
- forPartial:selector.
- bestSelectors addAll:bestForThisClass.
+ srchClasses isEmptyOrNil ifTrue:[
+ bestSelectors addAll:( Parser findBest:50 selectorsFor:selector in:nil forCompletion:true ).
+ ] ifFalse:[
+ srchClasses do:[:srchClass |
+ |bestForThisClass|
+
+ bestForThisClass := Parser findBest:50 selectorsFor:selector in:srchClass forCompletion:true.
+ bestForThisClass := self
+ withoutSelectorsUnlikelyFor:srchClass
+ from:bestForThisClass
+ forPartial:selector.
+ bestSelectors addAll:bestForThisClass.
+ ].
].
(bestSelectors includes:selector) ifTrue:[
bestSelectors := bestSelectors select:[:sel | sel size > selector size].
@@ -2267,16 +2359,28 @@
allBest sort:
[:a :b |
|aBeforeB|
- aBeforeB := a < b.
- (a asLowercase startsWith:lcSelector) ifTrue:[
- (b asLowercase startsWith:lcSelector) ifFalse:[
+
+ (a startsWith:selector) ifTrue:[
+ (b startsWith:selector) ifFalse:[
aBeforeB := true
]
] ifFalse:[
- (b asLowercase startsWith:lcSelector) ifTrue:[
+ (b startsWith:selector) ifTrue:[
aBeforeB := false
]
].
+ aBeforeB isNil ifTrue:[
+ aBeforeB := a asLowercase < b asLowercase.
+ (a asLowercase startsWith:lcSelector) ifTrue:[
+ (b asLowercase startsWith:lcSelector) ifFalse:[
+ aBeforeB := true
+ ]
+ ] ifFalse:[
+ (b asLowercase startsWith:lcSelector) ifTrue:[
+ aBeforeB := false
+ ]
+ ].
+ ].
aBeforeB
].
@@ -3850,18 +3954,53 @@
characterBeforeCursor == $. ifTrue:[ "at end of statement" ^ self].
node isVariable ifTrue:[
+ |classes cls|
+
nodeIsInTemporaries :=
nodeParent notNil
and:[ nodeParent isSequence
and:[ nodeParent temporaries notEmptyOrNil
and:[ node stop <= nodeParent temporaries last stop ]]].
+
nodeIsInTemporaries ifFalse:[
"/ cursor must be right after the variable
- characterPositionOfCursor >= (node stop) ifTrue:[
+ codeView characterPositionOfCursor = (node stop + 1) ifTrue:[
self codeCompletionForVariable:node into:actionBlock.
+ ^ self.
]
].
- ^ self.
+false ifTrue:[
+ codeView characterPositionOfCursor = (node stop + 2) ifTrue:[
+ "/ after a variable;
+ "/ offer local messages, if receiver type is known
+ classes := (self classesOfNode:node).
+ classes notEmptyOrNil ifTrue:[
+ classes size > 1 ifTrue:[
+ cls := classes anElement.
+ ] ifFalse:[
+ cls := Behavior commonSuperclassOf:classes.
+ ]
+ ].
+ cls notNil ifTrue:[
+ |clsSelectors moreSelectors|
+
+ "/ completion in a message-send
+ clsSelectors := cls methodDictionary keys. "/ Parser findBest:50 selectorsFor:'' in:cls forCompletion:true.
+ clsSelectors size < 30 ifTrue:[
+ cls superclass notNil ifTrue:[
+ moreSelectors := cls superclass methodDictionary keys.
+ clsSelectors size + moreSelectors size < 30 ifTrue:[
+ clsSelectors := clsSelectors , moreSelectors.
+ ].
+ ].
+ ].
+ "/ self codeCompletionForMessage:checkedNode into:actionBlock.
+ actionBlock value:clsSelectors value:nil value:nil.
+ ^ self.
+ ]
+ ]
+].
+^ self
].
node isLiteral ifTrue:[
@@ -4258,12 +4397,15 @@
].
findBest := [:node :selector |
- |srchClass bestSelectors bestPrefixes|
+ |srchClasses bestSelectors bestPrefixes|
codeView withCursor:(Cursor questionMark) do:[
- srchClass := self classOfNode:node receiver.
- srchClass notNil ifTrue:[
- bestSelectors := Parser findBest:30 selectorsFor:selector in:srchClass forCompletion:true.
+ srchClasses := self classesOfNode:node receiver.
+ srchClasses notNil ifTrue:[
+ bestSelectors := Set new.
+ srchClasses do:[:each |
+ bestSelectors addAll:(Parser findBest:30 selectorsFor:selector in:each forCompletion:true).
+ ]
] ifFalse:[
bestSelectors := Parser findBest:30 selectorsFor:selector in:nil forCompletion:true.
].