Frage

I have the name of a variable/identifier, say, x, and the JCCompilationUnit and Scope. Is there a way to find the type of x?

War es hilfreich?

Lösung

 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;
}

I ended up writing a full class with resolving methods. Inheriting it, or passing in the TreeMaker (and other parameters) it can be made static. Should someone find it worthwile, a patch is welcome.

Andere Tipps

The Scope object has a method getLocalElements(), which can be iterated over. Each element can then be asked by its name, and when this is the right one (and it is a variable, too), you can get its type.

This is the concept, untested:

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);
}

Edit: Yeah, really untested (there is no getType() method).

So, how to get from a Element (or VariableElement) from its type?

The Trees class has some utility methods allowing the retrieval of a Tree or TreePath from the Element, and thus we can get a VariableTree (since this came from a variable declaration). The VariableTree now has a getType() method, which returns a Tree - but in fact this is one of PrimitiveTypeTree, ParametrizedTypeTree, ArrayTypeTree and IdentifierTree (for simple reference types as well as type variables). So, if you only want to print the type, this may be enough. Otherwise, again with the Trees class we now can get a TypeMirror for this type.

(I did something similar once when I tried to write a new Doclet which would also output the formatted source code. Terrible flipping between all those APIs.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top