use of org.checkerframework.dataflow.cfg.node.ArrayAccessNode in project bazel by bazelbuild.
the class FlowExpressions method internalReprOf.
/**
* We ignore operations such as widening and
* narrowing when computing the internal representation.
*
* @return The internal representation (as {@link Receiver}) of any
* {@link Node}. Might contain {@link Unknown}.
*/
public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode, boolean allowNonDeterminitic) {
Receiver receiver = null;
if (receiverNode instanceof FieldAccessNode) {
FieldAccessNode fan = (FieldAccessNode) receiverNode;
if (fan.getFieldName().equals("this")) {
// For some reason, "className.this" is considered a field access.
// We right this wrong here.
receiver = new ThisReference(fan.getReceiver().getType());
} else {
receiver = internalReprOfFieldAccess(provider, fan);
}
} else if (receiverNode instanceof ExplicitThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof ThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof SuperNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof LocalVariableNode) {
LocalVariableNode lv = (LocalVariableNode) receiverNode;
receiver = new LocalVariable(lv);
} else if (receiverNode instanceof ArrayAccessNode) {
ArrayAccessNode a = (ArrayAccessNode) receiverNode;
receiver = internalReprOfArrayAccess(provider, a);
} else if (receiverNode instanceof StringConversionNode) {
// ignore string conversion
return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof WideningConversionNode) {
// ignore widening
return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof NarrowingConversionNode) {
// ignore narrowing
return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof ClassNameNode) {
ClassNameNode cn = (ClassNameNode) receiverNode;
receiver = new ClassName(cn.getType());
} else if (receiverNode instanceof ValueLiteralNode) {
ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
receiver = new ValueLiteral(vn.getType(), vn);
} else if (receiverNode instanceof MethodInvocationNode) {
MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
// check if this represents a boxing operation of a constant, in which
// case we treat the method call as deterministic, because there is no way
// to behave differently in two executions where two constants are being used.
boolean considerDeterministic = false;
if (invokedMethod.toString().equals("valueOf(long)") && mn.getTarget().getReceiver().toString().equals("Long")) {
Node arg = mn.getArgument(0);
if (arg instanceof ValueLiteralNode) {
considerDeterministic = true;
}
}
if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterminitic || considerDeterministic) {
List<Receiver> parameters = new ArrayList<>();
for (Node p : mn.getArguments()) {
parameters.add(internalReprOf(provider, p));
}
Receiver methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
} else {
methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
}
receiver = new PureMethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
}
}
if (receiver == null) {
receiver = new Unknown(receiverNode.getType());
}
return receiver;
}
use of org.checkerframework.dataflow.cfg.node.ArrayAccessNode in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitArrayAccess.
@Override
public Node visitArrayAccess(ArrayAccessTree tree, Void p) {
Node array = scan(tree.getExpression(), p);
Node index = unaryNumericPromotion(scan(tree.getIndex(), p));
Node arrayAccess = new ArrayAccessNode(tree, array, index);
extendWithNode(arrayAccess);
extendWithNodeWithException(arrayAccess, arrayIndexOutOfBoundsExceptionType);
extendWithNodeWithException(arrayAccess, nullPointerExceptionType);
return arrayAccess;
}
use of org.checkerframework.dataflow.cfg.node.ArrayAccessNode in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitEnhancedForLoop.
@Override
public Node visitEnhancedForLoop(EnhancedForLoopTree tree, Void p) {
// see JLS 14.14.2
Name parentLabel = getLabel(getCurrentPath());
Label conditionStart = new Label();
Label loopEntry = new Label();
Label loopExit = new Label();
// If the loop is a labeled statement, then its continue target is identical for continues with
// no label and continues with the loop's label.
Label updateStart;
if (parentLabel != null) {
updateStart = continueLabels.get(parentLabel);
} else {
updateStart = new Label();
}
TryFinallyScopeCell oldBreakTargetL = breakTargetL;
breakTargetL = new TryFinallyScopeCell(loopExit);
TryFinallyScopeCell oldContinueTargetL = continueTargetL;
continueTargetL = new TryFinallyScopeCell(updateStart);
// Distinguish loops over Iterables from loops over arrays.
VariableTree variable = tree.getVariable();
VariableElement variableElement = TreeUtils.elementFromDeclaration(variable);
ExpressionTree expression = tree.getExpression();
StatementTree statement = tree.getStatement();
TypeMirror exprType = TreeUtils.typeOf(expression);
if (types.isSubtype(exprType, iterableType)) {
// Take the upper bound of a type variable or wildcard
exprType = TypesUtils.upperBound(exprType);
assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType";
DeclaredType declaredExprType = (DeclaredType) exprType;
declaredExprType.getTypeArguments();
MemberSelectTree iteratorSelect = treeBuilder.buildIteratorMethodAccess(expression);
handleArtificialTree(iteratorSelect);
MethodInvocationTree iteratorCall = treeBuilder.buildMethodInvocation(iteratorSelect);
handleArtificialTree(iteratorCall);
VariableTree iteratorVariable = createEnhancedForLoopIteratorVariable(iteratorCall, variableElement);
handleArtificialTree(iteratorVariable);
VariableDeclarationNode iteratorVariableDecl = new VariableDeclarationNode(iteratorVariable);
iteratorVariableDecl.setInSource(false);
extendWithNode(iteratorVariableDecl);
Node expressionNode = scan(expression, p);
MethodAccessNode iteratorAccessNode = new MethodAccessNode(iteratorSelect, expressionNode);
iteratorAccessNode.setInSource(false);
extendWithNode(iteratorAccessNode);
MethodInvocationNode iteratorCallNode = new MethodInvocationNode(iteratorCall, iteratorAccessNode, Collections.emptyList(), getCurrentPath());
iteratorCallNode.setInSource(false);
extendWithNode(iteratorCallNode);
translateAssignment(iteratorVariable, new LocalVariableNode(iteratorVariable), iteratorCallNode);
// Test the loop ending condition
addLabelForNextNode(conditionStart);
IdentifierTree iteratorUse1 = treeBuilder.buildVariableUse(iteratorVariable);
handleArtificialTree(iteratorUse1);
LocalVariableNode iteratorReceiverNode = new LocalVariableNode(iteratorUse1);
iteratorReceiverNode.setInSource(false);
extendWithNode(iteratorReceiverNode);
MemberSelectTree hasNextSelect = treeBuilder.buildHasNextMethodAccess(iteratorUse1);
handleArtificialTree(hasNextSelect);
MethodAccessNode hasNextAccessNode = new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
hasNextAccessNode.setInSource(false);
extendWithNode(hasNextAccessNode);
MethodInvocationTree hasNextCall = treeBuilder.buildMethodInvocation(hasNextSelect);
handleArtificialTree(hasNextCall);
MethodInvocationNode hasNextCallNode = new MethodInvocationNode(hasNextCall, hasNextAccessNode, Collections.emptyList(), getCurrentPath());
hasNextCallNode.setInSource(false);
extendWithNode(hasNextCallNode);
extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
// Loop body, starting with declaration of the loop iteration variable
addLabelForNextNode(loopEntry);
extendWithNode(new VariableDeclarationNode(variable));
IdentifierTree iteratorUse2 = treeBuilder.buildVariableUse(iteratorVariable);
handleArtificialTree(iteratorUse2);
LocalVariableNode iteratorReceiverNode2 = new LocalVariableNode(iteratorUse2);
iteratorReceiverNode2.setInSource(false);
extendWithNode(iteratorReceiverNode2);
MemberSelectTree nextSelect = treeBuilder.buildNextMethodAccess(iteratorUse2);
handleArtificialTree(nextSelect);
MethodAccessNode nextAccessNode = new MethodAccessNode(nextSelect, iteratorReceiverNode2);
nextAccessNode.setInSource(false);
extendWithNode(nextAccessNode);
MethodInvocationTree nextCall = treeBuilder.buildMethodInvocation(nextSelect);
handleArtificialTree(nextCall);
MethodInvocationNode nextCallNode = new MethodInvocationNode(nextCall, nextAccessNode, Collections.emptyList(), getCurrentPath());
// If the type of iteratorVariable is a capture, its type tree may be missing annotations, so
// save the expression in the node so that the full type can be found later.
nextCallNode.setIterableExpression(expression);
nextCallNode.setInSource(false);
extendWithNode(nextCallNode);
AssignmentNode assignNode = translateAssignment(variable, new LocalVariableNode(variable), nextCall);
// translateAssignment() scans variable and creates new nodes, so set the expression
// there, too.
((MethodInvocationNode) assignNode.getExpression()).setIterableExpression(expression);
assert statement != null;
scan(statement, p);
// Loop back edge
addLabelForNextNode(updateStart);
extendWithExtendedNode(new UnconditionalJump(conditionStart));
} else {
// TODO: Shift any labels after the initialization of the
// temporary array variable.
VariableTree arrayVariable = createEnhancedForLoopArrayVariable(expression, variableElement);
handleArtificialTree(arrayVariable);
VariableDeclarationNode arrayVariableNode = new VariableDeclarationNode(arrayVariable);
arrayVariableNode.setInSource(false);
extendWithNode(arrayVariableNode);
Node expressionNode = scan(expression, p);
translateAssignment(arrayVariable, new LocalVariableNode(arrayVariable), expressionNode);
// Declare and initialize the loop index variable
TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
LiteralTree zero = treeBuilder.buildLiteral(Integer.valueOf(0));
handleArtificialTree(zero);
VariableTree indexVariable = treeBuilder.buildVariableDecl(intType, uniqueName("index"), variableElement.getEnclosingElement(), zero);
handleArtificialTree(indexVariable);
VariableDeclarationNode indexVariableNode = new VariableDeclarationNode(indexVariable);
indexVariableNode.setInSource(false);
extendWithNode(indexVariableNode);
IntegerLiteralNode zeroNode = new IntegerLiteralNode(zero);
extendWithNode(zeroNode);
translateAssignment(indexVariable, new LocalVariableNode(indexVariable), zeroNode);
// Compare index to array length
addLabelForNextNode(conditionStart);
IdentifierTree indexUse1 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse1);
LocalVariableNode indexNode1 = new LocalVariableNode(indexUse1);
indexNode1.setInSource(false);
extendWithNode(indexNode1);
IdentifierTree arrayUse1 = treeBuilder.buildVariableUse(arrayVariable);
handleArtificialTree(arrayUse1);
LocalVariableNode arrayNode1 = new LocalVariableNode(arrayUse1);
extendWithNode(arrayNode1);
MemberSelectTree lengthSelect = treeBuilder.buildArrayLengthAccess(arrayUse1);
handleArtificialTree(lengthSelect);
FieldAccessNode lengthAccessNode = new FieldAccessNode(lengthSelect, arrayNode1);
lengthAccessNode.setInSource(false);
extendWithNode(lengthAccessNode);
BinaryTree lessThan = treeBuilder.buildLessThan(indexUse1, lengthSelect);
handleArtificialTree(lessThan);
LessThanNode lessThanNode = new LessThanNode(lessThan, indexNode1, lengthAccessNode);
lessThanNode.setInSource(false);
extendWithNode(lessThanNode);
extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
// Loop body, starting with declaration of the loop iteration variable
addLabelForNextNode(loopEntry);
extendWithNode(new VariableDeclarationNode(variable));
IdentifierTree arrayUse2 = treeBuilder.buildVariableUse(arrayVariable);
handleArtificialTree(arrayUse2);
LocalVariableNode arrayNode2 = new LocalVariableNode(arrayUse2);
arrayNode2.setInSource(false);
extendWithNode(arrayNode2);
IdentifierTree indexUse2 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse2);
LocalVariableNode indexNode2 = new LocalVariableNode(indexUse2);
indexNode2.setInSource(false);
extendWithNode(indexNode2);
ArrayAccessTree arrayAccess = treeBuilder.buildArrayAccess(arrayUse2, indexUse2);
handleArtificialTree(arrayAccess);
ArrayAccessNode arrayAccessNode = new ArrayAccessNode(arrayAccess, arrayNode2, indexNode2);
arrayAccessNode.setArrayExpression(expression);
arrayAccessNode.setInSource(false);
extendWithNode(arrayAccessNode);
AssignmentNode arrayAccessAssignNode = translateAssignment(variable, new LocalVariableNode(variable), arrayAccessNode);
extendWithNodeWithException(arrayAccessNode, nullPointerExceptionType);
// translateAssignment() scans variable and creates new nodes, so set the expression
// there, too.
Node arrayAccessAssignNodeExpr = arrayAccessAssignNode.getExpression();
if (arrayAccessAssignNodeExpr instanceof ArrayAccessNode) {
((ArrayAccessNode) arrayAccessAssignNodeExpr).setArrayExpression(expression);
} else if (arrayAccessAssignNodeExpr instanceof MethodInvocationNode) {
// If the array component type is a primitive, there may be a boxing or unboxing
// conversion. Treat that as an iterator.
MethodInvocationNode boxingNode = (MethodInvocationNode) arrayAccessAssignNodeExpr;
boxingNode.setIterableExpression(expression);
}
assert statement != null;
scan(statement, p);
// Loop back edge
addLabelForNextNode(updateStart);
IdentifierTree indexUse3 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse3);
LocalVariableNode indexNode3 = new LocalVariableNode(indexUse3);
indexNode3.setInSource(false);
extendWithNode(indexNode3);
LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
handleArtificialTree(oneTree);
Node one = new IntegerLiteralNode(oneTree);
one.setInSource(false);
extendWithNode(one);
BinaryTree addOneTree = treeBuilder.buildBinary(intType, Tree.Kind.PLUS, indexUse3, oneTree);
handleArtificialTree(addOneTree);
Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
addOneNode.setInSource(false);
extendWithNode(addOneNode);
AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
handleArtificialTree(assignTree);
Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
assignNode.setInSource(false);
extendWithNode(assignNode);
extendWithExtendedNode(new UnconditionalJump(conditionStart));
}
// Loop exit
addLabelForNextNode(loopExit);
breakTargetL = oldBreakTargetL;
continueTargetL = oldContinueTargetL;
return null;
}
use of org.checkerframework.dataflow.cfg.node.ArrayAccessNode in project error-prone by google.
the class NullnessPropagationTransfer method visitAssignment.
@Override
Nullness visitAssignment(AssignmentNode node, SubNodeValues inputs, LocalVariableUpdates updates) {
Nullness value = inputs.valueOfSubNode(node.getExpression());
Node target = node.getTarget();
if (target instanceof LocalVariableNode) {
updates.set((LocalVariableNode) target, value);
}
if (target instanceof ArrayAccessNode) {
setNonnullIfLocalVariable(updates, ((ArrayAccessNode) target).getArray());
}
if (target instanceof FieldAccessNode) {
FieldAccessNode fieldAccess = (FieldAccessNode) target;
ClassAndField targetField = tryGetFieldSymbol(target.getTree());
setReceiverNonnull(updates, fieldAccess.getReceiver(), targetField);
}
/*
* We propagate the value of the target to the value of the assignment expressions as a whole.
* We do this regardless of whether the target is a local variable. For example:
*
* String s = object.field = "foo"; // Now |s| is non-null.
*
* It's not clear to me that this is technically correct, but it works in practice with the
* bytecode generated by both javac and ecj.
*
* http://stackoverflow.com/q/12850676/28465
*/
return value;
}
use of org.checkerframework.dataflow.cfg.node.ArrayAccessNode in project checker-framework by typetools.
the class FlowExpressions method internalReprOf.
/**
* We ignore operations such as widening and narrowing when computing the internal
* representation.
*
* @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain
* {@link Unknown}.
*/
public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) {
Receiver receiver = null;
if (receiverNode instanceof FieldAccessNode) {
FieldAccessNode fan = (FieldAccessNode) receiverNode;
if (fan.getFieldName().equals("this")) {
// For some reason, "className.this" is considered a field access.
// We right this wrong here.
receiver = new ThisReference(fan.getReceiver().getType());
} else if (fan.getFieldName().equals("class")) {
// "className.class" is considered a field access. This makes sense,
// since .class is similar to a field access which is the equivalent
// of a call to getClass(). However for the purposes of dataflow
// analysis, and value stores, this is the equivalent of a ClassNameNode.
receiver = new ClassName(fan.getReceiver().getType());
} else {
receiver = internalReprOfFieldAccess(provider, fan);
}
} else if (receiverNode instanceof ExplicitThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof ThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof SuperNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof LocalVariableNode) {
LocalVariableNode lv = (LocalVariableNode) receiverNode;
receiver = new LocalVariable(lv);
} else if (receiverNode instanceof ArrayAccessNode) {
ArrayAccessNode a = (ArrayAccessNode) receiverNode;
receiver = internalReprOfArrayAccess(provider, a);
} else if (receiverNode instanceof StringConversionNode) {
// ignore string conversion
return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof WideningConversionNode) {
// ignore widening
return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof NarrowingConversionNode) {
// ignore narrowing
return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof ClassNameNode) {
ClassNameNode cn = (ClassNameNode) receiverNode;
receiver = new ClassName(cn.getType());
} else if (receiverNode instanceof ValueLiteralNode) {
ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
receiver = new ValueLiteral(vn.getType(), vn);
} else if (receiverNode instanceof ArrayCreationNode) {
ArrayCreationNode an = (ArrayCreationNode) receiverNode;
List<Receiver> dimensions = new ArrayList<>();
for (Node dimension : an.getDimensions()) {
dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
}
List<Receiver> initializers = new ArrayList<>();
for (Node initializer : an.getInitializers()) {
initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
}
receiver = new ArrayCreation(an.getType(), dimensions, initializers);
} else if (receiverNode instanceof MethodInvocationNode) {
MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
// check if this represents a boxing operation of a constant, in which
// case we treat the method call as deterministic, because there is no way
// to behave differently in two executions where two constants are being used.
boolean considerDeterministic = false;
if (isLongValueOf(mn, invokedMethod)) {
Node arg = mn.getArgument(0);
if (arg instanceof ValueLiteralNode) {
considerDeterministic = true;
}
}
if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic || considerDeterministic) {
List<Receiver> parameters = new ArrayList<>();
for (Node p : mn.getArguments()) {
parameters.add(internalReprOf(provider, p));
}
Receiver methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
} else {
methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
}
receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
}
}
if (receiver == null) {
receiver = new Unknown(receiverNode.getType());
}
return receiver;
}
Aggregations