|
From: <caw...@us...> - 2007-05-23 19:57:19
|
Revision: 2531
http://svn.sourceforge.net/rubyeclipse/?rev=2531&view=rev
Author: cawilliams
Date: 2007-05-23 12:57:18 -0700 (Wed, 23 May 2007)
Log Message:
-----------
more search cleanup/new functionality added (specifically grabing arguments from block method calls, and indexing/finding method references)
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/MethodReferenceMatch.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceElementParser.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/InOrderVisitor.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MethodLocator.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/MethodReferenceMatch.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/MethodReferenceMatch.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/MethodReferenceMatch.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -10,6 +10,8 @@
*******************************************************************************/
package org.rubypeople.rdt.core.search;
+import java.util.List;
+
import org.eclipse.core.resources.IResource;
import org.rubypeople.rdt.core.IRubyElement;
@@ -25,6 +27,7 @@
public class MethodReferenceMatch extends SearchMatch {
private boolean constructor;
private IRubyElement binding;
+ private List<String> arguments;
/**
* Creates a new method reference match.
@@ -58,8 +61,9 @@
* @param resource the resource of the element
* @since 1.0
*/
- public MethodReferenceMatch(IRubyElement enclosingElement, IRubyElement binding, int accuracy, int offset, int length, boolean constructor, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+ public MethodReferenceMatch(IRubyElement enclosingElement, IRubyElement binding, List<String> args, int accuracy, int offset, int length, boolean constructor, boolean insideDocComment, SearchParticipant participant, IResource resource) {
this(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
+ this.arguments = args;
this.constructor = constructor;
this.binding = binding;
}
@@ -77,5 +81,9 @@
public IRubyElement getBinding() {
return this.binding;
}
+
+ public List<String> getArguments() {
+ return this.arguments;
+ }
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceElementParser.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceElementParser.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceElementParser.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -50,8 +50,10 @@
import org.jruby.ast.InstAsgnNode;
import org.jruby.ast.InstVarNode;
import org.jruby.ast.IterNode;
+import org.jruby.ast.ListNode;
import org.jruby.ast.LocalAsgnNode;
import org.jruby.ast.ModuleNode;
+import org.jruby.ast.MultipleAsgnNode;
import org.jruby.ast.Node;
import org.jruby.ast.RootNode;
import org.jruby.ast.SClassNode;
@@ -370,31 +372,29 @@
public Instruction visitFCallNode(FCallNode iVisited) {
String name = iVisited.getName();
+ List<String> arguments = getArgumentsFromFunctionCall(iVisited);
if (name.equals(REQUIRE) || name.equals(LOAD)) {
addImport(iVisited);
} else if (name.equals(INCLUDE)) { // Collect included mixins
includeModule(iVisited);
} if (name.equals(PUBLIC)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PUBLIC));
}
} else if (name.equals(PRIVATE)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PRIVATE));
}
} else if (name.equals(PROTECTED)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PROTECTED));
}
- } else if (name.equals(MODULE_FUNCTION)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
+ } else if (name.equals(MODULE_FUNCTION)) {
for (String methodName : arguments) {
requestor.acceptModuleFunction(methodName);
}
}
+ requestor.acceptMethodReference(name, arguments.size(), iVisited.getPosition().getStartOffset());
return super.visitFCallNode(iVisited);
}
@@ -455,8 +455,6 @@
}
public Instruction visitVCallNode(VCallNode iVisited) {
- // XXX If the call has arguments, we need to find the method matching the
- // symbols and mark their visibility differently
String functionName = iVisited.getName();
if (functionName.equals(PUBLIC)) {
currentVisibility = Visibility.PUBLIC;
@@ -467,53 +465,34 @@
} else if (functionName.equals(MODULE_FUNCTION)) {
inModuleFunction = true;
}
+ requestor.acceptMethodReference(functionName, 0, iVisited.getPosition().getStartOffset());
return super.visitVCallNode(iVisited);
}
@Override
public Instruction visitCallNode(CallNode iVisited) {
String name = iVisited.getName();
+ List<String> arguments = getArgumentsFromFunctionCall(iVisited);
if (name.equals(PUBLIC)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PUBLIC));
}
} else if (name.equals(PRIVATE)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PRIVATE));
}
} else if (name.equals(PROTECTED)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PROTECTED));
}
} else if (name.equals(MODULE_FUNCTION)) {
- List<String> arguments = getArgumentsFromFunctionCall(iVisited);
for (String methodName : arguments) {
requestor.acceptModuleFunction(methodName);
}
}
+ requestor.acceptMethodReference(name, arguments.size(), iVisited.getPosition().getStartOffset());
return super.visitCallNode(iVisited);
}
-
- private List<String> getArgumentsFromFunctionCall(IArgumentNode iVisited) {
- List<String> arguments = new ArrayList<String>();
- Node argsNode = iVisited.getArgsNode();
- Iterator iter = null;
- if (argsNode instanceof SplatNode) {
- SplatNode splat = (SplatNode) argsNode;
- iter = splat.childNodes().iterator();
- } else if (argsNode instanceof ArrayNode) {
- ArrayNode arrayNode = (ArrayNode) iVisited.getArgsNode();
- iter = arrayNode.childNodes().iterator();
- }
- for (; iter.hasNext();) {
- Node mixinNameNode = (Node) iter.next();
- arguments.add(ASTUtil.getNameReflectively(mixinNameNode));
- }
- return arguments;
- }
public Instruction visitAliasNode(AliasNode iVisited) {
String name = iVisited.getNewName();
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/InOrderVisitor.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/InOrderVisitor.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/InOrderVisitor.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -24,7 +24,9 @@
*/
package org.rubypeople.rdt.internal.core.parser;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import org.jruby.ast.AliasNode;
import org.jruby.ast.AndNode;
@@ -71,10 +73,12 @@
import org.jruby.ast.GlobalAsgnNode;
import org.jruby.ast.GlobalVarNode;
import org.jruby.ast.HashNode;
+import org.jruby.ast.IArgumentNode;
import org.jruby.ast.IfNode;
import org.jruby.ast.InstAsgnNode;
import org.jruby.ast.InstVarNode;
import org.jruby.ast.IterNode;
+import org.jruby.ast.ListNode;
import org.jruby.ast.LocalAsgnNode;
import org.jruby.ast.LocalVarNode;
import org.jruby.ast.Match2Node;
@@ -123,6 +127,7 @@
import org.jruby.ast.ZSuperNode;
import org.jruby.ast.visitor.AbstractVisitor;
import org.jruby.evaluator.Instruction;
+import org.rubypeople.rdt.internal.core.util.ASTUtil;
/**
* @author Chris
@@ -1190,5 +1195,47 @@
protected Instruction visitNode(Node iVisited) {
return null;
}
+
+ protected List<String> getArgumentsFromFunctionCall(IArgumentNode iVisited) {
+ List<String> arguments = new ArrayList<String>();
+ Node argsNode = iVisited.getArgsNode();
+ Iterator iter = null;
+ if (argsNode instanceof SplatNode) {
+ SplatNode splat = (SplatNode) argsNode;
+ iter = splat.childNodes().iterator();
+ } else if (argsNode instanceof ArrayNode) {
+ ArrayNode arrayNode = (ArrayNode) iVisited.getArgsNode();
+ iter = arrayNode.childNodes().iterator();
+ } else if (argsNode == null) {
+ // Block?
+ Node iterNode = null;
+ if (iVisited instanceof FCallNode) {
+ FCallNode fcall = (FCallNode) iVisited;
+ iterNode = fcall.getIterNode();
+ } else if (iVisited instanceof CallNode) {
+ CallNode call = (CallNode) iVisited;
+ iterNode = call.getIterNode();
+ }
+ if (iterNode == null) return arguments;
+ if (iterNode instanceof IterNode) { // yup, it has a block
+ IterNode yeah = (IterNode) iterNode;
+ Node varNode = yeah.getVarNode();
+ if (varNode instanceof DAsgnNode) { // single variable in block
+ DAsgnNode dassgn = (DAsgnNode) varNode;
+ arguments.add(dassgn.getName());
+ } else if (varNode instanceof MultipleAsgnNode) { // multiple variables in block
+ MultipleAsgnNode multi = (MultipleAsgnNode) varNode;
+ ListNode list = multi.getHeadNode();
+ iter = list.iterator();
+ }
+ }
+ }
+ if (iter == null) return arguments;
+ for (; iter.hasNext();) {
+ Node argument = (Node) iter.next();
+ arguments.add(ASTUtil.getNameReflectively(argument));
+ }
+ return arguments;
+ }
}
\ No newline at end of file
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -33,8 +33,11 @@
@Override
public void reportMatches(final RubyScript script, final MatchLocator locator) {
-// reportMatches((IParent) script, locator);
- reportASTMatches(script, locator);
+ if (!this.pattern.findReferences) { // just traverse our own model
+ reportMatches((IParent) script, locator);
+ } else { // they want references too, so we need to traverse the AST
+ reportASTMatches(script, locator);
+ }
}
private void reportASTMatches(final RubyScript script, final MatchLocator locator) {
@@ -43,6 +46,7 @@
if (ast == null) {
ast = new RubyParser().parse(script.getSource());
}
+ final boolean findDeclarations = this.pattern.findDeclarations;
new InOrderVisitor() {
@Override
@@ -51,7 +55,7 @@
return super.visitInstVarNode(iVisited);
}
- // XXX Handle constants!
+ // XXX Handle constant references!
@Override
public Instruction visitGlobalVarNode(GlobalVarNode iVisited) {
@@ -61,13 +65,13 @@
@Override
public Instruction visitConstDeclNode(ConstDeclNode iVisited) {
- match(iVisited);
+ if (findDeclarations) match(iVisited);
return super.visitConstDeclNode(iVisited);
}
@Override
public Instruction visitGlobalAsgnNode(GlobalAsgnNode iVisited) {
- match(iVisited);
+ match(iVisited); // TODO check whether we want to find write references
return super.visitGlobalAsgnNode(iVisited);
}
@@ -79,13 +83,13 @@
@Override
public Instruction visitClassVarAsgnNode(ClassVarAsgnNode iVisited) {
- match(iVisited);
+ match(iVisited); // TODO check whether we want to find write references
return super.visitClassVarAsgnNode(iVisited);
}
@Override
public Instruction visitInstAsgnNode(InstAsgnNode iVisited) {
- match(iVisited);
+ match(iVisited); // TODO check whether we want to find write references
return super.visitInstAsgnNode(iVisited);
}
@@ -154,10 +158,8 @@
private int getAccuracy(String name) {
if (this.pattern.findReferences)
- // must be a write only access with an initializer
- if (this.pattern.writeAccess)
- if (matchesName(this.pattern.name, name.toCharArray()))
- return ACCURATE_MATCH;
+ if (matchesName(this.pattern.name, name.toCharArray()))
+ return ACCURATE_MATCH;
if (this.pattern.findDeclarations) {
if (matchesName(this.pattern.name, name.toCharArray()))
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -4,6 +4,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
@@ -532,6 +533,7 @@
public SearchMatch newMethodReferenceMatch(
IRubyElement enclosingElement,
IRubyElement binding,
+ List<String> arguments,
int accuracy,
int offset,
int length,
@@ -539,7 +541,7 @@
Node reference) {
SearchParticipant participant = getParticipant();
IResource resource = this.currentPossibleMatch.resource;
- return new MethodReferenceMatch(enclosingElement, binding, accuracy, offset, length, isConstructor, false, participant, resource);
+ return new MethodReferenceMatch(enclosingElement, binding, arguments, accuracy, offset, length, isConstructor, false, participant, resource);
}
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MethodLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MethodLocator.java 2007-05-23 19:01:17 UTC (rev 2530)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MethodLocator.java 2007-05-23 19:57:18 UTC (rev 2531)
@@ -1,13 +1,28 @@
package org.rubypeople.rdt.internal.core.search.matching;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.core.runtime.CoreException;
+import org.jruby.ast.CallNode;
+import org.jruby.ast.DefnNode;
+import org.jruby.ast.DefsNode;
+import org.jruby.ast.FCallNode;
+import org.jruby.ast.IArgumentNode;
+import org.jruby.ast.Node;
+import org.jruby.ast.VCallNode;
+import org.jruby.ast.types.INameNode;
+import org.jruby.evaluator.Instruction;
import org.rubypeople.rdt.core.IMember;
import org.rubypeople.rdt.core.IMethod;
import org.rubypeople.rdt.core.IParent;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.ISourceRange;
+import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.RubyScript;
+import org.rubypeople.rdt.internal.core.parser.InOrderVisitor;
+import org.rubypeople.rdt.internal.core.parser.RubyParser;
public class MethodLocator extends PatternLocator {
@@ -20,16 +35,119 @@
@Override
public void reportMatches(RubyScript script, MatchLocator locator) {
- reportMatches((IParent) script, locator);
+ if (!this.pattern.findReferences) {
+ reportMatches((IParent) script, locator);
+ } else {
+ reportASTMatches(script, locator);
+ }
}
+ private void reportASTMatches(final RubyScript script, final MatchLocator locator) {
+ try {
+ Node ast = script.lastGoodAST;
+ if (ast == null) {
+ ast = new RubyParser().parse(script.getSource());
+ }
+ final boolean findDeclarations = this.pattern.findDeclarations;
+ new InOrderVisitor() {
+
+ @Override
+ public Instruction visitVCallNode(VCallNode iVisited) {
+ match(iVisited, 0);
+ return super.visitVCallNode(iVisited);
+ }
+
+ @Override
+ public Instruction visitFCallNode(FCallNode iVisited) {
+ Node args = iVisited.getArgsNode(); // FIXME Grab the actual argument count
+ match(iVisited, 0);
+ return super.visitFCallNode(iVisited);
+ }
+
+ @Override
+ public Instruction visitCallNode(CallNode iVisited) {
+ Node args = iVisited.getArgsNode();
+ match(iVisited, 0); // FIXME Grab the actual arg count
+ return super.visitCallNode(iVisited);
+ }
+
+ @Override
+ public Instruction visitDefnNode(DefnNode iVisited) {
+ if (findDeclarations) matchDeclaration(iVisited, iVisited.getArgsNode().getArgsCount());
+ return super.visitDefnNode(iVisited);
+ }
+
+ @Override
+ public Instruction visitDefsNode(DefsNode iVisited) {
+ if (findDeclarations) matchDeclaration(iVisited, iVisited.getArgsNode().getArgsCount());
+ return super.visitDefsNode(iVisited);
+ }
+
+ private void match(Node iVisited, int arity) {
+ String name = ((INameNode)iVisited).getName();
+ int accuracy = getAccuracy(name, arity);
+ if (accuracy != IMPOSSIBLE_MATCH) {
+ try {
+ IRubyElement element = script.getElementAt(iVisited.getPosition().getStartOffset());
+ if (element == null) element = script;
+ if (locator.encloses(element)) {
+ IRubyElement binding = resolve(element, iVisited);
+ int start = iVisited.getPosition().getStartOffset();
+ int length = iVisited.getPosition().getEndOffset() - start;
+ boolean isConstructor = false;
+ if (name.equals("new")) {
+ isConstructor = true;
+ }
+ List<String> args = new ArrayList<String>();
+ if (iVisited instanceof IArgumentNode) {
+ args = getArgumentsFromFunctionCall((IArgumentNode) iVisited);
+ }
+ locator.report(locator.newMethodReferenceMatch(element, binding, args, accuracy,
+ start, length, isConstructor, iVisited));
+ }
+ } catch (CoreException e) {
+ RubyCore.log(e);
+ }
+ }
+ }
+
+ private IRubyElement resolve(IRubyElement element, Node visited) {
+ // TODO resolve a method call to it's declaration!
+ return element;
+ }
+
+ private void matchDeclaration(Node iVisited, int arity) {
+ String name = ((INameNode)iVisited).getName();
+ int accuracy = getAccuracy(name, arity);
+ if (accuracy != IMPOSSIBLE_MATCH) {
+ try {
+ IRubyElement element = script.getElementAt(iVisited.getPosition().getStartOffset());
+ if (element == null) element = script;
+ if (locator.encloses(element)) {
+ int start = iVisited.getPosition().getStartOffset();
+ int length = iVisited.getPosition().getEndOffset() - start;
+ locator.report(locator.newDeclarationMatch(element, accuracy,
+ start, length));
+ }
+ } catch (CoreException e) {
+ RubyCore.log(e);
+ }
+ }
+ }
+ }.acceptNode(ast);
+ } catch(RubyModelException e) {
+ RubyCore.log(e);
+ }
+ }
+
private void reportMatches(IParent parent, MatchLocator locator) {
try {
IRubyElement[] children = parent.getChildren();
for (int i = 0; i < children.length; i++) {
IRubyElement child = children[i];
- if (child.isType(IRubyElement.METHOD) && locator.encloses(child)) {
- int accuracy = getAccuracy((IMethod) child);
+ if (child.isType(IRubyElement.METHOD) && locator.encloses(child)) {
+ IMethod method = (IMethod) child;
+ int accuracy = getAccuracy(method.getElementName(), method.getParameterNames().length);
if (accuracy != IMPOSSIBLE_MATCH) {
IMember member = (IMember) child;
ISourceRange range = member.getSourceRange();
@@ -52,29 +170,19 @@
}
}
- private int getAccuracy(IMethod method) {
- if (!this.pattern.findDeclarations)
- return IMPOSSIBLE_MATCH;
-
+ private int getAccuracy(String name, int arity) {
// Verify method name
- if (!matchesName(this.pattern.selector, method.getElementName().toCharArray()))
+ if (!matchesName(this.pattern.selector, name.toCharArray()))
return IMPOSSIBLE_MATCH;
// Verify parameter count
if (this.pattern.parameterNames != null) {
int length = this.pattern.parameterNames.length;
- String[] args = null;
- try {
- args = method.getParameterNames();
- } catch (RubyModelException e) {
- // ignore
- }
- int argsLength = args == null ? 0 : args.length;
- if (length != argsLength)
+ if (length != arity)
return IMPOSSIBLE_MATCH;
}
- // Method declaration may match pattern
+ // Method may match pattern
return ACCURATE_MATCH;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|