KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 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.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Set JavaDoc;
27
28 import org.apache.bcel.Repository;
29 import org.apache.bcel.generic.MethodGen;
30
31 import edu.umd.cs.findbugs.SystemProperties;
32 import edu.umd.cs.findbugs.ba.type.ExceptionSet;
33 import edu.umd.cs.findbugs.ba.type.TypeAnalysis;
34 import edu.umd.cs.findbugs.ba.type.TypeDataflow;
35
36 /**
37  * Prune a CFG to remove infeasible exception edges.
38  * In order to determine what kinds of exceptions can be thrown by
39  * explicit ATHROW instructions, type analysis must first be
40  * performed on the unpruned CFG.
41  *
42  * @author David Hovemeyer
43  * @see CFG
44  * @see TypeAnalysis
45  */

46 public class PruneInfeasibleExceptionEdges implements EdgeTypes {
47     private static final boolean DEBUG = SystemProperties.getBoolean("cfg.prune.debug");
48     private static final boolean STATS = SystemProperties.getBoolean("cfg.prune.stats");
49     private static int numEdgesPruned = 0;
50
51     static {
52         if (STATS) {
53             Runtime.getRuntime().addShutdownHook(new Thread JavaDoc() {
54                 @Override JavaDoc
55                 public void run() {
56                     System.err.println("Exception edges pruned: " + numEdgesPruned);
57                 }
58             });
59         }
60     }
61
62     /**
63      * A momento to remind us of how we classified a particular
64      * exception edge. If pruning and classifying succeeds,
65      * then these momentos can be applied to actually change
66      * the state of the edges. The issue is that the entire
67      * pruning/classifying operation must either fail or succeed
68      * as a whole. Thus, we don't commit any CFG changes until
69      * we know everything was successful.
70      */

71     private static class MarkedEdge {
72         private Edge edge;
73         private int flag;
74
75         public MarkedEdge(Edge edge, int flag) {
76             this.edge = edge;
77             this.flag = flag;
78         }
79
80         public void apply() {
81             int flags = edge.getFlags();
82             flags |= this.flag;
83             edge.setFlags(flags);
84         }
85     }
86
87     private CFG cfg;
88     private TypeDataflow typeDataflow;
89     private boolean cfgModified;
90
91     /**
92      * Constructor.
93      *
94      * @param cfg the CFG to prune
95      * @param methodGen the method
96      * @param typeDataflow initialized TypeDataflow object for the CFG,
97      * indicating the types of all stack locations
98      */

99     public PruneInfeasibleExceptionEdges(CFG cfg, MethodGen methodGen, TypeDataflow typeDataflow) {
100         this.cfg = cfg;
101         this.typeDataflow = typeDataflow;
102     }
103
104     /**
105      * Prune infeasible exception edges from the CFG.
106      * If the method returns normally, then the operation
107      * was successful, and the CFG should no longer contain infeasible
108      * exception edges. If ClassNotFoundException or DataflowAnalysisException
109      * are thrown, then the operation was unsuccessful,
110      * <em>but the CFG is still valid because it was not modified</em>.
111      * If a runtime exception is thrown, then the CFG may be
112      * partially modified and should be considered invalid.
113      */

114     public void execute() throws ClassNotFoundException JavaDoc {
115         Set JavaDoc<Edge> deletedEdgeSet = new HashSet JavaDoc<Edge>();
116         List JavaDoc<MarkedEdge> markedEdgeList = new LinkedList JavaDoc<MarkedEdge>();
117
118         // Mark edges to delete,
119
// mark edges to set properties of
120
for (Iterator JavaDoc<Edge> i = cfg.edgeIterator(); i.hasNext();) {
121             Edge edge = i.next();
122             if (!edge.isExceptionEdge())
123                 continue;
124
125             ExceptionSet exceptionSet = typeDataflow.getEdgeExceptionSet(edge);
126             if (exceptionSet.isEmpty()) {
127                 // No exceptions are actually thrown on this edge,
128
// so we can delete the edge.
129
deletedEdgeSet.add(edge);
130             } else {
131                 if (exceptionSet.isSingleton("java.lang.CloneNotSupportedException") && cfg.getMethodName().endsWith(".clone()")){
132                     String JavaDoc className = cfg.getMethodGen().getClassName();
133                     if (Repository.implementationOf(className,"java.lang.Cloneable")) {
134                         deletedEdgeSet.add(edge);
135                         continue;
136                     }
137                 }
138                 // Some exceptions appear to be thrown on the edge.
139
// Mark to indicate if any of the exceptions are checked,
140
// and if any are explicit (checked or explicitly declared
141
// or thrown unchecked).
142
boolean someChecked = exceptionSet.containsCheckedExceptions();
143                 boolean someExplicit = exceptionSet.containsExplicitExceptions();
144
145                 int flags = 0;
146                 if (someChecked) flags |= CHECKED_EXCEPTIONS_FLAG;
147                 if (someExplicit) flags |= EXPLICIT_EXCEPTIONS_FLAG;
148
149                 markedEdgeList.add(new MarkedEdge(edge, flags));
150             }
151         }
152
153         // Remove deleted edges
154
for (Edge edge : deletedEdgeSet) {
155             cfg.removeEdge(edge);
156             if (STATS) ++numEdgesPruned;
157             cfgModified = true;
158         }
159
160         // Mark edges
161
for (MarkedEdge markedEdge : markedEdgeList) {
162             markedEdge.apply();
163         }
164     }
165
166     /**
167      * @return true if modified
168      */

169     public boolean wasCFGModified() {
170         return cfgModified;
171     }
172 }
173
174 // vim:ts=4
175
Popular Tags