package org.rubypeople.rdt.internal.ti.util; import java.util.LinkedList; import java.util.List; import org.jruby.ast.ClassNode; import org.jruby.ast.DefnNode; import org.jruby.ast.DefsNode; import org.jruby.ast.ModuleNode; import org.jruby.ast.Node; import org.rubypeople.rdt.internal.ti.TypeInferenceHelper; /** * Visitor to find all method definitions within a specific scope. * @author Jason Morrison */ public class MethodDefinitionLocator extends NodeLocator { //Singleton pattern private MethodDefinitionLocator() {} private static MethodDefinitionLocator staticInstance = new MethodDefinitionLocator(); public static MethodDefinitionLocator Instance() { return staticInstance; } /** Inference helper */ private TypeInferenceHelper helper = TypeInferenceHelper.Instance(); /** Type of receiver to look for */ private String typeName; /** Name of method to search for invocations of */ private String methodName; /** Running total of results */ private List<Node> locatedNodes; /** * Finds all method definition node within rootNode whose enclosing type is of type typeName and method is named methodName * @param rootNode Node to search within * @param source Source to search within * @param typeName Name of type of method-send-expr receiver * @param methodName Name of method to find * @return */ public List<Node> findMethodDefinitions( Node rootNode, String typeName, String methodName ) { if ( rootNode == null ) { return null; } this.locatedNodes = new LinkedList<Node>(); this.typeNameStack = new LinkedList<String>(); this.typeName = typeName; this.methodName = methodName; typeNameStack.add("Kernel"); // Traverse to find all matches rootNode.accept(this); // Return the matches return locatedNodes; } public Object handleNode(Node iVisited) { if ( ( iVisited instanceof DefnNode ) || ( iVisited instanceof DefsNode ) ) { if ( peekType().equals(typeName)) { String methodName = helper.getMethodDefinitionNodeName( iVisited ); if ( methodName.equals(this.methodName) ) { locatedNodes.add(iVisited); } } } return super.handleNode(iVisited); } public Object visitClassNode(ClassNode iVisited) { pushType( helper.getTypeNodeName( iVisited ) ); super.visitClassNode( iVisited ); popType(); return null; } public Object visitModuleNode(ModuleNode iVisited) { pushType( helper.getTypeNodeName( iVisited ) ); super.visitModuleNode( iVisited ); popType(); return null; } }