KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > PruneUnconditionalExceptionThrowerEdges


1 /*
2  * Bytecode Analysis Framework
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.ba;
21
22 import java.util.BitSet JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import org.apache.bcel.Constants;
30 import org.apache.bcel.Repository;
31 import org.apache.bcel.classfile.JavaClass;
32 import org.apache.bcel.classfile.Method;
33 import org.apache.bcel.generic.ConstantPoolGen;
34 import org.apache.bcel.generic.Instruction;
35 import org.apache.bcel.generic.InvokeInstruction;
36 import org.apache.bcel.generic.MethodGen;
37
38 import edu.umd.cs.findbugs.AnalysisLocal;
39 import edu.umd.cs.findbugs.SystemProperties;
40 import edu.umd.cs.findbugs.ba.ch.Subtypes;
41
42 public class PruneUnconditionalExceptionThrowerEdges implements EdgeTypes {
43     private static final boolean DEBUG = SystemProperties.getBoolean("cfg.prune.throwers.debug");
44
45     private MethodGen methodGen;
46     private CFG cfg;
47     private ConstantPoolGen cpg;
48     private AnalysisContext analysisContext;
49     private boolean cfgModified;
50     
51     private static final BitSet JavaDoc RETURN_OPCODE_SET = new BitSet JavaDoc();
52     static {
53         RETURN_OPCODE_SET.set(Constants.ARETURN);
54         RETURN_OPCODE_SET.set(Constants.IRETURN);
55         RETURN_OPCODE_SET.set(Constants.LRETURN);
56         RETURN_OPCODE_SET.set(Constants.DRETURN);
57         RETURN_OPCODE_SET.set(Constants.FRETURN);
58         RETURN_OPCODE_SET.set(Constants.RETURN);
59     }
60
61     public PruneUnconditionalExceptionThrowerEdges(MethodGen methodGen, CFG cfg, ConstantPoolGen cpg,
62                                                    AnalysisContext analysisContext) {
63         this.methodGen = methodGen;
64         this.cfg = cfg;
65         this.cpg = cpg;
66         this.analysisContext = analysisContext;
67     }
68
69     static AnalysisLocal<Map JavaDoc<XMethod,Boolean JavaDoc>> cachedResults = new AnalysisLocal<Map JavaDoc<XMethod,Boolean JavaDoc>>() {
70         @Override JavaDoc
71         public Map JavaDoc<XMethod,Boolean JavaDoc> initialValue() {
72             return new HashMap JavaDoc<XMethod,Boolean JavaDoc>();
73         }
74     };
75     
76     public void execute() throws CFGBuilderException, DataflowAnalysisException {
77         AnalysisContext currentAnalysisContext = AnalysisContext.currentAnalysisContext();
78         if (currentAnalysisContext.getBoolProperty(AnalysisFeatures.CONSERVE_SPACE))
79             throw new IllegalStateException JavaDoc("This should not happen");
80
81         Set JavaDoc<Edge> deletedEdgeSet = new HashSet JavaDoc<Edge>();
82
83         if (DEBUG)
84             System.out.println("PruneUnconditionalExceptionThrowerEdges: examining " +
85                     SignatureConverter.convertMethodSignature(methodGen));
86          Subtypes subtypes = AnalysisContext.currentAnalysisContext()
87             .getSubtypes();
88         for (Iterator JavaDoc<BasicBlock> i = cfg.blockIterator(); i.hasNext();) {
89             BasicBlock basicBlock = i.next();
90             if (!basicBlock.isExceptionThrower())
91                 continue;
92
93             Instruction exceptionThrower = basicBlock.getExceptionThrower().getInstruction();
94             if (!(exceptionThrower instanceof InvokeInstruction))
95                 continue;
96
97             InvokeInstruction inv = (InvokeInstruction) exceptionThrower;
98             try {
99                 
100                 String JavaDoc className = inv.getClassName(cpg);
101                 if (DEBUG) System.out.println("\tlooking up method for " + basicBlock.getExceptionThrower() + " in " + className);
102                 
103                 if (className.startsWith("["))
104                     continue;
105                 String JavaDoc methodSig = inv.getSignature(cpg);
106                 if (!methodSig.endsWith("V"))
107                     continue;
108                 
109                 XMethod xMethod = XFactory.createXMethod(inv, cpg);
110                 JavaClass javaClass = Repository.lookupClass(xMethod.getClassName());
111                 
112                 JavaClassAndMethod classAndMethod = Hierarchy.findMethod(javaClass, xMethod.getName(), xMethod.getSignature(), Hierarchy.CONCRETE_METHOD);
113                 if (classAndMethod == null) {
114                     if (DEBUG) System.out.println("\tNOT FOUND");
115                     continue;
116                 }
117                 Method method = classAndMethod.getMethod();
118                 if (DEBUG) System.out.println("\tFound " + xMethod);
119         
120                 if (!(method.isStatic() || method.isPrivate() || method.isFinal() || javaClass.isFinal() || !subtypes.hasSubtypes(javaClass))) {
121                     if (!Repository.instanceOf(methodGen.getClassName(), javaClass)) continue;
122                 }
123                 
124                 // Ignore abstract and native methods
125
if (method.getCode() == null) continue;
126                 Boolean JavaDoc isUnconditionalThrower = doesMethodUnconditionallyThrowException(xMethod, javaClass, method);
127                 if (false && isUnconditionalThrower.booleanValue()) {
128                     ClassContext classContext = analysisContext.getClassContext(javaClass);
129                     MethodGen calledMethodGen = classContext.getMethodGen(method);
130                     // Ignore abstract and native methods
131

132                     if (calledMethodGen == null)
133                         continue;
134
135                     // Analyze exception paths of called method
136
// to see if it always throws an unhandled exception.
137
CFG calledCFG = classContext.getCFG(method);
138                     ReturnPathDataflow pathDataflow = classContext
139                             .getReturnPathDataflow(method);
140                     ReturnPath pathValue = pathDataflow.getStartFact(calledCFG
141                             .getExit());
142
143                     isUnconditionalThrower = pathValue.getKind() != ReturnPath.RETURNS;
144                     // System.out.println("isThrower: " + result + " " + method.getCode().getLength() + " " + method);
145
if (true) cachedResults.get().put(xMethod, isUnconditionalThrower);
146                 }
147
148                 if (isUnconditionalThrower.booleanValue()) {
149                     // Method always throws an unhandled exception
150
// Remove the normal control flow edge from the CFG.
151
Edge fallThrough = cfg.getOutgoingEdgeWithType(basicBlock,
152                             FALL_THROUGH_EDGE);
153                     if (fallThrough != null) {
154                         if (DEBUG) {
155                             System.out.println("\tREMOVING normal return for: " + xMethod);
156                         }
157                         deletedEdgeSet.add(fallThrough);
158                     }
159                 }
160             } catch (ClassNotFoundException JavaDoc e) {
161                 analysisContext.getLookupFailureCallback().reportMissingClass(e);
162             }
163         }
164
165         // Remove all edges marked for deletion
166
for (Edge edge : deletedEdgeSet) {
167             cfg.removeEdge(edge);
168             cfgModified = true;
169         }
170     }
171
172     /**
173      * @param xMethod
174      * @param javaClass
175      * @param method
176      * @return true if method unconditionally throws
177      */

178     static public Boolean JavaDoc doesMethodUnconditionallyThrowException(XMethod xMethod, JavaClass javaClass, Method method) {
179         Boolean JavaDoc isUnconditionalThrower = cachedResults.get().get(xMethod);
180         
181         
182         if (isUnconditionalThrower == null) {
183             isUnconditionalThrower = Boolean.FALSE;
184             try {
185                 ClassContext classContext = AnalysisContext.currentAnalysisContext().getClassContext(javaClass);
186                 BitSet JavaDoc bytecodeSet = classContext.getBytecodeSet(method);
187                 if (bytecodeSet != null) {
188
189                     if (DEBUG) System.out.println("\tChecking " + xMethod);
190                     isUnconditionalThrower = Boolean.valueOf(!bytecodeSet.intersects(RETURN_OPCODE_SET));
191                     if (DEBUG && isUnconditionalThrower) {
192                         System.out.println("Is unconditional thrower");
193                         System.out.println("Return opcode set: " + RETURN_OPCODE_SET);
194                         System.out.println("Code opcode set: " + bytecodeSet);
195                     }
196                 }
197             } catch (Exception JavaDoc e) {
198                 // ignore it
199
}
200
201             cachedResults.get().put(xMethod, isUnconditionalThrower);
202
203         }
204         return isUnconditionalThrower;
205     }
206     
207     /**
208      * Return whether or not the CFG was modified.
209      *
210      * @return true if CFG was modified, false otherwise
211      */

212     public boolean wasCFGModified() {
213         return cfgModified;
214     }
215 }
216
217 // vim:ts=4
218
Popular Tags