Introduce a simple, substitution-based compression scheme for USRs, so
that redundant types don't result in super-long USRs. Fixes
<rdar://problem/8447875>.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114347 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 8f3dacf..5541657 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -34,6 +34,9 @@
   bool IgnoreResults;
   ASTUnit *AU;
   bool generatedLoc;
+  
+  llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;
+  
 public:
   USRGenerator(const CXCursor *C = 0)
     : Out(Buf),
@@ -510,32 +513,6 @@
 
     // Mangle in ObjC GC qualifiers?
 
-    if (const PointerType *PT = T->getAs<PointerType>()) {
-      Out << '*';
-      T = PT->getPointeeType();
-      continue;
-    }
-    if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
-      Out << '&';
-      T = RT->getPointeeType();
-      continue;
-    }
-    if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
-      Out << 'F';
-      VisitType(FT->getResultType());
-      for (FunctionProtoType::arg_type_iterator
-            I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
-        VisitType(*I);
-      }
-      if (FT->isVariadic())
-        Out << '.';
-      return;
-    }
-    if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
-      Out << 'B';
-      T = BT->getPointeeType();
-      continue;
-    }
     if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
       unsigned char c = '\0';
       switch (BT->getKind()) {
@@ -598,6 +575,46 @@
       Out << c;
       return;
     }
+
+    // If we have already seen this (non-built-in) type, use a substitution
+    // encoding.
+    llvm::DenseMap<const Type *, unsigned>::iterator Substitution
+      = TypeSubstitutions.find(T.getTypePtr());
+    if (Substitution != TypeSubstitutions.end()) {
+      Out << 'S' << Substitution->second << '_';
+      return;
+    } else {
+      // Record this as a substitution.
+      unsigned Number = TypeSubstitutions.size();
+      TypeSubstitutions[T.getTypePtr()] = Number;
+    }
+    
+    if (const PointerType *PT = T->getAs<PointerType>()) {
+      Out << '*';
+      T = PT->getPointeeType();
+      continue;
+    }
+    if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+      Out << '&';
+      T = RT->getPointeeType();
+      continue;
+    }
+    if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
+      Out << 'F';
+      VisitType(FT->getResultType());
+      for (FunctionProtoType::arg_type_iterator
+            I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
+        VisitType(*I);
+      }
+      if (FT->isVariadic())
+        Out << '.';
+      return;
+    }
+    if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+      Out << 'B';
+      T = BT->getPointeeType();
+      continue;
+    }
     if (const ComplexType *CT = T->getAs<ComplexType>()) {
       Out << '<';
       T = CT->getElementType();