finally added all the new checks that I built during feature freeze

need to do more tests and write docs
This commit is contained in:
Lars Kühne 2003-02-18 05:19:08 +00:00
parent cbcc08934f
commit 669def894e
7 changed files with 555 additions and 0 deletions

View File

@ -0,0 +1,72 @@
////////////////////////////////////////////////////////////////////////////////
// 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;
/**
* Checks the style of array type definitions.
* Some like Java-style: <code>public static void main(String[] args)</code>
* and some like C-style: public static void main(String args[])
*
* By default the Check enforces Java style.
* @author lkuehne
*/
public class ArrayTypeStyleCheck extends Check
{
/** controls whether to use Java or C style */
private boolean mJavaStyle = true;
/** @see Check */
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.ARRAY_DECLARATOR};
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
final DetailAST typeAST = aAST.getParent();
if (typeAST.getType() != TokenTypes.TYPE) {
return;
}
DetailAST variableAST = (DetailAST) typeAST.getNextSibling();
boolean isJavaStyle = (variableAST.getColumnNo() > aAST.getColumnNo());
if (isJavaStyle != mJavaStyle) {
log(aAST.getLineNo(), aAST.getColumnNo(),
"Array brackets at illegal position.");
}
}
/**
* Controls whether to check for Java or C style.
* @param aJavaStyle true if Java style should be used.
*/
public void setJavaStyle(boolean aJavaStyle)
{
mJavaStyle = aJavaStyle;
}
}

View File

@ -0,0 +1,67 @@
////////////////////////////////////////////////////////////////////////////////
// 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;
/**
* Detects inline conditionals.
*
* An example inline conditional is this:
* <pre>
* String a = getParameter("a");
* String b = (a==null || a.length<1) ? null : a.substring(1);
* </pre>
*
* Rationale: Some developers find inline conditionals hard to read,
* so their company's coding standards forbids them.
*
* @author lkuehne
* @version $Revision: 1.1 $
*/
public class AvoidInlineConditionalsCheck extends Check
{
/** avoids multiple instantiations of equivalten arrays */
private static final int[] DEFAULT_TOKENS =
new int[]{TokenTypes.QUESTION};
/** @see Check */
public int[] getDefaultTokens()
{
return DEFAULT_TOKENS;
}
/** @see Check */
public int[] getRequiredTokens()
{
return DEFAULT_TOKENS;
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
// the only place a QUESTION token can occur is in inline conditionals
// so no need to do any further tricks here - pretty trivial Check!
log(aAST.getLineNo(), aAST.getColumnNo(),
"Avoid inline conditionals.");
}
}

View File

@ -0,0 +1,71 @@
////////////////////////////////////////////////////////////////////////////////
// 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;
/**
* Finds nested blocks.
* For example this Check finds the obsolete braces in
* <pre>
* switch (a)
* {
* case 0:
* {
* x = 1;
* }
* break;
* default:
* break;
* }
* </pre>
* and flags confusing code like
* <pre>
* public void guessTheOutput()
* {
* int whichIsWich = 0;
* {
* int whichIsWhich = 2;
* }
* System.out.println("value = " + whichIsWhich);
* }
* </pre>
*
* @author lkuehne
*/
public class AvoidNestedBlocksCheck extends Check
{
/** @see Check */
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.SLIST};
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
if (aAST.getParent().getType() == TokenTypes.SLIST) {
// TODO: i18n
log(aAST.getLineNo(), aAST.getColumnNo(), "Avoid nested blocks");
}
}
}

View File

@ -0,0 +1,147 @@
////////////////////////////////////////////////////////////////////////////////
// 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.ScopeUtils;
/**
* Checks that classes are designed for inheritance.
*
* <p>
* More specifically, it enforces a programming style
* where superclasses provide empty "hooks" that can be
* implemented by subclasses.
* </p>
*
* <p>
* The exact rule is that nonprivate methods in
* nonfinal classes (or classes that do not
* only have private constructors) must either be
* <ul>
* <li>abstract or</li>
* <li>final or</li>
* <li>have an empty implementation</li>
* </ul>
* </p>
*
* <p>
* This protects superclasses against beeing broken by
* subclasses. The downside is that subclasses are limited
* in their flexibility, in particular they cannot prevent
* execution of code in the superclass, but that also
* means that subclasses can't forget to call their super
* method.
* </p>
*
* @author lkuehne
* @version $Revision: 1.1 $
*/
public class DesignForInheritanceCheck extends Check
{
/** the default tokens for this check */
private static final int[] DEFAULT_TOKENS =
new int[] {TokenTypes.METHOD_DEF};
/** @see Check */
public int[] getDefaultTokens()
{
return DEFAULT_TOKENS;
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
// nothing to do for Interfaces
if (ScopeUtils.inInterfaceBlock(aAST)) {
return;
}
// method is ok if it is private or abstract or final
DetailAST modifiers = aAST.findFirstToken(TokenTypes.MODIFIERS);
if (modifiers.branchContains(TokenTypes.LITERAL_PRIVATE)
|| modifiers.branchContains(TokenTypes.ABSTRACT)
|| modifiers.branchContains(TokenTypes.FINAL))
{
return;
}
// method is ok if it is empty
DetailAST implemetation = aAST.findFirstToken(TokenTypes.SLIST);
if (implemetation.getFirstChild().getType() == TokenTypes.RCURLY) {
return;
}
// check if the containing class can be subclassed
DetailAST classDef = findContainingClass(aAST);
DetailAST classMods = classDef.findFirstToken(TokenTypes.MODIFIERS);
if (classMods.branchContains(TokenTypes.FINAL)) {
return;
}
// check if subclassing is prevented by having only private ctors
DetailAST objBlock = classDef.findFirstToken(TokenTypes.OBJBLOCK);
boolean hasDefaultConstructor = true;
boolean hasExplNonPrivateCtor = false;
DetailAST candidate = (DetailAST) objBlock.getFirstChild();
while (candidate != null) {
if (candidate.getType() == TokenTypes.CTOR_DEF) {
hasDefaultConstructor = false;
DetailAST ctorMods =
candidate.findFirstToken(TokenTypes.MODIFIERS);
if (!ctorMods.branchContains(TokenTypes.LITERAL_PRIVATE)) {
hasExplNonPrivateCtor = true;
break;
}
}
candidate = (DetailAST) candidate.getNextSibling();
}
if (hasDefaultConstructor || hasExplNonPrivateCtor) {
String name = aAST.findFirstToken(TokenTypes.IDENT).getText();
// TODO: i18n
log(aAST.getLineNo(), aAST.getColumnNo(),
"Method '" + name + "' is not designed for inheritance "
+ "- needs to be abstract, final or empty.");
}
}
/**
* Searches the tree towards the root until it finds a CLASS_DEF node.
* @param aAST the start node for searching
* @return the CLASS_DEF node.
*/
private DetailAST findContainingClass(DetailAST aAST)
{
DetailAST searchAST = aAST;
while (searchAST.getType() != TokenTypes.CLASS_DEF) {
searchAST = searchAST.getParent();
}
return searchAST;
}
}

View File

@ -0,0 +1,87 @@
////////////////////////////////////////////////////////////////////////////////
// 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;
/**
* Make sure that utility classes (classes that contain only static methods)
* do not have a public constructor.
* <p>
* Rationale: Instantiating utility classes does not make sense.
* A common mistake is forgetting to hide the default constructor.
* </p>
*
* @author lkuehne
* @version $Revision: 1.1 $
*/
public class HideUtilityClassConstructorCheck extends Check
{
/** @see Check */
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.CLASS_DEF};
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
DetailAST objBlock = aAST.findFirstToken(TokenTypes.OBJBLOCK);
DetailAST child = (DetailAST) objBlock.getFirstChild();
boolean hasMethod = false;
boolean hasNonStaticMethod = false;
boolean hasDefaultCtor = true;
boolean hasPublicCtor = false;
while (child != null) {
if (child.getType() == TokenTypes.METHOD_DEF) {
hasMethod = true;
final DetailAST modifiers =
child.findFirstToken(TokenTypes.MODIFIERS);
if (!modifiers.branchContains(TokenTypes.LITERAL_STATIC)) {
hasNonStaticMethod = true;
}
}
if (child.getType() == TokenTypes.CTOR_DEF) {
hasDefaultCtor = false;
final DetailAST modifiers =
child.findFirstToken(TokenTypes.MODIFIERS);
if (!modifiers.branchContains(TokenTypes.LITERAL_PRIVATE)
&& !modifiers.branchContains(TokenTypes.LITERAL_PROTECTED))
{
// treat package visible as public
// for the purpose of this Check
hasPublicCtor = true;
}
}
child = (DetailAST) child.getNextSibling();
}
boolean hasAccessibleCtor = (hasDefaultCtor || hasPublicCtor);
if (hasMethod && !hasNonStaticMethod && hasAccessibleCtor) {
log(aAST.getLineNo(), aAST.getColumnNo(),
"Utility classes should not have "
+ "a public or default constructor.");
}
}
}

View File

@ -0,0 +1,90 @@
////////////////////////////////////////////////////////////////////////////////
// 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;
/**
* Implements Bloch, Effective Java, Item 17 -
* Use Interfaces only to define types.
*
* <p>
* An interface should describe a <em>type</em>, it is therefore
* inappropriate to define an interface that does not contain any methods
* but only constants.
* </p>
*
* <p>
* The check can be configured to also disallow marker interfaces like
* <code>java.io.Serializable</code>, that do not contain methods or
* constants at all.
* </p>
*
* @author lkuehne
* @version $Revision: 1.1 $
*/
public final class InterfaceIsTypeCheck
extends Check
{
/** flag to control whether marker interfaces are allowed. */
private boolean mAllowMarkerInterfaces = true;
/** @see Check */
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.INTERFACE_DEF};
}
/** @see Check */
public int[] getRequiredTokens()
{
return getDefaultTokens();
}
/** @see Check */
public void visitToken(DetailAST aAST)
{
final DetailAST objBlock =
aAST.findFirstToken(TokenTypes.OBJBLOCK);
final DetailAST methodDef =
objBlock.findFirstToken(TokenTypes.METHOD_DEF);
final DetailAST variableDef =
objBlock.findFirstToken(TokenTypes.VARIABLE_DEF);
boolean methodRequired =
!mAllowMarkerInterfaces || variableDef != null;
if (methodDef == null && methodRequired) {
// TODO: i18n
log(aAST.getLineNo(), "interfaces should describe a type "
+ "and hence have methods.");
}
}
/**
* Controls whether marker interfaces like Serializable are allowed.
* @param aFlag whether to allow marker interfaces or not
*/
public void setAllowMarkerInterfaces(boolean aFlag)
{
mAllowMarkerInterfaces = aFlag;
}
}

View File

@ -0,0 +1,21 @@
package com.puppycrawl.tools.checkstyle.checks;
import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
public class AvoidInlineConditionalsCheckTest
extends BaseCheckTestCase
{
public void testIt()
throws Exception
{
final DefaultConfiguration checkConfig =
createCheckConfig(AvoidInlineConditionalsCheck.class);
final String[] expected = {
"97:29: Avoid inline conditionals.",
"98:20: Avoid inline conditionals.",
"150:34: Avoid inline conditionals.",
};
verify(checkConfig, getPath("InputWhitespace.java"), expected);
}
}