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

org.checkerframework.checker.initialization.InitializationStore 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.checker.initialization;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.VariableElement;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer;
import org.checkerframework.dataflow.expression.ClassName;
import org.checkerframework.dataflow.expression.FieldAccess;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.dataflow.expression.ThisReference;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFAbstractStore;
import org.checkerframework.framework.flow.CFAbstractValue;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.javacutil.AnnotationUtils;
import org.plumelib.util.CollectionsPlume;
import org.plumelib.util.ToStringComparator;

/**
 * A store that extends {@code CFAbstractStore} and additionally tracks which fields of the 'self'
 * reference have been initialized.
 *
 * @see InitializationTransfer
 */
public class InitializationStore, S extends InitializationStore>
    extends CFAbstractStore {

  /** The set of fields that are initialized. */
  protected final Set initializedFields;
  /** The set of fields that have the 'invariant' annotation, and their value. */
  protected final Map invariantFields;

  /**
   * Creates a new InitializationStore.
   *
   * @param analysis the analysis class this store belongs to
   * @param sequentialSemantics should the analysis use sequential Java semantics?
   */
  public InitializationStore(CFAbstractAnalysis analysis, boolean sequentialSemantics) {
    super(analysis, sequentialSemantics);
    initializedFields = new HashSet<>(4);
    invariantFields = new HashMap<>(4);
  }

  /**
   * {@inheritDoc}
   *
   * 

If the receiver is a field, and has an invariant annotation, then it can be considered * initialized. */ @Override public void insertValue(JavaExpression je, V value, boolean permitNondeterministic) { if (!shouldInsert(je, value, permitNondeterministic)) { return; } InitializationAnnotatedTypeFactory atypeFactory = (InitializationAnnotatedTypeFactory) analysis.getTypeFactory(); QualifierHierarchy qualifierHierarchy = atypeFactory.getQualifierHierarchy(); AnnotationMirror invariantAnno = atypeFactory.getFieldInvariantAnnotation(); // Remember fields that have the 'invariant' annotation in the store. if (je instanceof FieldAccess) { FieldAccess fieldAccess = (FieldAccess) je; if (!fieldValues.containsKey(je)) { Set declaredAnnos = atypeFactory.getAnnotatedType(fieldAccess.getField()).getAnnotations(); if (AnnotationUtils.containsSame(declaredAnnos, invariantAnno)) { if (!invariantFields.containsKey(fieldAccess)) { invariantFields.put( fieldAccess, analysis.createSingleAnnotationValue(invariantAnno, je.getType())); } } } } super.insertValue(je, value, permitNondeterministic); for (AnnotationMirror a : value.getAnnotations()) { if (qualifierHierarchy.isSubtype(a, invariantAnno)) { if (je instanceof FieldAccess) { FieldAccess fa = (FieldAccess) je; if (fa.getReceiver() instanceof ThisReference || fa.getReceiver() instanceof ClassName) { addInitializedField(fa.getField()); } } } } } /** * {@inheritDoc} * *

Additionally, the {@link InitializationStore} keeps all field values for fields that have * the 'invariant' annotation. */ @Override public void updateForMethodCall( MethodInvocationNode n, AnnotatedTypeFactory atypeFactory, V val) { // Remove invariant annotated fields to avoid performance issue reported in #1438. for (FieldAccess invariantField : invariantFields.keySet()) { fieldValues.remove(invariantField); } super.updateForMethodCall(n, atypeFactory, val); // Add invariant annotation again. fieldValues.putAll(invariantFields); } /** A copy constructor. */ public InitializationStore(S other) { super(other); initializedFields = new HashSet<>(other.initializedFields); invariantFields = new HashMap<>(other.invariantFields); } /** * Mark the field identified by the element {@code field} as initialized if it belongs to the * current class, or is static (in which case there is no aliasing issue and we can just add all * static fields). * * @param field a field that is initialized */ public void addInitializedField(FieldAccess field) { boolean fieldOnThisReference = field.getReceiver() instanceof ThisReference; boolean staticField = field.isStatic(); if (fieldOnThisReference || staticField) { initializedFields.add(field.getField()); } } /** * Mark the field identified by the element {@code f} as initialized (the caller needs to ensure * that the field belongs to the current class, or is a static field). * * @param f a field that is initialized */ public void addInitializedField(VariableElement f) { initializedFields.add(f); } /** Is the field identified by the element {@code f} initialized? */ public boolean isFieldInitialized(Element f) { return initializedFields.contains(f); } @Override protected boolean supersetOf(CFAbstractStore o) { if (!(o instanceof InitializationStore)) { return false; } @SuppressWarnings("unchecked") S other = (S) o; for (Element field : other.initializedFields) { if (!initializedFields.contains(field)) { return false; } } for (FieldAccess invariantField : other.invariantFields.keySet()) { if (!invariantFields.containsKey(invariantField)) { return false; } } Map removedFieldValues = new HashMap<>(invariantFields.size()); Map removedOtherFieldValues = new HashMap<>(other.invariantFields.size()); try { // Remove invariant annotated fields to avoid performance issue reported in #1438. for (FieldAccess invariantField : invariantFields.keySet()) { V v = fieldValues.remove(invariantField); removedFieldValues.put(invariantField, v); } for (FieldAccess invariantField : other.invariantFields.keySet()) { V v = other.fieldValues.remove(invariantField); removedOtherFieldValues.put(invariantField, v); } return super.supersetOf(other); } finally { // Restore removed values. fieldValues.putAll(removedFieldValues); other.fieldValues.putAll(removedOtherFieldValues); } } @Override public S leastUpperBound(S other) { // Remove invariant annotated fields to avoid performance issue reported in #1438. Map removedFieldValues = new HashMap<>(invariantFields.size()); Map removedOtherFieldValues = new HashMap<>(other.invariantFields.size()); for (FieldAccess invariantField : invariantFields.keySet()) { V v = fieldValues.remove(invariantField); removedFieldValues.put(invariantField, v); } for (FieldAccess invariantField : other.invariantFields.keySet()) { V v = other.fieldValues.remove(invariantField); removedOtherFieldValues.put(invariantField, v); } S result = super.leastUpperBound(other); // Restore removed values. fieldValues.putAll(removedFieldValues); other.fieldValues.putAll(removedOtherFieldValues); // Set intersection for initializedFields. result.initializedFields.addAll(other.initializedFields); result.initializedFields.retainAll(initializedFields); // Set intersection for invariantFields. for (Map.Entry e : invariantFields.entrySet()) { FieldAccess key = e.getKey(); if (other.invariantFields.containsKey(key)) { // TODO: Is the value other.invariantFields.get(key) the same as e.getValue()? Should the // two values be lubbed? result.invariantFields.put(key, e.getValue()); } } // Add invariant annotation. result.fieldValues.putAll(result.invariantFields); return result; } @Override protected String internalVisualize(CFGVisualizer viz) { String superVisualize = super.internalVisualize(viz); String initializedVisualize = viz.visualizeStoreKeyVal( "initialized fields", ToStringComparator.sorted(initializedFields)); List invariantVars = CollectionsPlume.mapList(FieldAccess::getField, invariantFields.keySet()); String invariantVisualize = viz.visualizeStoreKeyVal("invariant fields", ToStringComparator.sorted(invariantVars)); if (superVisualize.isEmpty()) { return String.join(viz.getSeparator(), initializedVisualize, invariantVisualize); } else { return String.join( viz.getSeparator(), superVisualize, initializedVisualize, invariantVisualize); } } /** * Returns the analysis associated with this store. * * @return the analysis associated with this store */ public CFAbstractAnalysis getAnalysis() { return analysis; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy