| package org.checkerframework.dataflow.util; |
| |
| import com.sun.source.tree.Tree; |
| import com.sun.tools.javac.code.Type; |
| import com.sun.tools.javac.tree.JCTree; |
| import javax.annotation.processing.ProcessingEnvironment; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.type.TypeKind; |
| import org.checkerframework.dataflow.cfg.node.BooleanLiteralNode; |
| import org.checkerframework.dataflow.cfg.node.ConditionalNotNode; |
| import org.checkerframework.dataflow.cfg.node.ConditionalOrNode; |
| import org.checkerframework.dataflow.cfg.node.FieldAccessNode; |
| import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; |
| import org.checkerframework.dataflow.cfg.node.Node; |
| import org.checkerframework.javacutil.ElementUtils; |
| import org.checkerframework.javacutil.TypesUtils; |
| |
| /** A utility class to operate on a given {@link Node}. */ |
| public class NodeUtils { |
| |
| /** |
| * Returns true iff {@code node} corresponds to a boolean typed expression (either the primitive |
| * type {@code boolean}, or class type {@link java.lang.Boolean}). |
| * |
| * @return true iff {@code node} corresponds to a boolean typed expression (either the primitive |
| * type {@code boolean}, or class type {@link java.lang.Boolean}) |
| */ |
| public static boolean isBooleanTypeNode(Node node) { |
| |
| if (node instanceof ConditionalOrNode) { |
| return true; |
| } |
| |
| // not all nodes have an associated tree, but those are all not of a boolean type. |
| Tree tree = node.getTree(); |
| if (tree == null) { |
| return false; |
| } |
| |
| Type type = ((JCTree) tree).type; |
| if (TypesUtils.isBooleanType(type)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Returns true iff {@code node} is a {@link FieldAccessNode} that is an access to an array's |
| * length. |
| * |
| * @return true iff {@code node} is a {@link FieldAccessNode} that is an access to an array's |
| * length |
| */ |
| public static boolean isArrayLengthFieldAccess(Node node) { |
| if (!(node instanceof FieldAccessNode)) { |
| return false; |
| } |
| FieldAccessNode fieldAccess = (FieldAccessNode) node; |
| return fieldAccess.getFieldName().equals("length") |
| && fieldAccess.getReceiver().getType().getKind() == TypeKind.ARRAY; |
| } |
| |
| /** Returns true iff {@code node} is an invocation of the given method. */ |
| public static boolean isMethodInvocation( |
| Node node, ExecutableElement method, ProcessingEnvironment env) { |
| if (!(node instanceof MethodInvocationNode)) { |
| return false; |
| } |
| ExecutableElement invoked = ((MethodInvocationNode) node).getTarget().getMethod(); |
| return ElementUtils.isMethod(invoked, method, env); |
| } |
| |
| /** |
| * Returns true if the given node statically evaluates to {@code value} and has no side effects. |
| * |
| * @param n a node |
| * @param value the boolean value that the node is tested against |
| * @return true if the node is equivalent to a literal with value {@code value} |
| */ |
| public static boolean isConstantBoolean(Node n, boolean value) { |
| if (n instanceof BooleanLiteralNode) { |
| return ((BooleanLiteralNode) n).getValue() == value; |
| } else if (n instanceof ConditionalNotNode) { |
| return isConstantBoolean(((ConditionalNotNode) n).getOperand(), !value); |
| } else { |
| return false; |
| } |
| } |
| } |