SummaryJavaDocCheck #307 by Max Vetrenko

This commit is contained in:
Roman Ivanov 2014-10-20 23:10:05 -07:00
parent cc9e00d9a0
commit d3b013d073
8 changed files with 530 additions and 7 deletions

View File

@ -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;
/**
* <p>
* Checks that <a href="
* http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html#firstsentence">
* Javadoc summary sentence</a> does not contain phrases that are not recommended to use.
* By default Check validate that first sentence is not empty:</p><br/>
* <pre>
* &lt;module name=&quot;SummaryJavadocCheck&quot;/&gt;
* </pre>
* <p>
* To ensure that summary do not contain phrase like "This method returns" , use following config:
* <p>
* <pre>
* &lt;module name=&quot;SummaryJavadocCheck&quot;&gt;
* &lt;property name=&quot;forbiddenSummaryFragments&quot;
* value=&quot;^This method returns.*&quot;/&gt;
* &lt;/module&gt;
* </pre>
*
* @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();
}
}

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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() {}
/**
* <a href="mailto:vlad@htmlbook.ru"/>
*/
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;}
/**
* <a href="mailto:vlad@htmlbook.ru"/>.
*/
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;}
};
}

View File

@ -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;
/**
* <a href="mailto:vlad@htmlbook.ru"/>
*/
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;}
/**
* <a href="mailto:vlad@htmlbook.ru"/>
*/
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() {}
};
}

View File

@ -658,6 +658,11 @@
<td>Checks that string literals are not used with
<code>==</code> or <code>&#33;=</code>.</td>
</tr>
<tr>
<td><a href="config_javadoc.html#SummaryJavadoc">SummaryJavadoc</a></td>
<td>
Checks that Javadoc summary sentence does not contain phrases that are not recommended to use.</td>
</tr>
<tr>
<td><a href="config_coding.html#SuperClone">SuperClone</a></td>
<td>

View File

@ -830,7 +830,6 @@ public boolean isSomething()
</subsection>
</section>
<<<<<<< HEAD
<section name="NonEmptyAtclauseDescription">
<subsection name="Description">
<p>
@ -917,5 +916,65 @@ public boolean isSomething()
</subsection>
</section>
<section name="SummaryJavadoc">
<subsection name="Description">
<p>
Checks that <a href="http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html#firstsentence">
Javadoc summary sentence</a> does not contain phrases that are not recommended to use.
</p>
</subsection>
<subsection name="Properties">
<table>
<tr>
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>forbiddenSummaryFragments</td>
<td>forbidden summary fragments</td>
<td><a href="property_types.html#regexp">regular expression</a></td>
<td><code>^$</code></td>
</tr>
</table>
</subsection>
<subsection name="Examples">
<p>
Default configuration
</p>
<source>
&lt;module name=&quot;JavaDocTagContinuationIndentation&quot;&gt;
&lt;property name=&quot;tagContinuationIndentation&quot; value=&quot;4&quot;/&gt;
By default Check validate that first sentence is not empty:
</p>
<source>
&lt;module name=&quot;SummaryJavadocCheck&quot;/&gt;
</source>
<p>
To ensure that summary do not contain phrase like "This method returns" , use following config:
</p>
<source>
&lt;module name=&quot;SummaryJavadocCheck&quot;&gt;
&lt;property name=&quot;forbiddenSummaryFragments&quot; value=&quot;^This method returns.*&quot;/&gt;
&lt;/module&gt;
</source>
</subsection>
<subsection name="Package">
<p>
com.puppycrawl.tools.checkstyle.checks
</p>
</subsection>
<subsection name="Parent Module">
<p>
<a href="config.html#TreeWalker">TreeWalker</a>
</p>
</subsection>
</section>
</body>
</document>

View File

@ -1266,12 +1266,10 @@
href="http://google-styleguide.googlecode.com/svn/trunk/javaguide.html#s7.2-summary-fragment">7.2 The summary fragment</a>
</td>
<td>
<a href="https://github.com/maxvetrenko/checkstyle/issues/17">SummaryJavaDocCheck</a>
(check for text before any at-clause).
<br />
additionally we need to have list of forbidden phrases
<br />
in the beginning of summary (regexp).
<img
src="images/ok_green.png"
alt="" />
<a href="config_javadoc.html#SummaryJavadoc">SummaryJavadoc</a>
</td>
<td>[]</td>
</tr>