} catch (TokenStreamException e) {
// the analysis phase should have reported all the errors,
// so we should ignore any failures at this point.
}
final Name CLASS = elements.getName("class");
// then semantic ones
new TreeScanner<Void,Void>() {
/**
* primitive types like int, long, void, etc.
*/
public Void visitPrimitiveType(PrimitiveTypeTree pt, Void _) {
// all primitives should be marked up by lexer
// gen.add(new Tag.PrimitiveType(cu,srcPos,pt));
return super.visitPrimitiveType(pt,_);
}
/**
* literal string, int, etc. Null.
*/
public Void visitLiteral(LiteralTree lit, Void _) {
gen.add(new Literal(cu,srcPos,lit));
return super.visitLiteral(lit, _);
}
/**
* Definition of a variable, such as parameter, field, and local variables.
*/
public Void visitVariable(VariableTree vt, Void _) {
VariableElement e = (VariableElement) TreeUtil.getElement(vt);
if(e!=null) {
switch (e.getKind()) {
case ENUM_CONSTANT:
case FIELD:
gen.add(new FieldDecl(cu,srcPos,vt));
break;
case EXCEPTION_PARAMETER:
case LOCAL_VARIABLE:
case PARAMETER:
gen.add(new LocalVarDecl(cu,srcPos,vt,e));
break;
}
Token token;
if(e.getKind()!= ElementKind.ENUM_CONSTANT) {
// put the marker just on the variable name.
// the token for the variable name is after its type.
// note that we need to handle declarations like "int a,b".
token = gen.findTokenAfter(vt.getType(), true, vt.getName().toString());
} else {
// for the enum constant put the anchor around vt
token = gen.findTokenAfter(vt, false, vt.getName().toString());
}
// TODO: handle declarations like "String abc[]"
if(token!=null)
gen.add(new DeclName(lineMap,token));
}
return super.visitVariable(vt,_);
}
/**
* Method declaration.
*/
public Void visitMethod(MethodTree mt, Void _) {
ExecutableElement e = (ExecutableElement) TreeUtil.getElement(mt);
if(e!=null) {
if(e.getKind()==ElementKind.CONSTRUCTOR && e.getEnclosingElement().getSimpleName().length()==0)
return _; // this is a synthesized constructor for an anonymous class
// TODO: I suspect we need some kind of uniform treatment for all synthesized methods
// mark up the method name
Tree prev = mt.getReturnType();
String name;
if(e.getKind()== ElementKind.CONSTRUCTOR)
name = e.getEnclosingElement().getSimpleName().toString();
else // constructor returns <init> from getName(), so we need the above code
name = mt.getName().toString();
Token token;
if(prev!=null)
token = gen.findTokenAfter(prev, true, name);
else
token = gen.findTokenAfter(mt,false,name);
if(token!=null)
gen.add(new DeclName(lineMap,token));
ParsedType pt = getParsedType((TypeElement) e.getEnclosingElement());
gen.add(new MethodDecl(cu, srcPos, mt, e,
pt.findOverriddenMethods(elements, e),
pt.findOverridingMethods(elements, e)
));
}
return super.visitMethod(mt, _);
}
/**
* Class declaration.
*/
public Void visitClass(ClassTree ct, Void _) {
TypeElement e = (TypeElement) TreeUtil.getElement(ct);
if(e!=null) {
// put the marker on the class name portion.
Token token=null;
if(ct.getModifiers()!=null)
token = gen.findTokenAfter(ct.getModifiers(), true, ct.getSimpleName().toString());
// on enum class, like "public enum En {ABC,DEF}", the above returns null somehow.
// so go with the plan B if it's not found.
// TODO: report to javac team
if(token==null)
token = gen.findTokenAfter(ct, false, ct.getSimpleName().toString());
if(token!=null)
gen.add(new DeclName(lineMap, token));
List<ParsedType> descendants = getParsedType(e).descendants;
gen.add(new ClassDecl(cu, srcPos, ct, e, descendants));
if(e.getNestingKind()== NestingKind.ANONYMOUS) {
// don't visit the extends and implements clause as
// they already show up in the NewClassTree
scan(ct.getMembers());
return _;
}
}
return super.visitClass(ct, _);
}
/**
* All the symbols found in the source code.
*/
public Void visitIdentifier(IdentifierTree id, Void _) {
if(!ReservedWords.LIST.contains(id.getName().toString())) {
Element e = TreeUtil.getElement(id);
if(e!=null) {
switch (e.getKind()) {
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
gen.add(new TypeRef(cu,srcPos,id,(TypeElement)e));
break;
case FIELD: // such as objects imported by static import.
case ENUM_CONSTANT:
gen.add(new FieldRef(cu,srcPos,id,(VariableElement)e));
break;
case PARAMETER:
case EXCEPTION_PARAMETER:
case LOCAL_VARIABLE:
gen.add(new LocalVarRef(cu,srcPos,id,(VariableElement)e));
break;
}
}
}
return super.visitIdentifier(id,_);
}
/**
* "exp.token"
*/
public Void visitMemberSelect(MemberSelectTree mst, Void _) {
// avoid marking 'Foo.class' as static reference
if(!mst.getIdentifier().equals(CLASS)) {
// just select the 'token' portion
long ep = srcPos.getEndPosition(cu,mst);
long sp = ep-mst.getIdentifier().length();
// marker for the selected identifier
Element e = TreeUtil.getElement(mst);
if(e!=null) {
switch(e.getKind()) {
case FIELD:
case ENUM_CONSTANT:
gen.add(new FieldRef(sp, ep, PositionUtils.getLineNumber(lineMap, sp), PositionUtils.getColNumber(lineMap, sp), (VariableElement)e));
break;
// these show up in the import statement
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
case INTERFACE:
gen.add(new TypeRef(sp, ep, PositionUtils.getLineNumber(lineMap, sp), PositionUtils.getLineNumber(lineMap, sp), (TypeElement)e));
break;
}
}
}
return super.visitMemberSelect(mst, _);
}
/**
* Constructor invocation.
*/
public Void visitNewClass(NewClassTree nt, Void _) {
long ep = srcPos.getEndPosition(cu, nt.getIdentifier());
long sp = srcPos.getStartPosition(cu, nt.getIdentifier());
// marker for jumping to the definition
Element e = TreeUtil.getElement(nt);
if(e instanceof ExecutableElement) {// this check is needed in case the source code contains errors
ExecutableElement ee = (ExecutableElement) e;
TypeElement ownerType = (TypeElement) ee.getEnclosingElement();
if(ownerType.getSimpleName().length()==0) {
// if this is the constructor for an anonymous class,
// can't link to the constructor as it's synthetic
scan(nt.getIdentifier());
} else {
// TODO: the identifier tree might contain type parameters, packaga names, etc.
// we should visit those
gen.add(new MethodRef(sp, ep, PositionUtils.getLineNumber(lineMap, sp), PositionUtils.getColNumber(lineMap, sp), ee));
}
}
scan(nt.getEnclosingExpression());
scan(nt.getArguments());
scan(nt.getTypeArguments());
scan(nt.getClassBody());
return _;
}
// TODO: how is the 'super' or 'this' constructor invocation handled?
/**
* Method invocation of the form "exp.method()"
*/
public Void visitMethodInvocation(MethodInvocationTree mi, Void _) {
ExpressionTree ms = mi.getMethodSelect(); // PRIMARY.methodName portion
Element e = TreeUtil.getElement(mi);
if (e instanceof ExecutableElement) {// this check is needed in case the source code contains errors
ExecutableElement ee = (ExecutableElement) e;
Name methodName = ee.getSimpleName();
long ep = srcPos.getEndPosition(cu, ms);
if(ep>=0) {
// marker for the method name (and jump to definition)
long sp = ep - methodName.length();
gen.add(new MethodRef(sp, ep, PositionUtils.getLineNumber(lineMap, sp), PositionUtils.getColNumber(lineMap, sp), ee));
}
}
return super.visitMethodInvocation(mi,_);