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

org.checkerframework.framework.source.AggregateChecker 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-eisop4
Show newest version
package org.checkerframework.framework.source;

import com.sun.source.util.TreePath;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;

import org.checkerframework.checker.nullness.qual.MonotonicNonNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

/**
 * An aggregate checker that packages multiple checkers together. The resulting checker invokes the
 * component checkers in turn on the processed files.
 *
 * 

There is no communication, interaction, or cooperation between the component checkers, even to * the extent of being able to read one another's qualifiers. An aggregate checker is merely * shorthand to invoke a sequence of checkers. * *

This class delegates {@code AbstractTypeProcessor} responsibilities to each component checker. * *

Checker writers need to subclass this class and only override {@link #getSupportedCheckers()} * to indicate the classes of the checkers to be bundled. */ public abstract class AggregateChecker extends SourceChecker { protected final List checkers; /** * Returns the list of supported checkers to be run together. Subclasses need to override this * method. * * @return the list of checkers to be run */ protected abstract Collection> getSupportedCheckers(); /** Supported options for this checker. */ private @MonotonicNonNull Set supportedOptions = null; /** Options passed to this checker. */ private @MonotonicNonNull Map options = null; /** Create a new AggregateChecker. */ protected AggregateChecker() { Collection> checkerClasses = getSupportedCheckers(); checkers = new ArrayList<>(checkerClasses.size()); for (Class checkerClass : checkerClasses) { try { SourceChecker instance = checkerClass.getDeclaredConstructor().newInstance(); instance.setParentChecker(this); checkers.add(instance); } catch (Exception e) { message( Diagnostic.Kind.ERROR, "Couldn't instantiate an instance of " + checkerClass); } } } /** * {@code processingEnv} needs to be set on each checker since we are not calling init on the * checker, which leaves it null. If one of checkers is an AggregateChecker, its visitors will * try use checker's processing env which should not be null. */ @Override protected void setProcessingEnvironment(ProcessingEnvironment env) { super.setProcessingEnvironment(env); for (SourceChecker checker : checkers) { checker.setProcessingEnvironment(env); } } @Override public void initChecker() { // No need to call super, it might result in reflective instantiations // of visitor/factory classes. // super.initChecker(); // To prevent the warning that initChecker wasn't called. messager = processingEnv.getMessager(); // first initialize all checkers for (SourceChecker checker : checkers) { checker.initChecker(); } // then share options as necessary for (SourceChecker checker : checkers) { // We need to add all options that are activated for the aggregate to // the individual checkers. checker.addOptions(super.getOptions()); // Each checker should "support" all possible lint options - otherwise // subchecker A would complain about a lint option for subchecker B. checker.setSupportedLintOptions(this.getSupportedLintOptions()); } allCheckersInited = true; } // Whether all checkers were successfully initialized. private boolean allCheckersInited = false; // AbstractTypeProcessor delegation @Override public final void typeProcess(TypeElement element, TreePath tree) { Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); Log log = Log.instance(context); if (log.nerrors > this.errsOnLastExit) { // If there is a Java error, do not perform any of the component type checks, but come // back for the next compilation unit. this.errsOnLastExit = log.nerrors; return; } if (!allCheckersInited) { // If there was an initialization problem, an // error was already output. Just quit. return; } for (SourceChecker checker : checkers) { checker.errsOnLastExit = this.errsOnLastExit; checker.typeProcess(element, tree); if (checker.javacErrored) { this.javacErrored = true; return; } this.errsOnLastExit = checker.errsOnLastExit; } } @Override public void typeProcessingOver() { for (SourceChecker checker : checkers) { checker.typeProcessingOver(); } super.typeProcessingOver(); } @Override public final Set getSupportedOptions() { if (this.supportedOptions == null) { Set options = new HashSet<>(); for (SourceChecker checker : checkers) { options.addAll(checker.getSupportedOptions()); } options.addAll( expandCFOptions( Arrays.asList(this.getClass()), options.toArray(new String[options.size()]))); this.supportedOptions = options; } return this.supportedOptions; } @Override public final Map getOptions() { if (this.options == null) { Map options = new HashMap<>(super.getOptions()); for (SourceChecker checker : checkers) { options.putAll(checker.getOptions()); } this.options = Collections.unmodifiableMap(options); } return this.options; } @Override public final Set getSupportedLintOptions() { Set lints = new HashSet<>(); for (SourceChecker checker : checkers) { lints.addAll(checker.getSupportedLintOptions()); } return lints; } @Override protected SourceVisitor createSourceVisitor() { return new SourceVisitor(this) { // Aggregate checkers do not visit source, // the checkers in the aggregate checker do. }; } // TODO some methods in a component checker should behave differently if they // are part of an aggregate, e.g. getSuppressWarningKeys should additionally // return the name of the aggregate checker. // We could add a query method in SourceChecker that refers to the aggregate, if present. // At the moment, all the component checkers manually need to add the name of the aggregate. }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy