Implemented the first Javadoc test. Still need to add some Javadoc (no pun

intended) and also refactor the utility methods.
This commit is contained in:
Oliver Burn 2002-10-24 14:33:31 +00:00
parent 7af9e82fc1
commit 5922229625
6 changed files with 338 additions and 55 deletions

View File

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

View File

@ -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 <code>null</code> 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]);
}
}

View File

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

View File

@ -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 <a href="mailto:checkstyle@puppycrawl.com">Oliver Burn</a>
* @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;
}
}

View File

@ -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."
};

View File

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