Explainer.st
branchjv
changeset 3873 707275c1f86d
parent 3841 a22f33410bdf
parent 3861 214e93764392
child 3874 4f9db2d4c2b7
equal deleted inserted replaced
3850:ca4ea3855eef 3873:707275c1f86d
    54 ! !
    54 ! !
    55 
    55 
    56 !Explainer class methodsFor:'explaining'!
    56 !Explainer class methodsFor:'explaining'!
    57 
    57 
    58 explainLiteralNode:node in:code forClass:cls short:short interval:intervalIfKnown
    58 explainLiteralNode:node in:code forClass:cls short:short interval:intervalIfKnown
    59     |expl literalValue findInnerMost elementIndex codeOfCharacterBeforeCursor|
    59     |expl literalValue literalsClass findInnerMost elementIndex codeOfCharacterBeforeCursor|
    60 
    60 
    61     literalValue := node value.
    61     literalValue := node value.
    62     expl := literalValue class name "allBold" , '-constant'.
    62     literalsClass := literalValue class.
       
    63     expl := (self asClassLink:literalsClass name "allBold") , '-constant'.
    63 
    64 
    64     (literalValue isInteger) ifTrue:[
    65     (literalValue isInteger) ifTrue:[
    65         (literalValue ~~ 0 and:[literalValue ~~ 1]) ifTrue:[
    66         (literalValue ~~ 0 and:[literalValue ~~ 1]) ifTrue:[
    66             expl := expl , ' ('.
    67             expl := expl , ' ('.
    67             #(2 10 16) with:#('binary: ' 'decimal: ' 'hex: ') do:[:base :baseExpl |
    68             #(2 10 16) with:#('binary: ' 'decimal: ' 'hex: ') do:[:base :baseExpl |
   144 explainMessageNode:node in:code forClass:cls short:short interval:intervalIfKnown
   145 explainMessageNode:node in:code forClass:cls short:short interval:intervalIfKnown
   145     "answer a string which explains node"
   146     "answer a string which explains node"
   146 
   147 
   147     |receiver nm srchClass selector selectorString implClass
   148     |receiver nm srchClass selector selectorString implClass
   148      boldSelectorString globalValue recClassSet
   149      boldSelectorString globalValue recClassSet
   149      implMethod implMethodComment info implMethods comments definer
   150      implMethod implMethodComment info definer
   150      instances classesOfInstVars implementingClasses canBeNil
   151      instances classesOfInstVars implementingClasses canBeNil
   151      bestMatches hint|
   152      bestMatches hint|
   152 
   153 
   153     selector := node buildSelectorString.
   154     selector := node buildSelectorString.
   154     selectorString := selector printString contractTo:30.
   155     selectorString := selector printString contractTo:50.
   155     selector := selector asSymbolIfInterned.    "/ avoid creating new symbols.
   156     selector := selector asSymbolIfInterned.    "/ avoid creating new symbols.
   156     selector isNil ifTrue:[
   157     selector isNil ifTrue:[
   157         ^ '%1 is NOWHERE impemented.' bindWith:boldSelectorString
   158         ^ '%1 is NOWHERE impemented.' bindWith:boldSelectorString
   158     ].
   159     ].
   159 
   160 
   160     selectorString := selectorString actionForAll:(self actionToBrowseImplementorsOf:selector).
   161     selectorString := self asLink:selectorString to:(self actionToBrowseImplementorsOf:selector).
   161     boldSelectorString := selectorString "allBold".
   162     boldSelectorString := selectorString "allBold".
   162     
   163     
   163     recClassSet := self guessPossibleImplementorClassesFor:(node receiver) in:code forClass:cls.
   164     recClassSet := self guessPossibleImplementorClassesFor:(node receiver) in:code forClass:cls.
   164     recClassSet size == 1 ifTrue:[
   165     recClassSet size == 1 ifTrue:[
   165         srchClass := recClassSet first.
   166         srchClass := recClassSet first.
   172                     bindWith:selector "allBold"
   173                     bindWith:selector "allBold"
   173                     with:(implementingClasses size - 1)
   174                     with:(implementingClasses size - 1)
   174             ].
   175             ].
   175 
   176 
   176             (#('self'  'super' 'true' 'false' 'thisContext') includes:selector) ifTrue:[
   177             (#('self'  'super' 'true' 'false' 'thisContext') includes:selector) ifTrue:[
   177                 ^ ('NOT understood here: %1 (missing period after previous statement?)' bindWith:selector allBold),hint
   178                 ^ ('NOT understood here: %1 (missing period after previous statement?)' 
   178             ].
   179                         bindWith:selector allBold)
   179 
   180             ].
       
   181 
       
   182             hint := ''.    
   180             (recClassSet contains:[:cls | cls isMeta not and:[cls theMetaclass canUnderstand:selector]]) ifTrue:[
   183             (recClassSet contains:[:cls | cls isMeta not and:[cls theMetaclass canUnderstand:selector]]) ifTrue:[
   181                 hint := '. But class understands it - did you mean "rcvr class ',selector,'..." ?'.
   184                 hint := '. But class understands it - did you mean "rcvr class ',selector,'..." ?'.
   182             ].
   185             ].
   183             bestMatches := Parser findBestSelectorsFor:selector in:srchClass.
   186             bestMatches := Parser findBestSelectorsFor:selector in:srchClass.
   184             bestMatches size > 0 ifTrue:[
   187             bestMatches size > 0 ifTrue:[
   185                 ^ ('NOT understood here: %1 (best guess is: "%2" from %3)'
   188                 ^ ('NOT understood here: %1 (best guess is: "%2" from %3)'
   186                     bindWith:selector allBold
   189                     bindWith:selector allBold
   187                     with:(bestMatches first "allBold")
   190                     with:(bestMatches first "allBold")
   188                     with:(srchClass whichClassIncludesSelector:bestMatches first) name) , (hint?'')
   191                     with:(srchClass whichClassIncludesSelector:bestMatches first) name) , hint
   189             ].
   192             ].
   190             ^ ('NOT understood here: %1' bindWith:selector allBold),(hint ? '')
   193             ^ ('NOT understood here: %1' bindWith:selector allBold),hint
   191         ].
   194         ].
   192     ].
   195     ].
   193 
   196 
   194     implementingClasses isNil ifTrue:[
   197     implementingClasses isNil ifTrue:[
   195         receiver := node receiver.
   198         receiver := node receiver.
   232         srchClass notNil ifTrue:[
   235         srchClass notNil ifTrue:[
   233             implClass := srchClass whichClassIncludesSelector:selector.
   236             implClass := srchClass whichClassIncludesSelector:selector.
   234             implClass isNil ifTrue:[
   237             implClass isNil ifTrue:[
   235                 ^ '%1 is NOT understood here.' bindWith:boldSelectorString
   238                 ^ '%1 is NOT understood here.' bindWith:boldSelectorString
   236             ].
   239             ].
   237 
   240             implementingClasses := { implClass }.
   238             implMethod := implClass compiledMethodAt:selector.
       
   239 
       
   240             info := '%1 >> %2' bindWith:implClass name "allBold" with:selectorString "allBold".
       
   241             info := info actionForAll:(self actionToBrowseClass:implClass selector:selector).
       
   242 
       
   243             implMethodComment := self fetchCommentOfMethod:implMethod.
       
   244             implMethodComment notNil ifTrue:[
       
   245                 info := info , ' ' , implMethodComment.
       
   246             ].
       
   247             ^ info
       
   248         ].
   241         ].
   249         implementingClasses isNil ifTrue:[
   242         implementingClasses isNil ifTrue:[
   250             implementingClasses := Smalltalk allImplementorsOf:selector
   243             implementingClasses := Smalltalk allImplementorsOf:selector
   251         ].
   244         ].
   252     ].
   245     ].
   253 
   246 
   254     implementingClasses size == 1 ifTrue:[
   247     implementingClasses size == 1 ifTrue:[
   255         |clsName|
   248         |clsName|
       
   249 
   256         implClass := implementingClasses anElement.
   250         implClass := implementingClasses anElement.
   257         implMethod := implClass compiledMethodAt:selector.
   251         implMethod := implClass compiledMethodAt:selector.
   258         clsName := implClass name.
   252         clsName := implClass name.
   259         clsName := clsName actionForAll:(self actionToBrowseClass:implClass selector:selector).
   253         clsName := self asLink:clsName to:(self actionToBrowseClass:implClass selector:selector).
   260         info := '%1 >> %2' bindWith:clsName "allBold" with:selectorString.
   254         info := '%1 >> %2' bindWith:clsName "allBold" with:selectorString.
   261         (srchClass isNil and:[(cls includesBehavior:implClass) not]) ifTrue:[
   255         info := self asLink:info to:(self actionToBrowseClass:implClass selector:selector).
   262             "/ info := 'guess: ', info.
   256 
   263             info := info , ' (guess)'.
   257         implMethodComment := self fetchCommentOfMethod:implMethod.
   264         ].
   258         implMethodComment notNil ifTrue:[
       
   259             info := info , ' ' , implMethodComment.
       
   260         ].
       
   261         ^ info
       
   262 "/        (srchClass isNil and:[(cls includesBehavior:implClass) not]) ifTrue:[
       
   263 "/            "/ info := 'guess: ', info.
       
   264 "/            info := info , ' (guess)'.
       
   265 "/        ].
   265     ] ifFalse:[
   266     ] ifFalse:[
   266         info := Explainer explainSelector:selector inClass:cls short:short.
   267         info := Explainer explainSelector:selector inClass:cls short:short.
   267     ].
   268     ].
   268 
   269 
   269 "/    implementingClasses notEmptyOrNil ifTrue:[
   270 "/    implementingClasses notEmptyOrNil ifTrue:[
   301     "Modified: / 30-04-2016 / 17:08:11 / cg"
   302     "Modified: / 30-04-2016 / 17:08:11 / cg"
   302 !
   303 !
   303 
   304 
   304 explainMethodNode:node in:code forClass:cls short:short interval:intervalIfKnown
   305 explainMethodNode:node in:code forClass:cls short:short interval:intervalIfKnown
   305     |srchClass selector selectorString implClass
   306     |srchClass selector selectorString implClass
   306      "sendingMethods numSendingMethods sendingClasses" boldSelectorString|
   307      "sendingMethods numSendingMethods sendingClasses" |
   307 
   308 
   308     selector := node selector.
   309     selector := node selector.
   309     selector := selector asSymbolIfInterned.    "/ avoid creating new symbols.
   310     selector := selector asSymbolIfInterned.    "/ avoid creating new symbols.
   310     selectorString := selector printString contractTo:30.
   311     selectorString := selector printString contractTo:50.
   311     boldSelectorString := selectorString "allBold".
       
   312 
   312 
   313     (srchClass := cls superclass) notNil ifTrue:[
   313     (srchClass := cls superclass) notNil ifTrue:[
   314         implClass := srchClass whichClassIncludesSelector:selector.
   314         implClass := srchClass whichClassIncludesSelector:selector.
   315         implClass notNil ifTrue:[
   315         implClass notNil ifTrue:[
   316             ^ '%1 hides implementation in %2.'
   316             ^ '%1 overrides implementation in %2.'
   317               bindWith:boldSelectorString
   317               bindWith:(self asLink:selectorString "allBold" to:(self actionToOpenMethodFinderFor:selector))
   318               with:implClass name "allBold"
   318               with:(self asLink:implClass name "allBold" to:(self actionToBrowseClass:implClass selector:selector))
   319         ].
   319         ].
   320     ].
   320     ].
   321     (cls includesSelector:selector) ifFalse:[
   321     (cls includesSelector:selector) ifFalse:[
   322         ^ '%1: a new method.' bindWith:boldSelectorString
   322         ^ '%1: a new method.' bindWith:selectorString "allBold"
   323     ].
   323     ].
   324 "/
   324 "/
   325 "/        sendingMethods := SystemBrowser
   325 "/        sendingMethods := SystemBrowser
   326 "/                                allCallsOn:selector
   326 "/                                allCallsOn:selector
   327 "/                                in:(cls withAllSubclasses , cls allSubclasses)
   327 "/                                in:(cls withAllSubclasses , cls allSubclasses)
   423 
   423 
   424     ^ nil
   424     ^ nil
   425 !
   425 !
   426 
   426 
   427 explainVariableNode:node in:code forClass:cls short:short interval:intervalIfKnown
   427 explainVariableNode:node in:code forClass:cls short:short interval:intervalIfKnown
   428     |expl nm nmBold definingNode namePart|
   428     |expl nm nmBold definingNode namePart argNode argClass argClassSet|
   429 
   429 
   430     nm := node name.
   430     nm := node name.
   431 
   431 
   432     (#( 'self' 'super' 'thisContext' 'here') includes:nm) ifTrue:[
   432     (#( 'self' 'super' 'thisContext' 'here') includes:nm) ifTrue:[
   433         ^ Explainer explainPseudoVariable:nm in:cls short:short
   433         ^ Explainer explainPseudoVariable:nm in:cls short:short
   437 
   437 
   438     definingNode := node whoDefines:nm.
   438     definingNode := node whoDefines:nm.
   439     definingNode notNil ifTrue:[
   439     definingNode notNil ifTrue:[
   440         namePart := '''' , nmBold , ''''.
   440         namePart := '''' , nmBold , ''''.
   441         definingNode isMethod ifTrue:[
   441         definingNode isMethod ifTrue:[
   442             (definingNode arguments contains:[:arg | arg name = nm]) ifTrue:[
   442             argNode := definingNode arguments detect:[:arg | arg name = nm] ifNone:nil.
   443                 expl := namePart , ' is a method argument.'
   443             argNode notNil ifTrue:[
       
   444                 expl := namePart , ' is a method argument.'.
       
   445 
       
   446                 argClassSet := self guessPossibleImplementorClassesFor:argNode in:code forClass:cls.
       
   447                 argClassSet size == 1 ifTrue:[
       
   448                     argClass := argClassSet first.
       
   449                 ].
   444             ].
   450             ].
   445         ].
   451         ].
   446         expl isNil ifTrue:[
   452         expl isNil ifTrue:[
   447             definingNode isBlock ifTrue:[
   453             definingNode isBlock ifTrue:[
   448                 (definingNode arguments contains:[:arg | arg name = nm]) ifTrue:[
   454                 (definingNode arguments contains:[:arg | arg name = nm]) ifTrue:[
   486 !
   492 !
   487 
   493 
   488 fetchCommentOfMethod:mthd
   494 fetchCommentOfMethod:mthd
   489     "retrieve the comment of a method (if possible and there is one; otherwise, return nil)"
   495     "retrieve the comment of a method (if possible and there is one; otherwise, return nil)"
   490 
   496 
   491     |methodComment lines|
   497     |windowGroup methodComment lines|
   492 
   498 
   493     "/ with wait cursor, because it accesses sourcecode (via SCM)
   499     "/ with wait cursor, because it accesses sourcecode (via SCM)
   494     WindowGroup activeGroup withWaitCursorDo:[
   500     "/ however: this class is in libcomp (should be in libtool)
       
   501     "/ so check if WindowGroup (from libview) is present
       
   502     windowGroup := Smalltalk at:#WindowGroup.
       
   503     windowGroup isNil ifTrue:[
   495         methodComment := mthd comment.
   504         methodComment := mthd comment.
   496     ].
   505     ] ifFalse:[
       
   506         windowGroup activeGroup withWaitCursorDo:[
       
   507             methodComment := mthd comment.
       
   508         ].
       
   509     ].
       
   510     "/ Transcript showCR:methodComment.
       
   511     
   497     methodComment isEmptyOrNil ifTrue:[^ nil].
   512     methodComment isEmptyOrNil ifTrue:[^ nil].
   498 
   513 
   499     lines := methodComment asStringCollection.
   514     lines := methodComment asStringCollection.
   500     methodComment := lines first.
   515     methodComment := lines first.
   501     methodComment := methodComment withoutSeparators.
   516     methodComment := methodComment withoutSeparators.
   645     c := aClass whichClassDefinesInstVar:string.
   660     c := aClass whichClassDefinesInstVar:string.
   646     c notNil ifTrue:[
   661     c notNil ifTrue:[
   647         c isMeta ifTrue:[
   662         c isMeta ifTrue:[
   648             clsName := c theNonMetaclass name.
   663             clsName := c theNonMetaclass name.
   649             shortText ifTrue:[
   664             shortText ifTrue:[
   650                 clsName := (clsName actionForAll:(self actionToBrowseClass:c selector:nil)).
   665                 clsName := self asLink:clsName to:(self actionToBrowseClass:c).
   651                 stringText := stringText , ': a class instVar in ' , clsName
   666                 stringText := stringText , ': a class instVar in ' , clsName
   652             ] ifFalse:[
   667             ] ifFalse:[
   653                 stringText := stringText, ': a class instance variable inherited from ' , clsName
   668                 stringText := stringText, ': a class instance variable inherited from ' , clsName
   654             ].
   669             ].
   655             val := aClass theNonMetaclass instVarNamed:string.
   670             val := aClass theNonMetaclass instVarNamed:string.
   663         "classvars"
   678         "classvars"
   664         c := explainer inWhichClassIsClassVar:string.
   679         c := explainer inWhichClassIsClassVar:string.
   665         c notNil ifTrue:[
   680         c notNil ifTrue:[
   666             clsName := c name.
   681             clsName := c name.
   667             shortText ifTrue:[
   682             shortText ifTrue:[
   668                 clsName := (clsName actionForAll:(self actionToBrowseClass:c selector:nil)).
   683                 clsName := self asLink:clsName to:(self actionToBrowseClass:c).
   669                 stringText := stringText , ': a classVar in ' , clsName
   684                 stringText := stringText , ': a classVar in ' , clsName
   670             ] ifFalse:[
   685             ] ifFalse:[
   671                 stringText := stringText , ': a class variable in ' , clsName
   686                 stringText := stringText , ': a class variable in ' , clsName
   672             ].
   687             ].
   673 
   688 
   679         "private classes"
   694         "private classes"
   680         c := aClass theNonMetaclass.
   695         c := aClass theNonMetaclass.
   681         c privateClasses do:[:pClass |
   696         c privateClasses do:[:pClass |
   682             (pClass name = string
   697             (pClass name = string
   683              or:[pClass nameWithoutPrefix = string]) ifTrue:[
   698              or:[pClass nameWithoutPrefix = string]) ifTrue:[
   684                 stringText := (stringText actionForAll:(self actionToBrowseClass:pClass selector:nil)).
   699                 stringText := self asLink:stringText to:(self actionToBrowseClass:pClass).
   685                 stringText := stringText , ': a private class in ''' , c name , '''.'.
   700                 stringText := stringText , ': a private class in ''' , c name , '''.'.
   686                 shortText ifFalse:[
   701                 shortText ifFalse:[
   687                     stringText := (stringText , '\\It is only visible locally.') withCRs
   702                     stringText := (stringText , '\\It is only visible locally.') withCRs
   688                 ].
   703                 ].
   689                 ^ stringText withCRs
   704                 ^ stringText withCRs
   700                     sharedPool isSharedPool ifFalse:[
   715                     sharedPool isSharedPool ifFalse:[
   701                         ^ 'oops - not a shared pool: ',eachPoolName
   716                         ^ 'oops - not a shared pool: ',eachPoolName
   702                     ].
   717                     ].
   703                     (sharedPool includesKey:sharedPoolSym) ifTrue:[
   718                     (sharedPool includesKey:sharedPoolSym) ifTrue:[
   704                         poolName := sharedPool name.
   719                         poolName := sharedPool name.
   705                         poolName := (poolName actionForAll:(self actionToBrowseClass:sharedPool selector:nil)).
   720                         poolName := self asLink:poolName to:(self actionToBrowseClass:sharedPool).
   706                         stringText := stringText , ': a pool variable in ',poolName.
   721                         stringText := stringText , ': a pool variable in ',poolName.
   707                         val := sharedPool at:sharedPoolSym.
   722                         val := sharedPool at:sharedPoolSym.
   708                         valString := self valueStringFor:val.
   723                         valString := self valueStringFor:val.
   709                         ^ stringText , ' (' , valString , ').'
   724                         ^ stringText , ' (' , valString , ').'
   710                     ].
   725                     ].
   715         "namespace & global variables"
   730         "namespace & global variables"
   716         (spc := aClass nameSpace) notNil ifTrue:[
   731         (spc := aClass nameSpace) notNil ifTrue:[
   717             sym := (spc name , '::' , string) asSymbolIfInterned.
   732             sym := (spc name , '::' , string) asSymbolIfInterned.
   718             sym notNil ifTrue:[
   733             sym notNil ifTrue:[
   719                 (cls := Smalltalk at:sym) isBehavior ifTrue:[
   734                 (cls := Smalltalk at:sym) isBehavior ifTrue:[
   720                     stringText := (stringText actionForAll:(self actionToBrowseClass:cls selector:nil)).
   735                     stringText := self asLink:stringText to:(self actionToBrowseClass:cls).
   721                     string :=  stringText , ': '.
   736                     string :=  stringText , ': '.
   722                     cls name = sym ifFalse:[
   737                     cls name = sym ifFalse:[
   723                         string :=  string , 'refers to ',cls name,', '
   738                         string :=  string , 'refers to ',cls name,', '
   724                     ].
   739                     ].
   725                     cls isSharedPool ifTrue:[
   740                     cls isSharedPool ifTrue:[
   942 
   957 
   943     "Created: / 28-02-2012 / 10:44:55 / cg"
   958     "Created: / 28-02-2012 / 10:44:55 / cg"
   944 !
   959 !
   945 
   960 
   946 explainInstanceVariable:instVarName inClass:aClass short:shortText
   961 explainInstanceVariable:instVarName inClass:aClass short:shortText
   947     |template stringText setOfTypes typesDescription|
   962     |varNameInText classNameInText template stringText setOfTypes typesDescription|
   948 
   963 
       
   964     varNameInText := instVarName allBold.
       
   965     classNameInText := aClass name.
       
   966     
   949     shortText ifTrue:[
   967     shortText ifTrue:[
   950         template := '%1: an instVar in %2'
   968         template := '%1: an instVar in %2'.
       
   969         varNameInText := self asLink:varNameInText to:(self actionToBrowseInstvarRefsTo:instVarName inClass:aClass).
       
   970         classNameInText := self asLink:classNameInText to:(self actionToBrowseClass:aClass).
   951     ] ifFalse:[
   971     ] ifFalse:[
   952         template := '%1: an instance variable in %2'
   972         template := '%1: an instance variable in %2'
   953     ].
   973     ].
   954     stringText := template bindWith:instVarName allBold with:aClass name.
   974     stringText := template bindWith:varNameInText with:classNameInText.
   955 
   975 
   956     "/ look for instances
   976     "/ look for instances
   957     setOfTypes := IdentitySet new.
   977     setOfTypes := IdentitySet new.
   958     self addTypesOfInstvar:instVarName inClass:aClass fromExistingInstancesTo:setOfTypes.
   978     self addTypesOfInstvar:instVarName inClass:aClass fromExistingInstancesTo:setOfTypes.
   959     "/ look for assignments
   979     "/ look for assignments
  1132         shortText ifTrue:[
  1152         shortText ifTrue:[
  1133             tmp := ' is implemented in '.
  1153             tmp := ' is implemented in '.
  1134         ] ifFalse:[
  1154         ] ifFalse:[
  1135             tmp := ' is a selector implemented in '.
  1155             tmp := ' is a selector implemented in '.
  1136         ].
  1156         ].
  1137         s := "'#' ," string allBold.
  1157         s := string allBold.
  1138         s := s actionForAll:(self actionToBrowseImplementorsOf:selector).
  1158         count > 1 ifTrue:[
       
  1159             s := self asLink:s to:(self actionToOpenMethodFinderFor:selector).
       
  1160         ] ifFalse:[    
       
  1161             s := self asLink:s to:(self actionToBrowseImplementorsOf:selector).
       
  1162         ].
  1139         
  1163         
  1140         shortText ifTrue:[
  1164         shortText ifTrue:[
  1141             |typesDescription|
  1165             |typesDescription|
  1142             
  1166             
  1143             msg := s , tmp.
  1167             msg := s , tmp.
  1144             typesDescription := (self typeDescriptionFor:listOfImplementingClasses andSelector:selector).
  1168             typesDescription := self typeDescriptionFor:listOfImplementingClasses andSelector:selector wordBetween:'and'.
  1145             typesDescription notNil ifTrue:[
  1169             typesDescription notNil ifTrue:[
  1146                 msg := msg,' (',typesDescription,')'
  1170                 msg := msg,typesDescription
  1147             ].
  1171             ].
  1148         ] ifFalse:[
  1172         ] ifFalse:[
  1149             (count == 1) ifTrue:[
  1173             (count == 1) ifTrue:[
  1150                 t := firstImplementingClassName.
  1174                 t := firstImplementingClassName.
  1151                 firstImplementingClass isMeta ifTrue:[
  1175                 firstImplementingClass isMeta ifTrue:[
  1401     |superName|
  1425     |superName|
  1402 
  1426 
  1403     superName := aClass superclass name.
  1427     superName := aClass superclass name.
  1404 
  1428 
  1405     shortText ifTrue:[
  1429     shortText ifTrue:[
  1406         ^ '"super" - message lookup starts in superclass "%1" (call redefined method).' bindWith:superName
  1430         ^ '"super" - message lookup starts in superclass "%1" (call redefined method).' bindWith:(self asClassLink:superName)
  1407     ].
  1431     ].
  1408 
  1432 
  1409     ^ 'like "self", "','super'allBold,'" refers to the object which received the message.
  1433     ^ 'like "self", "','super'allBold,'" refers to the object which received the message.
  1410 
  1434 
  1411 However, when sending a message to "super", the search for methods
  1435 However, when sending a message to "super", the search for methods
  1421 
  1445 
  1422     ^ self explainSyntax:string short:false
  1446     ^ self explainSyntax:string short:false
  1423 !
  1447 !
  1424 
  1448 
  1425 explainSyntax:string short:shortText
  1449 explainSyntax:string short:shortText
  1426     "try syntax ...; return explanation or nil"
  1450     "try syntax ...; return explanation or nil.
       
  1451      This is meant for beginners..."
  1427 
  1452 
  1428     ((string = ':=') or:[string = '_']) ifTrue:[
  1453     ((string = ':=') or:[string = '_']) ifTrue:[
  1429         shortText ifTrue:[
  1454         shortText ifTrue:[
  1430             ^ '":=" - assign to variable on the left (syntax)'.
  1455             string = '_' ifTrue:[
       
  1456                 ^ '"_" - old style for assignment. Consider changing to ":=".'
       
  1457             ].
       
  1458             ^ '":=" - assign to variable on the left (syntax).'.
  1431         ].
  1459         ].
  1432 
  1460 
  1433         ^ '<variable> := <expression>
  1461         ^ '<variable> := <expression>
  1434 
  1462 
  1435 ":=" and "_" (which is left-arrow in some fonts) mean assignment.
  1463 ":=" and "_" (which is left-arrow in some fonts) mean assignment.
  1470 "|" is also a selector understood by Booleans.'
  1498 "|" is also a selector understood by Booleans.'
  1471     ].
  1499     ].
  1472 
  1500 
  1473     (string startsWith:'$' ) ifTrue:[
  1501     (string startsWith:'$' ) ifTrue:[
  1474         shortText ifTrue:[
  1502         shortText ifTrue:[
  1475             ^ '"$x" - character literal (syntax)'.
  1503             ^ '"$x" - ',(self asClassLink:'Character'),' literal (syntax)'.
  1476         ].
  1504         ].
  1477         ^ 'is a Character literal constant.
  1505         ^ 'is a Character literal constant.
  1478 
  1506 
  1479 Character objects represent indivdual text cheracters in Unicode encoding.
  1507 Character objects represent indivdual text cheracters in Unicode encoding.
  1480 For example, $a is the character "a" with an encoding of 97 "hex: 16r61".
  1508 For example, $a is the character "a" with an encoding of 97 "hex: 16r61".
  1483     ].
  1511     ].
  1484 
  1512 
  1485     (string startsWith:'#' ) ifTrue:[
  1513     (string startsWith:'#' ) ifTrue:[
  1486         (string startsWith:'#(' ) ifTrue:[
  1514         (string startsWith:'#(' ) ifTrue:[
  1487             shortText ifTrue:[
  1515             shortText ifTrue:[
  1488                 ^ '"#(..)" - array literal (syntax)'.
  1516                 ^ '"#(..)" - ',(self asClassLink:'Array'),' literal (syntax)'.
  1489             ].
  1517             ].
  1490             ^ 'is a constant Array (literal).
  1518             ^ 'is a constant Array (literal).
  1491 
  1519 
  1492 The array-object is created at compilation time and a reference to this is
  1520 The array-object is created at compilation time and a reference to this is
  1493 used at execution time (thus, the same object is referred to every time).
  1521 used at execution time (thus, the same object is referred to every time).
  1497  element in an Array-constant).'
  1525  element in an Array-constant).'
  1498         ].
  1526         ].
  1499 
  1527 
  1500         (string startsWith:'#[') ifTrue:[
  1528         (string startsWith:'#[') ifTrue:[
  1501             shortText ifTrue:[
  1529             shortText ifTrue:[
  1502                 ^ '"#[..]" - byteArray literal (syntax)'.
  1530                 ^ '"#[..]" - ',(self asClassLink:'ByteArray'),' literal (syntax)'.
  1503             ].
  1531             ].
  1504             ^ 'is a constant ByteArray (literal).
  1532             ^ 'is a constant ByteArray (literal).
  1505 
  1533 
  1506 The elements of a constant ByteArray must be Integer constants in the range
  1534 The elements of a constant ByteArray must be Integer constants in the range
  1507 0 .. 255.
  1535 0 .. 255.
  1508 (notice, that not all Smalltalk implementations support constant ByteArrays).'
  1536 (notice, that not all Smalltalk implementations support constant ByteArrays).'
  1509         ].
  1537         ].
  1510 
  1538 
  1511         (string startsWith:'#''') ifTrue:[
  1539         (string startsWith:'#''') ifTrue:[
  1512             shortText ifTrue:[
  1540             shortText ifTrue:[
  1513                 ^ '"#''..''" - symbol literal (syntax)'.
  1541                 ^ '"#''..''" - ',(self asClassLink:'Symbol'),' literal (syntax)'.
  1514             ].
  1542             ].
  1515             ^ 'is a constant symbol containing non-alphanumeric characters.
  1543             ^ 'is a constant symbol containing non-alphanumeric characters.
  1516 
  1544 
  1517 Symbols are unique strings, meaning that there exists
  1545 Symbols are unique strings, meaning that there exists
  1518 exactly one instance of a given symbol. Therefore symbols can
  1546 exactly one instance of a given symbol. Therefore symbols can
  1519 be compared using == (identity compare) in addition to = (contents compare).
  1547 be compared using == (identity compare) in addition to = (contents compare).
  1520 Beside this, Symbols behave mostly like Strings but are immutable.'
  1548 Beside this, Symbols behave mostly like Strings but are immutable.'
  1521         ].
  1549         ].
  1522 
  1550 
  1523         shortText ifTrue:[
  1551         shortText ifTrue:[
  1524             ^ '"#.." - symbol literal (syntax)'.
  1552             ^ '"#.." - ',(self asClassLink:'Symbol'),' literal (syntax)'.
  1525         ].
  1553         ].
  1526         ^ 'is a constant symbol.
  1554         ^ 'is a constant symbol.
  1527 
  1555 
  1528 Symbols are unique strings, meaning that there exists
  1556 Symbols are unique strings, meaning that there exists
  1529 exactly one instance of a given symbol. Therefore symbols can
  1557 exactly one instance of a given symbol. Therefore symbols can
  1540 with unary messages preceeding binary messages, preceeding keyword mesages.'
  1568 with unary messages preceeding binary messages, preceeding keyword mesages.'
  1541     ].
  1569     ].
  1542 
  1570 
  1543     ((string startsWith:'[') or:[string endsWith:']']) ifTrue:[
  1571     ((string startsWith:'[') or:[string endsWith:']']) ifTrue:[
  1544         shortText ifTrue:[
  1572         shortText ifTrue:[
  1545             ^ '"[..]" - a block (aka lambda/closure for experts)'.
  1573             ^ '"[..]" - a ',(self asClassLink:'Block'),' (aka lambda/closure for experts)'.
  1546         ].
  1574         ].
  1547         ^ '[:arg1 .. :argN | statements]
  1575         ^ '[:arg1 .. :argN | statements]
  1548 
  1576 
  1549 defines a block.
  1577 defines a block.
  1550 Blocks represent pieces of executable code. The definition of a block does
  1578 Blocks represent pieces of executable code. The definition of a block does
  1556 Blocks are also often used as callbacks from UI components or as exception handlers.'
  1584 Blocks are also often used as callbacks from UI components or as exception handlers.'
  1557     ].
  1585     ].
  1558 
  1586 
  1559     ((string startsWith:'{') or:[string endsWith:'}']) ifTrue:[
  1587     ((string startsWith:'{') or:[string endsWith:'}']) ifTrue:[
  1560         shortText ifTrue:[
  1588         shortText ifTrue:[
  1561             ^ '"{..}" array instantiation (syntax)'.
  1589             ^ '"{..}" ',(self asClassLink:'Array'),' instantiation (syntax)'.
  1562         ].
  1590         ].
  1563         ^ '{ <expr1>. .. <exprN> }
  1591         ^ '{ <expr1>. .. <exprN> }
  1564 
  1592 
  1565 This is syntactic sugar for "Array with:<expr1> .. with:<exprN>".
  1593 This is syntactic sugar for "Array with:<expr1> .. with:<exprN>".
  1566 
  1594 
  1660 !
  1688 !
  1661 
  1689 
  1662 typeDescriptionFor:setOfTypes andSelector:selectorOrNil
  1690 typeDescriptionFor:setOfTypes andSelector:selectorOrNil
  1663     "up to 3 types are shown by name; more are simply counted"
  1691     "up to 3 types are shown by name; more are simply counted"
  1664     
  1692     
       
  1693     ^ self typeDescriptionFor:setOfTypes andSelector:selectorOrNil wordBetween:'or'
       
  1694 !
       
  1695 
       
  1696 typeDescriptionFor:setOfTypes andSelector:selectorOrNil wordBetween:wordbetween
       
  1697     "up to 3 types are shown by name; more are simply counted"
       
  1698     
  1665     |types numTypes
  1699     |types numTypes
  1666      type1 type2 type3
  1700      type1 type2 type3
  1667      nm1 nm2 nm3|
  1701      nm1 nm2 nm3 link|
  1668      
  1702      
  1669     "/ reduce...
  1703     "/ reduce...
  1670     self compressSetOfTypes:setOfTypes.
  1704     self compressSetOfTypes:setOfTypes.
  1671     setOfTypes isEmpty ifTrue:[^ nil].
  1705     setOfTypes isEmpty ifTrue:[^ nil].
  1672     
  1706     
  1674     types sortBySelector:#name.
  1708     types sortBySelector:#name.
  1675 
  1709 
  1676     "/ now make this a nice string
  1710     "/ now make this a nice string
  1677     numTypes := types size.
  1711     numTypes := types size.
  1678     type1 := types first.
  1712     type1 := types first.
  1679     nm1 := type1 name actionForAll:(self actionToBrowseClass:type1 selector:selectorOrNil).
  1713     nm1 := self asLink:type1 name to:(self actionToBrowseClass:type1 selector:selectorOrNil).
  1680     numTypes == 1 ifTrue:[
  1714     numTypes == 1 ifTrue:[
  1681         ^ nm1
  1715         ^ nm1
  1682     ].
  1716     ].
       
  1717     
  1683     type2 := types second.
  1718     type2 := types second.
  1684     nm2 := type2 name actionForAll:(self actionToBrowseClass:type2 selector:selectorOrNil).
  1719     nm2 := self asLink:type2 name to:(self actionToBrowseClass:type2 selector:selectorOrNil).
  1685     numTypes == 2 ifTrue:[
  1720     numTypes == 2 ifTrue:[
  1686         ^ nm1,' or ',nm2
  1721         ^ nm1,' ',wordbetween,' ',nm2
  1687     ].
  1722     ].
  1688     type3 := types third.
  1723     type3 := types third.
  1689     nm3 := type3 name actionForAll:(self actionToBrowseClass:type3 selector:selectorOrNil).
  1724     nm3 := self asLink:type3 name to:(self actionToBrowseClass:type3 selector:selectorOrNil).
  1690     numTypes == 3 ifTrue:[
  1725     numTypes == 3 ifTrue:[
  1691          ^ nm1,', ',nm2,' or ',nm3
  1726          ^ nm1,', ',nm2,' ',wordbetween,' ',nm3
  1692     ].
  1727     ].
  1693     ^ ('one of %1 classes' bindWith:numTypes) actionForAll:(self actionToBrowseClasses:types). 
  1728     link := self actionToBrowseClasses:types.
       
  1729 "/    selectorOrNil notNil ifTrue:[
       
  1730 "/        link := self actionToOpenMethodFinderFor:selectorOrNil. 
       
  1731 "/    ].
       
  1732     ^ self asLink:('%1 classes' bindWith:numTypes) to:link.
  1694 !
  1733 !
  1695 
  1734 
  1696 valueStringFor:aValue
  1735 valueStringFor:aValue
  1697     |valString|
  1736     |valString|
  1698 
  1737 
  1728 ! !
  1767 ! !
  1729 
  1768 
  1730 !Explainer class methodsFor:'naive type inferer'!
  1769 !Explainer class methodsFor:'naive type inferer'!
  1731 
  1770 
  1732 addTypeOfExpressionNode:expr forAssignmentTo:varName to:setOfTypes
  1771 addTypeOfExpressionNode:expr forAssignmentTo:varName to:setOfTypes
  1733     |val valClass msgSelector msgReceiver|
  1772     "pick up low hanging type information.
       
  1773      This is far from being complete, but often gives a hint good enough for code completion
       
  1774      and info in the browser."
       
  1775 
       
  1776     |val valClass|
  1734 
  1777 
  1735     "/ only look for wellknown types on the right side.
  1778     "/ only look for wellknown types on the right side.
  1736     expr isLiteral ifTrue:[
  1779     expr isLiteral ifTrue:[
  1737         val := expr value.
  1780         val := expr value.
  1738         valClass := val class.
  1781         valClass := val class.
  1742         self rememberType:valClass in:setOfTypes.
  1785         self rememberType:valClass in:setOfTypes.
  1743         ^ setOfTypes.
  1786         ^ setOfTypes.
  1744     ].
  1787     ].
  1745 
  1788 
  1746     expr isMessage ifTrue:[
  1789     expr isMessage ifTrue:[
  1747         msgSelector := expr selector.
  1790         self addTypeOfMessageNode:expr forAssignmentTo:varName to:setOfTypes.
  1748         msgReceiver := expr receiver.
  1791         ^ setOfTypes.
  1749             
  1792     ].
  1750         msgSelector == #? ifTrue:[
  1793 
  1751             self addTypeOfExpressionNode:(expr arg1) forAssignmentTo:varName to:setOfTypes.
       
  1752             ^ setOfTypes
       
  1753         ].
       
  1754         "/ really really only low hanging fruit...
       
  1755         "/ ignore / here, because of filename
       
  1756         ( #(+ - *) includes:msgSelector ) ifTrue:[
       
  1757             "/ ignore foo := foo OP expr
       
  1758             "/ ignore foo := expr OP foo
       
  1759             (msgReceiver isVariable and:[msgReceiver name = varName]) ifFalse:[
       
  1760                 (expr arg1 isVariable and:[expr arg1 name = varName]) ifFalse:[
       
  1761                     self rememberType:Number in:setOfTypes.
       
  1762                 ]
       
  1763             ].
       
  1764             ^ setOfTypes.
       
  1765         ].
       
  1766 
       
  1767         ( #(// size hash identityHash) includes:msgSelector ) ifTrue:[
       
  1768             self rememberType:Integer in:setOfTypes.
       
  1769             ^ setOfTypes.
       
  1770         ].
       
  1771         ( #(next next:) includes:msgSelector ) ifTrue:[
       
  1772             |rcvrTypes|
       
  1773             
       
  1774             rcvrTypes := self addTypeOfExpressionNode:msgReceiver forAssignmentTo:nil to:Set new.
       
  1775             rcvrTypes notEmpty ifTrue:[
       
  1776 self halt.
       
  1777                 self rememberType:Character in:setOfTypes.
       
  1778             ].
       
  1779             ^ setOfTypes.
       
  1780         ].
       
  1781         ( msgSelector startsWith:'as') ifTrue:[
       
  1782             valClass := Smalltalk classNamed:(msgSelector copyFrom:3).
       
  1783             valClass notNil ifTrue:[
       
  1784                 self rememberType:valClass in:setOfTypes.
       
  1785                 ^ setOfTypes.
       
  1786             ].
       
  1787         ].    
       
  1788         ( #(copy shallowCopy) includes:msgSelector ) ifTrue:[
       
  1789             msgReceiver isLiteral ifTrue:[
       
  1790                 self addTypeOfExpressionNode:msgReceiver forAssignmentTo:varName to:setOfTypes.
       
  1791             ].
       
  1792             ^ setOfTypes
       
  1793         ].
       
  1794 
       
  1795         msgReceiver isGlobal ifTrue:[
       
  1796             |globalValue|
       
  1797 
       
  1798             globalValue := msgReceiver value.
       
  1799             globalValue isBehavior ifTrue:[
       
  1800                 ( #(new new: basicNew basicNew:) includes:msgSelector ) ifTrue:[
       
  1801                     self rememberType:globalValue in:setOfTypes.
       
  1802                     ^ setOfTypes.
       
  1803                 ].
       
  1804             ].
       
  1805 self breakPoint:#cg.
       
  1806         ] ifFalse:[    
       
  1807 self breakPoint:#cg.
       
  1808         ]
       
  1809     ].
       
  1810     ^ setOfTypes
  1794     ^ setOfTypes
  1811     
  1795     
  1812     "Created: / 30-04-2016 / 15:28:59 / cg"
  1796     "Created: / 30-04-2016 / 15:28:59 / cg"
  1813     "Modified: / 30-04-2016 / 20:17:35 / cg"
  1797     "Modified: / 30-04-2016 / 20:17:35 / cg"
  1814 !
  1798 !
  1815 
  1799 
       
  1800 addTypeOfMessageNode:expr forAssignmentTo:varName to:setOfTypes
       
  1801     "pick up low hanging type information.
       
  1802      This is far from being complete, but often gives a hint good enough for code completion
       
  1803      and info in the browser."
       
  1804 
       
  1805     |valClass msgSelector msgReceiver|
       
  1806 
       
  1807     msgSelector := expr selector.
       
  1808     msgReceiver := expr receiver.
       
  1809         
       
  1810     msgSelector == #? ifTrue:[
       
  1811         self addTypeOfExpressionNode:(expr arg1) forAssignmentTo:varName to:setOfTypes.
       
  1812         ^ setOfTypes
       
  1813     ].
       
  1814     
       
  1815     "/ really really only very low hanging fruit...
       
  1816     "/ ignore #/ here, because of filename
       
  1817     ( #(+ - *) includes:msgSelector ) ifTrue:[
       
  1818         "/ ignore foo := foo OP expr
       
  1819         "/ ignore foo := expr OP foo
       
  1820         (msgReceiver isVariable and:[msgReceiver name = varName]) ifFalse:[
       
  1821             (expr arg1 isVariable and:[expr arg1 name = varName]) ifFalse:[
       
  1822                 self rememberType:Number in:setOfTypes.
       
  1823             ]
       
  1824         ].
       
  1825         ^ setOfTypes.
       
  1826     ].
       
  1827 
       
  1828     ( #(// size hash identityHash) includes:msgSelector ) ifTrue:[
       
  1829         self rememberType:Integer in:setOfTypes.
       
  1830         ^ setOfTypes.
       
  1831     ].
       
  1832     
       
  1833     ( #(next next:) includes:msgSelector ) ifTrue:[
       
  1834         |rcvrTypes|
       
  1835         
       
  1836         rcvrTypes := self addTypeOfExpressionNode:msgReceiver forAssignmentTo:nil to:Set new.
       
  1837         rcvrTypes notEmpty ifTrue:[
       
  1838 self breakPoint:#cg.
       
  1839             self rememberType:Character in:setOfTypes.
       
  1840         ].
       
  1841         ^ setOfTypes.
       
  1842     ].
       
  1843     
       
  1844     ( msgSelector startsWith:'as') ifTrue:[
       
  1845         valClass := Smalltalk classNamed:(msgSelector copyFrom:3).
       
  1846         valClass notNil ifTrue:[
       
  1847             self rememberType:valClass in:setOfTypes.
       
  1848             ^ setOfTypes.
       
  1849         ].
       
  1850     ].
       
  1851     
       
  1852     ( #(copy shallowCopy) includes:msgSelector ) ifTrue:[
       
  1853         msgReceiver isLiteral ifTrue:[
       
  1854             self addTypeOfExpressionNode:msgReceiver forAssignmentTo:varName to:setOfTypes.
       
  1855         ].
       
  1856         ^ setOfTypes
       
  1857     ].
       
  1858 
       
  1859     msgReceiver isGlobal ifTrue:[
       
  1860         |instCreatorMessages globalValue implMethod|
       
  1861 
       
  1862         instCreatorMessages := #(new new: basicNew basicNew:).
       
  1863         
       
  1864         globalValue := msgReceiver value.
       
  1865         globalValue isBehavior ifTrue:[
       
  1866             ( instCreatorMessages includes:msgSelector ) ifTrue:[
       
  1867                 self rememberType:globalValue in:setOfTypes.
       
  1868                 ^ setOfTypes.
       
  1869             ].
       
  1870             implMethod := globalValue class lookupMethodFor:msgSelector.
       
  1871             "/ mhmh - fuzzy; if the implementing message sends any of the above to itself...
       
  1872             "/ assume it is returning it.
       
  1873             implMethod isNil ifTrue:[
       
  1874                 "/ will not be understood
       
  1875 self breakPoint:#cg.
       
  1876                 ^ setOfTypes.
       
  1877             ].    
       
  1878             (implMethod messagesSentToSelf includesAny:instCreatorMessages) ifTrue:[
       
  1879 self breakPoint:#cg.
       
  1880                 self rememberType:globalValue in:setOfTypes.
       
  1881                 ^ setOfTypes.
       
  1882             ].    
       
  1883             "/ very fuzzy - if the implementing method is in the "instance creation" category...
       
  1884             ((implMethod category ? '') startsWith:'instance creation') ifTrue:[
       
  1885 self breakPoint:#cg.
       
  1886                 self rememberType:globalValue in:setOfTypes.
       
  1887                 ^ setOfTypes.
       
  1888             ].    
       
  1889         ].
       
  1890         self breakPoint:#cg.
       
  1891         ^ setOfTypes
       
  1892     ].
       
  1893     
       
  1894 self breakPoint:#cg.
       
  1895     ^ setOfTypes
       
  1896 !
       
  1897 
  1816 addTypesAssignedToInstvar:instVarName inClass:aClass method:aMethod to:setOfTypes
  1898 addTypesAssignedToInstvar:instVarName inClass:aClass method:aMethod to:setOfTypes
  1817     "look to asssignments to an instance variable, and pick up low hanging class information.
  1899     "look to asssignments to an instance variable, and pick up low hanging class information.
  1818      This is far from being complete, but gives a hint good enough for code completion
  1900      This is far from being complete, but often gives a hint good enough for code completion
  1819      and info in the browser."
  1901      and info in the browser."
  1820 
  1902 
  1821     | code |
  1903     | code |
  1822 
  1904 
  1823     code := aMethod source.
  1905     code := aMethod source.
  1828     "Created: / 30-04-2016 / 15:07:33 / cg"
  1910     "Created: / 30-04-2016 / 15:07:33 / cg"
  1829 !
  1911 !
  1830 
  1912 
  1831 addTypesAssignedToInstvar:instVarName inClass:aClass source:code to:setOfTypes
  1913 addTypesAssignedToInstvar:instVarName inClass:aClass source:code to:setOfTypes
  1832     "look to asssignments to an instance variable, and pick up low hanging class information.
  1914     "look to asssignments to an instance variable, and pick up low hanging class information.
  1833      This is far from being complete, but gives a hint good enough for code completion
  1915      This is far from being complete, but often gives a hint good enough for code completion
  1834      and info in the browser."
  1916      and info in the browser."
  1835 
  1917 
  1836     |tree|
  1918     |tree|
  1837 
  1919 
  1838     "/ quick check (avoids expensive parse)
  1920     "/ quick check (avoids expensive parse)
  1846     "Created: / 30-04-2016 / 15:09:18 / cg"
  1928     "Created: / 30-04-2016 / 15:09:18 / cg"
  1847 !
  1929 !
  1848 
  1930 
  1849 addTypesAssignedToInstvar:instVarName inClass:aClass to:setOfTypes
  1931 addTypesAssignedToInstvar:instVarName inClass:aClass to:setOfTypes
  1850     "look to asssignments to an instance variable, and pick up low hanging class information.
  1932     "look to asssignments to an instance variable, and pick up low hanging class information.
  1851      This is far from being complete, but gives a hint good enough for code completion
  1933      This is far from being complete, but often gives a hint good enough for code completion
  1852      and info in the browser."
  1934      and info in the browser."
  1853 
  1935 
  1854     aClass methodDictionary do:[:m |
  1936     aClass methodDictionary do:[:m |
  1855         self addTypesAssignedToInstvar:instVarName inClass:aClass method:m to:setOfTypes
  1937         self addTypesAssignedToInstvar:instVarName inClass:aClass method:m to:setOfTypes
  1856     ].
  1938     ].
  1858     "Created: / 30-04-2016 / 14:52:56 / cg"
  1940     "Created: / 30-04-2016 / 14:52:56 / cg"
  1859 !
  1941 !
  1860 
  1942 
  1861 addTypesAssignedToInstvar:instVarName inTree:tree to:setOfTypes
  1943 addTypesAssignedToInstvar:instVarName inTree:tree to:setOfTypes
  1862     "look to asssignments to an instance variable, and pick up low hanging class information.
  1944     "look to asssignments to an instance variable, and pick up low hanging class information.
  1863      This is far from being complete, but gives a hint good enough for code completion
  1945      This is far from being complete, but often gives a hint good enough for code completion
  1864      and info in the browser."
  1946      and info in the browser."
  1865 
  1947 
  1866     |visitor|
  1948     |visitor|
  1867 
  1949 
  1868     visitor := PluggableParseNodeVisitor new. 
  1950     visitor := PluggableParseNodeVisitor new. 
  1869     visitor 
  1951     visitor 
  1870         actionForNodeClass:AssignmentNode 
  1952         actionForNodeClass:AssignmentNode 
  1871         put:[:node |
  1953         put:[:node |
  1872             |leftSide expr|
  1954             (node variable isInstanceVariableNamed:instVarName) ifTrue:[
  1873 
  1955                 self addTypeOfExpressionNode:(node expression) forAssignmentTo:instVarName to:setOfTypes
  1874             leftSide := node variable.
       
  1875             (leftSide isInstanceVariable and:[ leftSide name = instVarName ]) ifTrue:[
       
  1876                 expr := node expression.
       
  1877                 self addTypeOfExpressionNode:expr forAssignmentTo:instVarName to:setOfTypes
       
  1878             ].
  1956             ].
  1879             true "/ yes - visit subnodes
  1957             true "/ yes - visit subnodes
  1880         ].        
  1958         ].        
  1881     visitor visit:tree.
  1959     visitor visit:tree.
  1882 !
  1960 !
  1883 
  1961 
  1884 addTypesAssignedToLocal:localName inTree:tree to:setOfTypes
  1962 addTypesAssignedToLocal:localName inTree:tree to:setOfTypes
  1885     "look to asssignments to an instance variable, and pick up low hanging class information.
  1963     "look to asssignments to a local variable, and pick up low hanging class information.
  1886      This is far from being complete, but gives a hint good enough for code completion
  1964      This is far from being complete, but often gives a hint good enough for code completion
  1887      and info in the browser."
  1965      and info in the browser."
  1888 
  1966 
  1889     |visitor|
  1967     |visitor|
  1890 
  1968 
  1891     "/ hack, allowing to deal with both types of AST (sigh)
  1969     "/ hack, allowing to deal with both types of AST (sigh)
  1892     (tree isKindOf:(Smalltalk at:#RBProgramNode)) ifTrue:[
  1970     (tree isKindOf:(Smalltalk at:#RBProgramNode)) ifTrue:[
  1893         visitor := (Smalltalk at:#RBPluggableProgramNodeVisitor) new.
  1971         visitor := (Smalltalk at:#RBPluggableProgramNodeVisitor) new.
  1894         visitor 
  1972         visitor 
  1895             actionForNodeClass:(Smalltalk at:#RBAssignmentNode)
  1973             actionForNodeClass:(Smalltalk at:#RBAssignmentNode)
  1896             put:[:node |
  1974             put:[:node |
  1897                 |leftSide expr|
  1975                 |leftSide|
  1898 
  1976 
  1899                 leftSide := node variable.
  1977                 leftSide := node variable.
  1900                 (leftSide isTemporary and:[ leftSide name = localName ]) ifTrue:[
  1978                 (leftSide isTemporary and:[ leftSide name = localName ]) ifTrue:[
  1901                     expr := node value.
  1979                     self addTypeOfExpressionNode:(node value) forAssignmentTo:localName to:setOfTypes
  1902                     self addTypeOfExpressionNode:expr forAssignmentTo:localName to:setOfTypes
       
  1903                 ].
  1980                 ].
  1904                 true "/ yes - visit subnodes
  1981                 true "/ yes - visit subnodes
  1905             ].        
  1982             ].        
  1906         visitor visitNode:tree.
  1983         visitor visitNode:tree.
  1907     ] ifFalse:[    
  1984     ] ifFalse:[    
  1996     "Modified: / 30-04-2016 / 20:05:09 / cg"
  2073     "Modified: / 30-04-2016 / 20:05:09 / cg"
  1997 ! !
  2074 ! !
  1998 
  2075 
  1999 !Explainer class methodsFor:'utilities'!
  2076 !Explainer class methodsFor:'utilities'!
  2000 
  2077 
       
  2078 actionToBrowseClass:class
       
  2079     ^ self actionToBrowseClass:class selector:nil.
       
  2080 !
       
  2081 
  2001 actionToBrowseClass:class selector:selectorOrNil
  2082 actionToBrowseClass:class selector:selectorOrNil
  2002     selectorOrNil isNil ifTrue:[
  2083     ^ [
  2003         ^ [Tools::NewSystemBrowser openInClass:class]
  2084         self thisOrNewBrowserInto:[:browser :openHow |
  2004     ] ifFalse:[
  2085             browser
  2005         ^ [Tools::NewSystemBrowser openInClass:class selector:selectorOrNil]
  2086                 spawnFullBrowserInClass:class selector:selectorOrNil in:openHow
  2006     ].    
  2087 "/                    spawnMethodBrowserFor:{class compiledMethodAt:selectorOrNil}
       
  2088 "/                    in:openHow 
       
  2089 "/                    label:nil
       
  2090         ]
       
  2091     ]. 
  2007 !
  2092 !
  2008 
  2093 
  2009 actionToBrowseClasses:classes 
  2094 actionToBrowseClasses:classes 
  2010     ^ [Tools::NewSystemBrowser browseClasses:classes]
  2095     ^ [
  2011 !
  2096         self thisOrNewBrowserInto:[:browser :openHow |
  2012 
  2097             browser
  2013 actionToBrowseImplementorsOf:selector 
  2098                 spawnClassBrowserFor:classes in:openHow
       
  2099         ]
       
  2100     ]
       
  2101     "/ ^ [Tools::NewSystemBrowser browseClasses:classes]
       
  2102 !
       
  2103 
       
  2104 actionToBrowseImplementorsOf:selector
       
  2105     ^ [
       
  2106         self thisOrNewBrowserInto:[:browser :openHow |
       
  2107             browser
       
  2108                 spawnMethodImplementorsBrowserFor:{ selector }
       
  2109                 in:openHow
       
  2110         ]
       
  2111     ]
       
  2112 !
       
  2113 
       
  2114 actionToBrowseInstvarRefsTo:instVarName inClass:class
       
  2115     ^ [(Tools::NewSystemBrowser basicNew)
       
  2116             browseVarRefsToAny:{ instVarName }
       
  2117             classes:{ class }
       
  2118             variables:#instVarNames access:#readOrWrite all:true
       
  2119             title:'references to ',instVarName
       
  2120             in:#newBrowser
       
  2121       ]
       
  2122 !
       
  2123 
       
  2124 actionToBrowseMethod:mthd
       
  2125     ^ self actionToBrowseClass:(mthd mclass) selector:(mthd selector).
       
  2126 !
       
  2127 
       
  2128 actionToOpenMethodFinderFor:selector 
  2014     MethodFinderWindow notNil ifTrue:[
  2129     MethodFinderWindow notNil ifTrue:[
  2015         ^ [MethodFinderWindow openOnSelectorPattern:selector].
  2130         ^ [MethodFinderWindow openOnSelectorPattern:selector].
  2016     ].
  2131     ].
       
  2132     ^ self actionToBrowseImplementorsOf:selector
       
  2133 !
       
  2134 
       
  2135 asClassLink:nameOfClass
       
  2136     "return text with a hyperlink to browse a class by that name"
  2017     
  2137     
  2018     ^ [UserPreferences systemBrowserClass browseImplementorsOf:selector]
  2138     |cls|
       
  2139     
       
  2140     cls := Smalltalk classNamed:nameOfClass string asUppercaseFirst.
       
  2141     cls isNil ifTrue:[^ nameOfClass].
       
  2142 
       
  2143     ^ self asLink:nameOfClass to:(self actionToBrowseClass:cls) 
       
  2144 !
       
  2145 
       
  2146 asLink:aString to:action
       
  2147     ^ (aString actionForAll:action)
       
  2148         withColor:(Color blue)
       
  2149 !
       
  2150 
       
  2151 infoStringForClasses:aCollectionOfClasses withPrefix:prefix
       
  2152     "get a nice user readable list for some classes.
       
  2153      Up to 4 are named, otherwise the count is presented.
       
  2154      The prefix can be sth like ' other', ' sub', ' super',
       
  2155      ' implementing' etc. Or it can be an empty string.
       
  2156      To be shown in the info line at the bottom."
       
  2157 
       
  2158     |nClassNames classes sortedByName classNames
       
  2159      link1 link2 link3 link4|
       
  2160 
       
  2161     aCollectionOfClasses isEmpty ifTrue:[
       
  2162         ^ 'No %1classes' bindWith:prefix.
       
  2163     ].
       
  2164 
       
  2165     classes := aCollectionOfClasses asIdentitySet asOrderedCollection. 
       
  2166     classNames := classes collect:[:each | each theNonMetaclass name].
       
  2167 
       
  2168     nClassNames := classNames size.
       
  2169 
       
  2170     nClassNames <= 4 ifTrue:[
       
  2171         sortedByName := classNames sortWith:classes.
       
  2172 
       
  2173         link1 := self asLink:classNames first "allBold" to:(self actionToBrowseClass:classes first).
       
  2174         nClassNames == 1 ifTrue:[
       
  2175             ^ '%2' "'1 %1class: %2'" 
       
  2176                 bindWith:prefix 
       
  2177                 with:link1.
       
  2178         ].
       
  2179         link2 := self asLink:classNames second "allBold" to:(self actionToBrowseClass:classes second).
       
  2180         nClassNames == 2 ifTrue:[
       
  2181             ^ '%2 and %3' "'2 %1classes: %2 and %3'" 
       
  2182                 bindWith:prefix
       
  2183                 with:link1
       
  2184                 with:link2.
       
  2185         ].
       
  2186         link3 := self asLink:classNames third "allBold" to:(self actionToBrowseClass:classes third).
       
  2187         nClassNames == 3 ifTrue:[
       
  2188             ^ '%2, %3 and %4' "'3 %1classes: %2, %3 and %4'" 
       
  2189                 bindWith:prefix
       
  2190                 with:link1
       
  2191                 with:link2
       
  2192                 with:link3.
       
  2193         ].
       
  2194         link4 := self asLink:classNames fourth "allBold" to:(self actionToBrowseClass:classes fourth).
       
  2195         nClassNames == 4 ifTrue:[
       
  2196             ^ '%2, %3, %4 and %5' "'4 %1classes: %2, %3, %4 and %5'" 
       
  2197                 bindWith:prefix
       
  2198                 with:link1
       
  2199                 with:link2
       
  2200                 with:link3
       
  2201                 with:link4.
       
  2202         ].
       
  2203     ].
       
  2204     ^ self asLink:('%1 %2classes' bindWith:(nClassNames printString "allBold") with:prefix)
       
  2205         to:(self actionToBrowseClasses:classes)    
       
  2206 
       
  2207     "Modified: / 27-07-2006 / 10:09:02 / cg"
       
  2208 !
       
  2209 
       
  2210 infoStringForMethods:aCollectionOfMethods withPrefix:prefix
       
  2211     "get a nice user readable list for some methods.
       
  2212      Up to 3 are named, otherwise the count is presented.
       
  2213      The prefix can be sth like ' other', ' sender', ' implementor',
       
  2214      Or it can be an empty string.
       
  2215      Result is meant to be shown in the info line at the bottom of a browser."
       
  2216 
       
  2217     |nMethodNames sortedByName methodNames|
       
  2218 
       
  2219     aCollectionOfMethods isEmpty ifTrue:[
       
  2220         ^ 'No %1' bindWith:prefix.
       
  2221     ].
       
  2222 
       
  2223     methodNames := aCollectionOfMethods asOrderedCollection 
       
  2224                     collect:[:each | each whoString].
       
  2225 
       
  2226     nMethodNames := methodNames size.
       
  2227 
       
  2228     nMethodNames <= 3 ifTrue:[
       
  2229         nMethodNames == 1 ifTrue:[
       
  2230             ^ '%2' "'1 %1class: %2'" bindWith:prefix with:(methodNames first allBold).
       
  2231         ].
       
  2232         sortedByName := methodNames sort.
       
  2233         nMethodNames == 2 ifTrue:[
       
  2234             ^ '%2 and %3' "'2 %1classes: %2 and %3'" bindWith:prefix
       
  2235                         with:(sortedByName first allBold)
       
  2236                         with:(sortedByName second allBold).
       
  2237         ].
       
  2238         nMethodNames == 3 ifTrue:[
       
  2239             ^ '%2, %3 and %4' "'3 %1classes: %2, %3 and %4'" bindWith:prefix
       
  2240                         with:(sortedByName first allBold)
       
  2241                         with:(sortedByName second allBold)
       
  2242                         with:(sortedByName third allBold).
       
  2243         ].
       
  2244         nMethodNames == 4 ifTrue:[
       
  2245             ^ '%2, %3, %4 and %5' "'4 %1classes: %2, %3, %4 and %5'" bindWith:prefix
       
  2246                         with:(sortedByName first allBold)
       
  2247                         with:(sortedByName second allBold)
       
  2248                         with:(sortedByName third allBold)
       
  2249                         with:(sortedByName fourth allBold).
       
  2250         ].
       
  2251     ].
       
  2252     ^ '%1 %2methods' bindWith:nMethodNames printString allBold with:prefix.
       
  2253 
       
  2254     "
       
  2255      Time millisecondsToRun:[
       
  2256          self infoStringForMethods:(SystemBrowser allCallsOn:#'at:put:') withPrefix:''
       
  2257      ].   
       
  2258      Time millisecondsToRun:[
       
  2259          self infoStringForMethods:(SystemBrowser allCallsOn:#'actionToBrowseClasses:') withPrefix:''
       
  2260      ].
       
  2261     "
       
  2262 !
       
  2263 
       
  2264 methodImplementorsInfoFor:aMethod inEnvironment:environment
       
  2265     "get something about the implementors of aMethod
       
  2266      to be shown in the info line at the bottom"
       
  2267 
       
  2268     |implementors msg senders msg2|
       
  2269 
       
  2270     implementors := SystemBrowser
       
  2271         findImplementorsOf:aMethod selector
       
  2272         in:(environment allClasses)
       
  2273         ignoreCase:false.
       
  2274 
       
  2275     implementors notEmpty ifTrue:[
       
  2276         msg := 'Only implemented here.'.
       
  2277         implementors remove:aMethod ifAbsent:nil.
       
  2278         implementors notEmpty ifTrue:[
       
  2279             implementors := implementors collect:[:mthd | mthd mclass ? mthd getMclass].
       
  2280             implementors notEmpty ifTrue:[
       
  2281                 msg := 'Also implemented in '.
       
  2282                 msg := msg , (self infoStringForClasses:implementors withPrefix:'other ').
       
  2283                 msg := msg , '.'.
       
  2284             ]
       
  2285         ].
       
  2286     ].
       
  2287 
       
  2288 false ifTrue:[  "/ too slow
       
  2289     senders := SystemBrowser
       
  2290         findSendersOf:aMethod selector
       
  2291         in:(environment allClasses)
       
  2292         ignoreCase:false.
       
  2293     senders notEmpty ifTrue:[
       
  2294         msg2 := 'Sent from ' , senders size printString, ' methods.'.
       
  2295     ] ifFalse:[
       
  2296         msg2 := 'No senders.'.
       
  2297     ].
       
  2298     msg := msg , '/' , msg2
       
  2299 ].
       
  2300 
       
  2301     ^ msg
       
  2302 !
       
  2303 
       
  2304 methodInheritanceInfoFor:aMethod
       
  2305     |methodsSuperclass inheritedClass msg methodsClass selector mthd selectorString|
       
  2306 
       
  2307     methodsClass := aMethod mclass.
       
  2308     methodsClass isNil ifTrue:[^ nil].
       
  2309 
       
  2310     methodsSuperclass := methodsClass superclass.
       
  2311     methodsSuperclass isNil ifTrue:[^ nil].
       
  2312 
       
  2313     selector := aMethod selector.
       
  2314     selector isNil ifTrue:[^ nil].
       
  2315 
       
  2316     inheritedClass := methodsSuperclass whichClassIncludesSelector:selector.
       
  2317     inheritedClass isNil ifTrue:[^ nil].
       
  2318     
       
  2319     mthd := inheritedClass compiledMethodAt:selector.
       
  2320 
       
  2321     (mthd sends:#'subclassResponsibility') ifTrue:[
       
  2322         msg := '%1 overrides subclassResponsibility in %2'.
       
  2323     ] ifFalse:[
       
  2324         msg := '%1 overrides implementation in %2'.
       
  2325     ].
       
  2326     selectorString := selector contractTo:30.
       
  2327     ^ msg 
       
  2328         bindWith:(self asLink:selectorString "allBold" to:(self actionToOpenMethodFinderFor:selector))
       
  2329         with:(self asLink:inheritedClass name "allBold" 
       
  2330                 to:(self actionToBrowseClass:inheritedClass selector:selector))
       
  2331 !
       
  2332 
       
  2333 methodRedefinitionInfoFor:aMethod
       
  2334     "return a user readable string telling in how many subclasses
       
  2335      a method is redefined.
       
  2336      To be shown in the info line of a browser"
       
  2337      
       
  2338     |redefiningClasses msg cls|
       
  2339 
       
  2340     cls := aMethod mclass.
       
  2341     cls isNil ifTrue:[^ nil].
       
  2342 
       
  2343     redefiningClasses := cls allSubclasses select:[:cls | cls includesSelector:aMethod selector. ].
       
  2344     redefiningClasses size > 0 ifTrue:[
       
  2345         msg := 'redefined in '.
       
  2346         msg := msg , (self infoStringForClasses:redefiningClasses withPrefix:'sub').
       
  2347         msg := msg , '.'.
       
  2348     ].
       
  2349 
       
  2350     ^ msg
       
  2351 !
       
  2352 
       
  2353 methodSendersInfoFor:selector inEnvironment:environment
       
  2354     "get something about the senders of a message.
       
  2355      to be shown in the info line at the bottom.
       
  2356      This may be slow; so think about doing it in background..."
       
  2357 
       
  2358     |senders|
       
  2359 
       
  2360     senders := SystemBrowser
       
  2361                 findSendersOf:selector
       
  2362                 in:(environment allClasses)
       
  2363                 ignoreCase:false
       
  2364                 match:false.
       
  2365 
       
  2366     senders notEmpty ifTrue:[
       
  2367         ^ 'Sent from ' , senders size printString, ' methods.'.
       
  2368     ] ifFalse:[
       
  2369         ^ 'No senders.'.
       
  2370     ].
       
  2371 !
       
  2372 
       
  2373 methodSpecialInfoFor:aMethod
       
  2374     "handles special cases - such as documentation methods"
       
  2375 
       
  2376     |cls sel|
       
  2377 
       
  2378     (cls := aMethod mclass) isNil ifTrue:[^ nil].
       
  2379     (sel := aMethod selector) isNil ifTrue:[^ nil].
       
  2380 
       
  2381     cls isMeta ifTrue:[
       
  2382         (AbstractSourceCodeManager isVersionMethodSelector:sel) ifTrue:[
       
  2383             ^ 'The version method is required for the source code repository - do not modify.'.
       
  2384         ].
       
  2385         sel == #documentation ifTrue:[
       
  2386             ^ 'ST/X stores documentation in this method (not in comment slots)'.
       
  2387         ].
       
  2388     ].
       
  2389     ^ nil
       
  2390 !
       
  2391 
       
  2392 thisOrNewBrowserInto:aTwoArgBlock
       
  2393     "if I am invoked by a browser, 
       
  2394      invoke the twoArgBlock withit and an #newBuffer arg.
       
  2395      Otherwise, create a new (invisible) browser and pass it to the block
       
  2396      with a #newBrowser arg."
       
  2397      
       
  2398     |windowGroupClass browserClass wg app|
       
  2399     
       
  2400     "/ stupid: I am in libcomp; should be in libtool
       
  2401     windowGroupClass := Smalltalk at:#WindowGroup.
       
  2402     windowGroupClass isNil ifTrue:[^ self].
       
  2403     browserClass := Smalltalk at:#'Tools::NewSystemBrowser'.
       
  2404     browserClass isNil ifTrue:[^ self].
       
  2405     
       
  2406     ((wg := windowGroupClass activeGroup) notNil
       
  2407         and:[ (app := wg application) isKindOf:browserClass ]
       
  2408     ) ifTrue:[
       
  2409         ^ aTwoArgBlock value:app value:#newBuffer
       
  2410     ].        
       
  2411     ^ aTwoArgBlock value:(browserClass basicNew) value:#newBrowser
  2019 ! !
  2412 ! !
  2020 
  2413 
  2021 !Explainer class methodsFor:'documentation'!
  2414 !Explainer class methodsFor:'documentation'!
  2022 
  2415 
  2023 version
  2416 version