KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003-2005 University of Maryland
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
20 package edu.umd.cs.findbugs.detect;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.BitSet JavaDoc;
24
25 import org.apache.bcel.Constants;
26 import org.apache.bcel.classfile.JavaClass;
27 import org.apache.bcel.classfile.Method;
28 import org.apache.bcel.generic.ConstantPoolGen;
29 import org.apache.bcel.generic.InstructionHandle;
30 import org.apache.bcel.generic.InvokeInstruction;
31 import org.apache.bcel.generic.MethodGen;
32
33 import edu.umd.cs.findbugs.AnalysisLocal;
34 import edu.umd.cs.findbugs.BugInstance;
35 import edu.umd.cs.findbugs.BugReporter;
36 import edu.umd.cs.findbugs.ByteCodePatternDetector;
37 import edu.umd.cs.findbugs.JavaVersion;
38 import edu.umd.cs.findbugs.StatelessDetector;
39 import edu.umd.cs.findbugs.SystemProperties;
40 import edu.umd.cs.findbugs.ba.ClassContext;
41 import edu.umd.cs.findbugs.ba.bcp.ByteCodePattern;
42 import edu.umd.cs.findbugs.ba.bcp.ByteCodePatternMatch;
43 import edu.umd.cs.findbugs.ba.bcp.Invoke;
44 import edu.umd.cs.findbugs.ba.bcp.MatchAny;
45 import edu.umd.cs.findbugs.ba.bcp.Opcode;
46 import edu.umd.cs.findbugs.ba.bcp.PatternElement;
47
48 /**
49  * This detector looks for places where the return value of a method
50  * is suspiciously ignored. Ignoring the return values from immutable
51  * objects such as java.lang.String are a common and easily found type of bug.
52  *
53  * @author David Hovemeyer
54  * @author Bill Pugh
55  */

56 public @Deprecated JavaDoc class BCPMethodReturnCheck extends ByteCodePatternDetector {
57     private final BugReporter bugReporter;
58
59     private static final boolean CHECK_ALL = SystemProperties.getBoolean("mrc.checkall");
60
61     private static AnalysisLocal<ByteCodePattern> localByteCodePattern
62             = new AnalysisLocal<ByteCodePattern>();
63
64         private static AnalysisLocal<ArrayList JavaDoc<PatternElement>> localPatternElementList
65             = new AnalysisLocal<ArrayList JavaDoc<PatternElement>>();
66
67     
68
69     
70     @Override JavaDoc
71          public ByteCodePattern getPattern() {
72         ByteCodePattern result = localByteCodePattern.get();
73         if (result == null) {
74             ArrayList JavaDoc<PatternElement> list = getPatternElementList();
75             PatternElement [] calls = list.toArray(new PatternElement[list.size()]);
76             // The ByteCodePattern which specifies the kind of code pattern
77
// we're looking for. We want to match the invocation of certain methods
78
// followed by a POP or POP2 instruction.
79
result = new ByteCodePattern()
80                 .add(new MatchAny(calls).label("call").setAllowTrailingEdges(false))
81                 .add(new MatchAny(new PatternElement[]{new Opcode(Constants.POP), new Opcode(Constants.POP2)}));
82             localByteCodePattern.set(result);
83             }
84         return result;
85         }
86
87     public static void
88         addMethodWhoseReturnMustBeChecked(String JavaDoc className, String JavaDoc methodName,
89                 String JavaDoc methodSig, int mode) {
90         ArrayList JavaDoc<PatternElement> list = getPatternElementList();
91         list.add(new Invoke(className, methodName, methodSig, mode, null));
92         localByteCodePattern.remove();
93         }
94             
95     /**
96      * Return List of PatternElement objects representing
97      * method invocations requiring a return value check.
98      */

99     private static
100         ArrayList JavaDoc<PatternElement> getPatternElementList() {
101         ArrayList JavaDoc<PatternElement> list = localPatternElementList.get();
102         if (list != null) return list;
103
104         list = new ArrayList JavaDoc<PatternElement>();
105
106         // Standard return check methods
107
list.add(new Invoke("/.*", "equals",
108                 "/\\(Ljava/lang/Object;\\)Z",
109                 Invoke.INSTANCE, null));
110         list.add(new Invoke("java.lang.String", "/.*",
111                 "/\\(.*\\)Ljava/lang/String;",
112                 Invoke.INSTANCE, null));
113         list.add(new Invoke("java.lang.StringBuffer", "toString",
114                 "()Ljava/lang/String;",
115                 Invoke.INSTANCE,
116                 null));
117         list.add(new Invoke("+java.lang.Thread", "<init>",
118                 "/.*",
119                 Invoke.CONSTRUCTOR,
120                 null));
121         list.add(new Invoke("+java.lang.Throwable", "<init>",
122                 "/.*",
123                 Invoke.CONSTRUCTOR,
124                 null));
125         list.add(new Invoke("java.security.MessageDigest",
126                 "digest", "([B)[B",
127                 Invoke.INSTANCE, null));
128         list.add(new Invoke("+java.sql.Connection", "/.*", "/.*",
129                 Invoke.INSTANCE, null));
130 // list.add(new Invoke("+java.net.InetAddress", "/.*", "/.*",
131
// Invoke.INSTANCE, null));
132
list.add(new Invoke("java.math.BigDecimal", "/.*", "/.*",
133                 Invoke.INSTANCE, null));
134         list.add(new Invoke("java.math.BigInteger", "/.*", "/.*",
135                 Invoke.INSTANCE, null));
136         list.add(new Invoke("+java.util.Enumeration", "hasMoreElements", "()Z", Invoke.INSTANCE, null));
137         list.add(new Invoke("+java.util.Iterator", "hasNext", "()Z", Invoke.INSTANCE, null));
138         list.add(new Invoke("java.io.File", "createNewFile", "()Z", Invoke.INSTANCE, null));
139
140         if (CHECK_ALL ||
141                 JavaVersion.getRuntimeVersion().isSameOrNewerThan(JavaVersion.JAVA_1_5)) {
142             // Add JDK 1.5 and later return check functions
143
list.add(new Invoke("+java.util.concurrent.locks.ReadWriteLock",
144                     "readLock",
145                     "()Ljava/util/concurrent/locks/Lock;",
146                     Invoke.INSTANCE,
147                     null));
148             list.add(new Invoke("+java.util.concurrent.locks.ReadWriteLock",
149                     "writeLock",
150                     "()Ljava/util/concurrent/locks/Lock;",
151                     Invoke.INSTANCE,
152                     null));
153             list.add(new Invoke("+java.util.concurrent.locks.Condition",
154                     "await",
155                     "(JLjava/util/concurrent/TimeUnit;)Z",
156                     Invoke.INSTANCE,
157                     null));
158             list.add(new Invoke("+java.util.concurrent.locks.Condition",
159                     "awaitUtil",
160                     "(Ljava/util/Date;)Z",
161                     Invoke.INSTANCE,
162                     null));
163             list.add(new Invoke("+java.util.concurrent.locks.Condition",
164                     "awaitNanos",
165                     "(J)Z",
166                     Invoke.INSTANCE,
167                     null));
168             list.add(new Invoke("+java.util.concurrent.Semaphore",
169                     "tryAcquire",
170                     "(JLjava/util/concurrent/TimeUnit;)Z",
171                     Invoke.INSTANCE,
172                     null));
173             list.add(new Invoke("+java.util.concurrent.Semaphore",
174                     "tryAcquire",
175                     "()Z",
176                     Invoke.INSTANCE,
177                     null));
178             list.add(new Invoke("+java.util.concurrent.locks.Lock",
179                     "tryLock",
180                     "(JLjava/util/concurrent/TimeUnit;)Z",
181                     Invoke.INSTANCE,
182                     null));
183             list.add(new Invoke("+java.util.concurrent.locks.Lock",
184                     "newCondition",
185                     "()Ljava/util/concurrent/locks/Condition;",
186                     Invoke.INSTANCE,
187                     null));
188             list.add(new Invoke("+java.util.concurrent.locks.Lock",
189                     "tryLock",
190                     "()Z",
191                     Invoke.INSTANCE,
192                     null));
193             list.add(new Invoke("+java.util.Queue",
194                     "offer",
195                     "(Ljava/lang/Object;)Z",
196                     Invoke.INSTANCE,
197                     null));
198             list.add(new Invoke("+java.util.concurrent.BlockingQueue",
199                     "offer",
200                     "(Ljava/lang/Object;JLjava/util/concurrent/TimeUnit;)Z",
201                     Invoke.INSTANCE,
202                     null));
203             list.add(new Invoke("+java.util.concurrent.BlockingQueue",
204                     "poll",
205                     "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;",
206                     Invoke.INSTANCE,
207                     null));
208             list.add(new Invoke("+java.util.Queue",
209                     "poll",
210                     "()Ljava/lang/Object;",
211                     Invoke.INSTANCE,
212                     null));
213         }
214
215
216         String JavaDoc externalCheckReturnValues = SystemProperties.getProperty("checkReturnValues");
217         if (externalCheckReturnValues != null) {
218             String JavaDoc [] checks = externalCheckReturnValues.split("[|]");
219             for (String JavaDoc check : checks) {
220                 String JavaDoc [] parts = check.split(":");
221                 if (parts.length != 3) continue;
222                 Invoke in =
223                         new Invoke(parts[0], parts[1], parts[2], Invoke.INSTANCE, null);
224                 list.add(in);
225             }
226             }
227             
228         
229         localPatternElementList.set(list);
230         return list;
231     }
232
233     /**
234      * Constructor.
235      *
236      * @param bugReporter the BugReporter to report bug instances with
237      */

238     public BCPMethodReturnCheck(BugReporter bugReporter) {
239         this.bugReporter = bugReporter;
240
241     }
242
243     //@Override
244
@Override JavaDoc
245          protected BugReporter getBugReporter() {
246         return bugReporter;
247     }
248
249
250     @Override JavaDoc
251          public boolean prescreen(Method method, ClassContext classContext) {
252         // Pre-screen for methods with POP or POP2 bytecodes.
253
// This gives us a speedup close to 5X.
254
BitSet JavaDoc bytecodeSet = classContext.getBytecodeSet(method);
255         return bytecodeSet != null && (bytecodeSet.get(Constants.POP) || bytecodeSet.get(Constants.POP2));
256     }
257
258     @Override JavaDoc
259          public void reportMatch(ClassContext classContext, Method method, ByteCodePatternMatch match) {
260         MethodGen methodGen = classContext.getMethodGen(method);
261         if (methodGen == null) return;
262         JavaClass javaClass = classContext.getJavaClass();
263
264         InstructionHandle call = match.getLabeledInstruction("call");
265
266         // Ignore inner-class access methods
267
InvokeInstruction inv = (InvokeInstruction) call.getInstruction();
268         ConstantPoolGen cp = methodGen.getConstantPool();
269         String JavaDoc calledMethodName = inv.getMethodName(cp);
270         if (calledMethodName.startsWith("access$")
271                 || calledMethodName.startsWith("access+"))
272             return;
273
274         /*
275         System.out.println("Found " + calledMethodName);
276         System.out.println(inv.getSignature(cp));
277         System.out.println(inv.getClassName(cp));
278         */

279         String JavaDoc calledMethodClass = inv.getClassName(cp);
280         if (inv.getSignature(cp).endsWith("V") && !calledMethodName.equals("<init>"))
281             return;
282         /*
283         if (calledMethodClass.equals(javaClass.getClassName()))
284             return;
285         */

286         String JavaDoc sourceFile = javaClass.getSourceFileName();
287         /*
288         System.out.println("CalledMethodClass: " + calledMethodClass);
289         System.out.println("CalledMethodName: " + calledMethodName);
290         */

291         int priority = HIGH_PRIORITY;
292         if (calledMethodName.equals("createNewFile"))
293             priority = LOW_PRIORITY;
294
295         if ( calledMethodClass.startsWith("java.lang")
296             || calledMethodClass.startsWith("java.math")
297                 || calledMethodClass.endsWith("Error")
298                 || calledMethodClass.endsWith("Exception"))
299             priority--;
300         if (calledMethodClass.equals(javaClass.getClassName()))
301             priority++;
302         String JavaDoc calledPackage = extractPackageName(calledMethodClass);
303         String JavaDoc callingPackage = extractPackageName(javaClass.getClassName());
304         if (calledPackage.length() > 0
305                 && callingPackage.length() > 0
306                 && (calledPackage.startsWith(callingPackage)
307                 || callingPackage.startsWith(calledPackage)))
308             priority++;
309         // System.out.println("priority: " + priority);
310

311         bugReporter.reportBug(new BugInstance(this, "RV_RETURN_VALUE_IGNORED2",
312                 priority)
313                 .addClassAndMethod(methodGen, sourceFile)
314                 .addCalledMethod(methodGen, inv)
315                 .addSourceLine(classContext, methodGen, sourceFile, call));
316     }
317
318     public static String JavaDoc extractPackageName(String JavaDoc className) {
319         int i = className.lastIndexOf('.');
320         if (i == -1) return "";
321         return className.substring(0, i);
322     }
323
324 }
325
326 // vim:ts=4
327
Popular Tags