All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.framework.util.Heuristics Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 3.0.0-b2
Show newest version
package org.checkerframework.framework.util;

import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IfTree;
import com.sun.source.tree.ParenthesizedTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.source.util.TreePath;
import java.util.ArrayDeque;
import java.util.Arrays;
import org.checkerframework.javacutil.TreeUtils;

/**
 * Utilities for determining tree-based heuristics.
 *
 * 

For an example, see {@code org.checkerframework.checker.interning.InterningVisitor}. */ public class Heuristics { /** * Determines whether a tree has a particular set of direct parents, ignoring blocks and * parentheses. * *

For example, to test whether an expression (specified by {@code path}) is immediately * contained by an if statement which is immediately contained in a method, one would invoke: * *

     * matchParents(path, Kind.IF, Kind.METHOD)
     * 
* * @param path the path to match * @param kinds the tree kinds to match against, in ascending order starting from the desired * kind of the parent * @return true if the tree path matches the desired kinds, skipping blocks and parentheses, for * as many kinds as specified */ public static boolean matchParents(TreePath path, Tree.Kind... kinds) { TreePath parentPath = path.getParentPath(); boolean result = true; ArrayDeque queue = new ArrayDeque<>(Arrays.asList(kinds)); Tree tree; while ((tree = parentPath.getLeaf()) != null) { if (queue.isEmpty()) { break; } if (tree.getKind() == Tree.Kind.BLOCK || tree.getKind() == Tree.Kind.PARENTHESIZED) { parentPath = parentPath.getParentPath(); continue; } result &= queue.removeFirst() == parentPath.getLeaf().getKind(); parentPath = parentPath.getParentPath(); } return result; } /** A convenience class for tree-matching algorithms. Skips parentheses by default. */ public static class Matcher extends SimpleTreeVisitor { @Override protected Boolean defaultAction(Tree node, Void p) { return false; } @Override public Boolean visitParenthesized(ParenthesizedTree node, Void p) { return visit(node.getExpression(), p); } public boolean match(TreePath path) { return visit(path.getLeaf(), null); } } public static class PreceededBy extends Matcher { private final Matcher matcher; public PreceededBy(Matcher matcher) { this.matcher = matcher; } @Override public boolean match(TreePath path) { StatementTree stmt = TreeUtils.enclosingOfClass(path, StatementTree.class); if (stmt == null) { return false; } TreePath p = path; while (p.getLeaf() != stmt) { p = p.getParentPath(); } assert p.getLeaf() == stmt; while (p != null && p.getLeaf() instanceof StatementTree) { if (p.getParentPath().getLeaf() instanceof BlockTree) { BlockTree block = (BlockTree) p.getParentPath().getLeaf(); for (StatementTree st : block.getStatements()) { if (st == p.getLeaf()) { break; } if (matcher.match(new TreePath(p, st))) { return true; } } } p = p.getParentPath(); } return false; } } public static class WithIn extends Matcher { private final Matcher matcher; public WithIn(Matcher matcher) { this.matcher = matcher; } @Override public boolean match(TreePath path) { TreePath p = path; while (p != null) { if (matcher.match(p)) { return true; } p = p.getParentPath(); } return false; } } public static class WithinTrueBranch extends Matcher { private final Matcher matcher; /** @param conditionMatcher for the condition */ public WithinTrueBranch(Matcher conditionMatcher) { this.matcher = conditionMatcher; } @Override public boolean match(TreePath path) { TreePath prev = path, p = path.getParentPath(); while (p != null) { if (p.getLeaf().getKind() == Tree.Kind.IF) { IfTree ifTree = (IfTree) p.getLeaf(); ExpressionTree cond = TreeUtils.skipParens(ifTree.getCondition()); if (ifTree.getThenStatement() == prev.getLeaf() && matcher.match(new TreePath(p, cond))) { return true; } if (cond.getKind() == Tree.Kind.LOGICAL_COMPLEMENT && matcher.match(new TreePath(p, ((UnaryTree) cond).getExpression()))) { return true; } } prev = p; p = p.getParentPath(); } return false; } } public static class OfKind extends Matcher { private final Tree.Kind kind; private final Matcher matcher; public OfKind(Tree.Kind kind, Matcher matcher) { this.kind = kind; this.matcher = matcher; } @Override public boolean match(TreePath path) { if (path.getLeaf().getKind() == kind) { return matcher.match(path); } return false; } } public static class OrMatcher extends Matcher { private final Matcher[] matchers; public OrMatcher(Matcher... matchers) { this.matchers = matchers; } @Override public boolean match(TreePath path) { for (Matcher matcher : matchers) { if (matcher.match(path)) { return true; } } return false; } } public static class Matchers { public static Matcher preceededBy(Matcher matcher) { return new PreceededBy(matcher); } public static Matcher withIn(Matcher matcher) { return new WithIn(matcher); } public static Matcher whenTrue(Matcher conditionMatcher) { return new WithinTrueBranch(conditionMatcher); } public static Matcher ofKind(Tree.Kind kind, Matcher matcher) { return new OfKind(kind, matcher); } public static Matcher or(Matcher... matchers) { return new OrMatcher(matchers); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy