eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'ParseTreeSearcher':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: ParseTreeSearcher


Inheritance:

   Object
   |
   +--RBProgramNodeVisitor
      |
      +--ParseTreeSearcher
         |
         +--ParseTreeRewriter

Package:
stx:goodies/refactoryBrowser/parser
Category:
Refactory-ParseTree Matching
Version:
rev: 1.89 date: 2024/01/22 14:20:55
user: cg
file: ParseTreeSearcher.st directory: goodies/refactoryBrowser/parser
module: stx stc-classLibrary: parser

Description:


ParseTreeSearcher walks over a normal source code parse tree using the visitor pattern, and then matches these nodes against the meta-nodes using the match:inContext: methods defined for the meta-nodes.

Instance Variables:
        answer              <Object>                
                            the 'answer' that is propagated between matches

        argumentSearches    <Collection of: (Association key: BRProgramNode value: BlockClosure)>   
                            argument searches (search for the BRProgramNode and perform the Block when it is found)

        context             <BRSmallDictionary>     
                            a dictionary that contains what each meta-node matches against. This could be a normal Dictionary that is created for each search, but is created once and reused (efficiency).

        searches            <Collection of: (Association key: BRProgramNode value: BlockClosure)>   
                            non-argument searches (search for the BRProgramNode and perform the Block when its found)

        currentSearchContext            
                            the current search context (from checkMethod:) 
                            so that match rules can determine where they are (see RBToDoFillRule)

        suppressQuickStringSearches
                            can be set to suppress quick string searches in the SearchRules;
                            this must be set to search in the expanded code of synthetic messageSends
                            (eg. to find the i'xxx' expressions when searching for senders of #resources).


Class protocol:

accessing
o  treeMatching: aString in: aParseTree

o  treeMatchingStatements: aString in: aParseTree

instance creation
o  allMessageSends
return a searcher which searches all messageSends
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m self foo. self bar. self baz:(self foe)'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSends.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allMessageSendsForWhich: aFilter
return a searcher which searches all messageSends
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m self foo. self bar. self baz:(self foe)'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsForWhich:[:aNode | aNode selector numArgs == 0].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allMessageSendsMatching: pattern ignoreCase: doIgnoreCase
return a searcher which searches all messageSends which GLOB match a given pattern
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m self foo. self barFoe. self baz:(self foe)'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsMatching:'*fo*' ignoreCase:false.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m self foo. self barFoe. self baz:(self foe)'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsMatching:'*fo*' ignoreCase:true.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allMessageSendsMatchingAny: patternCollection ignoreCase: doIgnoreCase
return a searcher which searches all messageSends which GLOB match any pattern of a given set of patterns
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m self foo. self fOO. self barFoe. self xFoe.  self baz:(self foe)'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsMatchingAny:#('fo*' 'b*Fo*') ignoreCase:false.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.
     searcher := ParseTreeSearcher allMessageSendsMatchingAny:#('fo*' 'b*Fo*') ignoreCase:true.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allMessageSendsTo: searchSelector ignoreCase: doIgnoreCase
return a searcher which searches all messageSends with a particular selector
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m self foo. self barFoe. self xFoe.  self baz:(self foe)'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsTo:#'xfoe' ignoreCase:true.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allMessageSendsToAny: selectorCollection ignoreCase: doIgnoreCase
return a searcher which searches all messageSends with a selector from a given set of selectors
(collects messageSend nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m self foo. self barFoe. self xFoe.  self baz:(self foe)'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allMessageSendsToAny:#('foe' 'xfoe') ignoreCase:true.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allModificationsOfAnyVariableIn: aCollectionOfVariableNames
return a searcher which searches all modifications of any variable in aCollectionOfVariableNames
(collects assignment nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz faz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := faz := 5.'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allModificationsOfAnyVariableIn:#('foo' 'baz').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz faz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := faz := 5.'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allModificationsOfAnyVariableIn:#('f*' '*z').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allModificationsOfGlobalVariablesMatching: aFilter
return a searcher which searches all variable modifications
(collects assignement nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m |foo bar baz| Array := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5.'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allModificationsOfGlobalVariablesMatching:[:aNode | true].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allModificationsOfVariable: aVariableNameOrPattern
return a searcher which searches all modifications of a variable
(collects assignment nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz faz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := faz := 5.'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allModificationsOfVariable:'foo'.
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allModificationsOfVariablesMatching: aFilter
return a searcher which searches all variable modifications
(collects assignement nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5.'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allModificationsOfVariablesMatching:[:aNode | true].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allReadsOfAnyVariableIn: aCollectionOfVariableNames
return a searcher which searches all reads of any variable in aCollectionOfVariableNames
(collects variable nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1.'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReadsOfAnyVariableIn:#('foo').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5. self bar. self bar:baz'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReadsOfAnyVariableIn:#('foo' 'bar').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5. self bar. self bar:baz'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReadsOfAnyVariableIn:#('b*').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allReadsOfVariablesMatching: aFilter
return a searcher which searches all variable reads
(collects variable nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5.'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReadsOfVariablesMatching:[:aNode | true].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m |foo bar baz| foo := 1. bar := foo. foo := foo.'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReadsOfVariablesMatching:[:aNode | true].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allReferencesToAnyVariableIn: aCollectionOfVariableNames
return a searcher which searches all references to any variable in aCollectionOfVariableNames
(collects variable nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1.'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReferencesToAnyVariableIn:#('foo').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5. self bar. self bar:baz'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReferencesToAnyVariableIn:#('foo' 'bar').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
                     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5. self bar. self bar:baz'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReferencesToAnyVariableIn:#('b*').
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  allReferencesToVariablesMatching: aFilter
return a searcher which searches all variable references
(collects variable nodes)

Usage example(s):

     |tree searcher nodes|

     tree := RBParser
		     parseSearchMethod:'m |foo bar baz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := 5.'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher allReferencesToVariablesMatching:[:aNode | true].
     searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
     nodes.

o  getterMethod: aVarName
return a searcher which matches a getter method for a variable named aVarName.
Returns nil if no match,
or the selector of the method (which may be different from varName) if it does.
Slightly different from isGetterMethod, which requires that the method's name is the same as the variable's

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ foo'
                     onError: [:str :pos | nil].

     searcher := self getterMethod:'foo'.
     searcher executeTree:tree.          

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ bar'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher getterMethod:'foo'.
     searcher executeTree:tree.        

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ bar'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher getterMethod:'bar'.
     searcher executeTree:tree.        

o  handlesException
return a searcher which matches a method which handles an exception.
Returns false if no match, true otherwise.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg [ foo := arg ] on:Error do:[]'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher handlesException.
     searcher executeTree:tree.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg foo := arg'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher handlesException.
     searcher executeTree:tree.

o  hasGuardingIf
|tree searcher|

tree := RBParser
parseSearchMethod:'foo:arg arg ifTrue:[ arg fooBar ]'
onError: [:str :pos | nil].

searcher := self hasGuardingIf.
searcher executeTree:tree initialAnswer:false.

tree := RBParser
parseSearchMethod:'foo:arg arg fooBar'
onError: [:str :pos | nil].

searcher := self hasGuardingIf.
searcher executeTree:tree initialAnswer:false.

o  isGetterMethod
return a searcher which matches any getter method (just gets a variable and has the same name).
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ foo'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterMethod.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ bar'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterMethod.
     searcher executeTree:tree initialAnswer:false.

o  isGetterMethod: aVarName
return a searcher which matches a getter method for aVarName.
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ foo'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterMethod:'foo'.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ foo + 1'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterMethod:'foo'.
     searcher executeTree:tree initialAnswer:false.

o  isGetterOrSetterMethod
return a searcher which matches a getter or setter method.
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg foo := arg'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterOrSetterMethod.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo ^ foo'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterOrSetterMethod.
     searcher executeTree:tree initialAnswer:false.

o  isGetterOrSetterMethod: aVarName
return a searcher which matches a getter or setter method for aVarName.
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg foo := arg'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isGetterOrSetterMethod:'foo'.
     searcher executeTree:tree initialAnswer:false.

o  isJustReturningBoolean
return a searcher which matches a simple ^true or ^false method (i.e. a tester).
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningBoolean.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

     tree := RBParser
                     parseSearchMethod:'foo ^false'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

     tree := RBParser
                     parseSearchMethod:'foo:bla ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

o  isJustReturningFalse
return a searcher which matches a simple ^false method (i.e. a tester).
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningFalse.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false) not.

     tree := RBParser
                     parseSearchMethod:'foo ^false'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

     tree := RBParser
                     parseSearchMethod:'foo:bla ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false) not.

o  isJustReturningItsArgument
return a searcher which matches a simple ^ arg.
That method definitely has no side effects.
Returns false if no match, true if it does.

Usage example(s):

should match

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg ^arg'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningItsArgument.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

should NOT match

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg1 foo:arg2 ^arg1'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningItsArgument.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

should NOT match
     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^123'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningItsArgument.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

should NOT match
     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ bar'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningItsArgument.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

should NOT match
     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ 123 bla'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningItsArgument.
     searcher executeTree:tree initialAnswer:false.

o  isJustReturningLiteralString: aLiteralString
return a searcher which matches a simple ^ literal.
Returns false if no match, true if it does.
Notice the somewhat misleading name of this method:
not a string-literal, but the string of a literal is passed in;
i.e. to test for a true-returner, pass 'true',
but for a true-string returner, pass '''true''' (with quotes).

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningLiteralString:'0'.
     self assert:( searcher executeTree:tree initialAnswer:false ) not.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningLiteralString:'true'.
     self assert:( searcher executeTree:tree initialAnswer:false ).

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ 0'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningLiteralString:'0'.
     self assert:( searcher executeTree:tree initialAnswer:false ).

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ ''true'''
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningLiteralString:'''true'''.
     self assert:( searcher executeTree:tree initialAnswer:false ).

o  isJustReturningSelf
return a searcher which matches a simple ^ self.
That method definitely has no side effects.
Returns false if no match, true if it does.

ATTENTION:
matches methods with or without arguments

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningSelf.

     tree := RBParser
                     parseSearchMethod:'foo ^self'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

     tree := RBParser
                     parseSearchMethod:'foo:bla ^self'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

o  isJustReturningSomething
return a searcher which matches a simple ^ something.
That method definitely has no side effects.
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningSomething.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

     tree := RBParser
                     parseSearchMethod:'foo:bla ^true'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

     tree := RBParser
                     parseSearchMethod:'foo:bla ^self'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

     tree := RBParser
                     parseSearchMethod:'foo self assert:true. ^true'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^123'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningSomething.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ bar'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningSomething.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ 123 bla'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningSomething.
     searcher executeTree:tree initialAnswer:false.

o  isJustReturningTrue
return a searcher which matches a simple ^true method (i.e. a tester).
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningTrue.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

     tree := RBParser
                     parseSearchMethod:'foo:bla ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^123'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningTrue.
     self assert:(searcher executeTree:tree initialAnswer:false) not

o  isJustReturningTrueOrFalse
return a searcher which matches a simple ^true or ^false method (i.e. a tester).
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningTrueOrFalse.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

     tree := RBParser
                     parseSearchMethod:'foo:bla ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^123'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isJustReturningTrueOrFalse.
     searcher executeTree:tree initialAnswer:false.

o  isJustReturningVariable
return a searcher which matches a simple ^ <var>
(i.e. a getter but not required to be named after the variable).
Returns false if no match, true if it does.

ATTENTION:
the original implementation (from RefactoryInc/Squeak) only matched unary methods;
this was changed in ST/X to also match methods with arguments
(i.e. `@method instead of `method in the match pattern)

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isJustReturningVariable.

     tree := RBParser
                     parseSearchMethod:'foo ^true'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false) not.

     tree := RBParser
                     parseSearchMethod:'foo ^x'
                     onError: [:str :pos | nil].
     self assert:(searcher executeTree:tree initialAnswer:false).

o  isSetterMethod
return a searcher which matches a setter method (just sets a variable and has the same name).
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg foo := arg'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isSetterMethod.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg bar := arg'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isSetterMethod.
     searcher executeTree:tree initialAnswer:false.

o  isSubclassResponsibility
return a searcher which matches a simple 'self subclassResponsibility'.
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher matches|

     searcher := ParseTreeSearcher isSubclassResponsibility.
     matches := OrderedCollection new.
     Method allInstancesDo:[:m |
         |tree|

         (tree := m parseTree) notNil ifTrue:[
             (searcher executeTree:(m parseTree) initialAnswer:false) ifTrue:[
                 matches add:m
             ] 
         ] 
     ].
     Tools::NewSystemBrowser browseMethods:matches.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^self subclassResponsibility'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isSubclassResponsibility.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo self subclassResponsibility'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isSubclassResponsibility.
     searcher executeTree:tree initialAnswer:false.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ self bla subclassResponsibility'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher isSubclassResponsibility.
     searcher executeTree:tree initialAnswer:false.

o  isUsingValueFromMessage: aSelector
return a searcher which searches for
senders of aSelector AND which use the returned value.
This is useful if one isn't sure, if self or sth. else should be returned from
a method. Especially, if one (re-)defines a methid which is already present in other
classes in the system; such as add:/do: etc.
Returns false if no match, true if it does.

ATTENTION:
matches methods with or without arguments

Usage example(s):

     |tree searcher|

     searcher := ParseTreeSearcher isUsingValueFromMessage:#add:.

     tree := RBParser
                     parseSearchMethod:'foo:arg ^arg add:10'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.   

     tree := RBParser
                     parseSearchMethod:'foo:arg arg add:10. ^self'
                     onError: [:str :pos | nil].
     searcher executeTree:tree initialAnswer:false.     

o  justDelegates
return a searcher which matches a delegating method;
that is one which simply forwards the message to someone else.
Returns false if no match, true if it does.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ instvar foo'
                     onError: [:str :pos | nil].

     searcher := self justDelegates.
     searcher executeTree:tree.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo ^ self foo + 1'
                     onError: [:str :pos | nil].

     searcher := self justDelegates.
     searcher executeTree:tree

o  justSendsSuper
return a searcher which matches a super-sending method.
Returns false if no match, true if it does.

o  raisesException
return a searcher which matches a method which raises an exception.
Returns false if no match, true otherwise.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg [ foo := arg ] on:Error do:[ Error raiseRequest ]'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher raisesException.
     searcher executeTree:tree.

Usage example(s):

     |tree searcher|

     tree := RBParser
		     parseSearchMethod:'foo:arg foo := arg'
		     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher raisesException.
     searcher executeTree:tree.

o  returnSetterMethod: aVarName
return a searcher which matches a returning setter method.
Returns nil if no match, the selector if it does.

o  setterMethod: aVarName
return a searcher which matches a setter method for a variable named aVarName.
Returns nil if no match,
or the selector of the method (which may be different from varName) if it does.
Slightly different from isSetterMethod, which requires that the method's name is the same as the variable's

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg foo := arg'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher setterMethod:'foo'.
     searcher executeTree:tree.

Usage example(s):

     |tree searcher|

     tree := RBParser
                     parseSearchMethod:'foo:arg bar := arg'
                     onError: [:str :pos | nil].

     searcher := ParseTreeSearcher setterMethod:'foo'.
     searcher executeTree:tree.

private
o  buildSelectorString: aSelector

o  buildSelectorTree: aSelector

o  buildTree: aString method: aBoolean

utilities
o  isDefinitelyGetterMethod: aMethod
checks a method for being a true getter (name equals variable returned)

o  matchMethod: aMethod with: aMatcher
common helper for common matches.
aMather (which was probably create with one of my isJustReturningSomething, is*** methods)
is applied to aMethod, and true is returned if it matches.

o  methodIsGetterMethod: aMethod
checks a method for being a true getter (name equals variable returned)

o  methodIsJustReturningSomething: aMethod
checks a method for being a simple return something method
(i.e. definitely no side effects)

Usage example(s):

     self methodIsJustReturningSomething:(Workflow::AbstractPin compiledMethodAt:#owner)

o  methodIsJustReturningTrue: aMethod
checks a method for being a simple return true method
(i.e. definitely no side effects)

Usage example(s):

     self methodIsJustReturningTrue:(TimeDuration compiledMethodAt:#isTimeDuration)

o  methodIsSetterMethod: aMethod
checks a method for being a true setter (name equals variable returned)


Instance protocol:

accessing
o  addArgumentRule: aParseTreeRule

o  addArgumentRules: ruleCollection

o  addArgumentSearches: aSearchCondition

o  addMethodSearches: aSearchCondition

o  addRule: aParseTreeRule

o  addRules: ruleCollection

o  addSearches: aSearchCondition

o  answer

o  computeQuickSearchStrings
Compute a collection of OR-strings to search for.
Each is a string or collection of AND-strings.
This is collected from the individual searches,
of which each may return a collection of AND-strings.
OR means: if any of the elements is present, do a full match;
otherwise reject.
AND means: all of the elements must be present for a full match,
otherwise reject

o  context

o  currentSearchContext

o  currentSearchContext: aSearchContext

o  executeMethod: aParseTree

o  executeMethod: aParseTree initialAnswer: anObject

o  executeTree: aParseTree
Save our current context, in case someone is performing another search inside a match.
Notice: kept for backward compatibility;
cannot forward this to executeTree:in: here, because not everyone (SmallLint and others)
are guaranteed to implement it (but instead redefine executeTree:).

o  executeTree: aParseTree in: optionalClassBeingProcessed
Save our current context, in case someone is performing another search inside a match.

o  executeTree: aParseTree initialAnswer: aValue

o  messages
in ST/X, optimized messages are also in the literal array..

o  moreAnswers
if the rule found multiple places, this returns the other answers

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  searches

o  setMessages: aCollection

converting
o  asSearcher

enumerating
o  matchingNodesForSource: aString tree: anRBProgramNode do: aBlock
Evaluate block for each node in source and its corresponding tree that matches

o  selectionIntervalsForSource: aString tree: anRBProgramNode do: aBlock
Evaluate block for each node's sourceInterval (for highlighting)

o  selectionIntervalsForSource: aString tree: anRBProgramNode in: aClass do: aBlock
Evaluate block for each node's sourceInterval (for highlighting)

o  selectionIntervalsForSource: aString tree: anRBProgramNode rule: aRuleOrNil in: aClass do: aBlock
Evaluate block for each node's sourceInterval (for highlighting).
If aRuleOrNil is not nil, it is given a chance to provide a better interval
for highlighting the seletor of the node only

initialize-release
o  answer: anObject
probably am only interested in the very first answer

o  initialize

obsolete
o  addArgumentSearch: aSearchCondition

o  addMethodSearch: aSearchCondition

o  addSearch: aSearchCondition

o  buildMethodParseTreeRuleFor: aSearchCondition

o  buildParseTreeRuleFor: aSearchCondition

private
o  foundMatch

o  lookForMoreMatchesInContext: oldContext

o  performSearches: aSearchCollection on: aNode
please read the comment in alwaysPerformAllSearches

o  recusivelySearchInContext
We need to save the matched context since the other searches might overwrite it.

o  visitNode: aNode matching: aSearchCollection

o  withSavedContextDo: aBlock
Protect our current context, in case someone is performing another search inside a match.

o  withSavedContextDo: aBlock in: optionalClassBeingProcessed
Protect our current context, in case someone is performing another search inside a match.

searching - setup
o  matches: aString do: aBlock

o  matchesAnyArgumentOf: stringCollection do: aBlock

o  matchesAnyMethodOf: aStringCollection do: aBlock

o  matchesAnyOf: aStringCollection do: aBlock

o  matchesAnyTreeOf: treeCollection do: aBlock

o  matchesArgument: aString do: aBlock

o  matchesArgumentTree: aBRProgramNode do: aBlock

o  matchesMethod: aString do: aBlock

o  matchesTree: aBRProgramNode do: aBlock

testing
o  alwaysPerformAllSearches
a flag, to fix a bug? in the performSearches,
which stops after the first matching searchRule, even if there are more rules to be
considered.
This bug affects the literal replacements, inside literal arrays,
in case multiple such replaces have been defined
eg. a rewriter like:
replacer := ParseTreeSourceRewriter new.
replacer replaceLiteral: #lit1 with: #newLit1.
replacer replaceLiteral: #lit2 with: #newLit2.

The original searcher would only replace one literal and stop performing other replaces,
after the first hit. However, if there is a single literal array with both lit1 and lit2 inside,
all other replaces must also be performed.

As I have no idea on what other effects an unconditional change in performSearches might have,
this new behavior is made conditional on the return value of this method
(and it is redefined in ParseTreeSourceRewriter

o  canMatchMethod: aCompiledMethod
this does a quickReject based on the set of sent messages
(in the searches vs. messages in the method)

o  canQuicklyReject: sourceCode
if I have quickSearchStrings, try a quick reject based on them.
This may generate false negatives (i.e. lets source pass, even though
it should not), but still reduces the amount of parser work in the order
of 90%, thus making code searches 10 times faster.

visiting
o  visitArgument: aNode
(comment from inherited method)
Here to allow subclasses to detect arguments or temporaries.

o  visitNode: aNode


Examples:


|tree searcher nodes|

'the tree to search'.
tree := RBParser
                parseSearchMethod:'m |foo bar baz faz| foo := 1. bar := 2. foo := 3. bar := foo := 4. foo := bar := faz := 5.'
                onError: [:str :pos | nil].

'setup the searcher'.
searcher := ParseTreeSearcher allModificationsOfVariable:'foo'.

'do the search'.
searcher executeTree:tree initialAnswer:(nodes := OrderedCollection new).
nodes.


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Mon, 18 Nov 2024 06:41:03 GMT