KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > UselessSubclassMethod


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2005 Dave Brosius <dbrosius@users.sourceforge.net>
4  * Copyright (C) 2005 University of Maryland
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */

20 package edu.umd.cs.findbugs.detect;
21
22
23 import edu.umd.cs.findbugs.*;
24 import edu.umd.cs.findbugs.ba.ClassContext;
25 import java.util.*;
26 import org.apache.bcel.*;
27 import org.apache.bcel.classfile.*;
28 import org.apache.bcel.generic.Type;
29
30 public class UselessSubclassMethod extends BytecodeScanningDetector implements StatelessDetector {
31
32     public static final int SEEN_NOTHING = 0;
33     public static final int SEEN_PARM = 1;
34     public static final int SEEN_LAST_PARM = 2;
35     public static final int SEEN_INVOKE = 3;
36     public static final int SEEN_RETURN = 4;
37     public static final int SEEN_INVALID = 5;
38     
39     private BugReporter bugReporter;
40     private String JavaDoc superclassName;
41     private int state;
42     private int curParm;
43     private int curParmOffset;
44     private int invokePC;
45     private Type[] argTypes;
46     private Set<String JavaDoc> interfaceMethods = null;
47     
48     public UselessSubclassMethod(BugReporter bugReporter) {
49         this.bugReporter = bugReporter;
50     }
51
52
53     
54     @Override JavaDoc
55          public void visitClassContext(ClassContext classContext) {
56         try {
57             JavaClass cls = classContext.getJavaClass();
58             superclassName = cls.getSuperclassName();
59             JavaClass[] interfaces = null;
60             if (cls.isClass() && ((cls.getAccessFlags() & Constants.ACC_ABSTRACT) != 0)) {
61                 interfaces = cls.getAllInterfaces();
62                 interfaceMethods = new HashSet<String JavaDoc>();
63                 for (JavaClass aInterface : interfaces) {
64                     Method[] infMethods = aInterface.getMethods();
65                     for (Method meth : infMethods) {
66                         interfaceMethods.add(meth.getName() + meth.getSignature());
67                     }
68                 }
69             }
70         } catch (ClassNotFoundException JavaDoc cnfe) {
71             bugReporter.reportMissingClass(cnfe);
72         }
73         super.visitClassContext(classContext);
74     }
75     
76     @Override JavaDoc
77     public void visitAfter(JavaClass obj) {
78         interfaceMethods = null;
79         super.visitAfter(obj);
80     }
81     
82     @Override JavaDoc
83          public void visitMethod(Method obj) {
84         if ((interfaceMethods != null) && ((obj.getAccessFlags() & Constants.ACC_ABSTRACT) != 0)) {
85             String JavaDoc curDetail = obj.getName() + obj.getSignature();
86             for (String JavaDoc infMethodDetail : interfaceMethods) {
87                 if (curDetail.equals(infMethodDetail))
88                     bugReporter.reportBug(new BugInstance(this, "USM_USELESS_ABSTRACT_METHOD", LOW_PRIORITY)
89                             .addClassAndMethod(getClassContext().getJavaClass(), obj));
90             }
91         }
92         super.visitMethod(obj);
93     }
94     
95     @Override JavaDoc
96          public void visitCode(Code obj)
97     {
98         try {
99             String JavaDoc methodName = getMethodName();
100             
101             if (!methodName.equals("<init>")
102             && !methodName.equals("clone")
103             && ((getMethod().getAccessFlags() & (Constants.ACC_STATIC|Constants.ACC_SYNTHETIC)) == 0)) {
104                 
105                 /* for some reason, access flags doesn't return Synthetic, so do this hocus pocus */
106                 Attribute[] atts = getMethod().getAttributes();
107                 for (Attribute att : atts) {
108                     if (att.getClass().equals(Synthetic.class))
109                         return;
110                 }
111                 
112                 byte[] codeBytes = obj.getCode();
113                 if ((codeBytes.length == 0) || (codeBytes[0] != ALOAD_0))
114                     return;
115                 
116                 state = SEEN_NOTHING;
117                 invokePC = 0;
118                 super.visitCode(obj);
119                 if ((state == SEEN_RETURN) && (invokePC != 0)) {
120                     //Do this check late, as it is potentially expensive
121
Method superMethod = findSuperclassMethod(superclassName, getMethod());
122                     if ((superMethod == null) || accessModifiersAreDifferent(getMethod(), superMethod))
123                         return;
124     
125                     bugReporter.reportBug( new BugInstance( this, "USM_USELESS_SUBCLASS_METHOD", LOW_PRIORITY )
126                         .addClassAndMethod(this)
127                         .addSourceLine(this, invokePC));
128                 }
129             }
130         }
131         catch (ClassNotFoundException JavaDoc cnfe) {
132             bugReporter.reportMissingClass(cnfe);
133         }
134     }
135     
136     @Override JavaDoc
137          public void sawOpcode(int seen) {
138         switch (state) {
139             case SEEN_NOTHING:
140                 if (seen == ALOAD_0) {
141                     argTypes = Type.getArgumentTypes(this.getMethodSig());
142                     curParm = 0;
143                     curParmOffset = 1;
144                     if (argTypes.length > 0)
145                         state = SEEN_PARM;
146                     else
147                         state = SEEN_LAST_PARM;
148                 } else
149                     state = SEEN_INVALID;
150             break;
151             
152             case SEEN_PARM:
153                 if (curParm >= argTypes.length)
154                     state = SEEN_INVALID;
155                 else {
156                     String JavaDoc signature = argTypes[curParm++].getSignature();
157                     char typeChar0 = signature.charAt(0);
158                     if ((typeChar0 == 'L') || (typeChar0 == '[')) {
159                         checkParm(seen, ALOAD_0, ALOAD, 1);
160                     }
161                     else if (typeChar0 == 'D') {
162                         checkParm(seen, DLOAD_0, DLOAD, 2);
163                     }
164                     else if (typeChar0 == 'F') {
165                         checkParm(seen, FLOAD_0, FLOAD, 1);
166                     }
167                     else if (typeChar0 == 'I') {
168                         checkParm(seen, ILOAD_0, ILOAD, 1);
169                     }
170                     else if (typeChar0 == 'J') {
171                         checkParm(seen, LLOAD_0, LLOAD, 2);
172                     }
173                     if ((state != SEEN_INVALID) && (curParm >= argTypes.length))
174                         state = SEEN_LAST_PARM;
175                         
176                 }
177             break;
178             
179             case SEEN_LAST_PARM:
180                 if ((seen == INVOKENONVIRTUAL) && getMethodName().equals(getNameConstantOperand()) && getMethodSig().equals(getSigConstantOperand())) {
181                     invokePC = getPC();
182                     state = SEEN_INVOKE;
183                 }
184                 else
185                     state = SEEN_INVALID;
186             break;
187             
188             case SEEN_INVOKE:
189                 Type returnType = getMethod().getReturnType();
190                 char retSigChar0 = returnType.getSignature().charAt(0);
191                 if ((retSigChar0 == 'V') && (seen == RETURN))
192                     state = SEEN_RETURN;
193                 else if (((retSigChar0 == 'L') || (retSigChar0 == '[')) && (seen == ARETURN))
194                     state = SEEN_RETURN;
195                 else if ((retSigChar0 == 'D') && (seen == DRETURN))
196                     state = SEEN_RETURN;
197                 else if ((retSigChar0 == 'F') && (seen == FRETURN))
198                     state = SEEN_RETURN;
199                 else if ((retSigChar0 == 'I') && (seen == IRETURN))
200                     state = SEEN_RETURN;
201                 else if ((retSigChar0 == 'J') && (seen == LRETURN))
202                     state = SEEN_RETURN;
203                 else
204                     state = SEEN_INVALID;
205             break;
206             
207             case SEEN_RETURN:
208                 state = SEEN_INVALID;
209             break;
210         }
211     }
212     
213     private void checkParm(int seen, int fastOpBase, int slowOp, int parmSize) {
214         if ((curParmOffset >= 1) && (curParmOffset <= 3)) {
215             if (seen == (fastOpBase + curParmOffset))
216                 curParmOffset += parmSize;
217             else
218                 state = SEEN_INVALID;
219         }
220         else if (curParmOffset == 0)
221             state = SEEN_INVALID;
222         else if ((seen == slowOp) && (getRegisterOperand() == curParmOffset))
223             curParmOffset += parmSize;
224         else
225             state = SEEN_INVALID;
226     }
227     
228     private Method findSuperclassMethod(String JavaDoc superclassName, Method subclassMethod)
229         throws ClassNotFoundException JavaDoc {
230         
231         String JavaDoc methodName = subclassMethod.getName();
232         Type[] subArgs = null;
233         JavaClass superClass = Repository.lookupClass(superclassName);
234         Method[] methods = superClass.getMethods();
235         outer:
236         for (Method m : methods) {
237             if (m.getName().equals(methodName)) {
238                 if (subArgs == null)
239                     subArgs = Type.getArgumentTypes(subclassMethod.getSignature());
240                 Type[] superArgs = Type.getArgumentTypes(m.getSignature());
241                 if (subArgs.length == superArgs.length) {
242                     for (int j = 0; j < subArgs.length; j++) {
243                         if (!superArgs[j].equals(subArgs[j]))
244                             continue outer;
245                     }
246                     return m;
247                 }
248             }
249         }
250         
251         if(!superclassName.equals("Object")) {
252             String JavaDoc superSuperClassName = superClass.getSuperclassName();
253             if (superSuperClassName.equals(superclassName)) {
254                 throw new ClassNotFoundException JavaDoc(
255                     "superclass of " + superclassName + " is itself");
256                 }
257             return findSuperclassMethod(superClass.getSuperclassName(), subclassMethod);
258             }
259         
260         return null;
261     }
262     
263     private boolean accessModifiersAreDifferent(Method m1, Method m2) {
264         int access1 = m1.getAccessFlags() & (Constants.ACC_PRIVATE|Constants.ACC_PROTECTED|Constants.ACC_PUBLIC);
265         int access2 = m2.getAccessFlags() & (Constants.ACC_PRIVATE|Constants.ACC_PROTECTED|Constants.ACC_PUBLIC);
266
267         return access1 != access2;
268     }
269 }
270
Popular Tags