【问题标题】:How do I find the type declaration of an identifier using the Java Tree Compiler API?如何使用 Java Tree Compiler API 找到标识符的类型声明?
【发布时间】:2011-02-03 00:01:02
【问题描述】:

我有一个变量/标识符的名称,比如x,以及JCCompilationUnitScope。有没有办法找到x的类型?

【问题讨论】:

    标签: java compiler-construction preprocessor javac java-compiler-api


    【解决方案1】:
     public Symbol getSymbol(CompilationUnitTree cut, JCStatement stmt, List<JCExpression> typeParams, Name varName, List<JCExpression> args) {
        java.util.List<Type> typeSyms = getArgTypes(typeParams, cut, stmt);
        java.util.List<Type> argsSyms = getArgTypes(args, cut, stmt);
        final Scope scope = getScope(cut, stmt);
        Symbol t = contains(scope, typeSyms, varName, argsSyms); //first lookup scope for all public identifiers
        TypeElement cl = scope.getEnclosingClass();
        while (t == null && cl != null) { //lookup hierarchy for inacessible identifiers too
            t = contains(elementUtils.getAllMembers(cl), typeSyms, varName, argsSyms);
            final TypeMirror superclass = cl.getSuperclass();
            if (superclass != null) {
                cl = (TypeElement) ((Type) superclass).asElement();
            }
        }
        return t;
    }
    
    public Symbol getSymbol(Name varName, Symbol accessor, CompilationUnitTree cut, JCStatement stmt) {
        if (varName.contentEquals("class")) {
            Symbol javaLangClassSym = getSymbol(cut, stmt, null, elementUtils.getName("java.lang.Class"), null);
            JCIdent id = tm.Ident(javaLangClassSym);
            JCExpression mName = tm.Select(id, elementUtils.getName("forName"));
            JCLiteral idLiteral = tm.Literal(accessor.toString());
            JCMethodInvocation mi = tm.Apply(List.<JCExpression>nil(), mName, List.<JCExpression>of(idLiteral));
            Symbol s = getSymbol(mi, cut, stmt);
            return s;
        }
        accessor = getTypeSymbol(accessor);
        java.util.List<Symbol> enclosedElements = getEnclosedElements(accessor, cut, stmt);
        Symbol s = contains(enclosedElements, null, varName, null);
        return s;
    }
    

    我最终写了一个完整的class with resolving methods。继承它,或者传入 TreeMaker(和其他参数),它可以是静态的。如果有人觉得它有价值,欢迎提供补丁。

    【讨论】:

      【解决方案2】:

      Scope 对象有一个方法 getLocalElements(), 可以迭代。然后可以通过它的名称询问每个元素,当这是正确的一个(它也是一个变量)时,你可以得到它的类型。

      这是概念,未经测试:

      private final static Set<ElementKind> variableKinds =
             Collections.unmodifiableSet(EnumSet.of(ElementKind.FIELD, ElementKind.ENUM_CONSTANT,
                                                    ElementKind.PARAMETER, ElementKind.LOCAL_VARIABLE));
      
      public Type getTypeOfVariable(Scope scope, String varName)
      {
         for(Element e : scope.getLocalElements()) {
             if(variableKinds.contains(e.getKind()) && e.getName().equals(varName)) {
                 return e.getType();
             }
         }
         throw new NoSuchElementException("No variable " + varName + " in " + scope);
      }
      

      编辑: 是的,确实未经测试(没有getType() 方法)。

      那么,如何从Element(或VariableElement)中获取其类型?

      Trees 类有一些实用方法允许从Element 检索TreeTreePath,因此我们可以获得VariableTree(因为它来自变量声明)。 VariableTree 现在有一个 getType() 方法,它返回一个 Tree - 但实际上这是 PrimitiveTypeTreeParametrizedTypeTreeArrayTypeTreeIdentifierTree 之一(对于简单的引用类型以及类型变量)。因此,如果您只想打印类型,这可能就足够了。否则,再次使用 Trees 类,我们现在可以获得该类型的 TypeMirror。

      (当我尝试编写一个新的 Doclet 时,我也做过类似的事情,它也会输出格式化的源代码。在所有这些 API 之间进行可怕的翻转。)

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多