KickJava   Java API By Example, From Geeks To Geeks.

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


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.HashSet JavaDoc;
23
24 import org.apache.bcel.classfile.Code;
25 import org.apache.bcel.classfile.CodeException;
26 import org.apache.bcel.classfile.Constant;
27 import org.apache.bcel.classfile.ConstantClass;
28 import org.apache.bcel.classfile.ConstantPool;
29 import org.apache.bcel.classfile.JavaClass;
30 import org.apache.bcel.classfile.Method;
31 import org.apache.bcel.generic.ObjectType;
32 import org.apache.bcel.generic.ReferenceType;
33 import org.apache.bcel.generic.Type;
34
35 import edu.umd.cs.findbugs.BugAccumulator;
36 import edu.umd.cs.findbugs.BugInstance;
37 import edu.umd.cs.findbugs.BugReporter;
38 import edu.umd.cs.findbugs.BytecodeScanningDetector;
39 import edu.umd.cs.findbugs.JavaVersion;
40 import edu.umd.cs.findbugs.OpcodeStack;
41 import edu.umd.cs.findbugs.SourceLineAnnotation;
42 import edu.umd.cs.findbugs.ba.AnalysisContext;
43 import edu.umd.cs.findbugs.ba.CFGBuilderException;
44 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
45 import edu.umd.cs.findbugs.ba.Hierarchy;
46 import edu.umd.cs.findbugs.ba.ObjectTypeFactory;
47 import edu.umd.cs.findbugs.ba.type.TypeDataflow;
48
49 public class DumbMethods extends BytecodeScanningDetector {
50     
51     private static final ObjectType CONDITION_TYPE = ObjectTypeFactory.getInstance("java.util.concurrent.locks.Condition");
52
53     private HashSet JavaDoc<String JavaDoc> alreadyReported = new HashSet JavaDoc<String JavaDoc>();
54     private BugReporter bugReporter;
55     private boolean sawCurrentTimeMillis;
56     private BugInstance gcInvocationBugReport;
57     private int gcInvocationPC;
58     private CodeException[] exceptionTable;
59 /*
60    private boolean sawLDCEmptyString;
61 */

62     private String JavaDoc primitiveObjCtorSeen;
63     private boolean ctorSeen;
64     private boolean prevOpcodeWasReadLine;
65     private int prevOpcode;
66     private boolean isPublicStaticVoidMain;
67     private boolean isEqualsObject;
68     private boolean sawInstanceofCheck;
69     private boolean reportedBadCastInEquals;
70     
71     private int randomNextIntState;
72     private boolean checkForBitIorofSignedByte;
73     
74     private boolean jdk15ChecksEnabled;
75
76     private BugAccumulator accumulator;
77     public DumbMethods(BugReporter bugReporter) {
78         this.bugReporter = bugReporter;
79         accumulator = new BugAccumulator(bugReporter);
80         jdk15ChecksEnabled = JavaVersion.getRuntimeVersion().isSameOrNewerThan(JavaVersion.JAVA_1_5);
81     }
82     
83     
84     OpcodeStack stack = new OpcodeStack();
85     
86     @Override JavaDoc
87     public void visitAfter(JavaClass obj) {
88         accumulator.reportAccumulatedBugs();
89     }
90     public static boolean isTestMethod(Method method) {
91         return method.getName().startsWith("test");
92     }
93     @Override JavaDoc
94          public void visit(Method method) {
95         String JavaDoc cName = getDottedClassName();
96         stack.resetForMethodEntry(this);
97         
98         isPublicStaticVoidMain = method.isPublic() && method.isStatic()
99                 && getMethodName().equals("main")
100                 || cName.toLowerCase().indexOf("benchmark") >= 0;
101         prevOpcodeWasReadLine = false;
102         Code code = method.getCode();
103         if (code != null)
104             this.exceptionTable = code.getExceptionTable();
105         if (this.exceptionTable == null)
106             this.exceptionTable = new CodeException[0];
107         primitiveObjCtorSeen = null;
108         ctorSeen = false;
109         randomNextIntState = 0;
110         checkForBitIorofSignedByte = false;
111         isEqualsObject = getMethodName().equals("equals") && getMethodSig().equals("(Ljava/lang/Object;)Z")
112         && !method.isStatic();
113         sawInstanceofCheck = false;
114         reportedBadCastInEquals = false;
115         
116     }
117
118     @Override JavaDoc
119          public void sawOpcode(int seen) {
120         stack.mergeJumps(this);
121         String JavaDoc opcodeName = OPCODE_NAMES[seen];
122         
123         if ((seen == INVOKEVIRTUAL
124                 && getClassConstantOperand().equals("java/util/HashMap") && getNameConstantOperand()
125                 .equals("get"))
126                 || (seen == INVOKEINTERFACE
127                         && getClassConstantOperand().equals("java/util/Map") && getNameConstantOperand()
128                         .equals("get"))
129                 || (seen == INVOKEVIRTUAL
130                         && getClassConstantOperand()
131                                 .equals("java/util/HashSet") && getNameConstantOperand()
132                         .equals("contains"))
133                 || (seen == INVOKEINTERFACE
134                         && getClassConstantOperand().equals("java/util/Set") && getNameConstantOperand()
135                         .equals("contains"))) {
136             OpcodeStack.Item top = stack.getStackItem(0);
137             if (top.getSignature().equals("Ljava/net/URL;"))
138                 bugReporter.reportBug(new BugInstance(this,
139                         "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY)
140                         .addClassAndMethod(this)
141                         .addSourceLine(this));
142         }
143         
144         
145         if (isEqualsObject && !reportedBadCastInEquals) {
146             if (seen == INSTANCEOF || seen == INVOKEVIRTUAL && getNameConstantOperand().equals("getClass")
147                     && getSigConstantOperand().equals("()Ljava/lang/Class;")
148                     ) {
149                 OpcodeStack.Item item = stack.getStackItem(0);
150                 if (item.getRegisterNumber() == 1) sawInstanceofCheck = true;
151             } else if (seen == INVOKESPECIAL && getNameConstantOperand().equals("equals")
152                     && getSigConstantOperand().equals("(Ljava/lang/Object;)Z")) {
153                 OpcodeStack.Item item0 = stack.getStackItem(0);
154                 OpcodeStack.Item item1 = stack.getStackItem(1);
155                 if (item1.getRegisterNumber() + item0.getRegisterNumber() == 1)
156                      sawInstanceofCheck = true;
157             } else if (seen == CHECKCAST && !sawInstanceofCheck) {
158                 OpcodeStack.Item item = stack.getStackItem(0);
159                 if (item.getRegisterNumber() == 1) {
160                     if (getSizeOfSurroundingTryBlock(getPC()) == Integer.MAX_VALUE)
161                     bugReporter.reportBug(new BugInstance(this, "BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS",
162                              NORMAL_PRIORITY)
163                         .addClassAndMethod(this)
164                         .addSourceLine(this));
165                     
166                     reportedBadCastInEquals = true;
167                 }
168             }
169         }
170         {
171             boolean foundVacuousComparison = false;
172         if (seen == IF_ICMPGT || seen == IF_ICMPLE) {
173             OpcodeStack.Item rhs = stack.getStackItem(0);
174             Object JavaDoc rhsConstant = rhs.getConstant();
175             if (rhsConstant instanceof Integer JavaDoc && ((Integer JavaDoc)rhsConstant).intValue() == Integer.MAX_VALUE)
176                 foundVacuousComparison = true;
177             OpcodeStack.Item lhs = stack.getStackItem(1);
178             Object JavaDoc lhsConstant = lhs.getConstant();
179             if (lhsConstant instanceof Integer JavaDoc && ((Integer JavaDoc)lhsConstant).intValue() == Integer.MIN_VALUE)
180                 foundVacuousComparison = true;
181         
182         }
183         if (seen == IF_ICMPLT || seen == IF_ICMPGE) {
184             OpcodeStack.Item rhs = stack.getStackItem(0);
185             Object JavaDoc rhsConstant = rhs.getConstant();
186             if (rhsConstant instanceof Integer JavaDoc && ((Integer JavaDoc)rhsConstant).intValue() == Integer.MIN_VALUE)
187                 foundVacuousComparison = true;
188             OpcodeStack.Item lhs = stack.getStackItem(1);
189             Object JavaDoc lhsConstant = lhs.getConstant();
190             if (lhsConstant instanceof Integer JavaDoc && ((Integer JavaDoc)lhsConstant).intValue() == Integer.MAX_VALUE)
191                 foundVacuousComparison = true;
192             
193             }
194         if (foundVacuousComparison)
195             bugReporter.reportBug(new BugInstance(this, "INT_VACUOUS_COMPARISON",
196                     getBranchOffset() < 0 ? HIGH_PRIORITY : NORMAL_PRIORITY)
197                 .addClassAndMethod(this)
198                 .addSourceLine(this));
199         }
200     
201         if (seen == INVOKESTATIC &&
202                 ( getClassConstantOperand().equals("java/lang/Math") || getClassConstantOperand().equals("java/lang/StrictMath"))
203                 && getNameConstantOperand().equals("abs")
204                 && getSigConstantOperand().equals("(I)I")) {
205             OpcodeStack.Item item0 = stack.getStackItem(0);
206             int special = item0.getSpecialKind();
207             if (special == OpcodeStack.Item.RANDOM_INT)
208                 bugReporter.reportBug(new BugInstance(this, "RV_ABSOLUTE_VALUE_OF_RANDOM_INT",
209                          HIGH_PRIORITY)
210                     .addClassAndMethod(this)
211                     .addSourceLine(this));
212             else if (special == OpcodeStack.Item.HASHCODE_INT)
213                 bugReporter.reportBug(new BugInstance(this, "RV_ABSOLUTE_VALUE_OF_HASHCODE",
214                         HIGH_PRIORITY)
215                     .addClassAndMethod(this)
216                     .addSourceLine(this));
217         }
218
219         try {
220             int stackLoc = stackEntryThatMustBeNonnegative(seen);
221             if (stackLoc >= 0) {
222                 OpcodeStack.Item tos = stack.getStackItem(stackLoc);
223                 switch (tos.getSpecialKind()) {
224                 case OpcodeStack.Item.HASHCODE_INT_REMAINDER:
225                     bugReporter.reportBug(new BugInstance(this, "RV_REM_OF_HASHCODE", HIGH_PRIORITY)
226                     .addClassAndMethod(this)
227                     .addSourceLine(this));
228                     break;
229                 case OpcodeStack.Item.RANDOM_INT:
230                 case OpcodeStack.Item.RANDOM_INT_REMAINDER:
231                     bugReporter.reportBug(new BugInstance(this, "RV_REM_OF_RANDOM_INT", HIGH_PRIORITY)
232                     .addClassAndMethod(this)
233                     .addSourceLine(this));
234                     break;
235                 }
236                 
237             }
238             if (seen == IREM) {
239                 OpcodeStack.Item item0 = stack.getStackItem(0);
240                 Object JavaDoc constant0 = item0.getConstant();
241                 OpcodeStack.Item item1 = stack.getStackItem(1);
242                 int special = item1.getSpecialKind();
243                 if (constant0 instanceof Integer JavaDoc && ((Integer JavaDoc)constant0).intValue() == 1)
244                     bugReporter.reportBug(new BugInstance(this, "INT_BAD_REM_BY_1", HIGH_PRIORITY)
245                     .addClassAndMethod(this)
246                     .addSourceLine(this));
247             }
248         
249         if (stack.getStackDepth() >= 1 && (seen == LOOKUPSWITCH || seen == TABLESWITCH)) {
250             OpcodeStack.Item item0 = stack.getStackItem(0);
251             if (item0.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE) {
252                 int[] switchLabels = getSwitchLabels();
253                 int [] switchOffsets = getSwitchOffsets();
254                 for(int i = 0; i < switchLabels.length; i++) {
255                     int v = switchLabels[i];
256                     if (v <= -129 || v >= 128)
257                         bugReporter.reportBug(new BugInstance(this, "INT_BAD_COMPARISON_WITH_SIGNED_BYTE",
258                                 HIGH_PRIORITY)
259                                     .addClassAndMethod(this)
260                                     .addInt(v)
261                                     .addSourceLine(this, getPC() + switchOffsets[i]));
262
263                 }
264             }
265         }
266         // check for use of signed byte where is it assumed it can be out of the -128...127 range
267
if (stack.getStackDepth() >= 2) switch (seen) {
268         case IF_ICMPEQ:
269         case IF_ICMPNE:
270         case IF_ICMPLT:
271         case IF_ICMPLE:
272         case IF_ICMPGE:
273         case IF_ICMPGT:
274             OpcodeStack.Item item0 = stack.getStackItem(0);
275             OpcodeStack.Item item1 = stack.getStackItem(1);
276             int seen2 = seen;
277             if (item1.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE) {
278                 OpcodeStack.Item tmp = item0;
279                 item0 = item1;
280                 item1 = tmp;
281                 if (seen >= IF_ICMPLT && seen <= IF_ICMPGE)
282                     seen2 += 2;
283                 else if (seen >= IF_ICMPGT && seen <= IF_ICMPLE)
284                     seen2 -= 2;
285             }
286             Object JavaDoc constant1 = item1.getConstant();
287             if (item0.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE
288                     && constant1 instanceof Number JavaDoc) {
289                 int v1 = ((Number JavaDoc)constant1).intValue();
290                 if (v1 <= -129 || v1 >= 128 || v1 == 127 && !(seen2 == IF_ICMPEQ || seen2 == IF_ICMPNE
291                         
292                         )) {
293                     int priority = HIGH_PRIORITY;
294                     if (v1 == 127 && seen2 == IF_ICMPLE ) priority = NORMAL_PRIORITY;
295                     if (v1 == 128 && seen2 == IF_ICMPLE) priority = NORMAL_PRIORITY;
296                     if (v1 <= -129) priority = NORMAL_PRIORITY;
297                     
298                     
299                     bugReporter.reportBug(new BugInstance(this, "INT_BAD_COMPARISON_WITH_SIGNED_BYTE", priority)
300                                 .addClassAndMethod(this)
301                                 .addInt(v1)
302                                 .addSourceLine(this));
303                 }
304             }
305         }
306         if (checkForBitIorofSignedByte && seen != I2B) {
307               bugReporter.reportBug(new BugInstance(this, "BIT_IOR_OF_SIGNED_BYTE",
308                     prevOpcode == LOR ? HIGH_PRIORITY : NORMAL_PRIORITY)
309                         .addClassAndMethod(this)
310                         .addSourceLine(this));
311               checkForBitIorofSignedByte = false;
312         } else if ((seen == IOR || seen == LOR) && stack.getStackDepth() >= 2) {
313             OpcodeStack.Item item0 = stack.getStackItem(0);
314             OpcodeStack.Item item1 = stack.getStackItem(1);
315             
316             int special0 = item0.getSpecialKind();
317             int special1 = item1.getSpecialKind();
318             if (special0 == OpcodeStack.Item.SIGNED_BYTE
319                     && special1 == OpcodeStack.Item.LOW_8_BITS_CLEAR
320                     || special0 == OpcodeStack.Item.LOW_8_BITS_CLEAR && special1 == OpcodeStack.Item.SIGNED_BYTE )
321                 checkForBitIorofSignedByte = true;
322             else checkForBitIorofSignedByte = false;
323         } else checkForBitIorofSignedByte = false;
324
325     if (prevOpcodeWasReadLine && seen == INVOKEVIRTUAL
326         && getClassConstantOperand().equals("java/lang/String")
327         && getSigConstantOperand().startsWith("()")) {
328         String JavaDoc method = getNameConstantOperand();
329         String JavaDoc sig = getSigConstantOperand();
330       bugReporter.reportBug(new BugInstance(this, "NP_IMMEDIATE_DEREFERENCE_OF_READLINE", NORMAL_PRIORITY)
331         .addClassAndMethod(this)
332         .addSourceLine(this));
333         }
334
335     prevOpcodeWasReadLine =
336         (seen == INVOKEVIRTUAL||seen == INVOKEINTERFACE)
337         && getNameConstantOperand().equals("readLine")
338         && getSigConstantOperand().equals("()Ljava/lang/String;");
339
340         // System.out.println(randomNextIntState + " " + OPCODE_NAMES[seen] + " " + getMethodName());
341
switch(randomNextIntState) {
342         case 0:
343             if (seen == INVOKEVIRTUAL
344                 && getClassConstantOperand().equals("java/util/Random")
345                 && getNameConstantOperand().equals("nextDouble")
346                || seen == INVOKESTATIC
347                 && getClassConstantOperand().equals("java/lang/Math")
348                 && getNameConstantOperand().equals("random"))
349               randomNextIntState = 1;
350             break;
351         case 1:
352             if (seen == D2I) {
353               bugReporter.reportBug(new BugInstance(this, "RV_01_TO_INT", HIGH_PRIORITY)
354                     .addClassAndMethod(this)
355                     .addSourceLine(this));
356               randomNextIntState = 0;
357               }
358             else if (seen == DMUL) randomNextIntState = 4;
359             else randomNextIntState = 2;
360             break;
361         case 2:
362             if (seen == I2D) randomNextIntState = 3;
363             else if (seen == DMUL) randomNextIntState = 4;
364             else randomNextIntState = 0;
365             break;
366         case 3:
367             if (seen == DMUL) randomNextIntState = 4;
368             else randomNextIntState = 0;
369             break;
370         case 4:
371             if (seen == D2I)
372               bugReporter.reportBug(new BugInstance(this, "DM_NEXTINT_VIA_NEXTDOUBLE", NORMAL_PRIORITY)
373                     .addClassAndMethod(this)
374                     .addSourceLine(this));
375             randomNextIntState = 0;
376             break;
377         default:
378             throw new IllegalStateException JavaDoc();
379             }
380         if (isPublicStaticVoidMain && seen == INVOKEVIRTUAL
381                 && getClassConstantOperand().startsWith("javax/swing/")
382                 && (getNameConstantOperand().equals("show")
383                 && getSigConstantOperand().equals("()V")
384                 || getNameConstantOperand().equals("pack")
385                 && getSigConstantOperand().equals("()V")
386                 || getNameConstantOperand().equals("setVisible")
387                 && getSigConstantOperand().equals("(Z)V")))
388             bugReporter.reportBug(new BugInstance(this, "SW_SWING_METHODS_INVOKED_IN_SWING_THREAD", LOW_PRIORITY)
389                     .addClassAndMethod(this)
390                     .addSourceLine(this));
391         
392 // if ((seen == INVOKEVIRTUAL)
393
// && getClassConstantOperand().equals("java/lang/String")
394
// && getNameConstantOperand().equals("substring")
395
// && getSigConstantOperand().equals("(I)Ljava/lang/String;")
396
// && stack.getStackDepth() > 1) {
397
// OpcodeStack.Item item = stack.getStackItem(0);
398
// Object o = item.getConstant();
399
// if (o != null && o instanceof Integer) {
400
// int v = ((Integer) o).intValue();
401
// if (v == 0)
402
// bugReporter.reportBug(new BugInstance(this, "DMI_USELESS_SUBSTRING", NORMAL_PRIORITY)
403
// .addClassAndMethod(this)
404
// .addSourceLine(this));
405
// }
406
// }
407

408         if ((seen == INVOKEVIRTUAL)
409                 && getNameConstantOperand().equals("isAnnotationPresent")
410                 && getSigConstantOperand().equals("(Ljava/lang/Class;)Z")
411                 && stack.getStackDepth() > 0) {
412             OpcodeStack.Item item = stack.getStackItem(0);
413             Object JavaDoc value = item.getConstant();
414             if (value instanceof String JavaDoc) {
415                 String JavaDoc annotationClassName = (String JavaDoc) value;
416                 boolean lacksClassfileRetention
417                 = AnalysisContext.currentAnalysisContext().getAnnotationRetentionDatabase().lacksClassfileRetention(
418                         annotationClassName.replace('/','.'));
419                 if (lacksClassfileRetention)
420                     bugReporter.reportBug(new BugInstance(this, "DMI_ANNOTATION_IS_NOT_VISIBLE_TO_REFLECTION",
421                         HIGH_PRIORITY)
422                         .addClassAndMethod(this)
423                         .addSourceLine(this)
424                         .addCalledMethod(this));
425             }
426
427         }
428         if ((seen == INVOKEVIRTUAL)
429                 && getNameConstantOperand().equals("next")
430                 && getSigConstantOperand().equals("()Ljava/lang/Object;")
431                 && getMethodName().equals("hasNext")
432                 && getMethodSig().equals("()Z")
433                 && stack.getStackDepth() > 0) {
434             OpcodeStack.Item item = stack.getStackItem(0);
435             
436                 bugReporter.reportBug(new BugInstance(this, "DMI_CALLING_NEXT_FROM_HASNEXT",
437                         item.isInitialParameter() && item.getRegisterNumber() == 0 ? NORMAL_PRIORITY : LOW_PRIORITY)
438                         .addClassAndMethod(this)
439                         .addSourceLine(this)
440                         .addCalledMethod(this));
441             
442         }
443             
444     
445         if ((seen == INVOKESPECIAL)
446                 && getClassConstantOperand().equals("java/lang/String")
447                 && getNameConstantOperand().equals("<init>")
448                 && getSigConstantOperand().equals("(Ljava/lang/String;)V"))
449             if (alreadyReported.add(getRefConstantOperand()))
450                 bugReporter.reportBug(new BugInstance(this, "DM_STRING_CTOR", NORMAL_PRIORITY)
451                         .addClassAndMethod(this)
452                         .addSourceLine(this));
453         if (seen == INVOKESTATIC
454                 && getClassConstantOperand().equals("java/lang/System")
455                 && getNameConstantOperand().equals("runFinalizersOnExit")
456             || seen == INVOKEVIRTUAL
457                 && getClassConstantOperand().equals("java/lang/Runtime")
458                 && getNameConstantOperand().equals("runFinalizersOnExit"))
459                 bugReporter.reportBug(new BugInstance(this, "DM_RUN_FINALIZERS_ON_EXIT", HIGH_PRIORITY)
460                         .addClassAndMethod(this)
461                         .addSourceLine(this));
462         if ((seen == INVOKESPECIAL)
463                 && getClassConstantOperand().equals("java/lang/String")
464                 && getNameConstantOperand().equals("<init>")
465                 && getSigConstantOperand().equals("()V"))
466             if (alreadyReported.add(getRefConstantOperand()))
467                 bugReporter.reportBug(new BugInstance(this, "DM_STRING_VOID_CTOR", NORMAL_PRIORITY)
468                         .addClassAndMethod(this)
469                         .addSourceLine(this));
470         if (!isPublicStaticVoidMain && seen == INVOKESTATIC
471                 && getClassConstantOperand().equals("java/lang/System")
472                 && getNameConstantOperand().equals("exit")
473                 && !getMethodName().equals("processWindowEvent")
474                 && !getMethodName().startsWith("windowClos")
475                 && getMethodName().indexOf("exit") == -1
476                 && getMethodName().indexOf("Exit") == -1
477                 && getMethodName().indexOf("crash") == -1
478                 && getMethodName().indexOf("Crash") == -1
479                 && getMethodName().indexOf("die") == -1
480                 && getMethodName().indexOf("Die") == -1
481                 && getMethodName().indexOf("main") == -1)
482             accumulator.accumulateBug(new BugInstance(this, "DM_EXIT",
483                 getMethod().isStatic() ? LOW_PRIORITY : NORMAL_PRIORITY)
484                     .addClassAndMethod(this),
485                         SourceLineAnnotation.fromVisitedInstruction(this));
486         if (((seen == INVOKESTATIC
487                 && getClassConstantOperand().equals("java/lang/System"))
488                 || (seen == INVOKEVIRTUAL
489                 && getClassConstantOperand().equals("java/lang/Runtime")))
490                 && getNameConstantOperand().equals("gc")
491                 && getSigConstantOperand().equals("()V")
492                 && !getDottedClassName().startsWith("java.lang")
493                 && !getMethodName().startsWith("gc")
494                 && !getMethodName().endsWith("gc"))
495             if (alreadyReported.add(getRefConstantOperand())) {
496                 // System.out.println("Saw call to GC");
497
if (isPublicStaticVoidMain) {
498                     // System.out.println("Skipping GC complaint in main method");
499
return;
500                 }
501                 if (isTestMethod(getMethod())) return;
502                 // Just save this report in a field; it will be flushed
503
// IFF there were no calls to System.currentTimeMillis();
504
// in the method.
505
gcInvocationBugReport = new BugInstance(this, "DM_GC", HIGH_PRIORITY)
506                         .addClassAndMethod(this)
507                         .addSourceLine(this);
508                 gcInvocationPC = getPC();
509                 //System.out.println("GC invocation at pc " + PC);
510
}
511         if ((seen == INVOKESPECIAL)
512                 && getClassConstantOperand().equals("java/lang/Boolean")
513                 && getNameConstantOperand().equals("<init>")
514                 && !getClassName().equals("java/lang/Boolean")
515         )
516             if (alreadyReported.add(getRefConstantOperand()))
517                 bugReporter.reportBug(new BugInstance(this, "DM_BOOLEAN_CTOR", NORMAL_PRIORITY)
518                         .addClassAndMethod(this)
519                         .addSourceLine(this));
520         if ((seen == INVOKESTATIC)
521                 && getClassConstantOperand().equals("java/lang/System")
522                 && (getNameConstantOperand().equals("currentTimeMillis")
523                    || getNameConstantOperand().equals("nanoTime")))
524             sawCurrentTimeMillis = true;
525         if ((seen == INVOKEVIRTUAL)
526                 && getClassConstantOperand().equals("java/lang/String")
527                 && getNameConstantOperand().equals("toString")
528                 && getSigConstantOperand().equals("()Ljava/lang/String;"))
529             if (alreadyReported.add(getRefConstantOperand()))
530                 bugReporter.reportBug(new BugInstance(this, "DM_STRING_TOSTRING", NORMAL_PRIORITY)
531                         .addClassAndMethod(this)
532                         .addSourceLine(this));
533         if ((seen == INVOKEVIRTUAL)
534                 && getClassConstantOperand().equals("java/lang/String")
535                 && (getNameConstantOperand().equals("toUpperCase")
536                 || getNameConstantOperand().equals("toLowerCase"))
537                 && getSigConstantOperand().equals("()Ljava/lang/String;"))
538             if (alreadyReported.add(getRefConstantOperand()))
539                 bugReporter.reportBug(new BugInstance(this, "DM_CONVERT_CASE", LOW_PRIORITY)
540                         .addClassAndMethod(this)
541                         .addSourceLine(this));
542         
543         if ((seen == INVOKESPECIAL) && getNameConstantOperand().equals("<init>")) {
544             String JavaDoc cls = getClassConstantOperand();
545             String JavaDoc sig = getSigConstantOperand();
546             if ((cls.equals("java/lang/Integer") && sig.equals("(I)V"))
547             || (cls.equals("java/lang/Float") && sig.equals("(F)V"))
548             || (cls.equals("java/lang/Double") && sig.equals("(D)V"))
549             || (cls.equals("java/lang/Long") && sig.equals("(J)V"))
550             || (cls.equals("java/lang/Byte") && sig.equals("(B)V"))
551             || (cls.equals("java/lang/Character") && sig.equals("(C)V"))
552             || (cls.equals("java/lang/Short") && sig.equals("(S)V"))
553             || (cls.equals("java/lang/Boolean") && sig.equals("(Z)V"))) {
554                 primitiveObjCtorSeen = cls;
555             } else {
556                 primitiveObjCtorSeen = null;
557             }
558         } else if ((primitiveObjCtorSeen != null)
559                && (seen == INVOKEVIRTUAL)
560                && getNameConstantOperand().equals("toString")
561                && getClassConstantOperand().equals(primitiveObjCtorSeen)
562                && getSigConstantOperand().equals("()Ljava/lang/String;")) {
563                 bugReporter.reportBug(new BugInstance(this, "DM_BOXED_PRIMITIVE_TOSTRING", LOW_PRIORITY)
564                         .addClassAndMethod(this)
565                         .addSourceLine(this));
566             primitiveObjCtorSeen = null;
567         }
568         else
569             primitiveObjCtorSeen = null;
570             
571         if ((seen == INVOKESPECIAL) && getNameConstantOperand().equals("<init>")) {
572             ctorSeen = true;
573         } else if (ctorSeen
574                 && (seen == INVOKEVIRTUAL)
575                 && getClassConstantOperand().equals("java/lang/Object")
576                 && getNameConstantOperand().equals("getClass")
577                 && getSigConstantOperand().equals("()Ljava/lang/Class;")) {
578                     accumulator.accumulateBug(new BugInstance(this, "DM_NEW_FOR_GETCLASS", LOW_PRIORITY)
579                             .addClassAndMethod(this), this);
580             ctorSeen = false;
581         } else {
582             ctorSeen = false;
583         }
584
585         if (jdk15ChecksEnabled
586                 && (seen == INVOKEVIRTUAL)
587                 && isMonitorWait(getNameConstantOperand(), getSigConstantOperand())) {
588             checkMonitorWait();
589         }
590
591
592         if ((seen == INVOKESPECIAL)
593         && getNameConstantOperand().equals("<init>")
594         && getClassConstantOperand().equals("java/lang/Thread")) {
595             String JavaDoc sig = getSigConstantOperand();
596             if (sig.equals("()V")
597             || sig.equals("(Ljava/lang/String;)V")
598             || sig.equals("(Ljava/lang/ThreadGroup;Ljava/lang/String;)V"))
599                 if (!getMethodName().equals("<init>") || (getPC() > 20)) {
600                     bugReporter.reportBug(new BugInstance(this, "DM_USELESS_THREAD", LOW_PRIORITY)
601                             .addClassAndMethod(this)
602                             .addSourceLine(this));
603                 }
604         }
605             
606                 
607     } finally {
608         stack.sawOpcode(this,seen);
609         prevOpcode = seen;
610     }
611     }
612
613     /**
614      * Return index of stack entry that must be nonnegative.
615      *
616      * Return -1 if no stack entry is required to be nonnegative.
617      * @param seen
618      * @return
619      */

620     private int stackEntryThatMustBeNonnegative(int seen) {
621         switch(seen) {
622         case INVOKEINTERFACE:
623             if (getClassConstantOperand().equals("java/util/List")) {
624                 return getStackEntryOfListCallThatMustBeNonnegative();
625             }
626             break;
627         case INVOKEVIRTUAL:
628             if (getClassConstantOperand().equals("java/util/LinkedList") || getClassConstantOperand().equals("java/util/ArrayList")) {
629                 return getStackEntryOfListCallThatMustBeNonnegative();
630             }
631             break;
632                    
633         case IALOAD:
634         case AALOAD:
635         case SALOAD:
636         case CALOAD:
637         case BALOAD:
638         case LALOAD:
639         case DALOAD:
640         case FALOAD:
641             return 0;
642         case IASTORE:
643         case AASTORE:
644         case SASTORE:
645         case CASTORE:
646         case BASTORE:
647         case LASTORE:
648         case DASTORE:
649         case FASTORE:
650             return 1;
651         }
652         return -1;
653     }
654     private int getStackEntryOfListCallThatMustBeNonnegative() {
655         String JavaDoc name = getNameConstantOperand();
656         if ((name.equals("add") || name.equals("set"))
657             && getSigConstantOperand().startsWith("(I"))
658             return 1;
659         if ((name.equals("get") || name.equals("remove"))
660                 && getSigConstantOperand().startsWith("(I)"))
661                 return 0;
662         return -1;
663     }
664     private void checkMonitorWait() {
665         try {
666             TypeDataflow typeDataflow = getClassContext().getTypeDataflow(getMethod());
667             TypeDataflow.LocationAndFactPair pair = typeDataflow.getLocationAndFactForInstruction(getPC());
668             
669             if (pair == null)
670                 return;
671
672             Type receiver = pair.frame.getInstance(
673                     pair.location.getHandle().getInstruction(),
674                     getClassContext().getConstantPoolGen()
675             );
676             
677             if (!(receiver instanceof ReferenceType))
678                 return;
679             
680             if (Hierarchy.isSubtype((ReferenceType) receiver, CONDITION_TYPE)) {
681                 bugReporter.reportBug(new BugInstance("DM_MONITOR_WAIT_ON_CONDITION", HIGH_PRIORITY)
682                         .addClassAndMethod(this)
683                         .addSourceLine(this));
684             }
685         } catch (ClassNotFoundException JavaDoc e) {
686             bugReporter.reportMissingClass(e);
687         } catch (DataflowAnalysisException e) {
688             bugReporter.logError("Exception caught by DumbMethods", e);
689         } catch (CFGBuilderException e) {
690             bugReporter.logError("Exception caught by DumbMethods", e);
691         }
692     }
693
694     private boolean isMonitorWait(String JavaDoc name, String JavaDoc sig) {
695 // System.out.println("Check call " + name + "," + sig);
696
return name.equals("wait")
697                 && (sig.equals("()V") || sig.equals("(J)V") || sig.equals("(JI)V"));
698     }
699
700     @Override JavaDoc
701     public void visit(Code obj) {
702         super.visit(obj);
703         flush();
704     }
705
706     /**
707      * A heuristic - how long a catch block for OutOfMemoryError might be.
708      */

709     private static final int OOM_CATCH_LEN = 20;
710
711     /**
712      * Flush out cached state at the end of a method.
713      */

714     private void flush() {
715         if (gcInvocationBugReport != null && !sawCurrentTimeMillis) {
716             // Make sure the GC invocation is not in an exception handler
717
// for OutOfMemoryError.
718
boolean outOfMemoryHandler = false;
719             for (CodeException handler : exceptionTable) {
720                 if (gcInvocationPC < handler.getHandlerPC() ||
721                         gcInvocationPC > handler.getHandlerPC() + OOM_CATCH_LEN)
722                     continue;
723                 int catchTypeIndex = handler.getCatchType();
724                 if (catchTypeIndex > 0) {
725                     ConstantPool cp = getThisClass().getConstantPool();
726                     Constant constant = cp.getConstant(catchTypeIndex);
727                     if (constant instanceof ConstantClass) {
728                         String JavaDoc exClassName = (String JavaDoc) ((ConstantClass) constant).getConstantValue(cp);
729                         if (exClassName.equals("java/lang/OutOfMemoryError")) {
730                             outOfMemoryHandler = true;
731                             break;
732                         }
733                     }
734                 }
735             }
736
737             if (!outOfMemoryHandler)
738                 bugReporter.reportBug(gcInvocationBugReport);
739         }
740
741         sawCurrentTimeMillis = false;
742         gcInvocationBugReport = null;
743         alreadyReported.clear();
744         exceptionTable = null;
745     }
746 }
747
Popular Tags