diff --git a/checkstyle_checks.xml b/checkstyle_checks.xml index f592690f5..1cdf361da 100755 --- a/checkstyle_checks.xml +++ b/checkstyle_checks.xml @@ -211,5 +211,6 @@ + diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java index d64c2f86e..4e2d6bae6 100755 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java @@ -58,6 +58,11 @@ public final class Main "Sets the output format. (plain|xml). Defaults to plain"); } + /** Stop instances being created. */ + private Main() + { + } + /** * Loops over the files specified checking them for errors. The exit code * is the number of errors found in all the files. diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java index a008a7004..783c1f4a5 100755 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java @@ -31,7 +31,6 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; *

* * @author lkuehne - * @version $Revision: 1.12 $ */ public class HideUtilityClassConstructorCheck extends Check { @@ -44,10 +43,17 @@ public class HideUtilityClassConstructorCheck extends Check @Override public void visitToken(DetailAST aAST) { + if (isAbstract(aAST)) { + // abstract class could not have private constructor + return; + } + final DetailAST objBlock = aAST.findFirstToken(TokenTypes.OBJBLOCK); DetailAST child = objBlock.getFirstChild(); + final boolean hasStaticModifier = isStatic(aAST); boolean hasMethodOrField = false; boolean hasNonStaticMethodOrField = false; + boolean hasNonPrivateStaticMethodOrField = false; boolean hasDefaultCtor = true; boolean hasPublicCtor = false; @@ -67,6 +73,9 @@ public class HideUtilityClassConstructorCheck extends Check if (!isStatic && !isPrivate) { hasNonStaticMethodOrField = true; } + if (isStatic && !isPrivate) { + hasNonPrivateStaticMethodOrField = true; + } } if (type == TokenTypes.CTOR_DEF) { hasDefaultCtor = false; @@ -93,11 +102,31 @@ public class HideUtilityClassConstructorCheck extends Check final boolean extendsJLO = // J.Lo even made it into in our sources :-) aAST.findFirstToken(TokenTypes.EXTENDS_CLAUSE) == null; - final boolean isUtilClass = - extendsJLO && hasMethodOrField && !hasNonStaticMethodOrField; + final boolean isUtilClass = extendsJLO && hasMethodOrField + && !hasNonStaticMethodOrField && hasNonPrivateStaticMethodOrField; - if (isUtilClass && hasAccessibleCtor) { + if (isUtilClass && (hasAccessibleCtor && !hasStaticModifier)) { log(aAST.getLineNo(), aAST.getColumnNo(), "hide.utility.class"); } } + + /** + * @param aAST class definition for check. + * @return true if a given class declared as abstract. + */ + private boolean isAbstract(DetailAST aAST) + { + return aAST.findFirstToken(TokenTypes.MODIFIERS) + .branchContains(TokenTypes.ABSTRACT); + } + + /** + * @param aAST class definition for check. + * @return true if a given class declared as static. + */ + private boolean isStatic(DetailAST aAST) + { + return aAST.findFirstToken(TokenTypes.MODIFIERS) + .branchContains(TokenTypes.LITERAL_STATIC); + } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java index 9594b33d5..af18a8cac 100755 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java @@ -41,6 +41,11 @@ public final class CheckDocsDoclet /** javadoc command line option for dest dir. */ private static final String DEST_DIR_OPT = "-d"; + /** Stop instances being created. */ + private CheckDocsDoclet() + { + } + /** * Comparator that compares the {@link ClassDoc ClassDocs} of two checks * by their check name. diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java index f083d1314..1ccd1e9ba 100755 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java @@ -33,11 +33,16 @@ import com.sun.javadoc.RootDoc; * * @author o_sukhodolsky */ -public class TokenTypesDoclet +public final class TokenTypesDoclet { /** Command line option to specify file to write output of the doclet. */ private static final String DEST_FILE_OPT = "-destfile"; + /** Stop instances being created. */ + private TokenTypesDoclet() + { + } + /** * The doclet's starter method. * @param aRoot RootDoc given to the doclet diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_1.java b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_1.java new file mode 100644 index 000000000..dc80fb3ff --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_1.java @@ -0,0 +1,8 @@ +package com.puppycrawl.tools.checkstyle.design; + +import java.io.Serializable; + +public abstract class HideUtilityClassContructor3041574_1 implements Serializable { + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_2.java b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_2.java new file mode 100644 index 000000000..af76f0d87 --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_2.java @@ -0,0 +1,8 @@ +package com.puppycrawl.tools.checkstyle.design; + +import java.io.Serializable; + +public class HideUtilityClassContructor3041574_2 implements Serializable { + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_3.java b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_3.java new file mode 100644 index 000000000..2fc8da047 --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/design/HideUtilityClassContructor3041574_3.java @@ -0,0 +1,48 @@ +package com.puppycrawl.tools.checkstyle.design; + +import java.io.Serializable; + +public class HideUtilityClassContructor3041574_3 implements Serializable { + private static final long serialVersionUID = 1L; + + public HideUtilityClassContructor3041574_3(int i) { + // no code + } + + public String getValue() { + return ""; + } + + // It is NOT Utility Inner class + @SuppressWarnings("unused") + public static class Event { + // Top level class have access to fields - no need in public getters + private String ind; + private String ind1; + + public Event(String value){ + // do a lot of calculations + } + + // static because this method is utility + public static String getEmptyString() { + return ""; + } + } + + // It is Utility Inner class + @SuppressWarnings("unused") + public static class Event1 { + private String ind; + private String ind1; + + private Event1(){ + // do a lot of calculations + } + + // static because this method is utility + public static String getEmptyString() { + return ""; + } + } +} \ No newline at end of file diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java index cd4a48051..130fbe7c8 100755 --- a/src/tests/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java @@ -69,4 +69,34 @@ public class HideUtilityClassConstructorCheckTest verify(checkConfig, getPath("design" + File.separator + "InputRegression1762702.java"), expected); } + @Test + public void testEmptyAbstractClass() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(HideUtilityClassConstructorCheck.class); + final String[] expected = { + }; + verify(checkConfig, getPath("design" + File.separator + "HideUtilityClassContructor3041574_1.java"), expected); + } + + @Test + public void testEmptyClassWithOnlyPrivateFields() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(HideUtilityClassConstructorCheck.class); + final String[] expected = { + }; + verify(checkConfig, getPath("design" + File.separator + "HideUtilityClassContructor3041574_2.java"), expected); + } + + @Test + public void testClassWithStaticInnerClass() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(HideUtilityClassConstructorCheck.class); + final String[] expected = { + }; + verify(checkConfig, getPath("design" + File.separator + "HideUtilityClassContructor3041574_3.java"), expected); + } + } diff --git a/src/xdocs/config_design.xml b/src/xdocs/config_design.xml index 5d42c58c8..ccb4e3d9e 100755 --- a/src/xdocs/config_design.xml +++ b/src/xdocs/config_design.xml @@ -219,7 +219,8 @@ public class StringUtils // not final to allow subclassing { protected StringUtils() { - throw new UnsupportedOperationException(); // prevents calls from subclass + // prevents calls from subclass + throw new UnsupportedOperationException(); } public static int count(char c, String s) { diff --git a/src/xdocs/releasenotes.xml b/src/xdocs/releasenotes.xml index c60b19fe7..7946a317a 100755 --- a/src/xdocs/releasenotes.xml +++ b/src/xdocs/releasenotes.xml @@ -72,6 +72,12 @@ checking of @throws tags for methods that throw multiple non-runtime exceptions. Thanks to Daan Kets for patch #3039869. +
  • + Fix + HideUtilityClassConstructor + to handle empty and inner classes. Thanks to Roman Ivanov for + patch #3045720. +
  • Notes: