001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2005 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle.checks.usage;
020:
021: import com.puppycrawl.tools.checkstyle.api.DetailAST;
022: import com.puppycrawl.tools.checkstyle.api.FullIdent;
023: import com.puppycrawl.tools.checkstyle.api.Scope;
024: import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
025: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026:
027: /**
028: * <p>Checks that a private method is used.
029: * </p>
030: * <p>
031: * An example of how to configure the check is:
032: * </p>
033: * <pre>
034: * <module name="usage.UnusedPrivateMethod"/>
035: * </pre>
036: *
037: * @author Rick Giles
038: */
039: public class UnusedPrivateMethodCheck extends AbstractUsageCheck
040:
041: {
042: /** Controls if checks skips serialization methods.*/
043: private boolean mAllowSerializationMethods;
044:
045: /** @see com.puppycrawl.tools.checkstyle.api.Check */
046: public int[] getDefaultTokens() {
047: return new int[] { TokenTypes.METHOD_DEF, };
048: }
049:
050: /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */
051: public String getErrorKey() {
052: return "unused.method";
053: }
054:
055: /**
056: * Configure the check to allow (or not) serialization-related methods.
057: * @param aFlag new value for allowSerializationMethods value.
058: */
059: public void setAllowSerializationMethods(boolean aFlag) {
060: mAllowSerializationMethods = aFlag;
061: }
062:
063: /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */
064: public boolean mustCheckReferenceCount(DetailAST aAST) {
065: final DetailAST mods = aAST
066: .findFirstToken(TokenTypes.MODIFIERS);
067: if ((mods == null)
068: || (ScopeUtils.getScopeFromMods(mods) != Scope.PRIVATE)) {
069: return false;
070: }
071:
072: return !mAllowSerializationMethods
073: || !(isWriteObject(aAST) || isReadObject(aAST) || isWriteReplaceOrReadResolve(aAST));
074: }
075:
076: /**
077: * Checks if a given method is writeObject().
078: * @param aAST method def to check
079: * @return true if this is a writeObject() definition
080: */
081: private boolean isWriteObject(DetailAST aAST) {
082: // name is writeObject...
083: final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT);
084: if (!"writeObject".equals(ident.getText())) {
085: return false;
086: }
087:
088: // returns void...
089: final DetailAST typeAST = (DetailAST) aAST.findFirstToken(
090: TokenTypes.TYPE).getFirstChild();
091: if (typeAST.getType() != TokenTypes.LITERAL_VOID) {
092: return false;
093: }
094:
095: // should have one parameter...
096: final DetailAST params = aAST
097: .findFirstToken(TokenTypes.PARAMETERS);
098: if (params == null || params.getChildCount() != 1) {
099: return false;
100: }
101: // and paramter's type should be java.io.ObjectOutputStream
102: final DetailAST type = (DetailAST) ((DetailAST) params
103: .getFirstChild()).findFirstToken(TokenTypes.TYPE)
104: .getFirstChild();
105: final String typeName = FullIdent.createFullIdent(type)
106: .getText();
107: if (!"java.io.ObjectOutputStream".equals(typeName)
108: && !"ObjectOutputStream".equals(typeName)) {
109: return false;
110: }
111:
112: // and, finally, it should throws java.io.IOException
113: final DetailAST throwsAST = aAST
114: .findFirstToken(TokenTypes.LITERAL_THROWS);
115: if (throwsAST == null || throwsAST.getChildCount() != 1) {
116: return false;
117: }
118: final DetailAST expt = (DetailAST) throwsAST.getFirstChild();
119: final String exceptionName = FullIdent.createFullIdent(expt)
120: .getText();
121: if (!"java.io.IOException".equals(exceptionName)
122: && !"IOException".equals(exceptionName)) {
123: return false;
124: }
125:
126: return true;
127: }
128:
129: /**
130: * Checks if a given method is readObject().
131: * @param aAST method def to check
132: * @return true if this is a readObject() definition
133: */
134: private boolean isReadObject(DetailAST aAST) {
135: // name is readObject...
136: final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT);
137: if (!"readObject".equals(ident.getText())) {
138: return false;
139: }
140:
141: // returns void...
142: final DetailAST typeAST = (DetailAST) aAST.findFirstToken(
143: TokenTypes.TYPE).getFirstChild();
144: if (typeAST.getType() != TokenTypes.LITERAL_VOID) {
145: return false;
146: }
147:
148: // should have one parameter...
149: final DetailAST params = aAST
150: .findFirstToken(TokenTypes.PARAMETERS);
151: if (params == null || params.getChildCount() != 1) {
152: return false;
153: }
154: // and paramter's type should be java.io.ObjectInputStream
155: final DetailAST type = (DetailAST) ((DetailAST) params
156: .getFirstChild()).findFirstToken(TokenTypes.TYPE)
157: .getFirstChild();
158: final String typeName = FullIdent.createFullIdent(type)
159: .getText();
160: if (!"java.io.ObjectInputStream".equals(typeName)
161: && !"ObjectInputStream".equals(typeName)) {
162: return false;
163: }
164:
165: // and, finally, it should throws java.io.IOException
166: // and java.lang.ClassNotFoundException
167: final DetailAST throwsAST = aAST
168: .findFirstToken(TokenTypes.LITERAL_THROWS);
169: if (throwsAST == null || throwsAST.getChildCount() != 3) {
170: return false;
171: }
172: final DetailAST excpt1 = (DetailAST) throwsAST.getFirstChild();
173: final String exception1 = FullIdent.createFullIdent(excpt1)
174: .getText();
175: final String exception2 = FullIdent.createFullIdent(
176: throwsAST.getLastChild()).getText();
177: if (!"java.io.IOException".equals(exception1)
178: && !"IOException".equals(exception1)
179: && !"java.io.IOException".equals(exception2)
180: && !"IOException".equals(exception2)
181: || !"java.lang.ClassNotFoundException"
182: .equals(exception1)
183: && !"ClassNotFoundException".equals(exception1)
184: && !"java.lang.ClassNotFoundException"
185: .equals(exception2)
186: && !"ClassNotFoundException".equals(exception2)) {
187: return false;
188: }
189:
190: return true;
191: }
192:
193: /**
194: * Checks if a given method is writeReplace() or readResolve().
195: * @param aAST method def to check
196: * @return true if this is a writeReplace() definition
197: */
198: private boolean isWriteReplaceOrReadResolve(DetailAST aAST) {
199: // name is writeReplace or readResolve...
200: final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT);
201: if (!"writeReplace".equals(ident.getText())
202: && !"readResolve".equals(ident.getText())) {
203: return false;
204: }
205:
206: // returns Object...
207: final DetailAST typeAST = (DetailAST) aAST.findFirstToken(
208: TokenTypes.TYPE).getFirstChild();
209: if (typeAST.getType() != TokenTypes.DOT
210: && typeAST.getType() != TokenTypes.IDENT) {
211: return false;
212: }
213:
214: // should have no parameters...
215: final DetailAST params = aAST
216: .findFirstToken(TokenTypes.PARAMETERS);
217: if (params != null && params.getChildCount() != 0) {
218: return false;
219: }
220:
221: // and, finally, it should throws java.io.ObjectStreamException
222: final DetailAST throwsAST = aAST
223: .findFirstToken(TokenTypes.LITERAL_THROWS);
224: if (throwsAST == null || throwsAST.getChildCount() != 1) {
225: return false;
226: }
227: final DetailAST excpt = (DetailAST) throwsAST.getFirstChild();
228: final String exception = FullIdent.createFullIdent(excpt)
229: .getText();
230: if (!"java.io.ObjectStreamException".equals(exception)
231: && !"ObjectStreamException".equals(exception)) {
232: return false;
233: }
234:
235: return true;
236: }
237: }
|