[analyzer] [NFC] Minor refactoring of RetainCountDiagnostics

Move visitors to the implementation file, move a complicated logic into
a function.

Differential Revision: https://reviews.llvm.org/D55036

llvm-svn: 347946
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index c75a7b0..f2f0156 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -39,6 +39,69 @@
   return State->remove<RefBindings>(Sym);
 }
 
+class UseAfterRelease : public CFRefBug {
+public:
+  UseAfterRelease(const CheckerBase *checker)
+      : CFRefBug(checker, "Use-after-release") {}
+
+  const char *getDescription() const override {
+    return "Reference-counted object is used after it is released";
+  }
+};
+
+class BadRelease : public CFRefBug {
+public:
+  BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {}
+
+  const char *getDescription() const override {
+    return "Incorrect decrement of the reference count of an object that is "
+           "not owned at this point by the caller";
+  }
+};
+
+class DeallocNotOwned : public CFRefBug {
+public:
+  DeallocNotOwned(const CheckerBase *checker)
+      : CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {}
+
+  const char *getDescription() const override {
+    return "-dealloc sent to object that may be referenced elsewhere";
+  }
+};
+
+class OverAutorelease : public CFRefBug {
+public:
+  OverAutorelease(const CheckerBase *checker)
+      : CFRefBug(checker, "Object autoreleased too many times") {}
+
+  const char *getDescription() const override {
+    return "Object autoreleased too many times";
+  }
+};
+
+class ReturnedNotOwnedForOwned : public CFRefBug {
+public:
+  ReturnedNotOwnedForOwned(const CheckerBase *checker)
+      : CFRefBug(checker, "Method should return an owned object") {}
+
+  const char *getDescription() const override {
+    return "Object with a +0 retain count returned to caller where a +1 "
+           "(owning) retain count is expected";
+  }
+};
+
+class Leak : public CFRefBug {
+public:
+  Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
+    // Leaks should not be reported if they are post-dominated by a sink.
+    setSuppressOnSink(true);
+  }
+
+  const char *getDescription() const override { return ""; }
+
+  bool isLeak() const override { return true; }
+};
+
 } // end namespace retaincountchecker
 } // end namespace ento
 } // end namespace clang
@@ -350,6 +413,56 @@
   checkSummary(*Summ, Call, C);
 }
 
+void RetainCountChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
+                                          ExprEngine &Eng) const {
+  // FIXME: This is a hack to make sure the summary log gets cleared between
+  // analyses of different code bodies.
+  //
+  // Why is this necessary? Because a checker's lifetime is tied to a
+  // translation unit, but an ExplodedGraph's lifetime is just a code body.
+  // Once in a blue moon, a new ExplodedNode will have the same address as an
+  // old one with an associated summary, and the bug report visitor gets very
+  // confused. (To make things worse, the summary lifetime is currently also
+  // tied to a code body, so we get a crash instead of incorrect results.)
+  //
+  // Why is this a bad solution? Because if the lifetime of the ExplodedGraph
+  // changes, things will start going wrong again. Really the lifetime of this
+  // log needs to be tied to either the specific nodes in it or the entire
+  // ExplodedGraph, not to a specific part of the code being analyzed.
+  //
+  // (Also, having stateful local data means that the same checker can't be
+  // used from multiple threads, but a lot of checkers have incorrect
+  // assumptions about that anyway. So that wasn't a priority at the time of
+  // this fix.)
+  //
+  // This happens at the end of analysis, but bug reports are emitted /after/
+  // this point. So we can't just clear the summary log now. Instead, we mark
+  // that the next time we access the summary log, it should be cleared.
+
+  // If we never reset the summary log during /this/ code body analysis,
+  // there were no new summaries. There might still have been summaries from
+  // the /last/ analysis, so clear them out to make sure the bug report
+  // visitors don't get confused.
+  if (ShouldResetSummaryLog)
+    SummaryLog.clear();
+
+  ShouldResetSummaryLog = !SummaryLog.empty();
+}
+
+CFRefBug *
+RetainCountChecker::getLeakWithinFunctionBug(const LangOptions &LOpts) const {
+  if (!leakWithinFunction)
+    leakWithinFunction.reset(new Leak(this, "Leak"));
+  return leakWithinFunction.get();
+}
+
+CFRefBug *
+RetainCountChecker::getLeakAtReturnBug(const LangOptions &LOpts) const {
+  if (!leakAtReturn)
+    leakAtReturn.reset(new Leak(this, "Leak of returned object"));
+  return leakAtReturn.get();
+}
+
 /// GetReturnType - Used to get the return type of a message expression or
 ///  function call with the intention of affixing that type to a tracked symbol.
 ///  While the return type can be queried directly from RetEx, when