org.checkerframework.dataflow.expression.MethodCall Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dataflow-shaded Show documentation
Show all versions of dataflow-shaded Show documentation
dataflow-shaded is a dataflow framework based on the javac compiler.
It differs from the org.checkerframework:dataflow artifact in two ways.
First, the packages in this artifact have been renamed to org.checkerframework.shaded.*.
Second, unlike the dataflow artifact, this artifact contains the dependencies it requires.
package org.checkerframework.dataflow.expression;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.util.PurityUtils;
import org.checkerframework.javacutil.AnnotationProvider;
/** A call to a @Deterministic method. */
public class MethodCall extends JavaExpression {
/** The method being called. */
protected final ExecutableElement method;
/** The receiver argument. */
protected final JavaExpression receiver;
/** The arguments. */
protected final List arguments;
/**
* Creates a new MethodCall.
*
* @param type the type of the method call
* @param method the method being called
* @param receiver the receiver argument
* @param arguments the arguments
*/
public MethodCall(
TypeMirror type,
ExecutableElement method,
JavaExpression receiver,
List arguments) {
super(type);
this.receiver = receiver;
this.arguments = arguments;
this.method = method;
}
/**
* Returns the ExecutableElement for the method call.
*
* @return the ExecutableElement for the method call
*/
public ExecutableElement getElement() {
return method;
}
/**
* Returns the method call receiver (for inspection only - do not modify).
*
* @return the method call receiver (for inspection only - do not modify)
*/
public JavaExpression getReceiver() {
return receiver;
}
/**
* Returns the method call arguments (for inspection only - do not modify any of the arguments).
*
* @return the method call arguments (for inspection only - do not modify any of the arguments)
*/
public List getArguments() {
return Collections.unmodifiableList(arguments);
}
@SuppressWarnings("unchecked") // generic cast
@Override
public @Nullable T containedOfClass(Class clazz) {
if (getClass() == clazz) {
return (T) this;
}
T result = receiver.containedOfClass(clazz);
if (result != null) {
return result;
}
for (JavaExpression p : arguments) {
result = p.containedOfClass(clazz);
if (result != null) {
return result;
}
}
return null;
}
@Override
public boolean isDeterministic(AnnotationProvider provider) {
return (PurityUtils.isDeterministic(provider, method) || provider.isDeterministic(method))
&& listIsDeterministic(arguments, provider);
}
@Override
public boolean isAssignableByOtherCode() {
// TODO: The following comment is no longer accurate. It should be removed and the
// implementation changed.
// There is no need to check that the method is deterministic, because a MethodCall is
// only created for deterministic methods.
return receiver.isModifiableByOtherCode()
|| arguments.stream().anyMatch(JavaExpression::isModifiableByOtherCode);
}
@Override
public boolean isModifiableByOtherCode() {
return isAssignableByOtherCode();
}
@Override
public boolean syntacticEquals(JavaExpression je) {
if (!(je instanceof MethodCall)) {
return false;
}
MethodCall other = (MethodCall) je;
return method.equals(other.method)
&& this.receiver.syntacticEquals(other.receiver)
&& JavaExpression.syntacticEqualsList(this.arguments, other.arguments);
}
@Override
public boolean containsSyntacticEqualJavaExpression(JavaExpression other) {
return syntacticEquals(other)
|| receiver.containsSyntacticEqualJavaExpression(other)
|| JavaExpression.listContainsSyntacticEqualJavaExpression(arguments, other);
}
@Override
public boolean containsModifiableAliasOf(Store> store, JavaExpression other) {
if (receiver.containsModifiableAliasOf(store, other)) {
return true;
}
for (JavaExpression p : arguments) {
if (p.containsModifiableAliasOf(store, other)) {
return true;
}
}
return false; // the method call itself is not modifiable
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof MethodCall)) {
return false;
}
if (method.getKind() == ElementKind.CONSTRUCTOR) {
return false;
}
MethodCall other = (MethodCall) obj;
boolean isComparingSuperWithThis =
(receiver instanceof SuperReference && other.receiver instanceof ThisReference)
|| (receiver instanceof ThisReference && other.receiver instanceof SuperReference);
return method.equals(other.method)
&& (receiver.equals(other.receiver) || isComparingSuperWithThis)
&& arguments.equals(other.arguments);
}
@Override
public int hashCode() {
if (method.getKind() == ElementKind.CONSTRUCTOR) {
return System.identityHashCode(this);
}
return Objects.hash(method, receiver, arguments);
}
@Override
public String toString() {
StringBuilder preParen = new StringBuilder();
if (receiver instanceof ClassName) {
preParen.append(receiver.getType());
} else {
preParen.append(receiver);
}
preParen.append(".");
String methodName = method.getSimpleName().toString();
preParen.append(methodName);
preParen.append("(");
StringJoiner result = new StringJoiner(", ", preParen, ")");
for (JavaExpression argument : arguments) {
result.add(argument.toString());
}
return result.toString();
}
@Override
public R accept(JavaExpressionVisitor visitor, P p) {
return visitor.visitMethodCall(this, p);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy