private State getTransferState(InstructionHandle handle) {
        StateSet stateSet;
        try {
          stateSet = dataflow.getFactAtLocation(new Location(handle, curBlock));
        } catch (DataflowAnalysisException e) {
          bugReporter.logError("Error checking obligation state at " + handle, e);
          return null;
        }

        List<State> prefixes = stateSet.getPrefixStates(state.getPath());
        if (prefixes.size() != 1) {
          // Could this happen?
          if (DEBUG_FP) {
            System.out.println(
                "at "
                    + handle
                    + " in "
                    + xmethod
                    + " found "
                    + prefixes.size()
                    + " states which are prefixes of error state");
          }
          return null;
        }

        return prefixes.get(0);
      }
    private void checkStateForLeakedObligations(
        State state, Map<Obligation, State> leakedObligationMap) throws IllegalStateException {
      if (DEBUG) {
        Path path = state.getPath();
        if (path.getLength() > 0
            && path.getBlockIdAt(path.getLength() - 1) != cfg.getExit().getLabel()) {
          throw new IllegalStateException(
              "path " + path + " at cfg exit has no label for exit block");
        }
      }

      for (int id = 0; id < database.getFactory().getMaxObligationTypes(); ++id) {
        Obligation obligation = database.getFactory().getObligationById(id);
        // If the raw count produced by the analysis
        // for this obligation type is 0,
        // assume everything is ok on this state's path.
        int rawLeakCount = state.getObligationSet().getCount(id);
        if (rawLeakCount == 0) {
          continue;
        }

        // Apply the false-positive suppression heuristics
        int leakCount = getAdjustedLeakCount(state, id);

        if (leakCount > 0) {
          leakedObligationMap.put(obligation, state);
        }
        // TODO: if the leak count is less than 0, then a nonexistent
        // resource was closed
      }
    }
    /**
     * Get the adjusted leak count for the given State and obligation type. Use heuristics to
     * account for:
     *
     * <ul>
     *   <li>null checks (count the number of times the supposedly leaked obligation is compared to
     *       null, and subtract those from the leak count)
     *   <li>field assignments (count number of times obligation type is assigned to a field, and
     *       subtract those from the leak count)
     *   <li>return statements (if an instance of the obligation type is returned from the method,
     *       subtract one from leak count)
     * </ul>
     *
     * @return the adjusted leak count (positive if leaked obligation, negative if attempt to
     *     release an un-acquired obligation)
     */
    private int getAdjustedLeakCount(State state, int obligationId) {

      final Obligation obligation = database.getFactory().getObligationById(obligationId);
      Path path = state.getPath();
      PostProcessingPathVisitor visitor = new PostProcessingPathVisitor(obligation, state);
      path.acceptVisitor(cfg, visitor);

      if (visitor.couldNotAnalyze()) {
        return 0;
      } else {
        return visitor.getAdjustedLeakCount();
      }
    }
    private void reportPath(
        final BugInstance bugInstance, final Obligation obligation, final State state) {

      Path path = state.getPath();

      // This PathVisitor will traverse the Path and add appropriate
      // SourceLineAnnotations to the BugInstance.
      PathVisitor visitor =
          new PathVisitor() {
            boolean sawFirstCreation;

            SourceLineAnnotation lastSourceLine; // = creationSourceLine;

            BasicBlock curBlock;

            @Override
            public void visitBasicBlock(BasicBlock basicBlock) {
              curBlock = basicBlock;

              // See if the initial instance of the leaked resource
              // is in the entry fact due to a @WillClose annotation.
              if (curBlock == cfg.getEntry()) {
                // Get the entry fact - it should have precisely one
                // state
                StateSet entryFact = dataflow.getResultFact(curBlock);
                Iterator<State> i = entryFact.stateIterator();
                if (i.hasNext()) {
                  State entryState = i.next();
                  if (entryState.getObligationSet().getCount(obligation.getId()) > 0) {
                    lastSourceLine = SourceLineAnnotation.forFirstLineOfMethod(methodDescriptor);
                    lastSourceLine.setDescription(
                        SourceLineAnnotation.ROLE_OBLIGATION_CREATED_BY_WILLCLOSE_PARAMETER);
                    bugInstance.add(lastSourceLine);
                    sawFirstCreation = true;

                    if (REPORT_PATH_DEBUG) {
                      System.out.println(
                          "  "
                              + obligation
                              + " created by @WillClose parameter at "
                              + lastSourceLine);
                    }
                  }
                }
              }
            }

            @Override
            public void visitInstructionHandle(InstructionHandle handle) {
              boolean isCreation =
                  (dataflow
                      .getAnalysis()
                      .getActionCache()
                      .addsObligation(curBlock, handle, obligation));

              if (!sawFirstCreation && !isCreation) {
                return;
              }

              SourceLineAnnotation sourceLine =
                  SourceLineAnnotation.fromVisitedInstruction(
                      methodDescriptor, new Location(handle, curBlock));
              sourceLine.setDescription(
                  isCreation
                      ? SourceLineAnnotation.ROLE_OBLIGATION_CREATED
                      : SourceLineAnnotation.ROLE_PATH_CONTINUES);

              boolean isInteresting =
                  (sourceLine.getStartLine() > 0)
                      && (lastSourceLine == null
                          || isCreation
                          || sourceLine.getStartLine() != lastSourceLine.getStartLine());

              if (REPORT_PATH_DEBUG) {
                System.out.println(
                    "  "
                        + handle.getPosition()
                        + " --> "
                        + sourceLine
                        + (isInteresting ? " **" : ""));
              }
              if (isInteresting) {
                bugInstance.add(sourceLine);
                lastSourceLine = sourceLine;
                if (isCreation) {
                  sawFirstCreation = true;
                }
              }
            }

            @Override
            public void visitEdge(Edge edge) {
              if (REPORT_PATH_DEBUG) {
                System.out.println(
                    "Edge of type "
                        + Edge.edgeTypeToString(edge.getType())
                        + " to "
                        + edge.getTarget().getLabel());
                if (edge.getTarget().getFirstInstruction() != null) {
                  System.out.println(
                      "  First instruction in target: " + edge.getTarget().getFirstInstruction());
                }
                if (edge.getTarget().isExceptionThrower()) {
                  System.out.println(
                      "  exception thrower for " + edge.getTarget().getExceptionThrower());
                }
                if (edge.isExceptionEdge()) {
                  System.out.println(
                      "  exceptions thrown: " + typeDataflow.getEdgeExceptionSet(edge));
                }
              }
            }
          };

      // Visit the Path
      path.acceptVisitor(cfg, visitor);
    }