KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2004 Brian Goetz <briangoetz@users.sourceforge.net>
4  * Copyright (C) 2004 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
21 package edu.umd.cs.findbugs.detect;
22
23
24 import edu.umd.cs.findbugs.*;
25 import edu.umd.cs.findbugs.ba.*;
26 import edu.umd.cs.findbugs.classfile.MethodDescriptor;
27
28 import java.util.*;
29 import org.apache.bcel.Repository;
30 import org.apache.bcel.classfile.*;
31 import org.apache.bcel.generic.*;
32 ;
33
34 /**
35  * RuntimeExceptionCapture
36  *
37  * @author Brian Goetz
38  * @author Bill Pugh
39  * @author David Hovemeyer
40  */

41 public class RuntimeExceptionCapture extends BytecodeScanningDetector implements Detector, StatelessDetector {
42     private static final boolean DEBUG = SystemProperties.getBoolean("rec.debug");
43
44     private BugReporter bugReporter;
45     private Method method;
46     private OpcodeStack stack = new OpcodeStack();
47     private List<ExceptionCaught> catchList;
48     private List<ExceptionThrown> throwList;
49
50     private BugAccumulator accumulator;
51     private static class ExceptionCaught {
52         public String JavaDoc exceptionClass;
53         public int startOffset, endOffset, sourcePC;
54         public boolean seen = false;
55         public boolean dead = false;
56
57         public ExceptionCaught(String JavaDoc exceptionClass, int startOffset, int endOffset, int sourcePC) {
58             this.exceptionClass = exceptionClass;
59             this.startOffset = startOffset;
60             this.endOffset = endOffset;
61             this.sourcePC = sourcePC;
62         }
63     }
64
65     private static class ExceptionThrown {
66         public String JavaDoc exceptionClass;
67         public int offset;
68
69         public ExceptionThrown(String JavaDoc exceptionClass, int offset) {
70             this.exceptionClass = exceptionClass;
71             this.offset = offset;
72         }
73     }
74
75
76     public RuntimeExceptionCapture(BugReporter bugReporter) {
77         this.bugReporter = bugReporter;
78         accumulator = new BugAccumulator(bugReporter);
79     }
80
81
82
83     @Override JavaDoc
84          public void visitMethod(Method method) {
85         this.method = method;
86         if (DEBUG) {
87             System.out.println("RuntimeExceptionCapture visiting " + method);
88         }
89         super.visitMethod(method);
90         accumulator.reportAccumulatedBugs();
91     }
92
93     @Override JavaDoc
94          public void visitCode(Code obj) {
95         catchList = new ArrayList<ExceptionCaught>();
96         throwList = new ArrayList<ExceptionThrown>();
97                 stack.resetForMethodEntry(this);
98
99         super.visitCode(obj);
100
101         for (ExceptionCaught caughtException : catchList) {
102             Set<String JavaDoc> thrownSet = new HashSet<String JavaDoc>();
103             for (ExceptionThrown thrownException : throwList) {
104                 if (thrownException.offset >= caughtException.startOffset
105                         && thrownException.offset < caughtException.endOffset) {
106                     thrownSet.add(thrownException.exceptionClass);
107                     if (thrownException.exceptionClass.equals(caughtException.exceptionClass))
108                         caughtException.seen = true;
109                 }
110             }
111             int catchClauses = 0;
112             if (caughtException.exceptionClass.equals("java.lang.Exception") && !caughtException.seen) {
113                 // Now we have a case where Exception is caught, but not thrown
114
boolean rteCaught = false;
115                 for (ExceptionCaught otherException : catchList) {
116                     if (otherException.startOffset == caughtException.startOffset
117                             && otherException.endOffset == caughtException.endOffset) {
118                         catchClauses++;
119                         if (otherException.exceptionClass.equals("java.lang.RuntimeException"))
120                             rteCaught = true;
121                     }
122                 }
123                 int range = caughtException.endOffset - caughtException.startOffset;
124                 if (!rteCaught) {
125                     int priority = LOW_PRIORITY + 1;
126                     if (range > 300) priority--;
127                     else if (range < 30) priority++;
128                     if (catchClauses > 1) priority++;
129                     if (thrownSet.size() > 1) priority--;
130                     if (caughtException.dead) priority--;
131                     accumulator.accumulateBug(new BugInstance(this, "REC_CATCH_EXCEPTION",
132                             priority)
133                             .addClassAndMethod(this),
134                             SourceLineAnnotation.fromVisitedInstruction(getClassContext(), this, caughtException.sourcePC));
135                 }
136             }
137         }
138     }
139
140     @Override JavaDoc
141          public void visit(CodeException obj) {
142         super.visit(obj);
143         int type = obj.getCatchType();
144         if (type == 0) return;
145         String JavaDoc name = getConstantPool().constantToString(getConstantPool().getConstant(type));
146
147         ExceptionCaught caughtException =
148             new ExceptionCaught(name, obj.getStartPC(), obj.getEndPC(), obj.getHandlerPC());
149         catchList.add(caughtException);
150
151         try {
152             // See if the store that saves the exception object
153
// is alive or dead. We rely on the fact that javac
154
// always (?) emits an ASTORE instruction to save
155
// the caught exception.
156
LiveLocalStoreDataflow dataflow = getClassContext().getLiveLocalStoreDataflow(this.method);
157             CFG cfg = getClassContext().getCFG(method);
158             Collection<BasicBlock> blockList = cfg.getBlocksContainingInstructionWithOffset(obj.getHandlerPC());
159             for (BasicBlock block : blockList) {
160                 InstructionHandle first = block.getFirstInstruction();
161                 if (first != null
162                         && first.getPosition() == obj.getHandlerPC()
163                         && first.getInstruction() instanceof ASTORE) {
164                     ASTORE astore = (ASTORE) first.getInstruction();
165                     BitSet liveStoreSet = dataflow.getFactAtLocation(new Location(first, block));
166                     if (!liveStoreSet.get(astore.getIndex())) {
167                         // The ASTORE storing the exception object is dead
168
if (DEBUG) {
169                             System.out.println("Dead exception store at " + first);
170                         }
171                         caughtException.dead = true;
172                         break;
173                     }
174                 }
175             }
176         } catch (MethodUnprofitableException e) {
177             Method m = getMethod();
178             bugReporter.reportSkippedAnalysis(new MethodDescriptor(getClassName(), getMethodName(), getMethodSig(), m.isStatic()));
179         } catch (DataflowAnalysisException e) {
180             bugReporter.logError("Error checking for dead exception store", e);
181         } catch (CFGBuilderException e) {
182             bugReporter.logError("Error checking for dead exception store", e);
183         }
184     }
185
186     @Override JavaDoc
187          public void sawOpcode(int seen) {
188         stack.mergeJumps(this);
189         try {
190             switch (seen) {
191             case ATHROW:
192                 if (stack.getStackDepth() > 0) {
193                     OpcodeStack.Item item = stack.getStackItem(0);
194                     String JavaDoc signature = item.getSignature();
195                     if (signature != null && signature.length() > 0) {
196                         if (signature.startsWith("L"))
197                             signature = SignatureConverter.convert(signature);
198                         else
199                             signature = signature.replace('/', '.');
200                         throwList.add(new ExceptionThrown(signature, getPC()));
201                     }
202                 }
203                 break;
204
205             case INVOKEVIRTUAL:
206             case INVOKESPECIAL:
207             case INVOKESTATIC:
208                 String JavaDoc className = getDottedClassConstantOperand();
209                 try {
210                     if (!className.startsWith("[")) {
211                         JavaClass clazz = Repository.lookupClass(className);
212                         Method[] methods = clazz.getMethods();
213                         for (Method method : methods) {
214                             if (method.getName().equals(getNameConstantOperand())
215                                     && method.getSignature().equals(getSigConstantOperand())) {
216                                 ExceptionTable et = method.getExceptionTable();
217                                 if (et != null) {
218                                     String JavaDoc[] names = et.getExceptionNames();
219                                     for (String JavaDoc name : names)
220                                         throwList.add(new ExceptionThrown(name, getPC()));
221                                 }
222                                 break;
223                             }
224                         }
225                     }
226                 } catch (ClassNotFoundException JavaDoc e) {
227                     bugReporter.reportMissingClass(e);
228                 }
229                 break;
230             default:
231                 break;
232             }
233         } finally {
234             stack.sawOpcode(this, seen);
235         }
236     }
237
238 }
239
240 // vim:ts=4
241
Popular Tags