首页 > 解决方案 > Eclipse JDT ASTParser - 在 lambdas 中解析

问题描述

我正在使用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]

标签: javaeclipseabstract-syntax-treeeclipse-jdtecj

解决方案


推荐阅读