gt:             if (className != null) {
context: /*
   * FindBugs - Find bugs in Java programs
   * Copyright (C) 2003,2004 University of Maryland
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package edu.umd.cs.findbugs.detect;
  
  import java.util.ArrayList;
  import java.util.BitSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.Constant;
  import org.apache.bcel.classfile.ConstantInterfaceMethodref;
  import org.apache.bcel.classfile.ConstantMethodref;
  import org.apache.bcel.classfile.JavaClass;
  import org.apache.bcel.classfile.Method;
  import org.apache.bcel.generic.MethodGen;
  import org.apache.bcel.generic.ObjectType;
  import org.apache.bcel.generic.Type;
  
  import edu.umd.cs.findbugs.BugInstance;
  import edu.umd.cs.findbugs.BugReporter;
  import edu.umd.cs.findbugs.ResourceCollection;
  import edu.umd.cs.findbugs.ResourceTrackingDetector;
  import edu.umd.cs.findbugs.SourceLineAnnotation;
  import edu.umd.cs.findbugs.StatelessDetector;
  import edu.umd.cs.findbugs.SystemProperties;
  import edu.umd.cs.findbugs.TypeAnnotation;
  import edu.umd.cs.findbugs.ba.CFG;
  import edu.umd.cs.findbugs.ba.CFGBuilderException;
  import edu.umd.cs.findbugs.ba.ClassContext;
  import edu.umd.cs.findbugs.ba.Dataflow;
  import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
  import edu.umd.cs.findbugs.ba.Hierarchy;
  import edu.umd.cs.findbugs.ba.Location;
  import edu.umd.cs.findbugs.ba.ObjectTypeFactory;
  import edu.umd.cs.findbugs.ba.ResourceValueAnalysis;
  import edu.umd.cs.findbugs.ba.ResourceValueFrame;
  
  /**
   * A Detector to look for streams that are opened in a method, do not escape the
   * method, and are not closed on all paths out of the method. Note that "stream"
   * is a bit misleading, since we also use the detector to look for database
   * resources that aren't closed.
   * 
   * @author David Hovemeyer
   */
  public final class FindOpenStream extends ResourceTrackingDetector<Stream, StreamResourceTracker> implements StatelessDetector {
      static final boolean DEBUG = SystemProperties.getBoolean("fos.debug");
  
      static final boolean IGNORE_WRAPPED_UNINTERESTING_STREAMS = !SystemProperties.getBoolean("fos.allowWUS");
  
      /*
       * ----------------------------------------------------------------------
       * Tracked resource types
       * ----------------------------------------------------------------------
       */
  
      /**
       * List of base classes of tracked resources.
       */
      static final ObjectType[] streamBaseList = { ObjectTypeFactory.getInstance("java.io.InputStream"),
              ObjectTypeFactory.getInstance("java.io.OutputStream"), ObjectTypeFactory.getInstance("java.util.zip.ZipFile"),
              ObjectTypeFactory.getInstance("java.io.Reader"), ObjectTypeFactory.getInstance("java.io.Writer"),
              ObjectTypeFactory.getInstance("java.sql.Connection"), 
              ObjectTypeFactory.getInstance("java.sql.Statement"), ObjectTypeFactory.getInstance("java.sql.ResultSet") };
  
      /**
       * StreamFactory objects used to detect resources created within analyzed
       * methods.
       */
      static final StreamFactory[] streamFactoryList;
  
      static {
          ArrayList<StreamFactory> streamFactoryCollection = new ArrayList<StreamFactory>();
  
          // Examine InputStreams, OutputStreams, Readers, and Writers,
          // ignoring byte array, char array, and String variants.
          streamFactoryCollection.add(new IOStreamFactory("java.io.InputStream", new String[] { "java.io.ByteArrayInputStream",
                  "java.io.StringBufferInputStream", "java.io.PipedInputStream" }, "OS_OPEN_STREAM"));
          streamFactoryCollection.add(new IOStreamFactory("java.io.OutputStream", new String[] { "java.io.ByteArrayOutputStream",
                  "java.io.PipedOutputStream" }, "OS_OPEN_STREAM"));
          streamFactoryCollection.add(new IOStreamFactory("java.io.Reader", new String[] { "java.io.StringReader",
                  "java.io.CharArrayReader", "java.io.PipedReader" }, "OS_OPEN_STREAM"));
          streamFactoryCollection.add(new IOStreamFactory("java.io.Writer", new String[] { "java.io.StringWriter",
                  "java.io.CharArrayWriter", "java.io.PipedWriter" }, "OS_OPEN_STREAM"));
          streamFactoryCollection.add(new IOStreamFactory("java.util.zip.ZipFile", new String[0], "OS_OPEN_STREAM"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.lang.Class", "getResourceAsStream",
                  "(Ljava/lang/String;)Ljava/io/InputStream;", "OS_OPEN_STREAM"));
  
          // Ignore socket input and output streams
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.net.Socket", "getInputStream",
                  "()Ljava/io/InputStream;"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.net.Socket", "getOutputStream",
                  "()Ljava/io/OutputStream;"));
  
          // Ignore servlet streams
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.servlet.ServletRequest", "getInputStream",
                  "()Ljavax/servlet/ServletInputStream;"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.servlet.ServletRequest", "getReader",
                  "()Ljava/io/BufferedReader;"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.servlet.ServletResponse", "getOutputStream",
                  "()Ljavax/servlet/ServletOutputStream;"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.servlet.ServletResponse", "getWriter",
                  "()Ljava/io/PrintWriter;"));
          
          // Ignore System.{in,out,err}
          streamFactoryCollection.add(new StaticFieldLoadStreamFactory("java.io.InputStream", "java.lang.System", "in",
                  "Ljava/io/InputStream;"));
          streamFactoryCollection.add(new StaticFieldLoadStreamFactory("java.io.OutputStream", "java.lang.System", "out",
                  "Ljava/io/PrintStream;"));
          streamFactoryCollection.add(new StaticFieldLoadStreamFactory("java.io.OutputStream", "java.lang.System", "err",
                  "Ljava/io/PrintStream;"));
  
          // Ignore input streams loaded from instance fields
          streamFactoryCollection.add(new InstanceFieldLoadStreamFactory("java.io.InputStream"));
          streamFactoryCollection.add(new InstanceFieldLoadStreamFactory("java.io.Reader"));
  
          // Ignore output streams loaded from instance fields.
          // FIXME: what we really should do here is ignore the stream
          // loaded from the field, but report any streams that wrap
          // it. This is an important and useful distinction that the
          // detector currently doesn't handle. Should be fairly
          // easy to add.
          streamFactoryCollection.add(new InstanceFieldLoadStreamFactory("java.io.OutputStream"));
          streamFactoryCollection.add(new InstanceFieldLoadStreamFactory("java.io.Writer"));
  
          // JDBC objects
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;I)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;[I)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;II)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;III)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareStatement",
                  "(Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
  
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareCall",
                  "(Ljava/lang/String;)Ljava/sql/CallableStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareCall",
                  "(Ljava/lang/String;II)Ljava/sql/CallableStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "prepareCall",
                  "(Ljava/lang/String;III)Ljava/sql/CallableStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
  
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.DriverManager", "getConnection",
                  "(Ljava/lang/String;)Ljava/sql/Connection;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.DriverManager", "getConnection",
                  "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.DriverManager", "getConnection",
                  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/Connection;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.sql.DataSource", "getConnection",
                  "()Ljava/sql/Connection;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("javax.sql.DataSource", "getConnection",
                  "(Ljava/lang/String;Ljava/lang/String;)Ljava/sql/Connection;", "ODR_OPEN_DATABASE_RESOURCE"));
  
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "()Ljava/sql/Statement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(II)Ljava/sql/Statement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(III)Ljava/sql/Statement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;I)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;II)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;III)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;[I)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
          streamFactoryCollection.add(new MethodReturnValueStreamFactory("java.sql.Connection", "createStatement",
                  "(Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/PreparedStatement;", "ODR_OPEN_DATABASE_RESOURCE"));
  
          streamFactoryList = streamFactoryCollection.toArray(new StreamFactory[streamFactoryCollection.size()]);
      }
  
      /*
       * ----------------------------------------------------------------------
       * Helper classes
       * ----------------------------------------------------------------------
       */
  
      private static class PotentialOpenStream {
          public final String bugType;
  
          public final int priority;
  
          public final Stream stream;
          
          @Override
          public String toString() {
              return stream.toString();
          }
  
          public PotentialOpenStream(String bugType, int priority, Stream stream) {
              this.bugType = bugType;
              this.priority = priority;
              this.stream = stream;
          }
      }
  
      /*
       * ----------------------------------------------------------------------
       * Fields
       * ----------------------------------------------------------------------
       */
  
      private List<PotentialOpenStream> potentialOpenStreamList;
  
      /*
       * ----------------------------------------------------------------------
       * Implementation
       * ----------------------------------------------------------------------
       */
  
      public FindOpenStream(BugReporter bugReporter) {
          super(bugReporter);
          this.potentialOpenStreamList = new LinkedList<PotentialOpenStream>();
      }
  
      @Override
      public Object clone() {
          try {
              return super.clone();
          } catch (CloneNotSupportedException e) {
              throw new AssertionError(e);
          }
      }
  
      // List of words that must appear in names of classes which
      // create possible resources to be tracked. If we don't see a
      // class containing one of these words, then we don't run the
      // detector on the class.
      private static final String[] PRESCREEN_CLASS_LIST = { "Stream", "Reader", "Writer", "ZipFile", "JarFile", "DriverManager",
              "Connection", "Statement" };
  
      /*
       * (non-Javadoc)
       * 
       * @see
       * edu.umd.cs.findbugs.Detector#visitClassContext(edu.umd.cs.findbugs.ba
       * .ClassContext)
       */
      @Override
      public void visitClassContext(ClassContext classContext) {
          JavaClass jclass = classContext.getJavaClass();
  
          // Check to see if the class references any other classes
          // which could be resources we want to track.
          // If we don't find any such classes, we skip analyzing
          // the class. (Note: could do this by method.)
          boolean sawResourceClass = false;
          for (int i = 0; i < jclass.getConstantPool().getLength(); ++i) {
              Constant constant = jclass.getConstantPool().getConstant(i);
              String className = null;
              if (constant instanceof ConstantMethodref) {
                  ConstantMethodref cmr = (ConstantMethodref) constant;
  
                  int classIndex = cmr.getClassIndex();
                  className = jclass.getConstantPool().getConstantString(classIndex, Constants.CONSTANT_Class);
              } else if (constant instanceof ConstantInterfaceMethodref) {
                  ConstantInterfaceMethodref cmr = (ConstantInterfaceMethodref) constant;
  
                  int classIndex = cmr.getClassIndex();
                  className = jclass.getConstantPool().getConstantString(classIndex, Constants.CONSTANT_Class);
              }
  
  