Added IllegalAbstractClassName check (request 750749).

This commit is contained in:
Oleg Sukhodolsky 2003-08-27 21:14:39 +00:00
parent 5245c14883
commit f06e7b12c3
7 changed files with 209 additions and 0 deletions

View File

@ -31,6 +31,9 @@
<li>
<a href="#HideUtilityClassConstructor">HideUtilityClassConstructor</a>
</li>
<li>
<a href="#IllegalAbstractClassName">IllegalAbstractClassName</a>
</li>
<li>
<a href="#InterfaceIsType">InterfaceIsType</a>
</li>
@ -346,6 +349,52 @@ public class StringUtils // not final to allow subclassing
<a href="config.html#treewalker">TreeWalker</a>
</p>
<!-- --> <a name="IllegalAbstractClassName"></a> <h2>IllegalAbstractClassName</h2>
<h4>Description</h4>
<p class="body">
Ensures that the names of abstract classes conforming to some
regular expression.
</p>
<p class="body">
Rationale:
Abtsract classes are conevnience base class
implementations of interfaces not types as such. As
such they should be named to indicate this.
</p>
<h4>Properties</h4>
<table width="100%" border="1" cellpadding="5" class="body">
<tr class="header">
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>format</td>
<td>pattern for abstract class name.</td>
<td><a href="property_types.html#regexp">regular expression</a></td>
<td><span class="default">^Abstract.*$|^.*Factory$</span></td>
</tr>
</table>
<h4>Examples</h4>
<p class="body">
To configure the check:
</p>
<pre class="body">
&lt;module name=&quot;IllegalAbstractClassName&quot;/&gt;
</pre>
<h4>Package</h4>
<p class="body">
com.puppycrawl.tools.checkstyle.checks.design
</p>
<h4>Parent Module</h4>
<p class="body">
<a href="config.html#treewalker">TreeWalker</a>
</p>
</td>
</tr>
</table>

View File

@ -149,6 +149,8 @@
<li class="body">Added MutableException check (request 750750).</li>
<li class="body">Added IllegalAbstractClassName check (request 750749).</li>
</ul>
<p class="body">

View File

@ -0,0 +1,109 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2003 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.design;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.checks.AbstractFormatCheck;
/**
* <p>
* Ensures that the names of abstract classes conforming to some
* regular expression.
* </p>
* <p>
* Rationale: Abtsract classes are conevnience base class
* implementations of interfaces not types as such. As such
* they should be named to indicate this.
* </p>
*
* @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
*/
public final class IllegalAbstractClassNameCheck extends AbstractFormatCheck
{
/** Defualt format for abstract class names */
private static final String DEFAULT_FORMAT = "^Abstract.*$|^.*Factory$";
/** Creates new instance of the check. */
public IllegalAbstractClassNameCheck()
{
super(DEFAULT_FORMAT);
}
/** @see com.puppycrawl.tools.checkstyle.api.Check */
public int[] getDefaultTokens()
{
return new int[]{TokenTypes.CLASS_DEF};
}
/** @see com.puppycrawl.tools.checkstyle.api.Check */
public int[] getRequiredTokens()
{
return getDefaultTokens();
}
/** @see com.puppycrawl.tools.checkstyle.api.Check */
public void visitToken(DetailAST aAST)
{
switch (aAST.getType()) {
case TokenTypes.CLASS_DEF:
visitClassDef(aAST);
break;
default:
throw new IllegalStateException(aAST.toString());
}
}
/**
* Checks class definition.
* @param aAST class definition for check.
*/
private void visitClassDef(DetailAST aAST)
{
if (isAbstract(aAST)) {
String className = aAST.findFirstToken(TokenTypes.IDENT).getText();
if (!isMatchingClassName(className)) {
log(aAST.getLineNo(), aAST.getColumnNo(),
"illegal.abstract.class.name", className, getFormat());
}
}
}
/**
* @param aAST class definition for check.
* @return true if a given class declared as abstract.
*/
private boolean isAbstract(DetailAST aAST)
{
final DetailAST abstractAST = aAST.findFirstToken(TokenTypes.MODIFIERS)
.findFirstToken(TokenTypes.ABSTRACT);
return abstractAST != null;
}
/**
* @param aClassName class name for check.
* @return true if class name matches format of abstract class names.
*/
private boolean isMatchingClassName(String aClassName)
{
return getRegexp().match(aClassName);
}
}

View File

@ -3,3 +3,4 @@ final.class=Class {0} should be declared as final.
interface.type=interfaces should describe a type and hence have methods.
variable.notPrivate=Variable ''{0}'' must be private and have accessor methods.
mutable.exception=The field ''{0}'' must be declared final.
illegal.abstract.class.name=Name ''{0}'' must match pattern ''{1}''.

View File

@ -0,0 +1,23 @@
package com.puppycrawl.tools.checkstyle.checks.design;
abstract public class InputAbstractClassName {
}
abstract class NonAbstractClassName {
}
abstract class FactoryWithBadName {
}
abstract class AbstractClassName {
abstract class NonAbstractInnerClass {
}
}
abstract class ClassFactory {
abstract class WellNamedFactory {
}
}
class NonAbstractClass {
}

View File

@ -47,6 +47,7 @@ import com.puppycrawl.tools.checkstyle.checks.coding.SuperFinalizeCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.DesignForExtensionCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.IllegalAbstractClassNameCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.InterfaceIsTypeCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.MutableExceptionCheckTest;
import com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheckTest;
@ -144,6 +145,7 @@ public class AllTests {
suite.addTest(new TestSuite(HeaderCheckTest.class));
suite.addTest(new TestSuite(HiddenFieldCheckTest.class));
suite.addTest(new TestSuite(HideUtilityClassConstructorCheckTest.class));
suite.addTest(new TestSuite(IllegalAbstractClassNameCheckTest.class));
suite.addTest(new TestSuite(IllegalCatchCheckTest.class));
suite.addTest(new TestSuite(IllegalImportCheckTest.class));
suite.addTest(new TestSuite(IllegalInstantiationCheckTest.class));

View File

@ -0,0 +1,23 @@
package com.puppycrawl.tools.checkstyle.checks.design;
import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import java.io.File;
public class IllegalAbstractClassNameCheckTest
extends BaseCheckTestCase
{
public void testIllegalAbstractClassName() throws Exception
{
final DefaultConfiguration checkConfig =
createCheckConfig(IllegalAbstractClassNameCheck.class);
final String[] expected = {
"3:1: Name 'InputAbstractClassName' must match pattern '^Abstract.*$|^.*Factory$'.",
"6:1: Name 'NonAbstractClassName' must match pattern '^Abstract.*$|^.*Factory$'.",
"9:1: Name 'FactoryWithBadName' must match pattern '^Abstract.*$|^.*Factory$'.",
"13:5: Name 'NonAbstractInnerClass' must match pattern '^Abstract.*$|^.*Factory$'.",
};
verify(checkConfig, getPath("design" + File.separator + "InputAbstractClassName.java"), expected);
}
}