我正在使用Eclipse JDT AST来解析 Java 源代码,目的是识别给定方法的所有用途。我正在使用 eclipse.jdt.core 3.21.0。
虽然该工具在大多数情况下都能正确解析方法绑定,但我遇到了一个问题,如果该方法在 lambda 中使用,如果 lambda 是解析器未知的类型,则它无法解决它们。
例如,在以下代码中,第一次调用 GuavaObjects.equal
将解析,但第二次不会:
LocalDate date = new LocalDate();
Objects.equal(date, null);
Optional.of(date).filter(d -> Objects.equal(d, null));
在这个例子中,我知道我正在寻找的方法调用,并且我可以将该方法 (Guava) 的类文件提供给 ASTParser。但是因为该工具需要分析一个非常大的代码库,而且并不是所有的依赖关系都是已知的,所以我不能为代码库中的所有类型传递类文件,所以像org.joda.time.LocalDate are unknown
. 对于像第一个这样的调用来说,这不是问题,但是像第二个这样的调用无法解决,我正在努力找出原因。
我已经在这里结束了我的这个例子和我的 ASTParser 创建:
import java.util.Hashtable;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
public class ResolveTest {
String source = "import java.util.Optional;\r\n" +
"\r\n" +
"import org.joda.time.LocalDate;\r\n" +
"\r\n" +
"import com.google.common.base.Objects;\r\n" +
"\r\n" +
"public class Source {\r\n" +
"\r\n" +
" public void test() {\r\n" +
" LocalDate date = new LocalDate();\r\n" +
" \r\n" +
" Objects.equal(date, null);\r\n" +
" Optional.of(date).filter(d -> Objects.equal(d, null));\r\n" +
" }\r\n" +
"}";
public static void main(String[] args) {
ResolveTest resolveTest = new ResolveTest();
resolveTest.test();
}
private void test() {
String userHome = System.getProperty("user.home");
String guavaClassPath = userHome + "\\.m2\\repository\\com\\google\\guava\\guava\\27.0-jre\\guava-27.0-jre.jar";
ASTParser parser = createParser(source, new String[] { "" }, new String[] { guavaClassPath });
CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
compilationUnit.accept(new ASTVisitor() {
@Override
public boolean visit(MethodInvocation node) {
if (node.getName().toString().equals("equal")) {
IMethodBinding resolvedMethodBinding = node.resolveMethodBinding();
System.out.println("Found method [" + node.toString() + "], Resolved [" + resolvedMethodBinding + "]");
}
return super.visit(node);
}
});
}
public static ASTParser createParser(String fileSource, String[] sources, String[] classPath) {
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setResolveBindings(true);
parser.setBindingsRecovery(true);
parser.setStatementsRecovery(true);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(fileSource.toCharArray());
parser.setUnitName("Source.java");
Hashtable<String, String> javaCoreOptions = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, javaCoreOptions);
parser.setCompilerOptions(javaCoreOptions);
String[] encodings = new String[] { "UTF-8" };
parser.setEnvironment(classPath, sources, encodings, true);
return parser;
}
}
输出是:
Found method [Objects.equal(date,null)], Resolved [public static boolean equal(@Nullable Object, @Nullable Object) ]
Found method [Objects.equal(d,null)], Resolved [null]