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

org.checkerframework.javacutil.AbstractTypeProcessor 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.44.0
Show newest version
package org.checkerframework.javacutil;

import com.sun.source.tree.ClassTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.comp.CompileStates.CompileState;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import org.checkerframework.dataflow.qual.SideEffectFree;

/**
 * This class is an abstract annotation processor designed to be a convenient superclass for
 * concrete "type processors", processors that require the type information in the processed source.
 *
 * 

Type processing occurs in one round after the tool (e.g. Java compiler) analyzes the source * (all sources taken as input to the tool and sources generated by other annotation processors). * *

The tool infrastructure will interact with classes extending this abstract class as follows. * *

1-3 are identical to the {@link Processor} life cycle. 4-5 are unique to {@code * AbstractTypeProcessor} subclasses. * *

    *
  1. If an existing {@code Processor} object is not being used, to create an instance of a * processor the tool calls the no-arg constructor of the processor class. *
  2. Next, the tool calls the {@link #init init} method with an appropriate {@code * ProcessingEnvironment}. *
  3. Afterwards, the tool calls {@link #getSupportedAnnotationTypes * getSupportedAnnotationTypes}, {@link #getSupportedOptions getSupportedOptions}, and {@link * #getSupportedSourceVersion getSupportedSourceVersion}. These methods are only called once * per run, not on each round. *
  4. For each class containing a supported annotation, the tool calls {@link * #typeProcess(TypeElement, TreePath) typeProcess} method on the {@code Processor}. The class * is guaranteed to be type-checked Java code and all the tree type and symbol information is * resolved. *
  5. Finally, the tool calls the {@link #typeProcessingOver typeProcessingOver} method on the * {@code Processor}. *
* *

The tool is permitted to ask type processors to process a class once it is analyzed before the * rest of classes are analyzed. The tool is also permitted to stop type processing immediately if * any errors are raised, without invoking {@link #typeProcessingOver}. * *

A subclass may override any of the methods in this class, as long as the general {@link * javax.annotation.processing.Processor Processor} contract is obeyed, with one notable exception. * {@link #process(Set, RoundEnvironment)} may not be overridden, as it is called during the * declaration annotation phase before classes are analyzed. */ public abstract class AbstractTypeProcessor extends AbstractProcessor { /** * The set of fully-qualified element names that should be type-checked. We store the names of the * elements, in order to prevent possible confusion between different Element instantiations. */ private final Set elements = new HashSet<>(); /** * Method {@link #typeProcessingStart()} must be invoked exactly once, before any invocation of * {@link #typeProcess(TypeElement, TreePath)}. */ private boolean hasInvokedTypeProcessingStart = false; /** * Method {@link #typeProcessingOver} must be invoked exactly once, after the last invocation of * {@link #typeProcess(TypeElement, TreePath)}. */ private boolean hasInvokedTypeProcessingOver = false; /** The TaskListener registered for completion of attribution. */ private final AttributionTaskListener listener = new AttributionTaskListener(); /** Constructor for subclasses to call. */ protected AbstractTypeProcessor() {} /** * {@inheritDoc} * *

Register a TaskListener that will get called after FLOW. */ @Override public synchronized void init(ProcessingEnvironment env) { super.init(env); JavacTask.instance(env).addTaskListener(listener); Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext(); JavaCompiler compiler = JavaCompiler.instance(ctx); compiler.shouldStopPolicyIfNoError = CompileState.max(compiler.shouldStopPolicyIfNoError, CompileState.FLOW); compiler.shouldStopPolicyIfError = CompileState.max(compiler.shouldStopPolicyIfError, CompileState.FLOW); } /** * The use of this method is obsolete in type processors. The method is called during declaration * annotation processing phase only. It registers the names of elements to process. */ @Override public final boolean process(Set annotations, RoundEnvironment roundEnv) { for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) { elements.add(elem.getQualifiedName()); } return false; } /** * A method to be called once before the first call to typeProcess. * *

Subclasses may override this method to do any initialization work. */ public void typeProcessingStart() {} /** * Processes a fully-analyzed class that contains a supported annotation (see {@link * #getSupportedAnnotationTypes()}). * *

The passed class is always valid type-checked Java code. * * @param element element of the analyzed class * @param tree the tree path to the element, with the leaf being a {@link ClassTree} */ public abstract void typeProcess(TypeElement element, TreePath tree); /** * A method to be called once all the classes are processed. * *

Subclasses may override this method to do any aggregate analysis (e.g. generate report, * persistence) or resource deallocation. * *

Method {@link #getCompilerLog()} can be used to access the number of compiler errors. */ public void typeProcessingOver() {} /** * Return the compiler log, which contains errors and warnings. * * @return the compiler log, which contains errors and warnings */ @SideEffectFree public Log getCompilerLog() { return Log.instance(((JavacProcessingEnvironment) processingEnv).getContext()); } /** A task listener that invokes the processor whenever a class is fully analyzed. */ private final class AttributionTaskListener implements TaskListener { @Override public void finished(TaskEvent e) { if (e.getKind() != TaskEvent.Kind.ANALYZE) { return; } if (!hasInvokedTypeProcessingStart) { typeProcessingStart(); hasInvokedTypeProcessingStart = true; } if (!hasInvokedTypeProcessingOver && elements.isEmpty()) { typeProcessingOver(); hasInvokedTypeProcessingOver = true; } if (e.getTypeElement() == null) { throw new BugInCF("event task without a type element"); } if (e.getCompilationUnit() == null) { throw new BugInCF("event task without compilation unit"); } if (!elements.remove(e.getTypeElement().getQualifiedName())) { return; } TypeElement elem = e.getTypeElement(); TreePath p = Trees.instance(processingEnv).getPath(elem); typeProcess(elem, p); if (!hasInvokedTypeProcessingOver && elements.isEmpty()) { typeProcessingOver(); hasInvokedTypeProcessingOver = true; } } @Override public void started(TaskEvent e) {} } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy