KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > metrics > AbstractClassCouplingCheck


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 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.metrics;
20
21 import com.puppycrawl.tools.checkstyle.api.Check;
22 import com.puppycrawl.tools.checkstyle.api.DetailAST;
23 import com.puppycrawl.tools.checkstyle.api.FullIdent;
24 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
25
26 import com.puppycrawl.tools.checkstyle.checks.CheckUtils;
27
28 import java.util.HashSet JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.Stack JavaDoc;
31
32 /**
33  * Base class for coupling calculation.
34  *
35  * @author <a HREF="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
36  * @author o_sukhodolsky
37  */

38 public abstract class AbstractClassCouplingCheck extends Check
39 {
40     /** Class names to ignore. */
41     private final Set JavaDoc mIgnoredClassNames = new HashSet JavaDoc();
42     /** Allowed complexity. */
43     private int mMax;
44     /** package of the file we check. */
45     private String JavaDoc mPackageName;
46
47     /** Stack of contexts. */
48     private final Stack JavaDoc mContextStack = new Stack JavaDoc();
49     /** Current context. */
50     private Context mContext;
51
52     /**
53      * Creates new instance of the check.
54      * @param aDefaultMax default value for allowed complexity.
55      */

56     protected AbstractClassCouplingCheck(int aDefaultMax)
57     {
58         setMax(aDefaultMax);
59
60         mIgnoredClassNames.add("boolean");
61         mIgnoredClassNames.add("byte");
62         mIgnoredClassNames.add("char");
63         mIgnoredClassNames.add("double");
64         mIgnoredClassNames.add("float");
65         mIgnoredClassNames.add("int");
66         mIgnoredClassNames.add("long");
67         mIgnoredClassNames.add("short");
68         mIgnoredClassNames.add("void");
69         mIgnoredClassNames.add("Boolean");
70         mIgnoredClassNames.add("Byte");
71         mIgnoredClassNames.add("Character");
72         mIgnoredClassNames.add("Double");
73         mIgnoredClassNames.add("Float");
74         mIgnoredClassNames.add("Integer");
75         mIgnoredClassNames.add("Long");
76         mIgnoredClassNames.add("Object");
77         mIgnoredClassNames.add("Short");
78         mIgnoredClassNames.add("String");
79         mIgnoredClassNames.add("StringBuffer");
80         mIgnoredClassNames.add("Void");
81         mIgnoredClassNames.add("ArrayIndexOutOfBoundsException");
82         mIgnoredClassNames.add("Exception");
83         mIgnoredClassNames.add("RuntimeException");
84         mIgnoredClassNames.add("IllegalArgumentException");
85         mIgnoredClassNames.add("IllegalStateException");
86         mIgnoredClassNames.add("IndexOutOfBoundsException");
87         mIgnoredClassNames.add("NullPointerException");
88         mIgnoredClassNames.add("Throwable");
89         mIgnoredClassNames.add("SecurityException");
90         mIgnoredClassNames.add("UnsupportedOperationException");
91     }
92
93     /** {@inheritDoc} */
94     public final int[] getDefaultTokens()
95     {
96         return getRequiredTokens();
97     }
98
99     /** @return allowed complexity. */
100     public final int getMax()
101     {
102         return mMax;
103     }
104
105     /**
106      * Sets maximul allowed complexity.
107      * @param aMax allowed complexity.
108      */

109     public final void setMax(int aMax)
110     {
111         mMax = aMax;
112     }
113
114     /** {@inheritDoc} */
115     public final void beginTree(DetailAST aAST)
116     {
117         mPackageName = "";
118     }
119
120     /** @return message key we use for log violations. */
121     protected abstract String JavaDoc getLogMessageId();
122
123     /** {@inheritDoc} */
124     public void visitToken(DetailAST aAST)
125     {
126         switch (aAST.getType()) {
127         case TokenTypes.PACKAGE_DEF:
128             visitPackageDef(aAST);
129             break;
130         case TokenTypes.CLASS_DEF:
131         case TokenTypes.INTERFACE_DEF:
132         case TokenTypes.ANNOTATION_DEF:
133         case TokenTypes.ENUM_DEF:
134             visitClassDef(aAST);
135             break;
136         case TokenTypes.TYPE:
137             mContext.visitType(aAST);
138             break;
139         case TokenTypes.LITERAL_NEW:
140             mContext.visitLiteralNew(aAST);
141             break;
142         case TokenTypes.LITERAL_THROWS:
143             mContext.visitLiteralThrows(aAST);
144             break;
145         default:
146             throw new IllegalStateException JavaDoc(aAST.toString());
147         }
148     }
149
150     /** {@inheritDoc} */
151     public void leaveToken(DetailAST aAST)
152     {
153         switch (aAST.getType()) {
154         case TokenTypes.CLASS_DEF:
155         case TokenTypes.INTERFACE_DEF:
156         case TokenTypes.ANNOTATION_DEF:
157         case TokenTypes.ENUM_DEF:
158             leaveClassDef();
159             break;
160         default:
161             // Do nothing
162
}
163     }
164
165     /**
166      * Stores package of current class we check.
167      * @param aPkg package definition.
168      */

169     private void visitPackageDef(DetailAST aPkg)
170     {
171         final FullIdent ident = FullIdent.createFullIdent(aPkg.getLastChild()
172                 .getPreviousSibling());
173         mPackageName = ident.getText();
174     }
175
176     /**
177      * Creates new context for a given class.
178      * @param aClassDef class definition node.
179      */

180     private void visitClassDef(DetailAST aClassDef)
181     {
182         mContextStack.push(mContext);
183         final String JavaDoc className =
184             aClassDef.findFirstToken(TokenTypes.IDENT).getText();
185         mContext = new Context(className,
186                                aClassDef.getLineNo(),
187                                aClassDef.getColumnNo());
188     }
189
190     /** Restores previous context. */
191     private void leaveClassDef()
192     {
193         mContext.checkCoupling();
194         mContext = (Context) mContextStack.pop();
195     }
196
197     /**
198      * Incapsulates information about class coupling.
199      *
200      * @author <a HREF="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
201      * @author o_sukhodolsky
202      */

203     private class Context
204     {
205         /** Set of referenced classes. */
206         private final Set JavaDoc mReferencedClassNames = new HashSet JavaDoc();
207         /** Own class name. */
208         private final String JavaDoc mClassName;
209         /* Location of own class. (Used to log violations) */
210         /** Line number of class definition. */
211         private final int mLineNo;
212         /** Column number of class definition. */
213         private final int mColumnNo;
214
215         /**
216          * Create new context associated with given class.
217          * @param aClassName name of the given class.
218          * @param aLineNo line of class definition.
219          * @param aColumnNo column of class definition.
220          */

221         public Context(String JavaDoc aClassName, int aLineNo, int aColumnNo)
222         {
223             mClassName = aClassName;
224             mLineNo = aLineNo;
225             mColumnNo = aColumnNo;
226         }
227
228         /**
229          * Visits throws clause and collects all exceptions we throw.
230          * @param aThrows throws to process.
231          */

232         public void visitLiteralThrows(DetailAST aThrows)
233         {
234             for (DetailAST childAST = (DetailAST) aThrows.getFirstChild();
235                  childAST != null;
236                  childAST = (DetailAST) childAST.getNextSibling())
237             {
238                 if (childAST.getType() != TokenTypes.COMMA) {
239                     addReferencedClassName(childAST);
240                 }
241             }
242         }
243
244         /**
245          * Visits type.
246          * @param aAST type to process.
247          */

248         public void visitType(DetailAST aAST)
249         {
250             final String JavaDoc className = CheckUtils.createFullType(aAST).getText();
251             mContext.addReferencedClassName(className);
252         }
253
254         /**
255          * Visits NEW.
256          * @param aAST NEW to process.
257          */

258         public void visitLiteralNew(DetailAST aAST)
259         {
260             mContext.addReferencedClassName((DetailAST) aAST.getFirstChild());
261         }
262
263         /**
264          * Adds new referenced class.
265          * @param aAST a node which represents referenced class.
266          */

267         private void addReferencedClassName(DetailAST aAST)
268         {
269             final String JavaDoc className = FullIdent.createFullIdent(aAST).getText();
270             addReferencedClassName(className);
271         }
272
273         /**
274          * Adds new referenced class.
275          * @param aClassName class name of the referenced class.
276          */

277         private void addReferencedClassName(String JavaDoc aClassName)
278         {
279             if (isSignificant(aClassName)) {
280                 mReferencedClassNames.add(aClassName);
281             }
282         }
283
284         /** Checks if coupling less than allowed or not. */
285         public void checkCoupling()
286         {
287             mReferencedClassNames.remove(mClassName);
288             mReferencedClassNames.remove(mPackageName + "." + mClassName);
289
290             if (mReferencedClassNames.size() > mMax) {
291                 log(mLineNo, mColumnNo, getLogMessageId(),
292                     new Object JavaDoc[] {
293                         new Integer JavaDoc(mReferencedClassNames.size()),
294                         new Integer JavaDoc(getMax()),
295                         mReferencedClassNames.toString(), });
296             }
297         }
298
299         /**
300          * Checks if given class shouldn't be ignored and not from java.lang.
301          * @param aClassName class to check.
302          * @return true if we should count this class.
303          */

304         private boolean isSignificant(String JavaDoc aClassName)
305         {
306             return (aClassName.length() > 0)
307                     && !mIgnoredClassNames.contains(aClassName)
308                     && !aClassName.startsWith("java.lang.");
309         }
310     }
311 }
312
Popular Tags