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

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.43.0
Show newest version
package org.checkerframework.common.util.debug;

import com.sun.source.util.TreePath;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
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.AbstractElementVisitor8;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.signature.qual.BinaryName;
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 org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.UserError;
import org.plumelib.reflection.Signatures;

/**
 * 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. Debugging the default annotations that are implicitly added by the checker *
* *

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: *

    {@code javac -processor SignaturePrinter ...} *

  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: *

    {@code java SignaturePrinter } *

* * 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 {@code -Achecker=} argument, e.g. * *
{@code
 * 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 ///////////// /** * Initialization. * * @param env the ProcessingEnvironment * @param checkerName the name of the checker */ private void init(ProcessingEnvironment env, @Nullable @BinaryName 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"); if (!Signatures.isBinaryName(checkerName)) { throw new UserError("Malformed checker name \"%s\"", checkerName); } 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 ////////// /** Element printer. */ static class ElementPrinter extends AbstractElementVisitor8 { /** String used for indentation. */ private static final 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: if (e.getKind().name().equals("RECORD")) { return "record"; } 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; } /** * Print the supertypes. * * @param dt the type whos supertypes to print */ 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 = null; if (args[0].startsWith(CHECKER_ARG)) { checkerName = args[0].substring(CHECKER_ARG.length()); if (!Signatures.isBinaryName(checkerName)) { throw new UserError("Bad checker name \"%s\"", checkerName); } } // 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