Source code: com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2003 Oliver Burn
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19 package com.puppycrawl.tools.checkstyle.checks.design;
20
21 import com.puppycrawl.tools.checkstyle.api.Check;
22 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
23 import com.puppycrawl.tools.checkstyle.api.DetailAST;
24
25 /**
26 * Make sure that utility classes (classes that contain only static methods)
27 * do not have a public constructor.
28 * <p>
29 * Rationale: Instantiating utility classes does not make sense.
30 * A common mistake is forgetting to hide the default constructor.
31 * </p>
32 *
33 * @author lkuehne
34 * @version $Revision: 1.4 $
35 */
36 public class HideUtilityClassConstructorCheck extends Check
37 {
38 /** @see Check */
39 public int[] getDefaultTokens()
40 {
41 return new int[] {TokenTypes.CLASS_DEF};
42 }
43
44 /** @see Check */
45 public void visitToken(DetailAST aAST)
46 {
47 DetailAST objBlock = aAST.findFirstToken(TokenTypes.OBJBLOCK);
48 DetailAST child = (DetailAST) objBlock.getFirstChild();
49 boolean hasMethod = false;
50 boolean hasNonStaticMethod = false;
51 boolean hasDefaultCtor = true;
52 boolean hasPublicCtor = false;
53
54 while (child != null) {
55 if (child.getType() == TokenTypes.METHOD_DEF) {
56 hasMethod = true;
57 final DetailAST modifiers =
58 child.findFirstToken(TokenTypes.MODIFIERS);
59 if (!modifiers.branchContains(TokenTypes.LITERAL_STATIC)) {
60 hasNonStaticMethod = true;
61 }
62 }
63 if (child.getType() == TokenTypes.CTOR_DEF) {
64 hasDefaultCtor = false;
65 final DetailAST modifiers =
66 child.findFirstToken(TokenTypes.MODIFIERS);
67 if (!modifiers.branchContains(TokenTypes.LITERAL_PRIVATE)
68 && !modifiers.branchContains(TokenTypes.LITERAL_PROTECTED))
69 {
70 // treat package visible as public
71 // for the purpose of this Check
72 hasPublicCtor = true;
73 }
74
75 }
76 child = (DetailAST) child.getNextSibling();
77 }
78
79 final boolean hasAccessibleCtor = (hasDefaultCtor || hasPublicCtor);
80
81 // figure out if class extends java.lang.object directly
82 // keep it simple for now and get a 99% solution
83 // TODO: check for "extends java.lang.Object" and "extends Object"
84 // consider "import org.omg.CORBA.*"
85 final DetailAST extendsClause =
86 aAST.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
87 final boolean extendsJLO = // J.Lo even made it into in our sources :-)
88 extendsClause.getFirstChild() == null;
89
90 if (extendsJLO
91 && hasMethod && !hasNonStaticMethod && hasAccessibleCtor)
92 {
93 log(aAST.getLineNo(), aAST.getColumnNo(),
94 "Utility classes should not have "
95 + "a public or default constructor.");
96 }
97 }
98 }