public void analyzeMethod() throws CheckedAnalysisException {
      if (DEBUG_METHOD != null && !methodDescriptor.getName().equals(DEBUG_METHOD)) {
        return;
      }

      if (DEBUG) {
        System.out.println("*** Analyzing method " + methodDescriptor);
      }

      xmethod = XFactory.createXMethod(methodDescriptor);
      analysisCache = Global.getAnalysisCache();

      //
      // Execute the obligation dataflow analysis
      //
      try {
        dataflow = analysisCache.getMethodAnalysis(ObligationDataflow.class, methodDescriptor);
      } catch (ObligationAcquiredOrReleasedInLoopException e) {
        // It is not possible to analyze this method.
        if (DEBUG) {
          System.out.println(
              "FindUnsatisifedObligation: " + methodDescriptor + ": " + e.getMessage());
        }
        return;
      }

      //
      // Additional analyses
      // needed these to apply the false-positive
      // suppression heuristics.
      //
      cpg =
          analysisCache.getClassAnalysis(
              ConstantPoolGen.class, methodDescriptor.getClassDescriptor());
      typeDataflow = analysisCache.getMethodAnalysis(TypeDataflow.class, methodDescriptor);
      subtypes2 = Global.getAnalysisCache().getDatabase(Subtypes2.class);

      //
      // Main loop: looking at the StateSet at the exit block of the CFG,
      // see if there are any states with nonempty obligation sets.
      //
      Map<Obligation, State> leakedObligationMap = new HashMap<Obligation, State>();
      StateSet factAtExit = dataflow.getResultFact(cfg.getExit());
      for (Iterator<State> i = factAtExit.stateIterator(); i.hasNext(); ) {
        State state = i.next();
        checkStateForLeakedObligations(state, leakedObligationMap);
      }

      //
      // Report a separate BugInstance for each Obligation,State pair.
      // (Two different obligations may be leaked in the same state.)
      //
      for (Map.Entry<Obligation, State> entry : leakedObligationMap.entrySet()) {
        Obligation obligation = entry.getKey();
        State state = entry.getValue();
        reportWarning(obligation, state, factAtExit);
      }
      // TODO: closing of nonexistent resources

    }
    private void reportWarning(Obligation obligation, State state, StateSet factAtExit) {
      String className = obligation.getClassName();

      if (methodDescriptor.isStatic()
          && methodDescriptor.getName().equals("main")
          && methodDescriptor.getSignature().equals("([Ljava/lang/String;)V")
          && (className.contains("InputStream")
              || className.contains("Reader")
              || factAtExit.isOnExceptionPath())) {
        // Don't report unclosed input streams and readers in main()
        // methods
        return;
      }
      String bugPattern =
          factAtExit.isOnExceptionPath()
              ? "OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE"
              : "OBL_UNSATISFIED_OBLIGATION";
      BugInstance bugInstance =
          new BugInstance(FindUnsatisfiedObligation.this, bugPattern, NORMAL_PRIORITY)
              .addClassAndMethod(methodDescriptor)
              .addClass(className)
              .describe("CLASS_REFTYPE");

      // Report how many instances of the obligation are remaining
      bugInstance
          .addInt(state.getObligationSet().getCount(obligation.getId()))
          .describe(IntAnnotation.INT_OBLIGATIONS_REMAINING);

      // Add source line information
      annotateWarningWithSourceLineInformation(state, obligation, bugInstance);

      if (REPORT_OBLIGATION_SET) {
        bugInstance
            .addString(state.getObligationSet().toString())
            .describe(StringAnnotation.REMAINING_OBLIGATIONS_ROLE);
      }

      bugReporter.reportBug(bugInstance);
    }