All Downloads are FREE. Search and download functionalities are using the official Maven repository.

framework.src.org.checkerframework.common.util.debug.SignaturePrinter Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.common.util.debug;

import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.List;

import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.AbstractElementVisitor6;

import org.checkerframework.framework.source.SourceChecker;
import org.checkerframework.framework.source.SourceVisitor;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.javacutil.AbstractTypeProcessor;

import com.sun.source.util.TreePath;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
import org.checkerframework.javacutil.AnnotationProvider;

/**
 * Outputs the method signatures of a class with fully annotated types.
 * 

* * The class determines the effective annotations for a checker in source or * the classfile. Finding the effective annotations is useful for the * following purposes: * *

    *
  1. Debugging annotations in classfile
  2. *
  3. Debugging the default annotations that are implicitly added * by the checker
  4. *
* *

The class can be used in two possible ways, depending on the type file: * *

    *
  1. From source: the class is to be used as an annotation processor * when reading annotations from source. It can be invoked via the command: *

    javac -processor SignaturePrinter <java files> ... * *

  2. From classfile: the class is to be used as an independent app * when reading annotations from classfile. It can be invoked via the command: *

    java SignaturePrinter <class name> * *

* * By default, only the annotations explicitly written by the user are emitted. * To view the default and effective annotations in a class that are associated * with a checker, the fully qualified name of the checker needs to be passed * as '-Achecker=' argument, e.g. *

javac -processor SignaturePrinter * -Achecker=org.checkerframework.checker.nullness.NullnessChecker JavaFile.java */ @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes("*") @SupportedOptions("checker") public class SignaturePrinter extends AbstractTypeProcessor { private SourceChecker checker; ///////// Initialization ///////////// private void init(ProcessingEnvironment env, String checkerName) { if (checkerName != null) { try { Class checkerClass = Class.forName(checkerName); Constructor cons = checkerClass.getConstructor(); checker = (SourceChecker) cons.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } else { checker = new SourceChecker() { @Override protected SourceVisitor createSourceVisitor() { return null; } @Override public AnnotationProvider getAnnotationProvider() { throw new UnsupportedOperationException("getAnnotationProvider is not implemented for this class."); } }; } checker.init(env); } @Override public void typeProcessingStart() { super.typeProcessingStart(); String checkerName = processingEnv.getOptions().get("checker"); init(processingEnv, checkerName); } @Override public void typeProcess(TypeElement element, TreePath p) { // TODO: fix this mess // checker.currentPath = p; // CompilationUnitTree root = p != null ? p.getCompilationUnit() : null; // ElementPrinter printer = new ElementPrinter(checker.createTypeFactory(), System.out); // printer.visit(element); } ////////// Printer ////////// static class ElementPrinter extends AbstractElementVisitor6 { private final static String INDENTION = " "; private final PrintStream out; private String indent = ""; private final AnnotatedTypeFactory factory; public ElementPrinter(AnnotatedTypeFactory factory, PrintStream out) { this.factory = factory; this.out = out; } public void printTypeParams(List params) { if (params.isEmpty()) { return; } out.print("<"); boolean isntFirst = false; for (AnnotatedTypeMirror param : params) { if (isntFirst) { out.print(", "); } isntFirst = true; out.print(param); } out.print("> "); } public void printParameters(AnnotatedExecutableType type) { ExecutableElement elem = type.getElement(); out.print("("); for (int i = 0; i < type.getParameterTypes().size(); ++i) { if (i != 0) { out.print(", "); } printVariable(type.getParameterTypes().get(i), elem.getParameters().get(i).getSimpleName()); } out.print(")"); } public void printThrows(AnnotatedExecutableType type) { if (type.getThrownTypes().isEmpty()) { return; } out.print(" throws "); boolean isntFirst = false; for (AnnotatedTypeMirror thrown : type.getThrownTypes()) { if (isntFirst) { out.print(", "); } isntFirst = true; out.print(thrown); } } public void printVariable(AnnotatedTypeMirror type, Name name, boolean isVarArg) { out.print(type); if (isVarArg) { out.println("..."); } out.print(' '); out.print(name); } public void printVariable(AnnotatedTypeMirror type, Name name) { printVariable(type, name, false); } public void printType(AnnotatedTypeMirror type) { out.print(type); out.print(' '); } public void printName(CharSequence name) { out.print(name); } @Override public Void visitExecutable(ExecutableElement e, Void p) { out.print(indent); AnnotatedExecutableType type = factory.getAnnotatedType(e); printTypeParams(type.getTypeVariables()); if (e.getKind() != ElementKind.CONSTRUCTOR) { printType(type.getReturnType()); } printName(e.getSimpleName()); printParameters(type); printThrows(type); out.println(';'); return null; } @Override public Void visitPackage(PackageElement e, Void p) { throw new IllegalArgumentException("Cannot process packages"); } private String typeIdentifier(TypeElement e) { switch (e.getKind()) { case INTERFACE: return "interface"; case CLASS: return "class"; case ANNOTATION_TYPE: return "@interface"; case ENUM: return "enum"; default: throw new IllegalArgumentException("Not a type element: " + e.getKind()); } } @Override public Void visitType(TypeElement e, Void p) { String prevIndent = indent; out.print(indent); out.print(typeIdentifier(e)); out.print(' '); out.print(e.getSimpleName()); out.print(' '); AnnotatedDeclaredType dt = factory.getAnnotatedType(e); printSupers(dt); out.println("{"); indent += INDENTION; for (Element enclosed : e.getEnclosedElements()) { this.visit(enclosed); } indent = prevIndent; out.print(indent); out.println("}"); return null; } private void printSupers(AnnotatedDeclaredType dt) { if (dt.directSuperTypes().isEmpty()) { return; } out.print("extends "); boolean isntFirst = false; for (AnnotatedDeclaredType st : dt.directSuperTypes()) { if (isntFirst) { out.print(", "); } isntFirst = true; out.print(st); } out.print(' '); } @Override public Void visitTypeParameter(TypeParameterElement e, Void p) { throw new IllegalStateException("Shouldn't visit any type parameters"); } @Override public Void visitVariable(VariableElement e, Void p) { if (!e.getKind().isField()) { throw new IllegalStateException("can only process fields, received " + e.getKind()); } out.print(indent); AnnotatedTypeMirror type = factory.getAnnotatedType(e); this.printVariable(type, e.getSimpleName()); out.println(';'); return null; } } public static void printUsage() { System.out.println(" Usage: java SignaturePrinter [-Achecker=] classname"); } private static final String CHECKER_ARG = "-Achecker="; public static void main(String[] args) { if (!(args.length == 1 && !args[0].startsWith(CHECKER_ARG)) && !(args.length == 2 && args[0].startsWith(CHECKER_ARG))) { printUsage(); return; } // process arguments String checkerName = ""; if (args[0].startsWith(CHECKER_ARG)) { checkerName = args[0].substring(CHECKER_ARG.length()); } // Setup compiler environment Context context = new Context(); JavacProcessingEnvironment env = JavacProcessingEnvironment.instance(context); SignaturePrinter printer = new SignaturePrinter(); printer.init(env, checkerName); String className = args[args.length - 1]; TypeElement elem = env.getElementUtils().getTypeElement(className); if (elem == null) { System.err.println("Couldn't find class: " + className); return; } printer.typeProcess(elem, null); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy