diff --git a/docs/config_misc.html b/docs/config_misc.html index 0d619dec3..64e2c8010 100644 --- a/docs/config_misc.html +++ b/docs/config_misc.html @@ -90,6 +90,12 @@
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Comment.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Comment.java index a78bd2636..6befb609f 100755 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Comment.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Comment.java @@ -102,4 +102,29 @@ class Comment implements TextBlock { return mLastCol; } + + /** + * Checks if this comment intersects with a specified + * part of the file. + * + * @param aStartLineNo the starting line number in the file + * @param aStartColNo the starting column number in the file + * @param aEndLineNo the ending line number in the file + * @param aEndColNo the ending column number in the file + * @return true if the positions intersects with this comment. + **/ + public boolean intersects(int aStartLineNo, int aStartColNo, + int aEndLineNo, int aEndColNo) + { + // compute a single number for start and end + // to simpify conditional logic + final long multiplier = Integer.MAX_VALUE; + final long thisStart = ((long) mFirstLine) * multiplier + mFirstCol; + final long thisEnd = ((long) mLastLine) * multiplier + mLastCol; + final long inStart = ((long) aStartLineNo) * multiplier + aStartColNo; + final long inEnd = ((long) aEndLineNo) * multiplier + aEndColNo; + + return ((thisStart < inStart) && (inStart < thisEnd)) + || ((thisStart < inEnd) && (inEnd < thisEnd)); + } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java index ddedf5974..ac80bad1a 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java @@ -25,6 +25,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.HashMap; +import java.util.Collection; +import java.util.Iterator; import com.puppycrawl.tools.checkstyle.grammars.CommentListener; @@ -241,4 +243,47 @@ public final class FileContents implements CommentListener return MATCH_SINGLELINE_COMMENT.match(mLines[aLineNo]); } + /** + * Checks if the specified position intersects with a comment. + * @param aStartLineNo the starting line number + * @param aStartColNo the starting column number + * @param aEndLineNo the ending line number + * @param aEndColNo the ending column number + * @return true if the positions intersects with a comment. + **/ + public boolean hasIntersectionWithComment( + int aStartLineNo, int aStartColNo, int aEndLineNo, int aEndColNo) + { + // Check C comments (all comments should be checked) + Collection values = mCComments.values(); + + Iterator it = values.iterator(); + while (it.hasNext()) { + List row = (List) it.next(); + Iterator rowIterator = row.iterator(); + while (rowIterator.hasNext()) { + Comment comment = (Comment) rowIterator.next(); + if (comment.intersects( + aStartLineNo, aStartColNo, aEndLineNo, aEndColNo)) + { + return true; + } + } + } + + // Check CPP comments (line searching is possible) + for (int lineNumber = aStartLineNo; lineNumber <= aEndLineNo; + lineNumber++) + { + Comment comment = (Comment) mCPlusPlusComments.get( + new Integer(lineNumber)); + if (comment != null && comment.intersects(aStartLineNo, aStartColNo, + aEndLineNo, aEndColNo)) + { + return true; + } + } + return false; + } + } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheck.java index a3eb96708..814610b31 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheck.java @@ -21,6 +21,7 @@ package com.puppycrawl.tools.checkstyle.checks; import org.apache.regexp.RE; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileContents; /** *
@@ -43,6 +44,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; * * @author lkuehne * @author Bill Schneider + * @author Daniel Grenner */ public class GenericIllegalRegexpCheck extends AbstractFormatCheck { @@ -55,6 +57,9 @@ public class GenericIllegalRegexpCheck extends AbstractFormatCheck /** case insensitive? **/ private boolean mIgnoreCase; + /** Ignore comments in code? **/ + private boolean mIgnoreComments; + /** * Setter for message property. * @param aMessage custom message which should be used @@ -88,6 +93,15 @@ public class GenericIllegalRegexpCheck extends AbstractFormatCheck mIgnoreCase = aCaseInsensitive; } + /** + * Sets if comments should be ignored. + * @param aIgnoreComments True if comments should be ignored. + */ + public void setIgnoreComments(boolean aIgnoreComments) + { + mIgnoreComments = aIgnoreComments; + } + /** * Instantiates an new GenericIllegalRegexpCheck. */ @@ -106,10 +120,18 @@ public class GenericIllegalRegexpCheck extends AbstractFormatCheck public void beginTree(DetailAST aRootAST) { final String[] lines = getLines(); + for (int i = 0; i < lines.length; i++) { final String line = lines[i]; - if (getRegexp().match(line)) { + final boolean foundMatch; + if (mIgnoreComments) { + foundMatch = findNonCommentMatch(line, i + 1, 0); + } + else { + foundMatch = getRegexp().match(line); + } + if (foundMatch) { if ("".equals(mMessage)) { log(i + 1, "illegal.regexp", getFormat()); } @@ -120,6 +142,47 @@ public class GenericIllegalRegexpCheck extends AbstractFormatCheck } } + /** + * Finds matches that are not inside comments. + * @param aLine The text that should be matched. + * @param aLineNumber The current line number. + * @param aStartPosition The position to start searching from. + * @return true if a match is done where there is no comment. + */ + private boolean findNonCommentMatch( + String aLine, int aLineNumber, int aStartPosition) + { + final RE regexp = getRegexp(); + final boolean foundMatch = regexp.match(aLine, aStartPosition); + if (foundMatch) { + // match is found, check for intersection with comment + int startCol = regexp.getParenStart(0); + int endCol = regexp.getParenEnd(0); + final FileContents fileContents = getFileContents(); + if (fileContents.hasIntersectionWithComment(aLineNumber, + startCol, aLineNumber, endCol)) + { + // was part of comment + if (endCol < aLine.length()) { + // check if the expression is on the rest of the line + return findNonCommentMatch(aLine, aLineNumber, endCol); + } + else { + // end of line reached + return false; + } + } + else { + // not intersecting with comment + return true; + } + } + else { + // no match is found + return false; + } + } + /** @return the regexp to match against */ public RE getRegexp() { diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/InputTrailingComment.java b/src/testinputs/com/puppycrawl/tools/checkstyle/InputTrailingComment.java index 521cf8455..41d2bca39 100644 --- a/src/testinputs/com/puppycrawl/tools/checkstyle/InputTrailingComment.java +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/InputTrailingComment.java @@ -17,5 +17,7 @@ public class InputTrailingComment { /* c-style 1 */ /*c-style 2 */ void method2(long ms /* we should ignore this */) { + /* comment before text */int z; + /* int y */int y/**/; } } diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheckTest.java index 3b2881ac1..bebedf7b1 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheckTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/GenericIllegalRegexpCheckTest.java @@ -68,4 +68,143 @@ public class GenericIllegalRegexpCheckTest final String[] expectedFalse = {}; verify(checkConfigFalse, getPath("InputSemantic.java"), expectedFalse); } + + public void testIgnoreCommentsCppStyle() + throws Exception + { + // See if the comment is removed properly + final String illegal = "don't use trailing comments"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsFalseCppStyle() + throws Exception + { + // See if the comment is removed properly + final String illegal = "don't use trailing comments"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "false"); + final String[] expected = { + "2: Line matches the illegal pattern '" + illegal + "'." + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsCStyle() + throws Exception + { + // See if the comment is removed properly + final String illegal = "c-style 1"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsFalseCStyle() + throws Exception + { + final String illegal = "c-style 1"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "false"); + final String[] expected = { + "17: Line matches the illegal pattern '" + illegal + "'." + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsMultipleCStyle() + throws Exception + { + // See if a second comment on the same line is removed properly + final String illegal = "c-style 2"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsMultiLine() + throws Exception + { + final String illegal = "Let's check multi-line comments"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsInlineStart() + throws Exception + { + final String illegal = "long ms /"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsInlineEnd() + throws Exception + { + final String illegal = "int z"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + "20: Line matches the illegal pattern '" + illegal + "'." + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsInlineMiddle() + throws Exception + { + final String illegal = "int y"; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + "21: Line matches the illegal pattern '" + illegal + "'." + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } + + public void testIgnoreCommentsNoSpaces() + throws Exception + { + // make sure the comment is not turned into spaces + final String illegal = "long ms "; + final DefaultConfiguration checkConfig = + createCheckConfig(GenericIllegalRegexpCheck.class); + checkConfig.addAttribute("format", illegal); + checkConfig.addAttribute("ignoreComments", "true"); + final String[] expected = { + }; + verify(checkConfig, getPath("InputTrailingComment.java"), expected); + } }