diff --git a/build.xml b/build.xml
index 5f323179d..4be728cad 100644
--- a/build.xml
+++ b/build.xml
@@ -334,6 +334,7 @@
+
+
+
+
+
+
+
+
+ CheckStyle Audit
+
+
+ Designed for use with CheckStyle and Ant.
+
+
+
+
+
+
+
+
+
+
+
+
+ Summary
+
+
+
+
+ Files
+ Errors
+ Warnings
+
+
+
+
+
+
+
+
+ Authors
+
+
+
+
+
+
+
+ Name
+ Errors
+ Warnings
+
+
+
+
+
+
+
+ File
+
+ Author
+
+ Back to top
+
+
+ Error Description
+ Line
+
+
+
+
+
+
+
+ * Outputs a JavaDoc tag as information. Can be used e.g. with the stylesheets + * that sort the report by author name. + * To define the format for a tag, set property tagFormat to a + * regular expression. + * This check uses two different severity levels. The normal one is used for + * reporting when the tag is missing. The additional one (tagSeverity) is used + * for the level of reporting when the tag exists. The default value for + * tagSeverity is info. + *
+ *An example of how to configure the check for printing author name is: + *
+ *+ * <module name="WriteTag"> + * <property name="tag" value="@author"/> + * <property name="tagFormat" value="\S"/> + * </module> + *+ *
An example of how to configure the check to print warnings if an + * "@incomplete" tag is found, and not print anything if it is not found: + *
+ *+ * <module name="WriteTag"> + * <property name="tag" value="@incomplete"/> + * <property name="tagFormat" value="\S"/> + * <property name="severity" value="ignore"/> + * <property name="tagSeverity" value="warning"/> + * </module> + *+ * + * @author Daniel Grenner + * @version 1.0 + */ +public class WriteTagCheck + extends Check +{ + /** compiled regexp to match tag **/ + private Pattern mTagRE; + /** compiled regexp to match tag content **/ + private Pattern mTagFormatRE; + + /** regexp to match tag */ + private String mTag; + /** regexp to match tag content */ + private String mTagFormat; + /** the severity level of found tag reports */ + private SeverityLevel mTagSeverityLevel = SeverityLevel.INFO; + + /** + * Sets the tag to check. + * @param aTag tag to check + * @throws ConversionException If the tag is not a valid regular exception. + */ + public void setTag(String aTag) + throws ConversionException + { + try { + mTag = aTag; + mTagRE = Utils.getPattern(aTag + "\\s+(.*$)"); + } + catch (PatternSyntaxException e) { + throw new ConversionException("unable to parse " + aTag, e); + } + } + + /** + * Set the tag format. + * @param aFormat a
String value
+ * @throws ConversionException unable to parse aFormat
+ */
+ public void setTagFormat(String aFormat)
+ throws ConversionException
+ {
+ try {
+ mTagFormat = aFormat;
+ mTagFormatRE = Utils.getPattern(aFormat);
+ }
+ catch (PatternSyntaxException e) {
+ throw new ConversionException("unable to parse " + aFormat, e);
+ }
+ }
+
+ /**
+ * Sets the tag severity level. The string should be one of the names
+ * defined in the SeverityLevel class.
+ *
+ * @param aSeverity The new severity level
+ * @see SeverityLevel
+ */
+ public final void setTagSeverity(String aSeverity)
+ {
+ mTagSeverityLevel = SeverityLevel.getInstance(aSeverity);
+ }
+
+ /** {@inheritDoc} */
+ public int[] getDefaultTokens()
+ {
+ return new int[] {TokenTypes.INTERFACE_DEF, TokenTypes.CLASS_DEF, };
+ }
+
+ /** {@inheritDoc} */
+ public int[] getAcceptableTokens()
+ {
+ return new int[] {TokenTypes.INTERFACE_DEF,
+ TokenTypes.CLASS_DEF,
+ TokenTypes.METHOD_DEF,
+ };
+ }
+
+ /** {@inheritDoc} */
+ public void visitToken(DetailAST aAST)
+ {
+ final DetailAST mods = aAST.findFirstToken(TokenTypes.MODIFIERS);
+ final Scope declaredScope = ScopeUtils.getScopeFromMods(mods);
+ final Scope typeScope =
+ ScopeUtils.inInterfaceBlock(aAST) ? Scope.PUBLIC : declaredScope;
+ final FileContents contents = getFileContents();
+ final int lineNo = aAST.getLineNo();
+ final TextBlock cmt =
+ contents.getJavadocBefore(lineNo);
+ if (cmt == null) {
+ log(lineNo, "type.missingTag", mTag);
+ }
+ else {
+ checkTag(lineNo, cmt.getText(), mTag, mTagRE, mTagFormatRE,
+ mTagFormat);
+ }
+ }
+
+ /**
+ * Verifies that a type definition has a required tag.
+ * @param aLineNo the line number for the type definition.
+ * @param aCmt the Javadoc comment for the type definition.
+ * @param aTag the required tag name.
+ * @param aTagRE regexp for the full tag.
+ * @param aFormatRE regexp for the tag value.
+ * @param aFormat pattern for the tag value.
+ */
+ private void checkTag(
+ int aLineNo,
+ String[] aCmt,
+ String aTag,
+ Pattern aTagRE,
+ Pattern aFormatRE,
+ String aFormat)
+ {
+ if (aTagRE == null) {
+ return;
+ }
+
+ int tagCount = 0;
+ for (int i = 0; i < aCmt.length; i++) {
+ final String s = aCmt[i];
+ final Matcher matcher = aTagRE.matcher(s);
+ if (matcher.find()) {
+ tagCount += 1;
+ final int contentStart = matcher.start(1);
+ final String content = s.substring(contentStart);
+ if (aFormatRE != null && !aFormatRE.matcher(content).find()) {
+ log(aLineNo + i - aCmt.length, "type.tagFormat", aTag,
+ aFormat);
+ }
+ else {
+ logTag(aLineNo + i - aCmt.length, aTag, content);
+ }
+
+ }
+ }
+ if (tagCount == 0) {
+ Object[] args = {aTag};
+ log(aLineNo, "type.missingTag", aTag);
+ }
+
+ }
+
+
+ /**
+ * Log a message.
+ *
+ * @param aLine the line number where the error was found
+ * @param aTag the javdoc tag to be logged
+ * @param aTagValue the contents of the tag
+ *
+ * @see java.text.MessageFormat
+ */
+ protected final void logTag(int aLine, String aTag, String aTagValue)
+ {
+ String originalSeverity = getSeverity();
+ setSeverity(mTagSeverityLevel.getName());
+
+ log(aLine, "javadoc.writeTag", aTag, aTagValue);
+
+ setSeverity(originalSeverity);
+ }
+}
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties
index 2b4b76db1..5a10e7e2c 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties
@@ -11,6 +11,7 @@ javadoc.unclosedhtml=Unclosed HTML tag found: {0}
javadoc.unusedTag=Unused {0} tag for ''{1}''.
javadoc.unusedTagGeneral=Unused Javadoc tag.
javadoc.empty=Javadoc has empty description section.
+javadoc.writeTag={0}={1}
type.missingTag=Type Javadoc comment is missing an {0} tag.
type.tagFormat=Type Javadoc tag {0} must match pattern ''{1}''.
diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/InputWriteTag.java b/src/testinputs/com/puppycrawl/tools/checkstyle/InputWriteTag.java
new file mode 100644
index 000000000..01be2277c
--- /dev/null
+++ b/src/testinputs/com/puppycrawl/tools/checkstyle/InputWriteTag.java
@@ -0,0 +1,27 @@
+////////////////////////////////////////////////////////////////////////////////
+// Test case file for checkstyle.
+// Created: 2004
+////////////////////////////////////////////////////////////////////////////////
+
+package com.puppycrawl.tools.checkstyle;
+
+/**
+ * Testing tag writing
+ * @author Daniel Grenner
+ * @incomplete This class needs more code...
+ * @doubletag first text
+ * @doubletag second text
+ */
+class InputWriteTag
+{
+ public void method()
+ {
+ }
+
+ /**
+ * @todo Add a comment
+ */
+ public void anotherMethod()
+ {
+ }
+}
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/BaseCheckTestCase.java b/src/tests/com/puppycrawl/tools/checkstyle/BaseCheckTestCase.java
index 2dc664799..eb79e0862 100644
--- a/src/tests/com/puppycrawl/tools/checkstyle/BaseCheckTestCase.java
+++ b/src/tests/com/puppycrawl/tools/checkstyle/BaseCheckTestCase.java
@@ -32,7 +32,7 @@ public abstract class BaseCheckTestCase
public void fileStarted(AuditEvent evt) {}
}
- private final ByteArrayOutputStream mBAOS = new ByteArrayOutputStream();
+ protected final ByteArrayOutputStream mBAOS = new ByteArrayOutputStream();
protected final PrintStream mStream = new PrintStream(mBAOS);
protected final Properties mProps = new Properties();
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/AllTests.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/AllTests.java
index 40a67f9d8..9a40e9d70 100644
--- a/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/AllTests.java
+++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/AllTests.java
@@ -18,6 +18,7 @@ public class AllTests {
suite.addTest(new TestSuite(JavadocTypeCheckTest.class));
suite.addTest(new TestSuite(JavadocVariableCheckTest.class));
suite.addTest(new TestSuite(PackageHtmlCheckTest.class));
+ suite.addTest(new TestSuite(WriteTagCheckTest.class));
return suite;
}
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheckTest.java
new file mode 100644
index 000000000..3663351c8
--- /dev/null
+++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheckTest.java
@@ -0,0 +1,173 @@
+package com.puppycrawl.tools.checkstyle.checks.javadoc;
+
+import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
+import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
+import com.puppycrawl.tools.checkstyle.api.Scope;
+import com.puppycrawl.tools.checkstyle.Checker;
+import java.io.File;
+import java.io.ByteArrayInputStream;
+import java.io.LineNumberReader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+/**
+ * @author Daniel Grenner
+ */
+public class WriteTagCheckTest extends BaseCheckTestCase
+{
+ private DefaultConfiguration mCheckConfig;
+
+ public void setUp() {
+ mCheckConfig = createCheckConfig(WriteTagCheck.class);
+ }
+
+ public void testDefaultSettings() throws Exception
+ {
+ final String[] expected =
+ {
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testTag() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@author");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ final String[] expected =
+ {
+ "10: @author=Daniel Grenner",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testMissingFormat() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@author");
+ final String[] expected =
+ {
+ "10: @author=Daniel Grenner",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testTagSeverity() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@incomplete");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ mCheckConfig.addAttribute("tagSeverity", "warning");
+ final String[] expected =
+ {
+ "11: warning: @incomplete=This class needs more code...",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testDoubleTag() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@doubletag");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ final String[] expected =
+ {
+ "12: @doubletag=first text",
+ "13: @doubletag=second text",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+
+ public void testMissingTag() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@missingtag");
+ final String[] expected =
+ {
+ "15: Type Javadoc comment is missing an @missingtag tag.",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testMethod() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@todo");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ mCheckConfig.addAttribute("tokens",
+ "INTERFACE_DEF, CLASS_DEF, METHOD_DEF");
+ mCheckConfig.addAttribute("severity", "ignore");
+ final String[] expected =
+ {
+ "22: @todo=Add a comment",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testSeverity() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@author");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ mCheckConfig.addAttribute("severity", "ignore");
+ final String[] expected =
+ {
+ "10: @author=Daniel Grenner",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testIgnoreMissing() throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@todo2");
+ mCheckConfig.addAttribute("tagFormat", "\\S");
+ mCheckConfig.addAttribute("severity", "ignore");
+ final String[] expected =
+ {
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testRegularEx()
+ throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@author");
+ mCheckConfig.addAttribute("tagFormat", "0*");
+ final String[] expected = {
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ public void testRegularExError()
+ throws Exception
+ {
+ mCheckConfig.addAttribute("tag", "@author");
+ mCheckConfig.addAttribute("tagFormat", "ABC");
+ final String[] expected = {
+ "10: Type Javadoc tag @author must match pattern 'ABC'.",
+ };
+ verify(mCheckConfig, getPath("InputWriteTag.java"), expected);
+ }
+
+ protected void verify(Checker aC,
+ File[] aProcessedFiles,
+ String aMessageFileName,
+ String[] aExpected)
+ throws Exception
+ {
+ mStream.flush();
+ final int errs = aC.process(aProcessedFiles);
+
+ // process each of the lines
+ final ByteArrayInputStream bais =
+ new ByteArrayInputStream(mBAOS.toByteArray());
+ final LineNumberReader lnr =
+ new LineNumberReader(new InputStreamReader(bais));
+
+ for (int i = 0; i < aExpected.length; i++) {
+ final String expected = aMessageFileName + ":" + aExpected[i];
+ final String actual = lnr.readLine();
+ assertEquals("error message " + i, expected, actual);
+ }
+
+ assertTrue("unexpected output: " + lnr.readLine(),
+ aExpected.length >= errs);
+
+ aC.destroy();
+ }
+}
diff --git a/src/xdocs/config_javadoc.xml b/src/xdocs/config_javadoc.xml
index 6a7aad342..919179fa5 100755
--- a/src/xdocs/config_javadoc.xml
+++ b/src/xdocs/config_javadoc.xml
@@ -682,5 +682,109 @@ public int checkReturnTag(final int aTagIndex,
+
+ + Outputs a JavaDoc tag as information. Can be used e.g. with the stylesheets + that sort the report by author name. + To define the format for a tag, set property tagFormat to a regular expression. + This check uses two different severity levels. The normal one is used for + reporting when the tag is missing. The additional one (tagSeverity) is used + for the level of reporting when the tag exists. +
+| name | +description | +type | +default value | +
|---|---|---|---|
| tag | +Name of tag | +String | +null | +
| tagFormat | +Format of tag | +regular expression | +null | +
| tagSeverity | +Severity level when tag is found and printed | +severity | +info | +
+ An example of how to configure the check for printing author name is: +
+ ++ An example of how to configure the check to print warnings if an + "@incomplete" tag is found, and not print anything if it is not found: +
+ ++ To configure the check for javadoc which is in private, but not in package scope: +
+ ++ To configure the check to turn off first sentence checking: +
+ ++ com.puppycrawl.tools.checkstyle.checks +
++ TreeWalker +
+