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

org.checkerframework.framework.flow.CFAbstractAnalysis 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.framework.flow;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.dataflow.analysis.ForwardAnalysisImpl;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
import org.checkerframework.dataflow.expression.FieldAccess;
import org.checkerframework.framework.source.SourceChecker;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.framework.type.GenericAnnotatedTypeFactory;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.type.TypeHierarchy;
import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.TypesUtils;

/**
 * {@link CFAbstractAnalysis} is an extensible org.checkerframework.dataflow analysis for the
 * Checker Framework that tracks the annotations using a flow-sensitive analysis. It uses an {@link
 * AnnotatedTypeFactory} to provide checker-specific logic how to combine types (e.g., what is the
 * type of a string concatenation, given the types of the two operands) and as an abstraction
 * function (e.g., determine the annotations on literals).
 *
 * 

The purpose of this class is twofold: Firstly, it serves as factory for abstract values, * stores and the transfer function. Furthermore, it makes it easy for the transfer function and the * stores to access the {@link AnnotatedTypeFactory}, the qualifier hierarchy, etc. */ public abstract class CFAbstractAnalysis< V extends CFAbstractValue, S extends CFAbstractStore, T extends CFAbstractTransfer> extends ForwardAnalysisImpl { /** The qualifier hierarchy for which to track annotations. */ protected final QualifierHierarchy qualifierHierarchy; /** The type hierarchy. */ protected final TypeHierarchy typeHierarchy; /** * The dependent type helper used to standardize both annotations belonging to the type hierarchy, * and contract expressions. */ protected final DependentTypesHelper dependentTypesHelper; /** A type factory that can provide static type annotations for AST Trees. */ protected final GenericAnnotatedTypeFactory> atypeFactory; /** A checker that contains command-line arguments and other information. */ protected final SourceChecker checker; /** * A triple of field, value corresponding to the annotations on its declared type, value of its * initializer. The value of the initializer is {@code null} if the field does not have one. * * @param type of value */ public static class FieldInitialValue> { /** A field access that corresponds to the declaration of a field. */ public final FieldAccess fieldDecl; /** The value corresponding to the annotations on the declared type of the field. */ public final V declared; /** The value of the initializer of the field, or null if no initializer exists. */ public final @Nullable V initializer; /** * Creates a new FieldInitialValue. * * @param fieldDecl a field access that corresponds to the declaration of a field * @param declared value corresponding to the annotations on the declared type of {@code field} * @param initializer value of the initializer of {@code field}, or null if no initializer * exists */ public FieldInitialValue(FieldAccess fieldDecl, V declared, @Nullable V initializer) { this.fieldDecl = fieldDecl; this.declared = declared; this.initializer = initializer; } } /** Initial abstract types for fields. */ protected final List> fieldValues; /** The associated processing environment. */ protected final ProcessingEnvironment env; /** Instance of the types utility. */ protected final Types types; /** * Create a CFAbstractAnalysis. * * @param checker a checker that contains command-line arguments and other information * @param factory an annotated type factory to introduce type and dataflow rules * @param maxCountBeforeWidening number of times a block can be analyzed before widening */ protected CFAbstractAnalysis( BaseTypeChecker checker, GenericAnnotatedTypeFactory> factory, int maxCountBeforeWidening) { super(maxCountBeforeWidening); env = checker.getProcessingEnvironment(); types = env.getTypeUtils(); qualifierHierarchy = factory.getQualifierHierarchy(); typeHierarchy = factory.getTypeHierarchy(); dependentTypesHelper = factory.getDependentTypesHelper(); this.atypeFactory = factory; this.checker = checker; this.transferFunction = createTransferFunction(); this.fieldValues = new ArrayList<>(); } /** * Create a CFAbstractAnalysis. * * @param checker a checker that contains command-line arguments and other information * @param factory an annotated type factory to introduce type and dataflow rules */ protected CFAbstractAnalysis( BaseTypeChecker checker, GenericAnnotatedTypeFactory> factory) { this(checker, factory, factory.getQualifierHierarchy().numberOfIterationsBeforeWidening()); } /** * Analyze the given control flow graph. * * @param cfg control flow graph to analyze * @param fieldValues initial values of the fields */ public void performAnalysis(ControlFlowGraph cfg, List> fieldValues) { this.fieldValues.clear(); this.fieldValues.addAll(fieldValues); super.performAnalysis(cfg); } /** * A list of initial abstract values for the fields. * * @return a list of initial abstract values for the fields */ public List> getFieldInitialValues() { return fieldValues; } /** * Returns the transfer function to be used by the analysis. * * @return the transfer function to be used by the analysis */ public T createTransferFunction() { return atypeFactory.createFlowTransferFunction(this); } /** * Returns an empty store of the appropriate type. * * @return an empty store of the appropriate type */ public abstract S createEmptyStore(boolean sequentialSemantics); /** * Returns an identical copy of the store {@code s}. * * @return an identical copy of the store {@code s} */ public abstract S createCopiedStore(S s); /** * Creates an abstract value from the annotated type mirror. The value contains the set of primary * annotations on the type, unless the type is an AnnotatedWildcardType. For an * AnnotatedWildcardType, the annotations in the created value are the primary annotations on the * extends bound. See {@link CFAbstractValue} for an explanation. * * @param type the type to convert into an abstract value * @return an abstract value containing the given annotated {@code type} */ public @Nullable V createAbstractValue(AnnotatedTypeMirror type) { Set annos; if (type.getKind() == TypeKind.WILDCARD) { annos = ((AnnotatedWildcardType) type).getExtendsBound().getAnnotations(); } else if (TypesUtils.isCapturedTypeVariable(type.getUnderlyingType())) { annos = ((AnnotatedTypeVariable) type).getUpperBound().getAnnotations(); } else { annos = type.getAnnotations(); } return createAbstractValue(annos, type.getUnderlyingType()); } /** * Returns an abstract value containing the given {@code annotations} and {@code underlyingType}. * Returns null if the annotation set has missing annotations. * * @return an abstract value containing the given {@code annotations} and {@code underlyingType} */ public abstract @Nullable V createAbstractValue( Set annotations, TypeMirror underlyingType); /** Default implementation for {@link #createAbstractValue(Set, TypeMirror)}. */ public CFValue defaultCreateAbstractValue( CFAbstractAnalysis analysis, Set annotations, TypeMirror underlyingType) { if (!CFAbstractValue.validateSet(annotations, underlyingType, qualifierHierarchy)) { return null; } return new CFValue(analysis, annotations, underlyingType); } public TypeHierarchy getTypeHierarchy() { return typeHierarchy; } public GenericAnnotatedTypeFactory> getTypeFactory() { return atypeFactory; } /** * Returns an abstract value containing an annotated type with the annotation {@code anno}, and * 'top' for all other hierarchies. The underlying type is {@code underlyingType}. */ public V createSingleAnnotationValue(AnnotationMirror anno, TypeMirror underlyingType) { QualifierHierarchy hierarchy = getTypeFactory().getQualifierHierarchy(); Set annos = AnnotationUtils.createAnnotationSet(); annos.addAll(hierarchy.getTopAnnotations()); AnnotationMirror f = hierarchy.findAnnotationInSameHierarchy(annos, anno); annos.remove(f); annos.add(anno); return createAbstractValue(annos, underlyingType); } /** * Get the types utility. * * @return {@link #types} */ public Types getTypes() { return types; } /** * Get the processing environment. * * @return {@link #env} */ public ProcessingEnvironment getEnv() { return env; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy