Eclipse JDT ASTParser - разрешение в лямбдах - PullRequest
1 голос
/ 11 апреля 2020

Я использую 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]
...