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

+ + + + + + + + + + + + + + + +
FilesErrorsWarnings
+ + + + + +
+
+ +

Authors

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameErrorsWarnings
+ + + +
+
+ + + + + + + +
+

File +
+ Author +

+ + + + + + + + + + + + + +
Error DescriptionLine
+ + + +
+
Back to top + + + + + + + + + + substring-after($path, '\') + + + + + + + + + + + ab + + + diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java new file mode 100644 index 000000000..59bec9a8d --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java @@ -0,0 +1,230 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2005 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.javadoc; + +import org.apache.commons.beanutils.ConversionException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileContents; +import com.puppycrawl.tools.checkstyle.api.Scope; +import com.puppycrawl.tools.checkstyle.api.ScopeUtils; +import com.puppycrawl.tools.checkstyle.api.SeverityLevel; +import com.puppycrawl.tools.checkstyle.api.TextBlock; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.api.Utils; + +/** + *

+ * 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. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
namedescriptiontypedefault value
tagName of tagStringnull
tagFormatFormat of tagregular expressionnull
tagSeveritySeverity level when tag is found and printedseverityinfo
+
+ + +

+ 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> + + +

+ To configure the check for javadoc which is in private, but not in package scope: +

+ + +<module name="JavadocStyle"> + <property name="scope" value="private"/> + <property name="excludeScope" value="package"/> +</module> + + +

+ To configure the check to turn off first sentence checking: +

+ + +<module name="JavadocStyle"> + <property name="checkFirstSentence" value="false"/> +</module> + +
+ + +

+ com.puppycrawl.tools.checkstyle.checks +

+
+ + +

+ TreeWalker +

+
+
diff --git a/src/xdocs/releasenotes.xml b/src/xdocs/releasenotes.xml index e5b366d3f..851fe8fca 100755 --- a/src/xdocs/releasenotes.xml +++ b/src/xdocs/releasenotes.xml @@ -26,6 +26,10 @@ TrailingComment now can be configured to accept some trailing comments (such as NOI18N) (property legalComment, rfe 1385344). +
  • + Added WriteTag check which outputs a JavaDoc tag as information (patch 902110) + Thanks to Daniel Grenner (dgrenner) for contribution. +
  • Fixed Bugs: