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

org.checkerframework.common.aliasing.AliasingTransfer Maven / Gradle / Ivy

package org.checkerframework.common.aliasing;

import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import java.util.List;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import org.checkerframework.common.aliasing.qual.LeakedToResult;
import org.checkerframework.common.aliasing.qual.NonLeaked;
import org.checkerframework.common.aliasing.qual.Unique;
import org.checkerframework.dataflow.analysis.FlowExpressions;
import org.checkerframework.dataflow.analysis.FlowExpressions.Receiver;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ObjectCreationNode;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.javacutil.TreeUtils;

/**
 * Type refinement is treated in the usual way, except that at (pseudo-)assignments the RHS may lose
 * its type refinement, before the LHS is type-refined.
 *
 * 

The RHS always loses its type refinement (it is widened to {@literal @}MaybeAliased, and its * declared type must have been {@literal @}MaybeAliased) except in the following cases: * *

    *
  1. The RHS is a fresh expression. *
  2. The LHS is a {@literal @}NonLeaked formal parameter and the RHS is an argument in a method * call or constructor invocation. *
  3. The LHS is a {@literal @}LeakedToResult formal parameter, the RHS is an argument in a * method call or constructor invocation, and the method's return value is discarded. *
*/ public class AliasingTransfer extends CFTransfer { private AnnotatedTypeFactory factory; public AliasingTransfer(CFAbstractAnalysis analysis) { super(analysis); factory = analysis.getTypeFactory(); } /** * Case 1: For every assignment, the LHS is refined if the RHS has type {@literal @}Unique and * is a method invocation or a new class instance. */ @Override public TransferResult visitAssignment( AssignmentNode n, TransferInput in) { Node rhs = n.getExpression(); Tree treeRhs = rhs.getTree(); AnnotatedTypeMirror rhsType = factory.getAnnotatedType(treeRhs); if (rhsType.hasAnnotation(Unique.class) && (rhs instanceof MethodInvocationNode || rhs instanceof ObjectCreationNode)) { return super.visitAssignment(n, in); // Do normal refinement. } // Widen the type of the rhs if the RHS's declared type wasn't @Unique. Receiver r = FlowExpressions.internalReprOf(factory, rhs); in.getRegularStore().clearValue(r); return new RegularTransferResult<>(null, in.getRegularStore()); } /** * Handling pseudo-assignments. Called by {@code CFAbstractTransfer.visitMethodInvocation()}. * *

Case 2: Given a method call, traverses all formal parameters of the method declaration, * and if it doesn't have the {@literal @}NonLeaked or {@literal @}LeakedToResult annotations, * we remove the node of the respective argument in the method call from the store. If parameter * has {@literal @}LeakedToResult, {@code visitMethodInvocation()} handles it. */ @Override protected void processPostconditions( MethodInvocationNode n, CFStore store, ExecutableElement methodElement, Tree tree) { super.processPostconditions(n, store, methodElement, tree); if (TreeUtils.isEnumSuper(n.getTree())) { // Skipping the init() method for enums. return; } List args = n.getArguments(); List params = methodElement.getParameters(); assert (args.size() == params.size()) : "Number of arguments in " + "the method call " + n.toString() + " is different from the" + " number of parameters for the method declaration: " + methodElement.getSimpleName().toString(); AnnotatedExecutableType annotatedType = factory.getAnnotatedType(methodElement); List paramTypes = annotatedType.getParameterTypes(); for (int i = 0; i < args.size(); i++) { Node arg = args.get(i); AnnotatedTypeMirror paramType = paramTypes.get(i); if (!paramType.hasAnnotation(NonLeaked.class) && !paramType.hasAnnotation(LeakedToResult.class)) { store.clearValue(FlowExpressions.internalReprOf(factory, arg)); } } // Now, doing the same as above for the receiver parameter Node receiver = n.getTarget().getReceiver(); AnnotatedDeclaredType receiverType = annotatedType.getReceiverType(); if (receiverType != null && !receiverType.hasAnnotation(LeakedToResult.class) && !receiverType.hasAnnotation(NonLeaked.class)) { store.clearValue(FlowExpressions.internalReprOf(factory, receiver)); } } /** * Case 3: Given a method invocation expression, if the parent of the expression is not a * statement, check if there are any arguments of the method call annotated as * {@literal @}LeakedToResult and remove it from the store, since it might be leaked. */ @Override public TransferResult visitMethodInvocation( MethodInvocationNode n, TransferInput in) { Tree parent = n.getTreePath().getParentPath().getLeaf(); boolean parentIsStatement = parent.getKind() == Kind.EXPRESSION_STATEMENT; if (!parentIsStatement) { ExecutableElement methodElement = TreeUtils.elementFromUse(n.getTree()); List args = n.getArguments(); List params = methodElement.getParameters(); assert (args.size() == params.size()) : "Number of arguments in " + "the method call " + n.toString() + " is different from the" + " number of parameters for the method declaration: " + methodElement.getSimpleName().toString(); CFStore store = in.getRegularStore(); for (int i = 0; i < args.size(); i++) { Node arg = args.get(i); VariableElement param = params.get(i); if (factory.getAnnotatedType(param).hasAnnotation(LeakedToResult.class)) { // If argument can leak to result, and parent is not a // single statement, remove that node from store. store.clearValue(FlowExpressions.internalReprOf(factory, arg)); } } // Now, doing the same as above for the receiver parameter Node receiver = n.getTarget().getReceiver(); AnnotatedExecutableType annotatedType = factory.getAnnotatedType(methodElement); AnnotatedDeclaredType receiverType = annotatedType.getReceiverType(); if (receiverType != null && receiverType.hasAnnotation(LeakedToResult.class)) { store.clearValue(FlowExpressions.internalReprOf(factory, receiver)); } } // If parent is a statement, processPostconditions will handle the // pseudo-assignments. return super.visitMethodInvocation(n, in); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy