SmallSense__SmalltalkCompletionEngine.st
changeset 233 fb33bd6466a4
parent 212 a2caebc602a7
parent 229 c82a22d2153d
child 234 97857872ee47
--- a/SmallSense__SmalltalkCompletionEngine.st	Mon May 19 16:57:14 2014 +0100
+++ b/SmallSense__SmalltalkCompletionEngine.st	Thu May 22 16:15:30 2014 +0100
@@ -3,7 +3,7 @@
 "{ NameSpace: SmallSense }"
 
 CompletionEngine subclass:#SmalltalkCompletionEngine
-	instanceVariableNames:'inferencer'
+	instanceVariableNames:'collector'
 	classVariableNames:'Debug'
 	poolDictionaries:''
 	category:'SmallSense-Smalltalk'
@@ -43,33 +43,58 @@
 
 !SmalltalkCompletionEngine class methodsFor:'utilities'!
 
-resultSetFor: mode source: source class: class line: line column: col 
+resultSetFor: mode source: source class: class line: line column: col
     | inferencer tree |
 
     mode == #method ifTrue:[
         inferencer := SmalltalkInferencer forClass: class methodSource: source asString.
         inferencer parserClass: SmalltalkParser.
+        inferencer process.
     ] ifFalse:[
         self breakPoint: #jv.
         ^nil.
         inferencer := Parser for: (source asString readStream).
         "JV@2011-06-13: HACK, use polymorphism"
         tree := inferencer
-            parseExpressionWithSelf:nil 
-            notifying:nil 
-            ignoreErrors:false 
-            ignoreWarnings:false 
+            parseExpressionWithSelf:nil
+            notifying:nil
+            ignoreErrors:false
+            ignoreWarnings:false
             inNameSpace:nil.
         inferencer tree: tree.
     ].
     ^ self new
         completeAtLine:line
         column:col
-        inferencer:inferencer
+        collector:inferencer
 
     "Modified: / 07-04-2011 / 22:55:58 / Jakub <zelenja7@fel.cvut.cz>"
     "Created: / 26-11-2011 / 17:53:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 13-05-2014 / 12:29:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 02-09-2013 / 14:43:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 02-10-2013 / 13:09:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!SmalltalkCompletionEngine methodsFor:'completion-helpers'!
+
+javaClassesDo: aBlock
+    | class loader loaders |
+
+    class := collector klass.
+    loaders := Set new.
+    loader := (class notNil and:[class isJavaClass]) ifTrue:[class classLoader] ifFalse:[JavaVM systemClassLoader].
+    [ loader notNil ] whileTrue:[
+        loaders add: loader.
+        loader := loader instVarNamed: #parent.
+    ].
+    loaders add: nil.
+
+    JavaVM registry  classesDo:[:cls|
+        (loaders includes: cls classLoader) ifTrue:[
+            aBlock value: cls.
+        ].
+    ].
+
+    "Created: / 04-10-2013 / 13:10:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SmalltalkCompletionEngine methodsFor:'completion-individual'!
@@ -77,7 +102,7 @@
 addClassVariables
     | class |
 
-    class := inferencer klass theNonMetaclass.
+    class := collector klass theNonMetaclass.
     class classVarNames do:[:nm|
         result add:(VariablePO classVariable: nm in: class).
     ].
@@ -89,7 +114,7 @@
 addGlobalsStartingWith: prefix
 
     | class ns cls environment |
-    class := inferencer klass.
+    class := collector klass.
     ns := class nameSpace.
     environment := context environment.
     "nameSpace may return private class, sigh"
@@ -99,10 +124,10 @@
             cls := ns classNamed: nm.
             (cls notNil and:[cls name = nm]) ifTrue:[
                 (JavaPackage isNil or:[cls isJavaPackage not]) ifTrue:[
-                    result add:(ClassPO new subject: cls; showPrefix: cls isJavaClass).
+                    result add:(((PO forClass: cls)) showPrefix: cls isJavaClass).
                 ]
             ] ifFalse:[
-                (self isGlobalKeyForClassVariable: nm) ifFalse:[  
+                (self isGlobalKeyForClassVariable: nm) ifFalse:[
                     result add:(VariablePO globalVariable: nm)
                 ].
             ].
@@ -115,9 +140,9 @@
                 (JavaPackage isNil or:[cls isJavaPackage not ]) ifTrue:[
                     cls notNil ifTrue:[
                         cls isBehavior ifTrue:[
-                            result add:(ClassPO new subject: cls; showPrefix: cls isJavaClass).
+                            result add:(((PO forClass: cls)) showPrefix: cls isJavaClass).
                         ] ifFalse:[
-                            (self isGlobalKeyForClassVariable: nm) ifFalse:[  
+                            (self isGlobalKeyForClassVariable: nm) ifFalse:[
                                 result add:(VariablePO globalVariable: nm).
                             ].
                         ]
@@ -128,13 +153,135 @@
     ]
 
     "Created: / 26-11-2011 / 17:29:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 13-05-2014 / 12:09:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-05-2014 / 09:58:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addJavaClassesInPackage: prefix
+    prefix isEmptyOrNil ifTrue:[
+        self javaClassesDo: [:cls |
+            result add: (ClassPO new klass: cls; showPrefix: true; yourself)
+        ].
+    ] ifFalse:[
+        self javaClassesDo: [:cls |
+            (cls binaryName startsWith: prefix) ifTrue:[
+                result add: (ClassPO new klass: cls; showPrefix: true; yourself)
+            ].
+        ].
+
+    ].
+
+    "Created: / 04-10-2013 / 13:09:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-10-2013 / 02:42:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addMethodsForType: type
+    ^ self addMethodsForType: type stripOff: nil
+
+    "Created: / 26-11-2011 / 17:03:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 09-05-2014 / 12:51:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addMethodsForType: type prefix: prefix stripOff: stripprefix
+
+    type isUnknownType ifFalse:[
+        self addMethodsForType:type stripOff: stripprefix.
+
+        "/ If the type is union of more than 6 types, then
+        "/ assume that the inferencer is likely wrong.
+        "/ then, if the prefix is at least 3 chars,
+        "/ also add methods with that prefix.
+
+        ((type classes size > 6) and:[ prefix size > 2 ]) ifTrue:[
+            self addMethodsStartingWith:prefix stripOff: stripprefix
+        ].
+    ] ifTrue:[
+        self addMethodsStartingWith:prefix stripOff: stripprefix
+    ].
+
+    "Created: / 08-04-2014 / 21:04:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 09-04-2014 / 09:31:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addMethodsForType: type stripOff: stripprefix
+    | classes seen selector2classesMap |
+
+    selector2classesMap := Dictionary new.
+    classes := type classes.
+    "/ Hack for Boolean: ifTrue:iFalse: etc are not defined
+    "/ in Boolean ?!!?
+    (classes size == 1 and:[classes anElement == Boolean ]) ifTrue:[
+        classes := Array with: True with: False.
+    ].
+    classes size == 1 ifTrue:[
+        classes anElement == JavaPackage class ifTrue:[
+            "/ Special hack for JAVA: for pattern `JAVA java lang reflect`
+            "/ complete all Java classes in that package
+            | node |
+
+            node := result context node.
+            node isUnaryMessage ifTrue:[
+                | package |
+                "/ Compute package prefix...
+
+                package := node selector.
+                node := node receiver.
+                [ node isUnaryMessage ] whileTrue:[
+                    package := node selector , '/' , package.
+                    node := node receiver.
+                ].
+                self addJavaClassesInPackage: package.
+                ^ self.
+            ]
+        ]
+    ].
+
+    seen := Set new.
+    classes do: [:each |
+        | class selector2classMap |
+
+        class := each.
+        selector2classMap := Dictionary new.
+
+        "/ Now, special care for Java classes, sigh...
+        (class isMetaclass and:[class theNonMetaclass isJavaClass]) ifTrue:[
+            seen add: class.
+            class theNonMetaclass selectorsAndMethodsDo: [:selector :met |
+                met isStatic ifTrue:[
+                    result add: (PO forClass: met mclass selector: selector)
+                ].
+            ].
+        ] ifFalse:[
+            [ class notNil and:[(seen includes: class) not]] whileTrue: [
+                class selectorsAndMethodsDo: [:selector :met |
+                    met isSynthetic ifFalse:[
+                        (stripprefix isNil or:[ selector size > stripprefix size and:[selector startsWith: stripprefix]]) ifTrue:[
+                            selector2classMap at: selector put: class.
+                        ].
+                    ]
+                ].
+                class := class superclass.
+            ]
+        ].
+        selector2classMap keysAndValuesDo:[:selector :class |
+            | classes |
+
+            classes := selector2classesMap at: selector ifAbsentPut: [ Set new ].
+            classes add: class.
+        ]
+    ].
+
+    selector2classesMap keysAndValuesDo: [:selector :classes|
+        result add:(MethodPO forClasses: classes selector: selector prefix: stripprefix)
+    ]
+
+    "Created: / 08-04-2014 / 21:23:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-05-2014 / 10:47:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 addPools
     | class |
 
-    class := inferencer klass theNonMetaclass.
+    class := collector klass theNonMetaclass.
     class theNonMetaclass sharedPools do:[:pool|
         pool theNonMetaclass classVarNames do:[:nm|
             result add:(VariablePO classVariable: nm in: pool).
@@ -149,15 +296,16 @@
     | class |
 
 
-    class := inferencer klass theNonMetaclass.
+    class := collector klass theNonMetaclass.
     class privateClassesDo:[:pclass|
         | nm |
 
         nm := pclass fullName copyFrom: class fullName size + 3.
-        result add:(ClassPO new subject: pclass; name: nm).
+        result add:((PO forClass: pclass) name: nm).
     ]
 
     "Created: / 06-08-2013 / 12:28:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-05-2014 / 10:00:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 addVariablesFor: node
@@ -165,11 +313,11 @@
     | n klass |
 
     "Add Instance variables"
-    klass := inferencer klass.
+    klass := collector klass.
     [ klass notNil ] whileTrue:[
         | usedInstVars |
 
-        usedInstVars := inferencer parser usedInstVars. 
+        usedInstVars := collector parser usedInstVars.
         klass instVarNames do:[:nm |
             | po |
 
@@ -184,7 +332,7 @@
         "/ When on class side (i.e., in class method), do not complete
         "/ instance variables of Class / ClassDescription / Behaviour
         "/ as STC won't compile such code.
-        klass := (klass isMetaclass and:[klass superclass == Class]) 
+        klass := (klass isMetaclass and:[klass superclass == Class])
                     ifTrue:[nil]
                     ifFalse:[klass superclass].
     ].
@@ -193,16 +341,16 @@
         result add: (VariablePO new name: nm).
     ].
     "Add arguments"
-    inferencer parser methodArgs ? #() do:[:nm|
+    collector parser methodArgs ? #() do:[:nm|
         result add: (VariablePO argument: nm).
     ].
     "Add temporaries"
-    inferencer parser methodVars ? #() do:[:nm|
+    collector parser methodVars ? #() do:[:nm|
         result add: (VariablePO variable: nm).
     ].
     "Add literals"
     #(#true #false #nil ) do:[:nm|
-        result add: (SnippetPO new subject: nm).
+        result add: (SnippetPO new value: nm).
     ].
 
 
@@ -216,7 +364,7 @@
     ]
 
     "Created: / 31-07-2013 / 00:32:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 22-01-2014 / 19:42:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-05-2014 / 10:09:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SmalltalkCompletionEngine methodsFor:'completion-private'!
@@ -229,7 +377,7 @@
 
     codeView := context codeView.
     class := codeView isCodeView2
-                ifTrue: [ codeView klass ]  
+                ifTrue: [ codeView klass ]
                 ifFalse: [ codeView editedClass ].
     class isNil ifTrue:[
         class := UndefinedObject.
@@ -240,13 +388,13 @@
     "Modified: / 21-01-2014 / 23:20:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
-complete: mode source: source class: class line: lineNrArg column: colNrArg 
-    | inf lineNr colNr |
+complete: mode source: source class: class line: lineNrArg column: colNrArg
+    | inferencer lineNr colNr |
 
     mode == #method ifTrue:[
         lineNr := lineNrArg.
         colNr := colNrArg.
-        inf := SmalltalkInferencer forClass: class methodSource: source asString.
+        inferencer := SmalltalkInferencer forClass: class methodSource: source asString.
     ] ifFalse:[
         | line |
 
@@ -254,17 +402,18 @@
         colNr := colNrArg.
         line := codeView list at: lineNrArg ifAbsent:[ nil ].
         line isEmptyOrNil ifTrue:[ ^ nil ].
-        inf := SmalltalkInferencer forExpression: line.
+        inferencer := SmalltalkInferencer forExpression: line.
     ].
-    inf parserClass: SmalltalkParser.
+    inferencer parserClass: SmalltalkParser.
+    inferencer process.
 
     ^ self
         completeAtLine:lineNr
         column:colNr
-        inferencer:inf
+        collector:inferencer
 
     "Created: / 02-10-2013 / 13:23:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 13-05-2014 / 12:29:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 07-10-2013 / 13:43:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 completeAfter:node
@@ -283,20 +432,17 @@
     "Modified: / 24-09-2013 / 02:15:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
-completeAtLine:line column:col inferencer:inferencerArg 
+completeAtLine:line column:col collector:coll
     "find most possible codeCompletion object"
 
     | nodeToPosition |
 
-    inferencer := inferencerArg.
-    inferencer process.
-    (inferencer tree isNil or:[inferencer tree == #Error]) ifTrue:[ 
-        ^ nil 
+    collector := coll.
+    (collector tree isNil or:[collector tree == #Error]) ifTrue:[
+        ^ nil
     ].
-    inferencer environment: context environment.
-
-    nodeToPosition := SmalltalkParseNodeFinder new 
-                        findNodeIn: inferencer source tree: inferencer tree comments: inferencer parser commentPositions
+    nodeToPosition := SmalltalkParseNodeFinder new
+                        findNodeIn: collector source tree: collector tree comments: collector parser commentPositions
                         line: line column: col.
     context node: nodeToPosition key position: nodeToPosition value.
 
@@ -315,7 +461,10 @@
     ].
     ^result.
 
-    "Created: / 13-05-2014 / 12:29:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Created: / 04-03-2011 / 13:01:14 / Jakub <zelenja7@fel.cvut.cz>"
+    "Modified: / 08-04-2011 / 10:52:59 / Jakub <zelenja7@fel.cvut.cz>"
+    "Created: / 26-11-2011 / 17:05:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 29-01-2014 / 10:36:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 completeBefore:node
@@ -327,9 +476,9 @@
     "Created: / 26-11-2011 / 17:07:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
-completeIn:node 
+completeIn:node
     "return collection which can be afterNode"
-    
+
     node isVariableNode ifTrue:[
         self completeInVariableNode:node.
         ^ self.
@@ -346,7 +495,7 @@
     "Modified: / 08-04-2014 / 20:52:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
-completeInMessageNode:node 
+completeInMessageNode:node
     | parent |
 
 
@@ -359,7 +508,7 @@
     "Modified (format): / 08-04-2014 / 21:16:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
-completeInVariableNode:node 
+completeInVariableNode:node
     node name first isUppercase ifTrue:[
         self addGlobalsStartingWith:node name.
         self addClassVariables.
@@ -376,12 +525,12 @@
     | i |
 
     i := 0.
-    [ 
+    [
         i := aString indexOf: $: startingAt: i + 1.
-        i ~~ 0 
-    ] whileTrue:[ 
-        aString size > i ifTrue:[ 
-            (aString at: i + 1) ~~ $: ifTrue:[ 
+        i ~~ 0
+    ] whileTrue:[
+        aString size > i ifTrue:[
+            (aString at: i + 1) ~~ $: ifTrue:[
                 ^ true
             ].
         ].