【问题标题】:Resolving overloaded methods with ASTVisitor in Eclipse JDT在 Eclipse JDT 中使用 ASTVisitor 解决重载方法
【发布时间】:2011-10-27 15:35:26
【问题描述】:

我目前正在从事一个使用 ASTVisitor 创建基本调用树的学术项目。

为此,需要将方法的调用与其声明相关联。

编辑:问题在很大程度上解决了:所描述的错误只出现在JUnit-Tests中,而不出现在standalone-plugin中。它似乎与 ASTVisitor 的单元测试工作流程有关。我会在一段时间内进一步调查原因并在此处发布答案。

下面的代码显示了一个最小的访问者,它将调用和相关的声明打印到控制台:

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;

/**
* Visits all method invocations and prints the declaration of the caller to
* console.
*/
public class InvocationLoggerASTVisitor extends ASTVisitor {

@Override
public boolean visit(MethodInvocation methodInvocation) {

if (methodInvocation.resolveMethodBinding() != null) {
    IMethodBinding declarationOfInvokedMethod = methodInvocation
    .resolveMethodBinding().getMethodDeclaration();

    System.out.println(String.format(
        "invocation of \"%s\" is resolved to declaration \"%s\"",
        methodInvocation, declarationOfInvokedMethod));

}
return super.visit(methodInvocation);
}

}

访问者适用于一些经过测试的场景。 但奇怪的是,当将其应用于包含重载方法的编译单元时,一些调用会与错误的声明相关联。让我们访问以下代码:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class OverloadedMethodsAndRawTypes implements ICallGraphTestSource {

void f(HashSet objects) {
f(new ArrayDeque(objects));
}

void f(ArrayDeque objects) {
f(new ArrayList(objects));
}

void f(ArrayList objects) {
f(new HashSet(objects));
}

}

访问这个编译单元时,控制台输出为:

invocation of "f(new ArrayDeque(objects))" is resolved to declaration "void f(HashSet) "
invocation of "f(new ArrayList(objects))" is resolved to declaration "void f(HashSet )"
invocation of "f(new HashSet(list))" is resolved to declaration "void f(HashSet) "

我希望这个输出:

invocation of "f(new ArrayDeque(objects))" is resolved to declaration "void f(ArrayDeque) "
invocation of "f(new ArrayList(objects))" is resolved to declaration "void f(ArrayList )"
invocation of "f(new HashSet(list))" is resolved to declaration "void f(HashSet) "

我注意到,重载方法的调用总是解析为与调用的方法名称匹配的第一个出现的声明,这对我来说似乎不正确。

为了证明方法重载是罪魁祸首,我附上了相同的代码,但没有方法重载:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class RawTypes implements ICallGraphTestSource {

void f_set(HashSet objects) {
    f_deque(new ArrayDeque(objects));
}

void f_deque(ArrayDeque objects) {
    f_list(new ArrayList(objects));
}

void f_list(ArrayList objects) {
    f_set(new HashSet(objects));
}

}

当被访问时,它会产生正确的输出:

invocation of "f_deque(new ArrayDeque(objects))" is resolved to declaration "void f_deque(ArrayDeque) "
invocation of "f_list(new ArrayList(objects))" is resolved to declaration "void f_list(ArrayList) "
invocation of "f_set(new HashSet(list))" is resolved to declaration "void f_set(HashSet) "

我的 ASTParser 配置如下:

public static ASTNode getAST(ICompilationUnit compilationUnit) {
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(compilationUnit);
parser.setResolveBindings(true);
parser.setBindingsRecovery(true);
parser.setProject(getJavaProject());
return parser.createAST(null);
}

编辑:所描述的设置在 JUnit-Tests 中不起作用,但它作为独立插件起作用。原因必须在 getJavaProject-Method 中,其中创建了一个临时项目。

【问题讨论】:

  • 这里还有问题吗?
  • 问题解决了,我已经发布了我的解决方案作为答案。
  • 你不妨接受你自己的答案。 :)

标签: eclipse eclipse-rcp rcp abstract-syntax-tree eclipse-jdt


【解决方案1】:

由于错误行为只发生在测试用例中,AST 的创建似乎没有正确设置。

我找到了一个有效的测试设置: 对于每个测试,我都从文件系统中读取 CompilationUnit 作为文本,并按照从描述 here 派生的方法以编程方式创建一个新项目。 正如您在原始问题的 ASTParser 配置中看到的那样,IJavaProject-instance 使用 parser.setProject(IJavaProject) 传递,拥有一个环境以正确解析调用。

这个实例必须配置一个类路径:

/**
 * @param project
 *            a project with JavaNature
 * @return a java project with classpath set to the default JRELibrary
 * @throws JavaModelException
 */
private static IJavaProject createJavaProject(IProject project)
    throws JavaModelException {

IJavaProject javaProject = JavaCore.create(project);
javaProject.setRawClasspath(PreferenceConstants.getDefaultJRELibrary(),
    null);

return javaProject;
}

就我而言,我只需要默认的 JRE 库。在您的情况下,可能需要增加类路径。无论如何,这解决了问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多