teach FormatDiagnostic to aggregate previously formatted arguments and
pass them down into the ArgToStringFn implementation.  This allows 
redundancy across operands to a diagnostic to be eliminated.

This isn't used yet, so no functionality change.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84602 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index d3bb9d5..d665e49 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -190,6 +190,8 @@
 static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
                                const char *Modifier, unsigned ML,
                                const char *Argument, unsigned ArgLen,
+                               const Diagnostic::ArgumentValue *PrevArgs,
+                               unsigned NumPrevArgs,
                                llvm::SmallVectorImpl<char> &Output,
                                void *Cookie) {
   const char *Str = "<can't format argument>";
@@ -685,6 +687,12 @@
   const char *DiagStr = getDiags()->getDescription(getID());
   const char *DiagEnd = DiagStr+strlen(DiagStr);
 
+  /// FormattedArgs - Keep track of all of the arguments formatted by
+  /// ConvertArgToString and pass them into subsequent calls to
+  /// ConvertArgToString, allowing the implementation to avoid redundancies in
+  /// obvious cases.
+  llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs;
+  
   while (DiagStr != DiagEnd) {
     if (DiagStr[0] != '%') {
       // Append non-%0 substrings to Str if we have one.
@@ -732,7 +740,9 @@
     assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
     unsigned ArgNo = *DiagStr++ - '0';
 
-    switch (getArgKind(ArgNo)) {
+    Diagnostic::ArgumentKind Kind = getArgKind(ArgNo);
+    
+    switch (Kind) {
     // ---- STRINGS ----
     case Diagnostic::ak_std_string: {
       const std::string &S = getArgStdStr(ArgNo);
@@ -802,11 +812,23 @@
     case Diagnostic::ak_nameddecl:
     case Diagnostic::ak_nestednamespec:
     case Diagnostic::ak_declcontext:
-      getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo),
+      getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
                                      Modifier, ModifierLen,
-                                     Argument, ArgumentLen, OutStr);
+                                     Argument, ArgumentLen,
+                                     FormattedArgs.data(), FormattedArgs.size(),
+                                     OutStr);
       break;
     }
+    
+    // Remember this argument info for subsequent formatting operations.  Turn
+    // std::strings into a null terminated string to make it be the same case as
+    // all the other ones.
+    if (Kind != Diagnostic::ak_std_string)
+      FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
+    else
+      FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string,
+                                        (intptr_t)getArgStdStr(ArgNo).c_str()));
+    
   }
 }
 
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 6e9362f..1cb0dcf 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -148,6 +148,8 @@
 static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
                                  const char *Modifier, unsigned ModLen,
                                  const char *Argument, unsigned ArgLen,
+                                 const Diagnostic::ArgumentValue *PrevArgs,
+                                 unsigned NumPrevArgs,
                                  llvm::SmallVectorImpl<char> &Output,
                                  void *Cookie) {
   ASTContext &Context = *static_cast<ASTContext*>(Cookie);