diff options
Diffstat (limited to 'third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java')
-rw-r--r-- | third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java | 1143 |
1 files changed, 0 insertions, 1143 deletions
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java deleted file mode 100644 index 85ad7b4b00..0000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java +++ /dev/null @@ -1,1143 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Symbol.VarSymbol; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.cfg.node.ArrayAccessNode; -import org.checkerframework.dataflow.cfg.node.ArrayCreationNode; -import org.checkerframework.dataflow.cfg.node.ClassNameNode; -import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.FieldAccessNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; -import org.checkerframework.dataflow.cfg.node.NarrowingConversionNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.StringConversionNode; -import org.checkerframework.dataflow.cfg.node.SuperNode; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.ValueLiteralNode; -import org.checkerframework.dataflow.cfg.node.WideningConversionNode; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.dataflow.util.PurityUtils; -import org.checkerframework.javacutil.AnnotationProvider; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.ErrorReporter; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; -import org.checkerframework.javacutil.TypeAnnotationUtils; -import org.checkerframework.javacutil.TypesUtils; - -/** - * Collection of classes and helper functions to represent Java expressions about which the - * org.checkerframework.dataflow analysis can possibly infer facts. Expressions include: - * - * <ul> - * <li>Field accesses (e.g., <em>o.f</em>) - * <li>Local variables (e.g., <em>l</em>) - * <li>This reference (e.g., <em>this</em>) - * <li>Pure method calls (e.g., <em>o.m()</em>) - * <li>Unknown other expressions to mark that something else was present. - * </ul> - * - * @author Stefan Heule - */ -public class FlowExpressions { - - /** - * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. - * Can contain {@link Unknown} as receiver. - */ - public static FieldAccess internalReprOfFieldAccess( - AnnotationProvider provider, FieldAccessNode node) { - Receiver receiver; - Node receiverNode = node.getReceiver(); - if (node.isStatic()) { - receiver = new ClassName(receiverNode.getType()); - } else { - receiver = internalReprOf(provider, receiverNode); - } - return new FieldAccess(receiver, node); - } - - /** - * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. - * Can contain {@link Unknown} as receiver. - */ - public static ArrayAccess internalReprOfArrayAccess( - AnnotationProvider provider, ArrayAccessNode node) { - Receiver receiver = internalReprOf(provider, node.getArray()); - Receiver index = internalReprOf(provider, node.getIndex()); - return new ArrayAccess(node.getType(), receiver, index); - } - - /** - * 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) { - return internalReprOf(provider, receiverNode, false); - } - - /** - * 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; - receiver = new ArrayCreation(an.getType(), an.getDimensions(), an.getInitializers()); - } 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) - || 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; - } - - /** - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. - */ - public static Receiver internalReprOf( - AnnotationProvider provider, ExpressionTree receiverTree) { - return internalReprOf(provider, receiverTree, true); - } - /** - * We ignore operations such as widening and narrowing when computing the internal - * representation. - * - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. - */ - public static Receiver internalReprOf( - AnnotationProvider provider, - ExpressionTree receiverTree, - boolean allowNonDeterministic) { - Receiver receiver; - switch (receiverTree.getKind()) { - case ARRAY_ACCESS: - ArrayAccessTree a = (ArrayAccessTree) receiverTree; - Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression()); - Receiver index = internalReprOf(provider, a.getIndex()); - receiver = new ArrayAccess(InternalUtils.typeOf(a), arrayAccessExpression, index); - break; - case BOOLEAN_LITERAL: - case CHAR_LITERAL: - case DOUBLE_LITERAL: - case FLOAT_LITERAL: - case INT_LITERAL: - case LONG_LITERAL: - case NULL_LITERAL: - case STRING_LITERAL: - LiteralTree vn = (LiteralTree) receiverTree; - receiver = new ValueLiteral(InternalUtils.typeOf(receiverTree), vn.getValue()); - break; - case NEW_ARRAY: - receiver = - new ArrayCreation( - InternalUtils.typeOf(receiverTree), - Collections.<Node>emptyList(), - Collections.<Node>emptyList()); - break; - case METHOD_INVOCATION: - MethodInvocationTree mn = (MethodInvocationTree) receiverTree; - ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn); - if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) { - List<Receiver> parameters = new ArrayList<>(); - for (ExpressionTree p : mn.getArguments()) { - parameters.add(internalReprOf(provider, p)); - } - Receiver methodReceiver; - if (ElementUtils.isStatic(invokedMethod)) { - methodReceiver = new ClassName(InternalUtils.typeOf(mn.getMethodSelect())); - } else { - methodReceiver = internalReprOf(provider, mn.getMethodSelect()); - } - TypeMirror type = InternalUtils.typeOf(mn); - receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters); - } else { - receiver = null; - } - break; - case MEMBER_SELECT: - receiver = internalRepOfMemberSelect(provider, (MemberSelectTree) receiverTree); - break; - case IDENTIFIER: - IdentifierTree identifierTree = (IdentifierTree) receiverTree; - TypeMirror typeOfId = InternalUtils.typeOf(identifierTree); - if (identifierTree.getName().contentEquals("this") - || identifierTree.getName().contentEquals("super")) { - receiver = new ThisReference(typeOfId); - break; - } - Element ele = TreeUtils.elementFromUse(identifierTree); - switch (ele.getKind()) { - case LOCAL_VARIABLE: - case RESOURCE_VARIABLE: - case EXCEPTION_PARAMETER: - case PARAMETER: - receiver = new LocalVariable(ele); - break; - case FIELD: - // Implicit access expression, such as "this" or a class name - Receiver fieldAccessExpression; - TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType(); - if (ElementUtils.isStatic(ele)) { - fieldAccessExpression = new ClassName(enclosingType); - } else { - fieldAccessExpression = new ThisReference(enclosingType); - } - receiver = - new FieldAccess( - fieldAccessExpression, typeOfId, (VariableElement) ele); - break; - case CLASS: - case ENUM: - case ANNOTATION_TYPE: - case INTERFACE: - receiver = new ClassName(ele.asType()); - break; - default: - receiver = null; - } - break; - default: - receiver = null; - } - - if (receiver == null) { - receiver = new Unknown(InternalUtils.typeOf(receiverTree)); - } - return receiver; - } - - /** - * Returns the implicit receiver of ele. - * - * <p>Returns either a new ClassName or a new ThisReference depending on whether ele is static - * or not. The passed element must be a field, method, or class. - * - * @param ele field, method, or class - * @return either a new ClassName or a new ThisReference depending on whether ele is static or - * not - */ - public static Receiver internalRepOfImplicitReceiver(Element ele) { - TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType(); - if (ElementUtils.isStatic(ele)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - /** - * Returns either a new ClassName or ThisReference Receiver object for the enclosingType - * - * <p>The Tree should be an expression or a statement that does not have a receiver or an - * implicit receiver. For example, a local variable declaration. - * - * @param path TreePath to tree - * @param enclosingType type of the enclosing type - * @return a new ClassName or ThisReference that is a Receiver object for the enclosingType - */ - public static Receiver internalRepOfPseudoReceiver(TreePath path, TypeMirror enclosingType) { - if (TreeUtils.isTreeInStaticScope(path)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - private static Receiver internalRepOfMemberSelect( - AnnotationProvider provider, MemberSelectTree memberSelectTree) { - TypeMirror expressionType = InternalUtils.typeOf(memberSelectTree.getExpression()); - if (TreeUtils.isClassLiteral(memberSelectTree)) { - return new ClassName(expressionType); - } - Element ele = TreeUtils.elementFromUse(memberSelectTree); - switch (ele.getKind()) { - case METHOD: - case CONSTRUCTOR: - return internalReprOf(provider, memberSelectTree.getExpression()); - case CLASS: // o instanceof MyClass.InnerClass - case ENUM: - case INTERFACE: // o instanceof MyClass.InnerInterface - case ANNOTATION_TYPE: - return new ClassName(expressionType); - case ENUM_CONSTANT: - case FIELD: - Receiver r = internalReprOf(provider, memberSelectTree.getExpression()); - return new FieldAccess(r, ElementUtils.getType(ele), (VariableElement) ele); - default: - ErrorReporter.errorAbort( - "Unexpected element kind: %s element: %s", ele.getKind(), ele); - return null; - } - } - - /** - * Returns Receiver objects for the formal parameters of the method in which path is enclosed. - * - * @param annotationProvider annotationProvider - * @param path TreePath that is enclosed by the method - * @return list of Receiver objects for the formal parameters of the method in which path is - * enclosed - */ - public static List<Receiver> getParametersOfEnclosingMethod( - AnnotationProvider annotationProvider, TreePath path) { - MethodTree methodTree = TreeUtils.enclosingMethod(path); - if (methodTree == null) { - return null; - } - List<Receiver> internalArguments = new ArrayList<>(); - for (VariableTree arg : methodTree.getParameters()) { - internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg))); - } - return internalArguments; - } - - public abstract static class Receiver { - protected final TypeMirror type; - - public Receiver(TypeMirror type) { - assert type != null; - this.type = type; - } - - public TypeMirror getType() { - return type; - } - - public abstract boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz); - - public boolean containsUnknown() { - return containsOfClass(Unknown.class); - } - - /** - * Returns true if and only if the value this expression stands for cannot be changed by a - * method call. This is the case for local variables, the self reference as well as final - * field accesses for whose receiver {@link #isUnmodifiableByOtherCode} is true. - */ - public abstract boolean isUnmodifiableByOtherCode(); - - /** @return true if and only if the two receiver are syntactically identical */ - public boolean syntacticEquals(Receiver other) { - return other == this; - } - - /** - * @return true if and only if this receiver contains a receiver that is syntactically equal - * to {@code other}. - */ - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - /** - * Returns true if and only if {@code other} appears anywhere in this receiver or an - * expression appears in this receiver such that {@code other} might alias this expression, - * and that expression is modifiable. - * - * <p>This is always true, except for cases where the Java type information prevents - * aliasing and none of the subexpressions can alias 'other'. - */ - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return this.equals(other) || store.canAlias(this, other); - } - } - - public static class FieldAccess extends Receiver { - protected Receiver receiver; - protected VariableElement field; - - public Receiver getReceiver() { - return receiver; - } - - public VariableElement getField() { - return field; - } - - public FieldAccess(Receiver receiver, FieldAccessNode node) { - super(node.getType()); - this.receiver = receiver; - this.field = node.getElement(); - } - - public FieldAccess(Receiver receiver, TypeMirror type, VariableElement fieldElement) { - super(type); - this.receiver = receiver; - this.field = fieldElement; - } - - public boolean isFinal() { - return ElementUtils.isFinal(field); - } - - public boolean isStatic() { - return ElementUtils.isStatic(field); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FieldAccess)) { - return false; - } - FieldAccess fa = (FieldAccess) obj; - return fa.getField().equals(getField()) && fa.getReceiver().equals(getReceiver()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getField(), getReceiver()); - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return super.containsModifiableAliasOf(store, other) - || receiver.containsModifiableAliasOf(store, other); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) || receiver.containsSyntacticEqualReceiver(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof FieldAccess)) { - return false; - } - FieldAccess fa = (FieldAccess) other; - return super.syntacticEquals(other) - || (fa.getField().equals(getField()) - && fa.getReceiver().syntacticEquals(getReceiver())); - } - - @Override - public String toString() { - if (receiver instanceof ClassName) { - return receiver.getType() + "." + field; - } else { - return receiver + "." + field; - } - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz) || receiver.containsOfClass(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return isFinal() && getReceiver().isUnmodifiableByOtherCode(); - } - } - - public static class ThisReference extends Receiver { - public ThisReference(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - return obj != null && obj instanceof ThisReference; - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(0); - } - - @Override - public String toString() { - return "this"; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return other instanceof ThisReference; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return false; // 'this' is not modifiable - } - } - - /** - * A ClassName represents the occurrence of a class as part of a static field access or method - * invocation. - */ - public static class ClassName extends Receiver { - public ClassName(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ClassName)) { - return false; - } - ClassName other = (ClassName) obj; - return getType().toString().equals(other.getType().toString()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getType().toString()); - } - - @Override - public String toString() { - return getType().toString() + ".class"; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return false; // not modifiable - } - } - - public static class Unknown extends Receiver { - public Unknown(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - return obj == this; - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public String toString() { - return "?"; - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return true; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - } - - public static class LocalVariable extends Receiver { - protected Element element; - - public LocalVariable(LocalVariableNode localVar) { - super(localVar.getType()); - this.element = localVar.getElement(); - } - - public LocalVariable(Element elem) { - super(ElementUtils.getType(elem)); - this.element = elem; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LocalVariable)) { - return false; - } - LocalVariable other = (LocalVariable) obj; - VarSymbol vs = (VarSymbol) element; - VarSymbol vsother = (VarSymbol) other.element; - // Use TypeAnnotationUtils.unannotatedType(type).toString().equals(...) instead of Types.isSameType(...) - // because Types requires a processing environment, and FlowExpressions is - // designed to be independent of processing environment. See also - // calls to getType().toString() in FlowExpressions. - return vsother.name.contentEquals(vs.name) - && TypeAnnotationUtils.unannotatedType(vsother.type) - .toString() - .equals(TypeAnnotationUtils.unannotatedType(vs.type).toString()) - && vsother.owner.toString().equals(vs.owner.toString()); - } - - public Element getElement() { - return element; - } - - @Override - public int hashCode() { - VarSymbol vs = (VarSymbol) element; - return HashCodeUtils.hash( - vs.name.toString(), - TypeAnnotationUtils.unannotatedType(vs.type).toString(), - vs.owner.toString()); - } - - @Override - public String toString() { - return element.toString(); - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof LocalVariable)) { - return false; - } - LocalVariable l = (LocalVariable) other; - return l.equals(this); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - } - - public static class ValueLiteral extends Receiver { - - protected final Object value; - - public ValueLiteral(TypeMirror type, ValueLiteralNode node) { - super(type); - value = node.getValue(); - } - - public ValueLiteral(TypeMirror type, Object value) { - super(type); - this.value = value; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ValueLiteral)) { - return false; - } - ValueLiteral other = (ValueLiteral) obj; - if (value == null) { - return type.toString().equals(other.type.toString()) && other.value == null; - } - return type.toString().equals(other.type.toString()) && value.equals(other.value); - } - - @Override - public String toString() { - if (TypesUtils.isString(type)) { - return "\"" + value + "\""; - } else if (type.getKind() == TypeKind.LONG) { - return value.toString() + "L"; - } - return value == null ? "null" : value.toString(); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(value, type.toString()); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - return false; // not modifiable - } - - public Object getValue() { - return value; - } - } - - /** A method call. */ - public static class MethodCall extends Receiver { - - protected final Receiver receiver; - protected final List<Receiver> parameters; - protected final ExecutableElement method; - - public MethodCall( - TypeMirror type, - ExecutableElement method, - Receiver receiver, - List<Receiver> parameters) { - super(type); - this.receiver = receiver; - this.parameters = parameters; - this.method = method; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - if (getClass().equals(clazz)) { - return true; - } - if (receiver.containsOfClass(clazz)) { - return true; - } - for (Receiver p : parameters) { - if (p.containsOfClass(clazz)) { - return true; - } - } - return false; - } - - /** @return the method call receiver (for inspection only - do not modify) */ - public Receiver getReceiver() { - return receiver; - } - - /** - * @return the method call parameters (for inspection only - do not modify any of the - * parameters) - */ - public List<Receiver> getParameters() { - return Collections.unmodifiableList(parameters); - } - - /** @return the ExecutableElement for the method call */ - public ExecutableElement getElement() { - return method; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) || receiver.syntacticEquals(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof MethodCall)) { - return false; - } - MethodCall otherMethod = (MethodCall) other; - if (!receiver.syntacticEquals(otherMethod.receiver)) { - return false; - } - if (parameters.size() != otherMethod.parameters.size()) { - return false; - } - int i = 0; - for (Receiver p : parameters) { - if (!p.syntacticEquals(otherMethod.parameters.get(i))) { - return false; - } - i++; - } - return method.equals(otherMethod.method); - } - - public boolean containsSyntacticEqualParameter(LocalVariable var) { - for (Receiver p : parameters) { - if (p.containsSyntacticEqualReceiver(var)) { - return true; - } - } - return false; - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - if (receiver.containsModifiableAliasOf(store, other)) { - return true; - } - for (Receiver p : parameters) { - if (p.containsModifiableAliasOf(store, other)) { - return true; - } - } - return false; // the method call itself is not modifiable - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof MethodCall)) { - return false; - } - MethodCall other = (MethodCall) obj; - int i = 0; - for (Receiver p : parameters) { - if (!p.equals(other.parameters.get(i))) { - return false; - } - i++; - } - return receiver.equals(other.receiver) && method.equals(other.method); - } - - @Override - public int hashCode() { - int hash = HashCodeUtils.hash(method, receiver); - for (Receiver p : parameters) { - hash = HashCodeUtils.hash(hash, p); - } - return hash; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (receiver instanceof ClassName) { - result.append(receiver.getType()); - } else { - result.append(receiver); - } - result.append("."); - String methodName = method.getSimpleName().toString(); - result.append(methodName); - result.append("("); - boolean first = true; - for (Receiver p : parameters) { - if (!first) { - result.append(", "); - } - result.append(p.toString()); - first = false; - } - result.append(")"); - return result.toString(); - } - } - - /** A deterministic method call. */ - public static class ArrayAccess extends Receiver { - - protected final Receiver receiver; - protected final Receiver index; - - public ArrayAccess(TypeMirror type, Receiver receiver, Receiver index) { - super(type); - this.receiver = receiver; - this.index = index; - } - - @Override - public boolean containsOfClass(Class<? extends FlowExpressions.Receiver> clazz) { - if (getClass().equals(clazz)) { - return true; - } - if (receiver.containsOfClass(clazz)) { - return true; - } - return index.containsOfClass(clazz); - } - - public Receiver getReceiver() { - return receiver; - } - - public Receiver getIndex() { - return index; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) - || receiver.syntacticEquals(other) - || index.syntacticEquals(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof ArrayAccess)) { - return false; - } - ArrayAccess otherArrayAccess = (ArrayAccess) other; - if (!receiver.syntacticEquals(otherArrayAccess.receiver)) { - return false; - } - return index.syntacticEquals(otherArrayAccess.index); - } - - @Override - public boolean containsModifiableAliasOf(Store<?> store, Receiver other) { - if (receiver.containsModifiableAliasOf(store, other)) { - return true; - } - return index.containsModifiableAliasOf(store, other); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayAccess)) { - return false; - } - ArrayAccess other = (ArrayAccess) obj; - return receiver.equals(other.receiver) && index.equals(other.index); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(receiver, index); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append(receiver.toString()); - result.append("["); - result.append(index.toString()); - result.append("]"); - return result.toString(); - } - } - - public static class ArrayCreation extends Receiver { - - protected List<Node> dimensions; - protected List<Node> initializers; - - public ArrayCreation(TypeMirror type, List<Node> dimensions, List<Node> initializers) { - super(type); - this.dimensions = dimensions; - this.initializers = initializers; - } - - public List<Node> getDimensions() { - return dimensions; - } - - public List<Node> getInitializers() { - return initializers; - } - - @Override - public boolean containsOfClass(Class<? extends Receiver> clazz) { - for (Node n : dimensions) { - if (n.getClass().equals(clazz)) return true; - } - for (Node n : initializers) { - if (n.getClass().equals(clazz)) return true; - } - return false; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode()); - result = prime * result + ((initializers == null) ? 0 : initializers.hashCode()); - result = prime * result + HashCodeUtils.hash(getType().toString()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayCreation)) { - return false; - } - ArrayCreation other = (ArrayCreation) obj; - return this.dimensions.equals(other.getDimensions()) - && this.initializers.equals(other.getInitializers()) - && getType().toString().equals(other.getType().toString()); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("new " + type); - if (!dimensions.isEmpty()) { - boolean needComma = false; - sb.append(" ("); - for (Node dim : dimensions) { - if (needComma) { - sb.append(", "); - } - sb.append(dim); - needComma = true; - } - sb.append(")"); - } - if (!initializers.isEmpty()) { - boolean needComma = false; - sb.append(" = {"); - for (Node init : initializers) { - if (needComma) { - sb.append(", "); - } - sb.append(init); - needComma = true; - } - sb.append("}"); - } - return sb.toString(); - } - } -} |