diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/DetailAST.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/DetailAST.java index b83b89aae..d432953b1 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/DetailAST.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/DetailAST.java @@ -18,6 +18,8 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.api; +import java.util.Arrays; + import antlr.CommonAST; import antlr.Token; import antlr.collections.AST; @@ -44,6 +46,14 @@ public class DetailAST /** the parent token */ private DetailAST mParent; + /** + * All token types in this branch, sorted. + * + * Note: This is not a Set to avoid creating zillions of + * Integer objects in branchContains(). + */ + private int[] mBranchTokenTypes = null; + /** @see antlr.CommonAST **/ public void initialize(Token aTok) { @@ -159,4 +169,45 @@ public class DetailAST } return (DetailAST) ast; } + + /** + * @return the token types that occur in the branch as a sorted set. + */ + private int[] getBranchTokenTypes() + { + // lazy init + if (mBranchTokenTypes == null) { + + // TODO improve algorithm to avoid most array creation + int[] bag = new int[] { getType() }; + + // add union of all childs + DetailAST child = (DetailAST) getFirstChild(); + while (child != null) { + int[] childTypes = child.getBranchTokenTypes(); + int[] savedBag = bag; + bag = new int[savedBag.length + childTypes.length]; + System.arraycopy(savedBag, 0, bag, 0, savedBag.length); + System.arraycopy(childTypes, 0, bag, savedBag.length, + childTypes.length); + child = (DetailAST) child.getNextSibling(); + } + // TODO: remove duplicates to speed up searching + mBranchTokenTypes = bag; + Arrays.sort(mBranchTokenTypes); + } + return mBranchTokenTypes; + } + + /** + * Checks if this branch of the parse tree contains a token + * of the provided type. + * @param aType a TokenType + * @return true if and only if this branch (including this node) + * contains a token of type aType. + */ + public boolean branchContains(int aType) + { + return Arrays.binarySearch(getBranchTokenTypes(), aType) >= 0; + } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/EqualsHashCodeCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/EqualsHashCodeCheck.java index dc7bbbe05..0a1c21d87 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/EqualsHashCodeCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/EqualsHashCodeCheck.java @@ -72,13 +72,7 @@ public class EqualsHashCodeCheck return; } - AST modifiers = aAST.getFirstChild(); - final Set mods = new HashSet(); - AST modifier = modifiers.getFirstChild(); - while (modifier != null) { - mods.add(modifier.getText()); - modifier = modifier.getNextSibling(); - } + DetailAST modifiers = (DetailAST) aAST.getFirstChild(); AST type = modifiers.getNextSibling(); AST methodName = type.getNextSibling(); @@ -86,7 +80,7 @@ public class EqualsHashCodeCheck if (type.getFirstChild().getType() == TokenTypes.LITERAL_BOOLEAN && "equals".equals(methodName.getText()) - && mods.contains("public") + && modifiers.branchContains(TokenTypes.LITERAL_PUBLIC) && parameters.getChildCount() == 1 && isObjectParam(parameters.getFirstChild()) ) @@ -95,7 +89,7 @@ public class EqualsHashCodeCheck } else if (type.getFirstChild().getType() == TokenTypes.LITERAL_INT && "hashCode".equals(methodName.getText()) -// && modifiers.subTreeContains(TokenTypes.LITERAL_PUBLIC) + && modifiers.branchContains(TokenTypes.LITERAL_PUBLIC) && parameters.getFirstChild() == null) // no params { objBlockWithHashCode.add(aAST.getParent());