public void analyzeMethod(ClassContext classContext, Method method, StreamResourceTracker resourceTracker,
ResourceCollection<Stream> resourceCollection) throws CFGBuilderException, DataflowAnalysisException {
potentialOpenStreamList.clear();
JavaClass javaClass = classContext.getJavaClass();
MethodGen methodGen = classContext.getMethodGen(method);
if (methodGen == null) {
return;
}
CFG cfg = classContext.getCFG(method);
// Add Streams passed into the method as parameters.
// These are uninteresting, and should poison
// any streams which wrap them.
try {
Type[] parameterTypeList = Type.getArgumentTypes(methodGen.getSignature());
Location firstLocation = new Location(cfg.getEntry().getFirstInstruction(), cfg.getEntry());
int local = methodGen.isStatic() ? 0 : 1;
for (Type type : parameterTypeList) {
if (type instanceof ObjectType) {
ObjectType objectType = (ObjectType) type;
for (ObjectType streamBase : streamBaseList) {
if (Hierarchy.isSubtype(objectType, streamBase)) {
// OK, found a parameter that is a resource.
// Create a Stream object to represent it.
// The Stream will be uninteresting, so it will
// inhibit reporting for any stream that wraps it.
Stream paramStream = new Stream(firstLocation, objectType.getClassName(), streamBase.getClassName());
paramStream.setIsOpenOnCreation(true);
paramStream.setOpenLocation(firstLocation);
paramStream.setInstanceParam(local);
resourceCollection.addPreexistingResource(paramStream);
break;
}
}
}
switch (type.getType()) {
case Constants.T_LONG:
case Constants.T_DOUBLE:
local += 2;
break;
default:
local += 1;
break;
}
}
} catch (ClassNotFoundException e) {
bugReporter.reportMissingClass(e);
}
// Set precomputed map of Locations to Stream creation points.
// That way, the StreamResourceTracker won't have to
// repeatedly try to figure out where Streams are created.
resourceTracker.setResourceCollection(resourceCollection);
super.analyzeMethod(classContext, method, resourceTracker, resourceCollection);
// Compute streams that escape into other streams:
// this takes wrapper streams into account.
// This will also compute equivalence classes of streams,
// so that if one stream in a class is closed,
// they are all considered closed.
// (FIXME: this is too simplistic, especially if buffering
// is involved. Sometime we should really think harder
// about how this should work.)
resourceTracker.markTransitiveUninterestingStreamEscapes();
// For each stream closed on all paths, mark its equivalence
// class as being closed.
for (Iterator<Stream> i = resourceCollection.resourceIterator(); i.hasNext();) {
Stream stream = i.next();
StreamEquivalenceClass equivalenceClass = resourceTracker.getStreamEquivalenceClass(stream);
if (stream.isClosed()) {
equivalenceClass.setClosed();
}
}
// Iterate through potential open streams, reporting warnings
// for the "interesting" streams that haven't been closed
// (and aren't in an equivalence class with another stream
// that was closed).
for (PotentialOpenStream pos : potentialOpenStreamList) {
Stream stream = pos.stream;
if (stream.isClosed()) {
// Stream was in an equivalence class with another
// stream that was properly closed.
continue;
}
if (stream.isUninteresting()) {
continue;
}
Location openLocation = stream.getOpenLocation();
if (openLocation == null) {
continue;
}
if (IGNORE_WRAPPED_UNINTERESTING_STREAMS && resourceTracker.isUninterestingStreamEscape(stream)) {
continue;
}
String sourceFile = javaClass.getSourceFileName();
String leakClass = stream.getStreamBase();
if (isMainMethod(method) && (leakClass.contains("InputStream") || leakClass.contains("Reader"))) {
return;
}