This commit is contained in:
Oliver Burn 2010-10-07 12:40:40 +11:00
commit e300a3a0bc
11 changed files with 152 additions and 6 deletions

View File

@ -211,5 +211,6 @@
<module name="PackageAnnotation"/>
<module name="SuppressWarnings"/>
<module name="OuterTypeFilename"/>
<module name="HideUtilityClassConstructor"/>
</module>
</module>

View File

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

View File

@ -31,7 +31,6 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST;
* </p>
*
* @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);
}
}

View File

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

View File

@ -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 <code>RootDoc</code> given to the doclet

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

@ -72,6 +72,12 @@
checking of <code>@throws</code> tags for methods that throw multiple
non-runtime exceptions. Thanks to Daan Kets for patch #3039869.
</li>
<li>
Fix
<a href="config_design.html#HideUtilityClassConstructor">HideUtilityClassConstructor</a>
to handle empty and inner classes. Thanks to Roman Ivanov for
patch #3045720.
</li>
</ul>
<p>Notes:</p>
<ul>