Я использую Eclipse JDT AST для анализа Java исходного кода с целью определения всех применений данного метода. Я использую eclipse.jdt.core 3.21.0.
Хотя инструмент в большинстве случаев правильно разрешает привязки методов, я сталкиваюсь с проблемой, когда он не разрешит их, если метод используется внутри лямбда-выражения, если лямбда-тип неизвестен синтаксический анализатор.
Например, в следующем коде первый вызов Guava's Objects.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]