Source code: com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.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.DetailAST;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24 import java.util.Stack;
25
26 /**
27 * <p>
28 * Checks that class which has only private ctors
29 * is declared as final.
30 * </p>
31 * <p>
32 * An example of how to configure the check is:
33 * </p>
34 * <pre>
35 * <module name="FinalClass"/>
36 * </pre>
37 * @author o_sukhodolsky
38 */
39 public class FinalClassCheck
40 extends Check
41 {
42 /** keeps ClassDesc objects for stack of declared classes */
43 private final Stack mClasses = new Stack();
44
45 /** @see Check */
46 public int[] getDefaultTokens()
47 {
48 return new int[]{TokenTypes.CLASS_DEF, TokenTypes.CTOR_DEF};
49 }
50
51 /** @see Check */
52 public void visitToken(DetailAST aAST)
53 {
54 final DetailAST modifiers = aAST.findFirstToken(TokenTypes.MODIFIERS);
55
56 if (aAST.getType() == TokenTypes.CLASS_DEF) {
57 final boolean isFinal = (modifiers != null)
58 && modifiers.branchContains(TokenTypes.FINAL);
59 final boolean isAbstract = (modifiers != null)
60 && modifiers.branchContains(TokenTypes.ABSTRACT);
61 mClasses.push(new ClassDesc(isFinal, isAbstract));
62 }
63 else {
64 final ClassDesc desc = (ClassDesc) mClasses.peek();
65 if ((modifiers != null)
66 && modifiers.branchContains(TokenTypes.LITERAL_PRIVATE))
67 {
68 desc.reportPrivateCtor();
69 }
70 else {
71 desc.reportNonPrivateCtor();
72 }
73 }
74 }
75
76 /** @see Check */
77 public void leaveToken(DetailAST aAST)
78 {
79 if (aAST.getType() != TokenTypes.CLASS_DEF) {
80 return;
81 }
82
83 final ClassDesc desc = (ClassDesc) mClasses.pop();
84 if (!desc.isDeclaredAsFinal()
85 && !desc.isDeclaredAsAbstract()
86 && desc.hasPrivateCtor()
87 && !desc.hasNonPrivateCtor())
88 {
89 final String className =
90 aAST.findFirstToken(TokenTypes.IDENT).getText();
91 log(aAST.getLineNo(), "final.class", className);
92 }
93 }
94
95 /** maintains information about class' ctors */
96 private static final class ClassDesc
97 {
98 /** is class declared as final */
99 private final boolean mDeclaredAsFinal;
100
101 /** is class declared as abstract */
102 private final boolean mDeclaredAsAbstract;
103
104 /** does class have non-provate ctors */
105 private boolean mHasNonPrivateCtor;
106
107 /** does class have private ctors */
108 private boolean mHasPrivateCtor;
109
110 /**
111 * create a new ClassDesc instance.
112 * @param aDeclaredAsFinal indicates if the
113 * class declared as final
114 * @param aDeclaredAsAbstract indicates if the
115 * class declared as abstract
116 */
117 ClassDesc(boolean aDeclaredAsFinal, boolean aDeclaredAsAbstract)
118 {
119 mDeclaredAsFinal = aDeclaredAsFinal;
120 mDeclaredAsAbstract = aDeclaredAsAbstract;
121 }
122
123 /** adds private ctor. */
124 void reportPrivateCtor()
125 {
126 mHasPrivateCtor = true;
127 }
128
129 /** adds non-private ctor. */
130 void reportNonPrivateCtor()
131 {
132 mHasNonPrivateCtor = true;
133 }
134
135 /**
136 * does class have private ctors.
137 * @return true if class has private ctors
138 */
139 boolean hasPrivateCtor()
140 {
141 return mHasPrivateCtor;
142 }
143
144 /**
145 * does class have non-private ctors.
146 * @return true if class has non-private ctors
147 */
148 boolean hasNonPrivateCtor()
149 {
150 return mHasNonPrivateCtor;
151 }
152
153 /**
154 * is class declared as final.
155 * @return true if class is declared as final
156 */
157 boolean isDeclaredAsFinal()
158 {
159 return mDeclaredAsFinal;
160 }
161
162 /**
163 * is class declared as abstract.
164 * @return true if class is declared as final
165 */
166 boolean isDeclaredAsAbstract()
167 {
168 return mDeclaredAsAbstract;
169 }
170
171 /**
172 * Returns a string representation of the object.
173 * @return a string representation of the object
174 */
175 public String toString()
176 {
177 return this.getClass().getName()
178 + "["
179 + "final=" + mDeclaredAsFinal
180 + " abstract=" + mDeclaredAsAbstract
181 + " pctor=" + mHasPrivateCtor
182 + " ctor=" + mHasNonPrivateCtor
183 + "]";
184 }
185 }
186 }