KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > design > DesignForExtensionCheck


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.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.Scope;
24 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26
27 /**
28  * Checks that classes are designed for inheritance.
29  *
30  * <p>
31  * More specifically, it enforces a programming style
32  * where superclasses provide empty "hooks" that can be
33  * implemented by subclasses.
34  * </p>
35  *
36  * <p>
37  * The exact rule is that nonprivate, nonstatic methods in
38  * nonfinal classes (or classes that do not
39  * only have private constructors) must either be
40  * <ul>
41  * <li>abstract or</li>
42  * <li>final or</li>
43  * <li>have an empty implementation</li>
44  * </ul>
45  * </p>
46  *
47  * <p>
48  * This protects superclasses against beeing broken by
49  * subclasses. The downside is that subclasses are limited
50  * in their flexibility, in particular they cannot prevent
51  * execution of code in the superclass, but that also
52  * means that subclasses can't forget to call their super
53  * method.
54  * </p>
55  *
56  * @author lkuehne
57  * @version $Revision: 1.12 $
58  */

59 public class DesignForExtensionCheck extends Check
60 {
61     /** {@inheritDoc} */
62     public int[] getDefaultTokens()
63     {
64         return new int[] {TokenTypes.METHOD_DEF};
65     }
66
67     /** {@inheritDoc} */
68     public void visitToken(DetailAST aAST)
69     {
70         // nothing to do for Interfaces
71
if (ScopeUtils.inInterfaceOrAnnotationBlock(aAST)) {
72             return;
73         }
74
75         // method is ok if it is private or abstract or final
76
final DetailAST modifiers = aAST.findFirstToken(TokenTypes.MODIFIERS);
77         if (modifiers.branchContains(TokenTypes.LITERAL_PRIVATE)
78             || modifiers.branchContains(TokenTypes.ABSTRACT)
79             || modifiers.branchContains(TokenTypes.FINAL)
80             || modifiers.branchContains(TokenTypes.LITERAL_STATIC))
81         {
82             return;
83         }
84
85         // method is ok if containing class is not visible in API and
86
// cannot be extended by 3rd parties (bug #884035)
87
if (!ScopeUtils.getSurroundingScope(aAST).isIn(Scope.PROTECTED)) {
88             return;
89         }
90
91         // method is ok if it is implementation can verified to be empty
92
// Note: native methods don't have impl in java code, so
93
// implementation can be null even if method not abstract
94
final DetailAST implementation = aAST.findFirstToken(TokenTypes.SLIST);
95         if ((implementation != null)
96             && (implementation.getFirstChild().getType() == TokenTypes.RCURLY))
97         {
98             return;
99         }
100
101         // check if the containing class can be subclassed
102
final DetailAST classDef = findContainingClass(aAST);
103         final DetailAST classMods =
104             classDef.findFirstToken(TokenTypes.MODIFIERS);
105         if ((classDef.getType() == TokenTypes.ENUM_DEF)
106             || classMods.branchContains(TokenTypes.FINAL))
107         {
108             return;
109         }
110
111         // check if subclassing is prevented by having only private ctors
112
final DetailAST objBlock = classDef.findFirstToken(TokenTypes.OBJBLOCK);
113
114         boolean hasDefaultConstructor = true;
115         boolean hasExplNonPrivateCtor = false;
116
117         DetailAST candidate = (DetailAST) objBlock.getFirstChild();
118
119         while (candidate != null) {
120             if (candidate.getType() == TokenTypes.CTOR_DEF) {
121                 hasDefaultConstructor = false;
122
123                 final DetailAST ctorMods =
124                     candidate.findFirstToken(TokenTypes.MODIFIERS);
125                 if (!ctorMods.branchContains(TokenTypes.LITERAL_PRIVATE)) {
126                     hasExplNonPrivateCtor = true;
127                     break;
128                 }
129             }
130             candidate = (DetailAST) candidate.getNextSibling();
131         }
132
133         if (hasDefaultConstructor || hasExplNonPrivateCtor) {
134             final String JavaDoc name = aAST.findFirstToken(TokenTypes.IDENT).getText();
135             log(aAST.getLineNo(), aAST.getColumnNo(),
136                 "design.forExtension", name);
137         }
138
139
140
141     }
142
143     /**
144      * Searches the tree towards the root until it finds a CLASS_DEF node.
145      * @param aAST the start node for searching
146      * @return the CLASS_DEF node.
147      */

148     private DetailAST findContainingClass(DetailAST aAST)
149     {
150         DetailAST searchAST = aAST;
151         while ((searchAST.getType() != TokenTypes.CLASS_DEF)
152                && (searchAST.getType() != TokenTypes.ENUM_DEF))
153         {
154             searchAST = searchAST.getParent();
155         }
156         return searchAST;
157     }
158 }
159
Popular Tags