如何使用Java Tree Compiler API找到标识符的类型声明?

时间:2011-02-03 00:01:03

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

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

2 个答案:

答案 0 :(得分:3)

 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(和其他参数),它可以是静态的。如果有人发现它值得,我们欢迎补丁。

答案 1 :(得分:1)

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

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