package checkers.util.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import checkers.source.SourceChecker;
import checkers.source.SourceVisitor;
import checkers.types.AnnotatedTypeFactory;
import checkers.types.AnnotatedTypeMirror;
import checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType;
import checkers.util.TreeUtils;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
/**
* A testing class that can be used to test {@link TypeElement}. In particular
* it tests that the types read from classfiles are the same to the ones
* from java files.
*
* For testing, you need to do the following:
* 1. Run the Checker on the source file like any checker:
* <pre><code>
* java -processor checkers.util.test.TypeOutputtingChecker [source-file]
* </code></pre>
*
* 2. Run the Checker on the bytecode, by simply running the main and passing
* the qualified name, e.g.
* <pre><code>
* java checkers.util.test.TypeOutputtingChecker [qualified-name]
* </code></pre>
*
* 3. Apply a simple diff on the two outputs
*
*/
public class TypeOutputtingChecker extends SourceChecker {
@Override
protected SourceVisitor<?, ?> createSourceVisitor(CompilationUnitTree root) {
return new Visitor(this, root);
}
/**
* Prints the types of the class and all of its enclosing
* fields, methods, and inner classes
*/
public static class Visitor extends SourceVisitor<Void, Void> {
String currentClass;
public Visitor(SourceChecker checker, CompilationUnitTree root) {
super(checker, root);
}
// Print types of classes, methods, and fields
public Void visitClass(ClassTree node, Void p) {
TypeElement element = TreeUtils.elementFromDeclaration(node);
currentClass = element.getSimpleName().toString();
AnnotatedDeclaredType type = atypeFactory.getAnnotatedType(node);
System.out.println(node.getSimpleName() + "\t" + type + "\t" + type.directSuperTypes());
return super.visitClass(node, p);
}
public Void visitMethod(MethodTree node, Void p) {
ExecutableElement elem = TreeUtils.elementFromDeclaration(node);
AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(node);
System.out.println(currentClass + "." + elem + "\t\t" + type);
// Don't dig deeper
return null;
}
public Void visitVariable(VariableTree node, Void p) {
VariableElement elem = TreeUtils.elementFromDeclaration(node);
if (elem.getKind().isField()) {
AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(node);
System.out.println(currentClass + "." + elem + "\t\t" + type);
}
// Don't dig deeper
return null;
}
}
public static void main(String[] args) {
ProcessingEnvironment env =
new JavacProcessingEnvironment(new Context(), Collections.<Processor>emptyList());
Elements elements = env.getElementUtils();
AnnotatedTypeFactory atypeFactory = new AnnotatedTypeFactory(env, null, null, null);
for (String className : args) {
TypeElement typeElt = elements.getTypeElement(className);
printClassType(typeElt, atypeFactory);
}
}
/**
* Prints the types of the class and all of its enclosing
* fields, methods, and inner classes
*/
protected static void printClassType(TypeElement typeElt, AnnotatedTypeFactory atypeFactory) {
assert typeElt != null;
String simpleName = typeElt.getSimpleName().toString();
// Output class info
AnnotatedDeclaredType type = atypeFactory.fromElement(typeElt);
System.out.println(simpleName + "\t" + type + "\t" + type.directSuperTypes());
// output fields and methods
for (Element enclosedElt : typeElt.getEnclosedElements()) {
if (enclosedElt instanceof TypeElement)
printClassType((TypeElement)enclosedElt, atypeFactory);
if (!enclosedElt.getKind().isField()
&& !(enclosedElt instanceof ExecutableElement))
continue;
AnnotatedTypeMirror memberType = atypeFactory.fromElement(enclosedElt);
System.out.println(simpleName + "." + enclosedElt + "\t\t" + memberType);
}
}
}