diff --git a/docs/config_design.html b/docs/config_design.html index ab48ac427..d7135ff93 100644 --- a/docs/config_design.html +++ b/docs/config_design.html @@ -31,6 +31,9 @@
  • HideUtilityClassConstructor
  • +
  • + IllegalAbstractClassName +
  • InterfaceIsType
  • @@ -346,6 +349,52 @@ public class StringUtils // not final to allow subclassing TreeWalker

    +

    IllegalAbstractClassName

    +

    Description

    +

    + Ensures that the names of abstract classes conforming to some + regular expression. +

    + +

    + Rationale: + Abtsract classes are conevnience base class + implementations of interfaces not types as such. As + such they should be named to indicate this. +

    + +

    Properties

    + + + + + + + + + + + + + +
    namedescriptiontypedefault value
    formatpattern for abstract class name.regular expression^Abstract.*$|^.*Factory$
    + +

    Examples

    +

    + To configure the check: +

    +
    +<module name="IllegalAbstractClassName"/>
    +      
    +

    Package

    +

    + com.puppycrawl.tools.checkstyle.checks.design +

    +

    Parent Module

    +

    + TreeWalker +

    + diff --git a/docs/releasenotes.html b/docs/releasenotes.html index 34a797708..9d4bdc43f 100644 --- a/docs/releasenotes.html +++ b/docs/releasenotes.html @@ -149,6 +149,8 @@
  • Added MutableException check (request 750750).
  • +
  • Added IllegalAbstractClassName check (request 750749).
  • +

    diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheck.java new file mode 100644 index 000000000..3cdd60697 --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheck.java @@ -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; + +/** + *

    + * Ensures that the names of abstract classes conforming to some + * regular expression. + *

    + *

    + * Rationale: Abtsract classes are conevnience base class + * implementations of interfaces not types as such. As such + * they should be named to indicate this. + *

    + * + * @author Simon Harris + */ +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); + } +} diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/messages.properties b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/messages.properties index 57c5090b5..4a40cc10b 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/messages.properties +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/messages.properties @@ -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}''. diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/design/InputAbstractClassName.java b/src/testinputs/com/puppycrawl/tools/checkstyle/design/InputAbstractClassName.java new file mode 100644 index 000000000..fefc8bbab --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/design/InputAbstractClassName.java @@ -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 { +} diff --git a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java index 32d25329a..beb2e5fa1 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java @@ -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)); diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheckTest.java new file mode 100644 index 000000000..a0df6349f --- /dev/null +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/design/IllegalAbstractClassNameCheckTest.java @@ -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); + } +}