diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java
index 2489c5a2b..67408a837 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java
@@ -50,7 +50,7 @@ class Verifier
private static final String MATCH_JAVADOC_ARG_PAT
= "@(throws|exception|param)\\s+(\\S+)\\s+\\S";
/** compiled regexp to match Javadoc tags that take an argument **/
- private static final RE MATCH_JAVADOC_ARG = createRE(MATCH_JAVADOC_ARG_PAT);
+ private static final RE MATCH_JAVADOC_ARG = Utils.createRE(MATCH_JAVADOC_ARG_PAT);
/**
* the pattern to match a single line comment containing only the comment
@@ -60,7 +60,7 @@ class Verifier
= "^\\s*//.*$";
/** compiled regexp to match a single-line comment line **/
private static final RE MATCH_SINGLELINE_COMMENT =
- createRE(MATCH_SINGLELINE_COMMENT_PAT);
+ Utils.createRE(MATCH_SINGLELINE_COMMENT_PAT);
/**
* the pattern to match the first line of a multi-line Javadoc
@@ -71,14 +71,14 @@ class Verifier
= "@(throws|exception|param)\\s+(\\S+)\\s*$";
/** compiled regexp to match first part of multilineJavadoc tags **/
private static final RE MATCH_JAVADOC_MULTILINE_START =
- createRE(MATCH_JAVADOC_MULTILINE_START_PAT);
+ Utils.createRE(MATCH_JAVADOC_MULTILINE_START_PAT);
/** the pattern that looks for a continuation of the comment **/
private static final String MATCH_JAVADOC_MULTILINE_CONT_PAT
= "(\\*/|@|[^\\s\\*])";
/** compiled regexp to look for a continuation of the comment **/
private static final RE MATCH_JAVADOC_MULTILINE_CONT =
- createRE(MATCH_JAVADOC_MULTILINE_CONT_PAT);
+ Utils.createRE(MATCH_JAVADOC_MULTILINE_CONT_PAT);
/** Multiline finished at end of comment **/
private static final String END_JAVADOC = "*/";
/** Multiline finished at next Javadoc **/
@@ -89,19 +89,19 @@ class Verifier
= "@(return|see|author)\\s+\\S";
/** compiled regexp to match Javadoc tags with no argument **/
private static final RE MATCH_JAVADOC_NOARG
- = createRE(MATCH_JAVADOC_NOARG_PAT);
+ = Utils.createRE(MATCH_JAVADOC_NOARG_PAT);
/** the pattern to match author tag **/
private static final String MATCH_JAVADOC_AUTHOR_PAT = "@author\\s+\\S";
/** compiled regexp to match author tag **/
private static final RE MATCH_JAVADOC_AUTHOR
- = createRE(MATCH_JAVADOC_AUTHOR_PAT);
+ = Utils.createRE(MATCH_JAVADOC_AUTHOR_PAT);
/** the pattern to match version tag **/
private static final String MATCH_JAVADOC_VERSION_PAT = "@version\\s+\\S";
/** compiled regexp to match version tag **/
private static final RE MATCH_JAVADOC_VERSION
- = createRE(MATCH_JAVADOC_VERSION_PAT);
+ = Utils.createRE(MATCH_JAVADOC_VERSION_PAT);
////////////////////////////////////////////////////////////////////////////
// Member variables
@@ -315,13 +315,6 @@ class Verifier
final Scope variableScope =
inInterfaceBlock() ? Scope.PUBLIC : declaredScope;
- if (inCheckScope(variableScope)
- && (getJavadocBefore(aVar.getStartLineNo() - 1) == null))
- {
- mMessages.add(aVar.getLineNo(), aVar.getColumnNo() - 1,
- "javadoc.missing");
- }
-
// Check correct format
if (inInterfaceBlock()) {
// The only declarations allowed in interfaces are all static final,
@@ -883,28 +876,6 @@ class Verifier
}
-
- /**
- * Helper method to create a regular expression. Will exit if unable to
- * create the object.
- * @param aPattern the pattern to match
- * @return a created regexp object
- **/
- private static RE createRE(String aPattern)
- {
- RE retVal = null;
- try {
- retVal = Utils.getRE(aPattern);
- }
- catch (RESyntaxException e) {
- System.out.println("Failed to initialise regexp expression "
- + aPattern);
- e.printStackTrace(System.out);
- System.exit(1);
- }
- return retVal;
- }
-
/**
* Checks that a variable confirms to a specified regular expression. Logs
* a message if it does not.
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java
index ad017b072..439385b63 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileContents.java
@@ -1,10 +1,22 @@
package com.puppycrawl.tools.checkstyle.api;
+import org.apache.regexp.RE;
+
import java.util.Map;
import java.util.HashMap;
public class FileContents
{
+ /**
+ * the pattern to match a single line comment containing only the comment
+ * itself -- no code.
+ */
+ private static final String MATCH_SINGLELINE_COMMENT_PAT
+ = "^\\s*//.*$";
+ /** compiled regexp to match a single-line comment line */
+ private static final RE MATCH_SINGLELINE_COMMENT =
+ Utils.createRE(MATCH_SINGLELINE_COMMENT_PAT);
+
/** the file name */
private final String mFilename;
@@ -84,6 +96,24 @@ public class FileContents
return retVal;
}
+ /**
+ * Returns the Javadoc comment before the specified line. null is none.
+ * @return the Javadoc comment, or null if none
+ * @param aLineNo the line number to check before
+ **/
+ public String[] getJavadocBefore(int aLineNo)
+ {
+ // Lines start at 1 to the callers perspective, so nee to take off 2
+ int lineNo = aLineNo - 2;
+
+ // skip blank lines
+ while ((lineNo > 0) && (lineIsBlank(lineNo) || lineIsComment(lineNo))) {
+ lineNo--;
+ }
+
+ return (String[]) mJavadocComments.get(new Integer(lineNo));
+ }
+
public String[] getLines()
{
return mLines;
@@ -93,4 +123,27 @@ public class FileContents
{
return mFilename;
}
+
+ /**
+ * Checks if the specified line is blank.
+ * @param aLineNo the line number to check
+ * @return if the specified line consists only of tabs and spaces.
+ **/
+ private boolean lineIsBlank(int aLineNo)
+ {
+ // possible improvement: avoid garbage creation in trim()
+ return "".equals(mLines[aLineNo].trim());
+ }
+
+ /**
+ * Checks if the specified line is a single-line comment without code.
+ * @param aLineNo the line number to check
+ * @return if the specified line consists of only a single line comment
+ * without code.
+ **/
+ private boolean lineIsComment(int aLineNo)
+ {
+ return MATCH_SINGLELINE_COMMENT.match(mLines[aLineNo]);
+ }
+
}
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Utils.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Utils.java
index a14a80110..386720c65 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Utils.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Utils.java
@@ -30,6 +30,7 @@ import java.io.FileReader;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
+import org.apache.commons.beanutils.ConversionException;
import antlr.collections.AST;
/**
@@ -237,4 +238,26 @@ public final class Utils
}
return count;
}
+
+ /**
+ * Helper method to create a regular expression.
+ * @param aPattern the pattern to match
+ * @return a created regexp object
+ * @throws ConversionException if unable to create RE object.
+ **/
+ public static RE createRE(String aPattern)
+ {
+ RE retVal = null;
+ try {
+ retVal = getRE(aPattern);
+ }
+ catch (RESyntaxException e) {
+ System.out.println("Failed to initialise regexp expression "
+ + aPattern);
+ e.printStackTrace(System.out);
+ throw new ConversionException(
+ "Failed to initialise regexp expression " + aPattern, e);
+ }
+ return retVal;
+ }
}
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocVariableCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocVariableCheck.java
new file mode 100644
index 000000000..15e390513
--- /dev/null
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocVariableCheck.java
@@ -0,0 +1,169 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2002 Oliver Burn
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+////////////////////////////////////////////////////////////////////////////////
+package com.puppycrawl.tools.checkstyle.checks;
+
+import com.puppycrawl.tools.checkstyle.api.Check;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.Utils;
+import com.puppycrawl.tools.checkstyle.api.FileContents;
+import com.puppycrawl.tools.checkstyle.Scope;
+import antlr.collections.AST;
+
+/**
+ * Checks that a variable has Javadoc comment
+ *
+ * @author Oliver Burn
+ * @version 1.0
+ */
+public class JavadocVariableCheck
+ extends Check
+{
+ private Scope mScope = Scope.PRIVATE;
+
+ public void setScope(String aFrom)
+ {
+ mScope = Scope.getInstance(aFrom);
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check */
+ public int[] getDefaultTokens()
+ {
+ return new int[] {TokenTypes.VARIABLE_DEF};
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check */
+ public void visitToken(DetailAST aAST)
+ {
+ if (!inCodeBlock(aAST)) {
+ final DetailAST mods =
+ Utils.findFirstToken(aAST.getFirstChild(),
+ TokenTypes.MODIFIERS);
+ final Scope declaredScope = getScopeFromMods(mods);
+ final Scope variableScope =
+ inInterfaceBlock(aAST) ? Scope.PUBLIC : declaredScope;
+ if (variableScope.isIn(mScope)) {
+ final Scope surroundingScope = getSurroundingScope(aAST);
+ if (surroundingScope.isIn(mScope)) {
+ final FileContents contents = getFileContents();
+ final String[] cmt =
+ contents.getJavadocBefore(aAST.getLineNo());
+ if (cmt == null) {
+ log(aAST.getLineNo(), aAST.getColumnNo(),
+ "javadoc.missing");
+ }
+ }
+ }
+ }
+ }
+
+ private boolean inCodeBlock(DetailAST aAST)
+ {
+ boolean retVal = false;
+
+ // Loop up looking for a containing code block
+ for (DetailAST token = aAST.getParent();
+ token != null;
+ token = token.getParent())
+ {
+ final int type = token.getType();
+ if ((type == TokenTypes.METHOD_DEF)
+ || (type == TokenTypes.CTOR_DEF)
+ || (type == TokenTypes.INSTANCE_INIT)
+ || (type == TokenTypes.STATIC_INIT))
+ {
+ retVal = true;
+ break;
+ }
+ }
+
+ return retVal;
+ }
+
+ private boolean inInterfaceBlock(DetailAST aAST)
+ {
+ boolean retVal = false;
+
+ // Loop up looking for a containing interface block
+ for (DetailAST token = aAST.getParent();
+ token != null;
+ token = token.getParent())
+ {
+ final int type = token.getType();
+ if (type == TokenTypes.CLASS_DEF) {
+ break; // in a class
+ }
+ else if (type == TokenTypes.INTERFACE_DEF) {
+ retVal = true;
+ break;
+ }
+ }
+
+ return retVal;
+ }
+
+ private static Scope getSurroundingScope(DetailAST aAST)
+ {
+ Scope retVal = null;
+ for (DetailAST token = aAST.getParent();
+ token != null;
+ token = token.getParent())
+ {
+ final int type = token.getType();
+ if ((type == TokenTypes.CLASS_DEF)
+ || (type == TokenTypes.INTERFACE_DEF))
+ {
+ final DetailAST mods =
+ Utils.findFirstToken(token.getFirstChild(),
+ TokenTypes.MODIFIERS);
+ final Scope modScope = getScopeFromMods(mods);
+ if ((retVal == null) || (retVal.isIn(modScope))) {
+ retVal = modScope;
+ }
+ }
+ }
+
+ return retVal;
+ }
+
+
+ private static Scope getScopeFromMods(DetailAST aMods)
+ {
+ Scope retVal = Scope.PACKAGE; // default scope
+ for (AST token = aMods.getFirstChild();
+ token != null;
+ token = token.getNextSibling())
+ {
+ if ("public".equals(token.getText())) {
+ retVal = Scope.PUBLIC;
+ break;
+ }
+ else if ("protected".equals(token.getText())) {
+ retVal = Scope.PROTECTED;
+ break;
+ }
+ else if ("private".equals(token.getText())) {
+ retVal = Scope.PRIVATE;
+ break;
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java b/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java
index cffc3441e..83d5e556a 100644
--- a/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java
+++ b/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java
@@ -225,7 +225,6 @@ public class CheckerTest
assertNotNull(c);
final String[] expected = {
filepath + ":8: Missing a Javadoc comment.",
- filepath + ":11:17: Missing a Javadoc comment.",
filepath + ":14:5: Missing a Javadoc comment.",
filepath + ":18: Unused @param tag for 'unused'.",
filepath + ":24: Expected an @return tag.",
@@ -262,7 +261,6 @@ public class CheckerTest
assertNotNull(c);
final String[] expected = {
filepath + ":8: Missing a Javadoc comment.",
- filepath + ":11:17: Missing a Javadoc comment.",
filepath + ":14:5: Missing a Javadoc comment.",
filepath + ":18: Unused @param tag for 'unused'.",
filepath + ":24: Expected an @return tag.",
@@ -297,12 +295,9 @@ public class CheckerTest
assertNotNull(c);
final String[] expected = {
filepath + ":14: Missing a Javadoc comment.",
- filepath + ":17:20: Missing a Javadoc comment.",
filepath + ":21: Missing a Javadoc comment.",
- filepath + ":24:16: Missing a Javadoc comment.",
filepath + ":24:16: Name 'data' must match pattern '^[A-Z](_?[A-Z0-9]+)*$'.",
filepath + ":27: Missing a Javadoc comment.",
- filepath + ":30:24: Missing a Javadoc comment.",
};
verify(c, filepath, expected);
}
@@ -317,12 +312,9 @@ public class CheckerTest
assertNotNull(c);
final String[] expected = {
filepath + ":14: Missing a Javadoc comment.",
- filepath + ":17:20: Missing a Javadoc comment.",
filepath + ":21: Missing a Javadoc comment.",
- filepath + ":24:16: Missing a Javadoc comment.",
filepath + ":24:16: Name 'data' must match pattern '^[A-Z](_?[A-Z0-9]+)*$'.",
filepath + ":27: Missing a Javadoc comment.",
- filepath + ":30:24: Missing a Javadoc comment.",
};
verify(c, filepath, expected);
}
@@ -369,19 +361,12 @@ public class CheckerTest
final String[] expected = {
filepath + ":7: Missing a Javadoc comment.",
filepath + ":9: Missing a Javadoc comment.",
- filepath + ":11:16: Missing a Javadoc comment.",
filepath + ":12:9: Missing a Javadoc comment.",
filepath + ":14: Missing a Javadoc comment.",
- filepath + ":16:25: Missing a Javadoc comment.",
filepath + ":18:13: Missing a Javadoc comment.",
filepath + ":25:13: Missing a Javadoc comment.",
filepath + ":34: Missing a Javadoc comment.",
- filepath + ":36:21: Missing a Javadoc comment.",
filepath + ":38:9: Missing a Javadoc comment.",
- filepath + ":43:17: Missing a Javadoc comment.",
- filepath + ":44:9: Missing a Javadoc comment.",
- filepath + ":45:19: Missing a Javadoc comment.",
- filepath + ":46:16: Missing a Javadoc comment.",
filepath + ":49:5: Missing a Javadoc comment.",
filepath + ":54:5: Missing a Javadoc comment.",
filepath + ":59:5: Missing a Javadoc comment.",
@@ -421,8 +406,6 @@ public class CheckerTest
assertNotNull(c);
final String[] expected = {
filepath + ":7: Missing a Javadoc comment.",
- filepath + ":45:19: Missing a Javadoc comment.",
- filepath + ":46:16: Missing a Javadoc comment.",
filepath + ":59:5: Missing a Javadoc comment.",
filepath + ":64:5: Missing a Javadoc comment.",
filepath + ":79:5: Missing a Javadoc comment.",
@@ -442,8 +425,6 @@ public class CheckerTest
final String[] expected = {
filepath + ":7: Missing a Javadoc comment.",
filepath + ":38: Missing a Javadoc comment.",
- filepath + ":40:23: Missing a Javadoc comment.",
- filepath + ":41:16: Missing a Javadoc comment.",
filepath + ":43:9: Missing a Javadoc comment.",
filepath + ":44:9: Missing a Javadoc comment."
};
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/JavadocVariableCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/JavadocVariableCheckTest.java
new file mode 100644
index 000000000..8b0f990f4
--- /dev/null
+++ b/src/tests/com/puppycrawl/tools/checkstyle/JavadocVariableCheckTest.java
@@ -0,0 +1,86 @@
+package com.puppycrawl.tools.checkstyle;
+
+import com.puppycrawl.tools.checkstyle.checks.JavadocVariableCheck;
+
+
+public class JavadocVariableCheckTest
+ extends BaseCheckTestCase
+{
+ public JavadocVariableCheckTest(String aName)
+ {
+ super(aName);
+ }
+
+ public void testDefault()
+ throws Exception
+ {
+ final CheckConfiguration checkConfig = new CheckConfiguration();
+ checkConfig.setClassname(JavadocVariableCheck.class.getName());
+ final Checker c = createChecker(checkConfig);
+ final String fname = getPath("InputTags.java");
+ final String[] expected = {
+ "11:5: Missing a Javadoc comment.",
+ };
+ verify(c, fname, expected);
+ }
+
+ public void testAnother()
+ throws Exception
+ {
+ final CheckConfiguration checkConfig = new CheckConfiguration();
+ checkConfig.setClassname(JavadocVariableCheck.class.getName());
+ final Checker c = createChecker(checkConfig);
+ final String fname = getPath("InputInner.java");
+ final String[] expected = {
+ "17:9: Missing a Javadoc comment.",
+ "24:9: Missing a Javadoc comment.",
+ "30:13: Missing a Javadoc comment.",
+ };
+ verify(c, fname, expected);
+ }
+
+ public void testAnother2()
+ throws Exception
+ {
+ final CheckConfiguration checkConfig = new CheckConfiguration();
+ checkConfig.setClassname(JavadocVariableCheck.class.getName());
+ checkConfig.addProperty("scope", Scope.PUBLIC.getName());
+ final Checker c = createChecker(checkConfig);
+ final String fname = getPath("InputInner.java");
+ final String[] expected = {
+ };
+ verify(c, fname, expected);
+ }
+
+ public void testAnother3()
+ throws Exception
+ {
+ final CheckConfiguration checkConfig = new CheckConfiguration();
+ checkConfig.setClassname(JavadocVariableCheck.class.getName());
+ final Checker c = createChecker(checkConfig);
+ final String fname = getPath("InputPublicOnly.java");
+ final String[] expected = {
+ "11:9: Missing a Javadoc comment.",
+ "16:13: Missing a Javadoc comment.",
+ "36:9: Missing a Javadoc comment.",
+ "43:5: Missing a Javadoc comment.",
+ "44:5: Missing a Javadoc comment.",
+ "45:5: Missing a Javadoc comment.",
+ "46:5: Missing a Javadoc comment.",
+ };
+ verify(c, fname, expected);
+ }
+ public void testAnother4()
+ throws Exception
+ {
+ final CheckConfiguration checkConfig = new CheckConfiguration();
+ checkConfig.setClassname(JavadocVariableCheck.class.getName());
+ checkConfig.addProperty("scope", Scope.PUBLIC.getName());
+ final Checker c = createChecker(checkConfig);
+ final String fname = getPath("InputPublicOnly.java");
+ final String[] expected = {
+ "46:5: Missing a Javadoc comment.",
+ };
+ verify(c, fname, expected);
+ }
+}