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

checker.src.org.checkerframework.checker.initialization.InitializationTransfer 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
Show newest version
package org.checkerframework.checker.initialization;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;

import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
import org.checkerframework.dataflow.analysis.FlowExpressions;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess;
import org.checkerframework.dataflow.analysis.FlowExpressions.Receiver;
import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ThisLiteralNode;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFAbstractTransfer;
import org.checkerframework.framework.flow.CFAbstractValue;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;

import org.checkerframework.javacutil.TreeUtils;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol;

/**
 * A transfer function that extends {@link CFAbstractTransfer} and tracks
 * {@link InitializationStore}s. In addition to the features of
 * {@link CFAbstractTransfer}, this transfer function also track which fields of
 * the current class ('self' receiver) have been initialized.
 *
 * 

* More precisely, the following refinements are performed: *

    *
  1. After the call to a constructor ("this()" call), all non-null fields of * the current class can safely be considered initialized. *
  2. After a method call with a postcondition that ensures a field to be * non-null, that field can safely be considered initialized (this is done in * {@link InitializationStore#insertValue(FlowExpressions.Receiver, CFAbstractValue)}). *
  3. All non-null fields with an initializer can be considered initialized * (this is done in {@link InitializationStore#insertValue(FlowExpressions.Receiver, CFAbstractValue)}). *
  4. After the call to a super constructor ("super()" call), all non-null * fields of the super class can safely be considered initialized. *
* * @author Stefan Heule * @see InitializationStore * * @param The type of the transfer function. */ public class InitializationTransfer, T extends InitializationTransfer, S extends InitializationStore> extends CFAbstractTransfer { protected final InitializationAnnotatedTypeFactory atypeFactory; public InitializationTransfer(CFAbstractAnalysis analysis) { super(analysis); this.atypeFactory = (InitializationAnnotatedTypeFactory) analysis.getTypeFactory(); } @Override protected boolean isNotFullyInitializedReceiver(MethodTree methodTree) { if (super.isNotFullyInitializedReceiver(methodTree)) { return true; } final AnnotatedDeclaredType receiverType = analysis.getTypeFactory() .getAnnotatedType(methodTree).getReceiverType(); if (receiverType != null) { return atypeFactory.isUnclassified(receiverType) || atypeFactory.isFree(receiverType); } else { // There is no receiver e.g. in static methods. return false; } } /** * Returns the fields that can safely be considered initialized after * the method call {@code node}. */ protected List initializedFieldsAfterCall( MethodInvocationNode node, ConditionalTransferResult transferResult) { List result = new ArrayList<>(); MethodInvocationTree tree = node.getTree(); ExecutableElement method = TreeUtils.elementFromUse(tree); boolean isConstructor = method.getSimpleName().contentEquals(""); Node receiver = node.getTarget().getReceiver(); String methodString = tree.getMethodSelect().toString(); // Case 1: After a call to the constructor of the same class, all // invariant fields are guaranteed to be initialized. if (isConstructor && receiver instanceof ThisLiteralNode && methodString.equals("this")) { ClassTree clazz = TreeUtils.enclosingClass(analysis.getTypeFactory() .getPath(tree)); TypeElement clazzElem = TreeUtils.elementFromDeclaration(clazz); markInvariantFieldsAsInitialized(result, clazzElem); } // Case 4: After a call to the constructor of the super class, all // invariant fields of any super class are guaranteed to be initialized. if (isConstructor && receiver instanceof ThisLiteralNode && methodString.equals("super")) { ClassTree clazz = TreeUtils.enclosingClass(analysis.getTypeFactory() .getPath(tree)); TypeElement clazzElem = TreeUtils.elementFromDeclaration(clazz); TypeMirror superClass = clazzElem.getSuperclass(); while (superClass != null && superClass.getKind() != TypeKind.NONE) { clazzElem = (TypeElement) analysis.getTypes().asElement( superClass); superClass = clazzElem.getSuperclass(); markInvariantFieldsAsInitialized(result, clazzElem); } } return result; } /** * Adds all the fields of the class {@code clazzElem} that have the * 'invariant annotation' to the set of initialized fields {@code result}. */ protected void markInvariantFieldsAsInitialized(List result, TypeElement clazzElem) { List fields = ElementFilter.fieldsIn(clazzElem .getEnclosedElements()); for (VariableElement field : fields) { if (((Symbol)field).type.tsym.completer != null) { // If the type is not completed yet, we might run // into trouble. Skip the field. // TODO: is there a nicer solution? // This was raised by Issue 244. continue; } AnnotatedTypeMirror fieldAnno = atypeFactory.getAnnotatedType(field); if (fieldAnno.hasAnnotation(atypeFactory.getFieldInvariantAnnotation())) { result.add(field); } } } @Override public TransferResult visitAssignment(AssignmentNode n, TransferInput in) { TransferResult result = super.visitAssignment(n, in); assert result instanceof RegularTransferResult; Receiver expr = FlowExpressions.internalReprOf(analysis.getTypeFactory(), n.getTarget()); // If this is an assignment to a field of 'this', then mark the field as // initialized. if (!expr.containsUnknown()) { if (expr instanceof FieldAccess) { FieldAccess fa = (FieldAccess) expr; result.getRegularStore().addInitializedField(fa); } } return result; } /** * If an invariant field is initialized and has the invariant annotation, * than it has at least the invariant annotation. Note that only field of * the 'this' receiver are tracked for initialization. */ @Override public TransferResult visitFieldAccess(FieldAccessNode n, TransferInput p) { TransferResult result = super.visitFieldAccess(n, p); assert !result.containsTwoStores(); S store = result.getRegularStore(); if (store.isFieldInitialized(n.getElement()) && n.getReceiver() instanceof ThisLiteralNode) { AnnotatedTypeMirror fieldAnno = analysis.getTypeFactory() .getAnnotatedType(n.getElement()); // Only if the field has the type system's invariant annotation, // such as @NonNull. if (fieldAnno.hasAnnotation(atypeFactory.getFieldInvariantAnnotation())) { AnnotationMirror inv = atypeFactory.getFieldInvariantAnnotation(); V oldResultValue = result.getResultValue(); V refinedResultValue = analysis.createSingleAnnotationValue( inv, oldResultValue.getType().getUnderlyingType()); V newResultValue = refinedResultValue.mostSpecific( oldResultValue, null); result.setResultValue(newResultValue); } } return result; } @Override public TransferResult visitMethodInvocation(MethodInvocationNode n, TransferInput in) { TransferResult result = super.visitMethodInvocation(n, in); assert result instanceof ConditionalTransferResult; List newlyInitializedFields = initializedFieldsAfterCall(n, (ConditionalTransferResult) result); if (newlyInitializedFields.size() > 0) { for (VariableElement f : newlyInitializedFields) { result.getThenStore().addInitializedField(f); result.getElseStore().addInitializedField(f); } } return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy