[analyzer] Create symbol-aware stack hints (building upon r152837).

The symbol-aware stack hint combines the checker-provided message
with the information about how the symbol was passed to the callee: as
a parameter or a return value.

For malloc, the generated messages look like this :
"Returning from 'foo'; released memory via 1st parameter"
"Returning from 'foo'; allocated memory via 1st parameter"
"Returning from 'foo'; allocated memory returned"
"Returning from 'foo'; reallocation of 1st parameter failed"


(We are yet to handle cases when the symbol is a field in a struct or
an array element.)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152962 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index e071626..2926fd5 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -243,6 +243,29 @@
                                    const ExplodedNode *PrevN,
                                    BugReporterContext &BRC,
                                    BugReport &BR);
+  private:
+    class StackHintGeneratorForReallocationFailed
+        : public StackHintGeneratorForSymbol {
+    public:
+      StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
+        : StackHintGeneratorForSymbol(S, M) {}
+
+      virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+        SmallString<200> buf;
+        llvm::raw_svector_ostream os(buf);
+
+        os << "; reallocation of ";
+        // Printed parameters start at 1, not 0.
+        printOrdinal(++ArgIndex, os);
+        os << " parameter failed";
+
+        return os.str();
+      }
+
+      virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+        return "; reallocation of returned value failed";
+      }
+    };
   };
 };
 } // end anonymous namespace
@@ -1249,7 +1272,7 @@
 
   const Stmt *S = 0;
   const char *Msg = 0;
-  const char *StackMsg = 0;
+  StackHintGeneratorForSymbol *StackHint = 0;
 
   // Retrieve the associated statement.
   ProgramPoint ProgLoc = N->getLocation();
@@ -1269,14 +1292,15 @@
   if (Mode == Normal) {
     if (isAllocated(RS, RSPrev, S)) {
       Msg = "Memory is allocated";
-      StackMsg = ", which allocated memory";
+      StackHint = new StackHintGeneratorForSymbol(Sym, "; allocated memory");
     } else if (isReleased(RS, RSPrev, S)) {
       Msg = "Memory is released";
-      StackMsg = ", which released memory";
+      StackHint = new StackHintGeneratorForSymbol(Sym, "; released memory");
     } else if (isReallocFailedCheck(RS, RSPrev, S)) {
       Mode = ReallocationFailed;
       Msg = "Reallocation failed";
-      StackMsg = ", where reallocation failed";
+      StackHint = new StackHintGeneratorForReallocationFailed(Sym,
+                                                   "; reallocation failed");
     }
 
   // We are in a special mode if a reallocation failed later in the path.
@@ -1296,18 +1320,18 @@
     if (!(FunName.equals("realloc") || FunName.equals("reallocf")))
       return 0;
     Msg = "Attempt to reallocate memory";
-    StackMsg = ", which attempted to reallocate memory";
+    StackHint = new StackHintGeneratorForSymbol(Sym, "; reallocated memory");
     Mode = Normal;
   }
 
   if (!Msg)
     return 0;
-  assert(StackMsg);
+  assert(StackHint);
 
   // Generate the extra diagnostic.
   PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
                              N->getLocationContext());
-  return new PathDiagnosticEventPiece(Pos, Msg, true, StackMsg);
+  return new PathDiagnosticEventPiece(Pos, Msg, true, StackHint);
 }