diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java new file mode 100644 index 000000000..43c3af208 --- /dev/null +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java @@ -0,0 +1,144 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2014 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 java.util.regex.Pattern; + +import com.google.common.base.CharMatcher; +import com.puppycrawl.tools.checkstyle.api.DetailNode; +import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; +import com.puppycrawl.tools.checkstyle.api.Utils; + +/** + *
+ * Checks that + * Javadoc summary sentence does not contain phrases that are not recommended to use. + * By default Check validate that first sentence is not empty:
+ * <module name="SummaryJavadocCheck"/> + *+ *
+ * To ensure that summary do not contain phrase like "This method returns" , use following config: + *
+ *
+ * <module name="SummaryJavadocCheck"> + * <property name="forbiddenSummaryFragments" + * value="^This method returns.*"/> + * </module> + *+ * + * @author max + * + */ +public class SummaryJavadocCheck extends AbstractJavadocCheck +{ + + /** + * Some javadoc. + */ + private Pattern mForbiddenSummaryFragments = Utils.createPattern("^$"); + + /** + * Some javadoc. + * @param aPattern Some javadoc. + */ + public void setForbiddenSummaryFragments(String aPattern) + { + mForbiddenSummaryFragments = Utils.createPattern(aPattern); + } + + @Override + public int[] getDefaultJavadocTokens() + { + return new int[] { + JavadocTokenTypes.JAVADOC, + }; + } + + @Override + public void visitJavadocToken(DetailNode aAst) + { + String firstSentence = getFirstSentence(aAst); + final int endOfSentence = firstSentence.lastIndexOf("."); + if (endOfSentence == -1) { + log(aAst.getLineNumber(), "summary.first.sentence"); + } + else { + firstSentence = firstSentence.substring(0, endOfSentence); + if (containsForbiddenFragment(firstSentence)) { + log(aAst.getLineNumber(), "summary.javaDoc"); + } + } + } + + /** + * Some javadoc. + * @param aAst Some javadoc. + * @return Some javadoc. + */ + private String getFirstSentence(DetailNode aAst) + { + final StringBuilder result = new StringBuilder(); + for (DetailNode child : aAst.getChildren()) { + if (child.getType() != JavadocTokenTypes.JAVADOC_INLINE_TAG + && child.getText().contains(". ")) + { + result.append(getCharsTillDot(child)); + break; + } + else { + result.append(child.getText()); + } + } + return result.toString(); + } + + /** + * Some javadoc. + * @param aTextNode Some javadoc. + * @return Some javadoc. + */ + private String getCharsTillDot(DetailNode aTextNode) + { + final StringBuilder result = new StringBuilder(); + for (DetailNode child : aTextNode.getChildren()) { + result.append(child.getText()); + if (".".equals(child.getText()) + && JavadocUtils.getNextSibling(child).getType() == JavadocTokenTypes.WS) + { + break; + } + } + return result.toString(); + } + + /** + * Some javadoc. + * @param aFirstSentence Some javadoc. + * @return Some javadoc. + */ + private boolean containsForbiddenFragment(String aFirstSentence) + { + // This regexp is used to convert multiline javadoc to single line without stars. + String javadocText = aFirstSentence.replaceAll("\n[ ]+(\\*)|^[ ]+(\\*)", " "); + javadocText = CharMatcher.WHITESPACE.trimAndCollapseFrom(javadocText, ' '); + return mForbiddenSummaryFragments.matcher(javadocText).find(); + } +} diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties index acf51d0d1..731aad668 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/messages.properties @@ -32,3 +32,6 @@ non.empty.atclause=At-clause should have a non-empty description. tag.continuation.indent=Line continuation have incorrect indentation level, expected level should be {0}. +summary.javaDoc=Forbidden summary fragment. +summary.first.sentence=First sentence should be present. + diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheckTest.java new file mode 100644 index 000000000..ee05091cb --- /dev/null +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheckTest.java @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2014 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 com.puppycrawl.tools.checkstyle.BaseCheckTestSupport; +import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import org.junit.Before; +import org.junit.Test; + +public class SummaryJavadocCheckTest extends BaseCheckTestSupport +{ + private DefaultConfiguration mCheckConfig; + + @Before + public void setUp() + { + mCheckConfig = createCheckConfig(SummaryJavadocCheck.class); + } + + @Test + public void testCorrect() throws Exception + { + mCheckConfig.addAttribute("forbiddenSummaryFragments", + "^@return the *|^This method returns *|^A [{]@code [a-zA-Z0-9]+[}]( is a )"); + final String[] expected = { + }; + + verify(mCheckConfig, getPath("javadoc/InputCorrectSummaryJavaDocCheck.java"), expected); + } + + @Test + public void testIncorrect() throws Exception + { + mCheckConfig.addAttribute("forbiddenSummaryFragments", + "^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"); + final String[] expected = { + "14: First sentence should be present.", + "37: First sentence should be present.", + "47: Forbidden summary fragment.", + "58: Forbidden summary fragment.", + "69: First sentence should be present.", + "83: Forbidden summary fragment.", + "103: First sentence should be present.", + }; + verify(mCheckConfig, getPath("javadoc/InputIncorrectSummaryJavaDocCheck.java"), expected); + } +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputCorrectSummaryJavaDocCheck.java b/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputCorrectSummaryJavaDocCheck.java new file mode 100644 index 000000000..967f9aada --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputCorrectSummaryJavaDocCheck.java @@ -0,0 +1,135 @@ +package com.puppycrawl.tools.checkstyle.javadoc; + +/** + * Some Javadoc A {@code Foo} is a simple Javadoc. + */ +class InputCorrectJavaDocParagraphCheck { + + /** + * Some Javadoc This method returns. + */ + public static final byte NUL = 0; + + /** + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)}. + */ + void foo3() {} + + /** + * @throws Exception if an error occurs. + */ + void foo4() throws Exception {} + + /** An especially This method returns short bit of Javadoc. */ + void foo5() {} + + /** + * An especially short + * bit of Javadoc. This method returns. + */ + void foo6() {} + + /** + * + */ + class InnerInputCorrectJavaDocParagraphCheck { + + /** + * foooo@foooo. + */ + public static final byte NUL = 0; + + /** + * Some java@doc. + * This method returns. + */ + public static final byte NUL_2 = 0; + + /** + * Returns the customer ID. This method returns + */ + int getId() {return 666;} + + /** + * . + */ + void foo2() {} + + /** + * As of JDK 1.1, + * replaced by {@link #setBounds(int,int,int,int)}. This method returns. + */ + void foo3() {} + + /** + * @throws Exception if an error occurs. + */ + void foo4() throws Exception {} + + /** + * JAXB Provider Use Only: Provides partial default + * implementations for some of the javax.xml.bind interfaces. + */ + void foo5() {} + + /** + * An especially short (int... A) bit of Javadoc. This + * method returns + */ + void foo6() {} + } + + /** + * Some + * javadoc. A {@code Foo} is a simple Javadoc. + * + * Some Javadoc. A {@code Foo} + * is a simple Javadoc. + */ + InnerInputCorrectJavaDocParagraphCheck anon = new InnerInputCorrectJavaDocParagraphCheck() { + + /** + * JAXB 1.0 only default validation event handler. + */ + public static final byte NUL = 0; + + /** + * Returns the current state. + * This method returns. + */ + boolean emulated(String s) {return false;} + + /** + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)}. + */ + void foo3() {} + + /** + * @throws Exception if an error occurs. + */ + void foo4() throws Exception {} + + /** An especially short bit of Javadoc. */ + void foo5() {} + + /** + * An especially short bit of Javadoc. + */ + void foo6() {} + + /** + * Some Javadoc. This method returns some javadoc. + */ + boolean emulated() {return false;} + + /** + * Some Javadoc. This method returns some javadoc. Some Javadoc. + */ + boolean emulated1() {return false;} + + /** + * @return Some Javadoc the customer ID. + */ + int geId() {return 666;} + }; +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputIncorrectSummaryJavaDocCheck.java b/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputIncorrectSummaryJavaDocCheck.java new file mode 100644 index 000000000..8b9a435af --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/javadoc/InputIncorrectSummaryJavaDocCheck.java @@ -0,0 +1,116 @@ +package com.puppycrawl.tools.checkstyle.javadoc; + +/** + * A {@code Foo. Foo} + * is a simple Javadoc. Some javadoc. + */ +class InputCorrectJavaDocParagraphCheck { + + /** + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)} + */ + void foo3() {} + + /** + * @throws Exception if an error occurs + */ + void foo4() throws Exception {} + + /** An especially short bit of Javadoc. */ + void foo5() {} + + /** + * An especially short bit of Javadoc. + */ + void foo6() {} + + /** + * Some Javadoc. + */ + public static final byte NUL = 0; + + /** + * + */ + class InnerInputCorrectJavaDocParagraphCheck { + + /** + * foooo@foooo + */ + public static final byte NUL = 0; + + /** + * Some java@doc. + */ + public static final byte NUL_2 = 0; + + /** + * This method + * returns some javadoc. Some javadoc. + */ + boolean emulated() {return false;} + + /** + * + */ + void foo2() {} + + /** + * @return the + * customer ID some javadoc. + */ + int geId() {return 666;} + + /** + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)} + */ + void foo3() {} + + /** + * @throws Exception if an error occurs + */ + void foo4() throws Exception {} + + /** An especially short bit of Javadoc. */ + void foo5() {} + + /** + * An especially short bit of Javadoc. + */ + void foo6() {} + } + + /** + * A {@code InnerInputCorrectJavaDocParagraphCheck} is a simple code. + */ + InnerInputCorrectJavaDocParagraphCheck anon = new InnerInputCorrectJavaDocParagraphCheck() { + + /** + * Some Javadoc. + */ + public static final byte NUL = 0; + + /** + * Some Javadoc. + */ + void emulated(String s) {} + + /** + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)} + */ + void foo3() {} + + /** + * @throws Exception if an error occurs + */ + void foo4() throws Exception {} + + /** An especially short bit of Javadoc. */ + void foo5() {} + + /** + * An especially short bit of Javadoc. + */ + void foo6() {} + }; +} diff --git a/src/xdocs/availablechecks.xml b/src/xdocs/availablechecks.xml index cdae47c5f..895d3cc5c 100644 --- a/src/xdocs/availablechecks.xml +++ b/src/xdocs/availablechecks.xml @@ -658,6 +658,11 @@
== or !=.@@ -917,5 +916,65 @@ public boolean isSomething()
+ Checks that + Javadoc summary sentence does not contain phrases that are not recommended to use. +
+| name | +description | +type | +default value | +
|---|---|---|---|
| forbiddenSummaryFragments | +forbidden summary fragments | +regular expression | +^$ |
+
+ Default configuration +
++ To ensure that summary do not contain phrase like "This method returns" , use following config: +
++ com.puppycrawl.tools.checkstyle.checks +
++ TreeWalker +
+