KickJava   Java API By Example, From Geeks To Geeks.

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


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.HashMap JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.TreeSet JavaDoc;
28
29 import org.apache.bcel.generic.ConstantPoolGen;
30 import org.apache.bcel.generic.Instruction;
31 import org.apache.bcel.generic.InstructionHandle;
32 import org.apache.bcel.generic.ObjectType;
33 import org.apache.bcel.generic.Type;
34 import org.apache.bcel.generic.TypedInstruction;
35
36 import edu.umd.cs.findbugs.ResourceCollection;
37 import edu.umd.cs.findbugs.ba.BasicBlock;
38 import edu.umd.cs.findbugs.ba.Edge;
39 import edu.umd.cs.findbugs.ba.Location;
40 import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback;
41 import edu.umd.cs.findbugs.ba.ResourceTracker;
42 import edu.umd.cs.findbugs.ba.ResourceValueFrame;
43 import edu.umd.cs.findbugs.ba.ResourceValueFrameModelingVisitor;
44
45 /**
46  * Resource tracker which determines where streams are created,
47  * and how they are used within the method.
48  *
49  * @author David Hovemeyer
50  */

51 public class StreamResourceTracker implements ResourceTracker<Stream> {
52     private StreamFactory[] streamFactoryList;
53     private RepositoryLookupFailureCallback lookupFailureCallback;
54     private ResourceCollection<Stream> resourceCollection;
55
56     /**
57      * Map of locations where streams are opened to the actual
58      * Stream objects.
59      */

60     private Map JavaDoc<Location, Stream> streamOpenLocationMap;
61
62     /**
63      * Set of all open locations and escapes of uninteresting streams.
64      */

65     //private HashSet<Location> uninterestingStreamEscapeSet;
66
private HashSet JavaDoc<Stream> uninterestingStreamEscapeSet;
67
68     /**
69      * Set of all (potential) stream escapes.
70      */

71     private TreeSet JavaDoc<StreamEscape> streamEscapeSet;
72
73     /**
74      * Map of individual streams to equivalence classes.
75      * Any time a stream "A" is wrapped with a stream "B",
76      * "A" and "B" belong to the same equivalence class.
77      * If any stream in an equivalence class is closed,
78      * then we consider all of the streams in the equivalence
79      * class as having been closed.
80      */

81     private Map JavaDoc<Stream, StreamEquivalenceClass> streamEquivalenceMap;
82
83     /**
84      * Constructor.
85      *
86      * @param streamFactoryList array of StreamFactory objects which determine
87      * where streams are created
88      * @param lookupFailureCallback used when class hierarchy lookups fail
89      */

90     //@SuppressWarnings("EI2")
91
public StreamResourceTracker(StreamFactory[] streamFactoryList,
92                                  RepositoryLookupFailureCallback lookupFailureCallback) {
93
94         this.streamFactoryList = streamFactoryList;
95         this.lookupFailureCallback = lookupFailureCallback;
96         this.streamOpenLocationMap = new HashMap JavaDoc<Location, Stream>();
97         this.uninterestingStreamEscapeSet = new HashSet JavaDoc<Stream>();
98         this.streamEscapeSet = new TreeSet JavaDoc<StreamEscape>();
99         this.streamEquivalenceMap = new HashMap JavaDoc<Stream, StreamEquivalenceClass>();
100     }
101
102     /**
103      * Set the precomputed ResourceCollection for the method.
104      */

105     public void setResourceCollection(ResourceCollection<Stream> resourceCollection) {
106         this.resourceCollection = resourceCollection;
107     }
108
109     /**
110      * Indicate that a stream escapes at the given target Location.
111      *
112      * @param source the Stream that is escaping
113      * @param target the target Location (where the stream escapes)
114      */

115     public void addStreamEscape(Stream source, Location target) {
116         StreamEscape streamEscape = new StreamEscape(source, target);
117         streamEscapeSet.add(streamEscape);
118         if (FindOpenStream.DEBUG)
119             System.out.println("Adding potential stream escape " + streamEscape);
120     }
121
122     /**
123      * Transitively mark all streams into which uninteresting streams
124      * (such as System.out) escape. This handles the rule that
125      * wrapping an uninteresting stream makes the wrapper uninteresting
126      * as well.
127      */

128     public void markTransitiveUninterestingStreamEscapes() {
129         // Eliminate all stream escapes where the target isn't really
130
// a stream open location point.
131
for (Iterator JavaDoc<StreamEscape> i = streamEscapeSet.iterator(); i.hasNext();) {
132             StreamEscape streamEscape = i.next();
133             if (!isStreamOpenLocation(streamEscape.target)) {
134                 if (FindOpenStream.DEBUG)
135                     System.out.println("Eliminating false stream escape " + streamEscape);
136                 i.remove();
137             }
138         }
139
140         // Build initial stream equivalence classes.
141
// Each stream starts out in its own separate
142
// equivalence class.
143
for (Iterator JavaDoc<Stream> i = resourceCollection.resourceIterator(); i.hasNext();) {
144             Stream stream = i.next();
145             StreamEquivalenceClass equivalenceClass = new StreamEquivalenceClass();
146             equivalenceClass.addMember(stream);
147             streamEquivalenceMap.put(stream, equivalenceClass);
148         }
149
150         // Starting with the set of uninteresting stream open location points,
151
// propagate all uninteresting stream escapes. Iterate until there
152
// is no change. This also builds the map of stream equivalence classes.
153
Set JavaDoc<Stream> orig = new HashSet JavaDoc<Stream>();
154         do {
155             orig.clear();
156             orig.addAll(uninterestingStreamEscapeSet);
157
158             for (StreamEscape streamEscape : streamEscapeSet) {
159                 if (isUninterestingStreamEscape(streamEscape.source)) {
160                     if (FindOpenStream.DEBUG)
161                         System.out.println("Propagating stream escape " + streamEscape);
162                     Stream target = streamOpenLocationMap.get(streamEscape.target);
163                     if (target == null)
164                         throw new IllegalStateException JavaDoc();
165                     uninterestingStreamEscapeSet.add(target);
166
167                     // Combine equivalence classes for source and target
168
StreamEquivalenceClass sourceClass = streamEquivalenceMap.get(streamEscape.source);
169                     StreamEquivalenceClass targetClass = streamEquivalenceMap.get(target);
170                     if (sourceClass != targetClass) {
171                         sourceClass.addAll(targetClass);
172                         for (Iterator JavaDoc<Stream> j = targetClass.memberIterator(); j.hasNext();) {
173                             Stream stream = j.next();
174                             streamEquivalenceMap.put(stream, sourceClass);
175                         }
176                     }
177                 }
178             }
179         } while (!orig.equals(uninterestingStreamEscapeSet));
180     }
181
182     /**
183      * Determine if an uninteresting stream escapes at given location.
184      * markTransitiveUninterestingStreamEscapes() should be called first.
185      *
186      * @param stream the stream
187      * @return true if an uninteresting stream escapes at the location
188      */

189     public boolean isUninterestingStreamEscape(Stream stream) {
190         return uninterestingStreamEscapeSet.contains(stream);
191     }
192
193     /**
194      * Indicate that a stream is constructed at this Location.
195      *
196      * @param streamOpenLocation the Location
197      * @param stream the Stream opened at this Location
198      */

199     public void addStreamOpenLocation(Location streamOpenLocation, Stream stream) {
200         if (FindOpenStream.DEBUG)
201             System.out.println("Stream open location at " + streamOpenLocation);
202         streamOpenLocationMap.put(streamOpenLocation, stream);
203         if (stream.isUninteresting())
204             uninterestingStreamEscapeSet.add(stream);
205     }
206
207     /**
208      * Get the equivalence class for given stream.
209      * May only be called if markTransitiveUninterestingStreamEscapes()
210      * has been called.
211      *
212      * @param stream the stream
213      * @return the set containing the equivalence class for the given stream
214      */

215     public StreamEquivalenceClass getStreamEquivalenceClass(Stream stream) {
216         return streamEquivalenceMap.get(stream);
217     }
218
219     /**
220      * Determine if given Location is a stream open location point.
221      *
222      * @param location the Location
223      */

224     private boolean isStreamOpenLocation(Location location) {
225         return streamOpenLocationMap.get(location) != null;
226     }
227
228     public Stream isResourceCreation(BasicBlock basicBlock, InstructionHandle handle,
229                                      ConstantPoolGen cpg) {
230
231         // Use precomputed map of Locations to Stream creations,
232
// if present. Note that we don't care about preexisting
233
// resources here.
234
if (resourceCollection != null)
235             return resourceCollection.getCreatedResource(new Location(handle, basicBlock));
236
237         Instruction ins = handle.getInstruction();
238         if (!(ins instanceof TypedInstruction))
239             return null;
240
241         Type type = ((TypedInstruction) ins).getType(cpg);
242         if (!(type instanceof ObjectType))
243             return null;
244
245         Location location = new Location(handle, basicBlock);
246
247         // All StreamFactories are given an opportunity to
248
// look at the location and possibly identify a created stream.
249
for (StreamFactory aStreamFactoryList : streamFactoryList) {
250             Stream stream = aStreamFactoryList.createStream(location, (ObjectType) type,
251                     cpg, lookupFailureCallback);
252             if (stream != null)
253                 return stream;
254         }
255
256         return null;
257     }
258
259     public boolean isResourceOpen(BasicBlock basicBlock, InstructionHandle handle,
260                                   ConstantPoolGen cpg, Stream resource, ResourceValueFrame frame) {
261         return resource.isStreamOpen(basicBlock, handle, cpg, frame);
262     }
263
264     public boolean isResourceClose(BasicBlock basicBlock, InstructionHandle handle,
265                                    ConstantPoolGen cpg, Stream resource, ResourceValueFrame frame) {
266         return resource.isStreamClose(basicBlock, handle, cpg, frame, lookupFailureCallback);
267     }
268
269     public ResourceValueFrameModelingVisitor createVisitor(Stream resource, ConstantPoolGen cpg) {
270         return new StreamFrameModelingVisitor(cpg, this, resource);
271     }
272     
273     public boolean ignoreImplicitExceptions(Stream resource) {
274         return resource.ignoreImplicitExceptions();
275     }
276
277     public boolean ignoreExceptionEdge(Edge edge, Stream resource, ConstantPoolGen cpg) {
278         return false;
279     }
280
281     public boolean isParamInstance(Stream resource, int slot) {
282         return resource.getInstanceParam() == slot;
283     }
284 }
285
286 // vim:ts=3
287
Popular Tags