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 checker Show documentation
Show all versions of checker Show documentation
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.
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);
}
@Override
public boolean containsOfClass(Class extends JavaExpression> clazz) {
if (getClass() == clazz) {
return true;
}
if (receiver.containsOfClass(clazz)) {
return true;
}
for (JavaExpression p : arguments) {
if (p.containsOfClass(clazz)) {
return true;
}
}
return false;
}
@Override
public boolean isDeterministic(AnnotationProvider provider) {
return (PurityUtils.isDeterministic(provider, method) || provider.isDeterministic(method))
&& listIsDeterministic(arguments, provider);
}
@Override
public boolean isUnassignableByOtherCode() {
// There is no need to check that the method is deterministic, because a MethodCall is
// only created for deterministic methods.
return receiver.isUnmodifiableByOtherCode()
&& arguments.stream().allMatch(JavaExpression::isUnmodifiableByOtherCode);
}
@Override
public boolean isUnmodifiableByOtherCode() {
return isUnassignableByOtherCode();
}
@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;
return method.equals(other.method)
&& receiver.equals(other.receiver)
&& arguments.equals(other.arguments);
}
@Override
public int hashCode() {
if (method.getKind() == ElementKind.CONSTRUCTOR) {
return super.hashCode();
}
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);
}
}