juliehockett updated this revision to Diff 136793.
juliehockett added a comment.

Updating for parent diff & refactoring reader.


https://reviews.llvm.org/D43341

Files:
  clang-doc/BitcodeReader.cpp
  clang-doc/BitcodeReader.h
  clang-doc/BitcodeWriter.cpp
  clang-doc/BitcodeWriter.h
  clang-doc/CMakeLists.txt
  clang-doc/Reducer.cpp
  clang-doc/Reducer.h
  clang-doc/Representation.cpp
  clang-doc/Representation.h
  clang-doc/tool/ClangDocMain.cpp
  test/clang-doc/comment-bc.cpp
  test/clang-doc/mapper-class-in-class.cpp
  test/clang-doc/mapper-class-in-function.cpp
  test/clang-doc/mapper-class.cpp
  test/clang-doc/mapper-comments.cpp
  test/clang-doc/mapper-enum.cpp
  test/clang-doc/mapper-function.cpp
  test/clang-doc/mapper-method.cpp
  test/clang-doc/mapper-namespace.cpp
  test/clang-doc/mapper-struct.cpp
  test/clang-doc/mapper-union.cpp
  test/clang-doc/namespace-bc.cpp
  test/clang-doc/record-bc.cpp

Index: test/clang-doc/record-bc.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/record-bc.cpp
@@ -0,0 +1,133 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/docs.bc --dump | FileCheck %s
+
+union A { int X; int Y; };
+
+enum B { X, Y };
+
+struct C { int i; };
+
+class D {};
+
+class E {
+public:
+  E() {}
+  ~E() {}
+
+protected:
+  void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+class F : virtual private D, public E {};
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK: <Version abbrevid=4 op0=1/>
+// CHECK: </VersionBlock>
+// CHECK: <FunctionBlock NumWords=21 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=11/> blob data = 'c:@S@E@F@E#'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <IsMethod abbrevid=12 op0=1/>
+  // CHECK: <Parent abbrevid=10 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK: </TypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <FunctionBlock NumWords=21 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=12/> blob data = 'c:@S@E@F@~E#'
+  // CHECK: <Name abbrevid=5 op0=2/> blob data = '~E'
+  // CHECK: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <IsMethod abbrevid=12 op0=1/>
+  // CHECK: <Parent abbrevid=10 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK: </TypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <FunctionBlock NumWords=28 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=25/> blob data = 'c:@S@E@F@ProtectedMethod#'
+  // CHECK: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod'
+  // CHECK: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <IsMethod abbrevid=12 op0=1/>
+  // CHECK: <Parent abbrevid=10 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK: </TypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <FunctionBlock NumWords=28 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=25/> blob data = 'c:@S@E@F@ProtectedMethod#'
+  // CHECK: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod'
+  // CHECK: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <IsMethod abbrevid=12 op0=1/>
+  // CHECK: <Parent abbrevid=10 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK: </TypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <RecordBlock NumWords=23 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@U@A'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'A'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TagType abbrevid=10 op0=2/>
+  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'A::X'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'A::Y'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+// CHECK: </RecordBlock>
+// CHECK: <RecordBlock NumWords=15 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@C'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'C'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TagType abbrevid=10 op0=2/>
+  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'C::i'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+// CHECK: </RecordBlock>
+// CHECK: <RecordBlock NumWords=6 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@D'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'D'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TagType abbrevid=10 op0=3/>
+// CHECK: </RecordBlock>
+// CHECK: <RecordBlock NumWords=6 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@E'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TagType abbrevid=10 op0=3/>
+// CHECK: </RecordBlock>
+// CHECK: <RecordBlock NumWords=14 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@F'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'F'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TagType abbrevid=10 op0=3/>
+  // CHECK: <Parent abbrevid=11 op0=1 op1=6/> blob data = 'c:@S@E'
+  // CHECK: <VParent abbrevid=12 op0=1 op1=6/> blob data = 'c:@S@D'
+// CHECK: </RecordBlock>
+// CHECK: <EnumBlock NumWords=18 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@E@B'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'B'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=3 op1=1/> blob data = 'X'
+  // CHECK: </TypeBlock>
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=3 op1=1/> blob data = 'Y'
+  // CHECK: </TypeBlock>
+// CHECK: </EnumBlock>
Index: test/clang-doc/namespace-bc.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/namespace-bc.cpp
@@ -0,0 +1,74 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/docs.bc --dump | FileCheck %s
+
+namespace A {
+
+void f();
+void f() {};
+
+} // A
+
+namespace A {
+namespace B {
+
+enum E { X };
+
+E func(int i) { 
+  return X;
+}
+
+}
+}
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK: <Version abbrevid=4 op0=1/>
+// CHECK: </VersionBlock>
+// CHECK: <NamespaceBlock NumWords=6 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@N@A'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK: </NamespaceBlock>
+// CHECK: <NamespaceBlock NumWords=11 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=10/> blob data = 'c:@N@A@N@B'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'B'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=6/> blob data = 'c:@N@A'
+// CHECK: </NamespaceBlock>
+// CHECK: <FunctionBlock NumWords=17 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=11/> blob data = 'c:@N@A@F@f#'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'f'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=6/> blob data = 'c:@N@A'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK: </TypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <FunctionBlock NumWords=34 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=20/> blob data = 'c:@N@A@N@B@F@func#I#'
+  // CHECK: <Name abbrevid=5 op0=4/> blob data = 'func'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=10/> blob data = 'c:@N@A@N@B'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=6/> blob data = 'c:@N@A'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=12/> blob data = 'enum A::B::E'
+  // CHECK: </TypeBlock>
+  // CHECK: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=1/> blob data = 'i'
+  // CHECK: </FieldTypeBlock>
+// CHECK: </FunctionBlock>
+// CHECK: <EnumBlock NumWords=24 BlockCodeSize=4>
+  // CHECK: <USR abbrevid=4 op0=14/> blob data = 'c:@N@A@N@B@E@E'
+  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=10/> blob data = 'c:@N@A@N@B'
+  // CHECK: <Namespace abbrevid=6 op0=0 op1=6/> blob data = 'c:@N@A'
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
+  // CHECK: <TypeBlock NumWords=5 BlockCodeSize=4>
+    // CHECK: <Type abbrevid=4 op0=3 op1=7/> blob data = 'A::B::X'
+  // CHECK: </TypeBlock>
+// CHECK: </EnumBlock>
+
+
Index: test/clang-doc/mapper-union.cpp
===================================================================
--- test/clang-doc/mapper-union.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@u...@d.bc --dump | FileCheck %s
-
-union D { int X; int Y; };
-// CHECK: <BLOCKINFO_BLOCK/>
-// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK: <Version abbrevid=4 op0=1/>
-// CHECK: </VersionBlock>
-// CHECK: <RecordBlock NumWords=23 BlockCodeSize=4>
-  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@U@D'
-  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'D'
-  // CHECK: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK: <TagType abbrevid=10 op0=2/>
-  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'D::X'
-    // CHECK: <Access abbrevid=6 op0=3/>
-  // CHECK: </MemberTypeBlock>
-  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'D::Y'
-    // CHECK: <Access abbrevid=6 op0=3/>
-  // CHECK: </MemberTypeBlock>
-// CHECK: </RecordBlock>
Index: test/clang-doc/mapper-struct.cpp
===================================================================
--- test/clang-doc/mapper-struct.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@s...@c.bc --dump | FileCheck %s
-
-struct C { int i; };
-// CHECK: <BLOCKINFO_BLOCK/>
-// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK: <Version abbrevid=4 op0=1/>
-// CHECK: </VersionBlock>
-// CHECK: <RecordBlock NumWords=14 BlockCodeSize=4>
-  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@C'
-  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'C'
-  // CHECK: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'C::i'
-    // CHECK: <Access abbrevid=6 op0=3/>
-  // CHECK: </MemberTypeBlock>
-// CHECK: </RecordBlock>
Index: test/clang-doc/mapper-namespace.cpp
===================================================================
--- test/clang-doc/mapper-namespace.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@n...@a.bc --dump | FileCheck %s
-
-namespace A {}
-// CHECK: <BLOCKINFO_BLOCK/>
-// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK: <Version abbrevid=4 op0=1/>
-// CHECK: </VersionBlock>
-// CHECK: <NamespaceBlock NumWords=6 BlockCodeSize=4>
-  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@N@A'
-  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'A'
-// CHECK: </NamespaceBlock>
Index: test/clang-doc/mapper-method.cpp
===================================================================
--- test/clang-doc/mapper-method.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@S@G@F@Method#I#.bc --dump | FileCheck %s --check-prefix CHECK-G-F
-// RUN: llvm-bcanalyzer %t/docs/c:@s...@g.bc --dump | FileCheck %s --check-prefix CHECK-G
-
-class G {
-public: 
-	int Method(int param) { return param; }
-};
-
-// CHECK-G: <BLOCKINFO_BLOCK/>
-// CHECK-G: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-G: <Version abbrevid=4 op0=1/>
-// CHECK-G: </VersionBlock>
-// CHECK-G: <RecordBlock NumWords=6 BlockCodeSize=4>
-  // CHECK-G: <USR abbrevid=4 op0=6/> blob data = 'c:@S@G'
-  // CHECK-G: <Name abbrevid=5 op0=1/> blob data = 'G'
-  // CHECK-G: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-G: <TagType abbrevid=10 op0=3/>
-// CHECK-G: </RecordBlock>
-
-
-// CHECK-G-F: <BLOCKINFO_BLOCK/>
-// CHECK-G-F: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-G-F: <Version abbrevid=4 op0=1/>
-// CHECK-G-F: </VersionBlock>
-// CHECK-G-F: <FunctionBlock NumWords=33 BlockCodeSize=4>
-  // CHECK-G-F: <USR abbrevid=4 op0=18/> blob data = 'c:@S@G@F@Method#I#'
-  // CHECK-G-F: <Name abbrevid=5 op0=6/> blob data = 'Method'
-  // CHECK-G-F: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@G'
-  // CHECK-G-F: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-G-F: <IsMethod abbrevid=12 op0=1/>
-  // CHECK-G-F: <Parent abbrevid=10 op0=1 op1=6/> blob data = 'c:@S@G'
-  // CHECK-G-F: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-G-F: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-  // CHECK-G-F: </TypeBlock>
-  // CHECK-G-F: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
-    // CHECK-G-F: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-    // CHECK-G-F: <Name abbrevid=5 op0=5/> blob data = 'param'
-  // CHECK-G-F: </FieldTypeBlock>
-// CHECK-G-F: </FunctionBlock>
Index: test/clang-doc/mapper-function.cpp
===================================================================
--- test/clang-doc/mapper-function.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@F@F#I#.bc --dump | FileCheck %s
-
-int F(int param) { return param; }
-// CHECK: <BLOCKINFO_BLOCK/>
-// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK: <Version abbrevid=4 op0=1/>
-// CHECK: </VersionBlock>
-// CHECK: <FunctionBlock NumWords=22 BlockCodeSize=4>
-  // CHECK: <USR abbrevid=4 op0=9/> blob data = 'c:@F@F#I#'
-  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'F'
-  // CHECK: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-  // CHECK: </TypeBlock>
-  // CHECK: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
-    // CHECK: <Name abbrevid=5 op0=5/> blob data = 'param'
-  // CHECK: </FieldTypeBlock>
-// CHECK: </FunctionBlock>
Index: test/clang-doc/mapper-enum.cpp
===================================================================
--- test/clang-doc/mapper-enum.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@e...@b.bc --dump | FileCheck %s --check-prefix CHECK-B
-// RUN: llvm-bcanalyzer %t/docs/c:@e...@c.bc --dump | FileCheck %s --check-prefix CHECK-C
-
-enum B { X, Y };
-enum class C { A, B };
-// CHECK-B: <BLOCKINFO_BLOCK/>
-// CHECK-B: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-B: <Version abbrevid=4 op0=1/>
-// CHECK-B: </VersionBlock>
-// CHECK-B: <EnumBlock NumWords=18 BlockCodeSize=4>
-  // CHECK-B: <USR abbrevid=4 op0=6/> blob data = 'c:@E@B'
-  // CHECK-B: <Name abbrevid=5 op0=1/> blob data = 'B'
-  // CHECK-B: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-B: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-B: <Type abbrevid=4 op0=3 op1=1/> blob data = 'X'
-  // CHECK-B: </TypeBlock>
-  // CHECK-B: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-B: <Type abbrevid=4 op0=3 op1=1/> blob data = 'Y'
-  // CHECK-B: </TypeBlock>
-// CHECK-B: </EnumBlock>
-
-// CHECK-C: <BLOCKINFO_BLOCK/>
-// CHECK-C: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-C: <Version abbrevid=4 op0=1/>
-// CHECK-C: </VersionBlock>
-// CHECK-C: <EnumBlock NumWords=18 BlockCodeSize=4>
-  // CHECK-C: <USR abbrevid=4 op0=6/> blob data = 'c:@E@C'
-  // CHECK-C: <Name abbrevid=5 op0=1/> blob data = 'C'
-  // CHECK-C: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-C: <Scoped abbrevid=10 op0=1/>
-  // CHECK-C: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-C: <Type abbrevid=4 op0=3 op1=4/> blob data = 'C::A'
-  // CHECK-C: </TypeBlock>
-  // CHECK-C: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-C: <Type abbrevid=4 op0=3 op1=4/> blob data = 'C::B'
-  // CHECK-C: </TypeBlock>
-// CHECK-C: </EnumBlock>
Index: test/clang-doc/mapper-class.cpp
===================================================================
--- test/clang-doc/mapper-class.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@s...@e.bc --dump | FileCheck %s
-
-class E {};
-// CHECK: <BLOCKINFO_BLOCK/>
-// CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK: <Version abbrevid=4 op0=1/>
-// CHECK: </VersionBlock>
-// CHECK: <RecordBlock NumWords=6 BlockCodeSize=4>
-  // CHECK: <USR abbrevid=4 op0=6/> blob data = 'c:@S@E'
-  // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
-  // CHECK: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK: <TagType abbrevid=10 op0=3/>
-// CHECK: </RecordBlock>
Index: test/clang-doc/mapper-class-in-function.cpp
===================================================================
--- test/clang-doc/mapper-class-in-function.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:test.cpp@396@F@H#@s...@i.bc --dump | FileCheck %s --check-prefix CHECK-H-I
-// RUN: llvm-bcanalyzer %t/docs/c:@F@H#.bc --dump | FileCheck %s --check-prefix CHECK-H
-
-void H() {
-	class I {};
-}
-
-// CHECK-H: <BLOCKINFO_BLOCK/>
-// CHECK-H: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-H: <Version abbrevid=4 op0=1/>
-// CHECK-H: </VersionBlock>
-// CHECK-H: <FunctionBlock NumWords=12 BlockCodeSize=4>
-  // CHECK-H: <USR abbrevid=4 op0=7/> blob data = 'c:@F@H#'
-  // CHECK-H: <Name abbrevid=5 op0=1/> blob data = 'H'
-  // CHECK-H: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-H: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK-H: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
-  // CHECK-H: </TypeBlock>
-// CHECK-H: </FunctionBlock>
-
-// CHECK-H-I: <BLOCKINFO_BLOCK/>
-// CHECK-H-I: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-H-I: <Version abbrevid=4 op0=1/>
-// CHECK-H-I: </VersionBlock>
-// CHECK-H-I: <RecordBlock NumWords=14 BlockCodeSize=4>
-  // CHECK-H-I: <USR abbrevid=4 op0=23/> blob data = 'c:test.cpp@396@F@H#@S@I'
-  // CHECK-H-I: <Name abbrevid=5 op0=1/> blob data = 'I'
-  // CHECK-H-I: <Namespace abbrevid=6 op0=2 op1=7/> blob data = 'c:@F@H#'
-  // CHECK-H-I: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-H-I: <TagType abbrevid=10 op0=3/>
-// CHECK-H-I: </RecordBlock>
Index: test/clang-doc/mapper-class-in-class.cpp
===================================================================
--- test/clang-doc/mapper-class-in-class.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir %t
-// RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@s...@x.bc --dump | FileCheck %s --check-prefix CHECK-X
-// RUN: llvm-bcanalyzer %t/docs/c:@S@X@s...@y.bc --dump | FileCheck %s --check-prefix CHECK-X-Y
-
-class X {
-	class Y {};
-};
-
-// CHECK-X: <BLOCKINFO_BLOCK/>
-// CHECK-X: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-X: <Version abbrevid=4 op0=1/>
-// CHECK-X: </VersionBlock>
-// CHECK-X: <RecordBlock NumWords=6 BlockCodeSize=4>
-  // CHECK-X: <USR abbrevid=4 op0=6/> blob data = 'c:@S@X'
-  // CHECK-X: <Name abbrevid=5 op0=1/> blob data = 'X'
-  // CHECK-X: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-X: <TagType abbrevid=10 op0=3/>
-// CHECK-X: </RecordBlock>
-
-// CHECK-X-Y: <BLOCKINFO_BLOCK/>
-// CHECK-X-Y: <VersionBlock NumWords=1 BlockCodeSize=4>
-  // CHECK-X-Y: <Version abbrevid=4 op0=1/>
-// CHECK-X-Y: </VersionBlock>
-// CHECK-X-Y: <RecordBlock NumWords=11 BlockCodeSize=4>
-  // CHECK-X-Y: <USR abbrevid=4 op0=10/> blob data = 'c:@S@X@S@Y'
-  // CHECK-X-Y: <Name abbrevid=5 op0=1/> blob data = 'Y'
-  // CHECK-X-Y: <Namespace abbrevid=6 op0=1 op1=6/> blob data = 'c:@S@X'
-  // CHECK-X-Y: <IsDefinition abbrevid=7 op0=1/>
-  // CHECK-X-Y: <TagType abbrevid=10 op0=3/>
-// CHECK-X-Y: </RecordBlock>
Index: test/clang-doc/comment-bc.cpp
===================================================================
--- test/clang-doc/comment-bc.cpp
+++ test/clang-doc/comment-bc.cpp
@@ -3,7 +3,7 @@
 // RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
 // RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: llvm-bcanalyzer %t/docs/c:@F@F#I#I#.bc --dump | FileCheck %s
+// RUN: llvm-bcanalyzer %t/docs/docs.bc --dump | FileCheck %s
 
 /// \brief Brief description.
 ///
@@ -20,18 +20,20 @@
 ///
 /// \param [out] I is a parameter.
 /// \param J is a parameter.
-/// \return int
-int F(int I, int J);
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
 
 // CHECK: <BLOCKINFO_BLOCK/>
 // CHECK: <VersionBlock NumWords=1 BlockCodeSize=4>
   // CHECK: <Version abbrevid=4 op0=1/>
 // CHECK: </VersionBlock>
-// CHECK: <FunctionBlock NumWords=375 BlockCodeSize=4>
+// CHECK: <FunctionBlock NumWords=398 BlockCodeSize=4>
   // CHECK: <USR abbrevid=4 op0=11/> blob data = 'c:@F@F#I#I#'
   // CHECK: <Name abbrevid=5 op0=1/> blob data = 'F'
-  // CHECK: <CommentBlock NumWords=344 BlockCodeSize=4>
-    // CHECK: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+  // CHECK: <CommentBlock NumWords=341 BlockCodeSize=4>
     // CHECK: <CommentBlock NumWords=13 BlockCodeSize=4>
       // CHECK: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
       // CHECK: <CommentBlock NumWords=5 BlockCodeSize=4>
@@ -143,20 +145,30 @@
         // CHECK: </CommentBlock>
       // CHECK: </CommentBlock>
     // CHECK: </CommentBlock>
-    // CHECK: <CommentBlock NumWords=27 BlockCodeSize=4>
+    // CHECK: <CommentBlock NumWords=28 BlockCodeSize=4>
       // CHECK: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
       // CHECK: <Name abbrevid=6 op0=6/> blob data = 'return'
-      // CHECK: <CommentBlock NumWords=15 BlockCodeSize=4>
+      // CHECK: <CommentBlock NumWords=16 BlockCodeSize=4>
         // CHECK: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
-        // CHECK: <CommentBlock NumWords=7 BlockCodeSize=4>
+        // CHECK: <CommentBlock NumWords=8 BlockCodeSize=4>
           // CHECK: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
-          // CHECK: <Text abbrevid=5 op0=4/> blob data = ' int'
+          // CHECK: <Text abbrevid=5 op0=5/> blob data = ' void'
         // CHECK: </CommentBlock>
       // CHECK: </CommentBlock>
     // CHECK: </CommentBlock>
   // CHECK: </CommentBlock>
+  // CHECK: <CommentBlock NumWords=24 BlockCodeSize=4>
+    // CHECK: <CommentBlock NumWords=21 BlockCodeSize=4>
+      // CHECK: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK: <CommentBlock NumWords=13 BlockCodeSize=4>
+        // CHECK: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition'
+      // CHECK: </CommentBlock>
+    // CHECK: </CommentBlock>
+  // CHECK: </CommentBlock>
+  // CHECK: <IsDefinition abbrevid=7 op0=1/>
   // CHECK: <TypeBlock NumWords=4 BlockCodeSize=4>
-    // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
   // CHECK: </TypeBlock>
   // CHECK: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
     // CHECK: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
Index: clang-doc/tool/ClangDocMain.cpp
===================================================================
--- clang-doc/tool/ClangDocMain.cpp
+++ clang-doc/tool/ClangDocMain.cpp
@@ -19,7 +19,9 @@
 //===----------------------------------------------------------------------===//
 
 #include <string>
+#include "BitcodeWriter.h"
 #include "ClangDoc.h"
+#include "Reducer.h"
 #include "clang/AST/AST.h"
 #include "clang/AST/Decl.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -88,27 +90,37 @@
       ArgAdjuster);
   if (Err) llvm::errs() << toString(std::move(Err)) << "\n";
 
+  // Reducing phase
+  llvm::outs() << "Reducing infos...\n";
+  auto Infos = doc::mergeInfos(Exec->get()->getToolResults());
+  if (!Infos) {
+    llvm::errs() << "Error reducing infos.\n";
+    return 1;
+  }
+
   if (DumpResult) {
-    Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
-                                                     StringRef Value) {
-      SmallString<128> IRRootPath;
-      llvm::sys::path::native(OutDirectory, IRRootPath);
-      std::error_code DirectoryStatus =
-          llvm::sys::fs::create_directories(IRRootPath);
-      if (DirectoryStatus != OK) {
-        llvm::errs() << "Unable to create documentation directories.\n";
-        return;
-      }
-      llvm::sys::path::append(IRRootPath, Key + ".bc");
-      std::error_code OutErrorInfo;
-      llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
-      if (OutErrorInfo != OK) {
-        llvm::errs() << "Error opening documentation file.\n";
-        return;
-      }
-      OS << Value;
-      OS.close();
-    });
+    llvm::outs() << "Writing intermediate results...\n";
+    SmallString<2048> Buffer;
+    llvm::BitstreamWriter Stream(Buffer);
+    doc::ClangDocBitcodeWriter Writer(Stream, OmitFilenames);
+    Writer.emitInfoSet(Infos);
+    SmallString<128> IRRootPath;
+    llvm::sys::path::native(OutDirectory, IRRootPath);
+    std::error_code DirectoryStatus =
+        llvm::sys::fs::create_directories(IRRootPath);
+    if (DirectoryStatus != OK) {
+      llvm::errs() << "Unable to create documentation directories.\n";
+      return 1;
+    }
+    llvm::sys::path::append(IRRootPath, "docs.bc");
+    std::error_code OutErrorInfo;
+    llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
+    if (OutErrorInfo != OK) {
+      llvm::errs() << "Error opening documentation file.\n";
+      return 1;
+    }
+    OS << Buffer;
+    OS.close();
   }
 
   return 0;
Index: clang-doc/Representation.h
===================================================================
--- clang-doc/Representation.h
+++ clang-doc/Representation.h
@@ -34,10 +34,17 @@
   IT_default
 };
 
+enum class TypeInfoType {
+  TT_type,
+  TT_field_type,
+  TT_member_type,
+};
+
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
   CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {}
+
   SmallString<16> Kind;
   SmallString<64> Text;
   SmallString<16> Name;
@@ -58,6 +65,7 @@
 
   SmallString<16> USR;
   InfoType RefType = InfoType::IT_default;
+  Info *Ref;
 };
 
 // TODO: Pull the CommentInfo for a type out of the info's CommentInfo.
@@ -101,13 +109,26 @@
 /// A base struct for Infos.
 struct Info {
   Info() = default;
-  Info(Info &&Other) : Description(std::move(Other.Description)) {}
-  virtual ~Info() = default;
+  Info(Info &&Other)
+      : USR(Other.USR),
+        Name(Other.Name),
+        Namespace(std::move(Other.Namespace)),
+        Description(std::move(Other.Description)),
+        Namespaces(std::move(Other.Namespaces)),
+        Records(std::move(Other.Records)),
+        Functions(std::move(Other.Functions)),
+        Enums(std::move(Other.Enums)) {}
 
   SmallString<16> USR;
   SmallString<16> Name;
   llvm::SmallVector<Reference, 4> Namespace;
   std::vector<CommentInfo> Description;
+
+  // References to be populated after reducer phase.
+  llvm::SmallVector<Reference, 4> Namespaces;
+  llvm::SmallVector<Reference, 4> Records;
+  llvm::SmallVector<Reference, 4> Functions;
+  llvm::SmallVector<Reference, 4> Enums;
 };
 
 struct NamespaceInfo : public Info {};
@@ -147,6 +168,47 @@
 
 // TODO: Add functionality to include separate markdown pages.
 
+class InfoSet {
+ public:
+  InfoSet() = default;
+
+  void insert(StringRef Key, NamespaceInfo &&I);
+  void insert(StringRef Key, RecordInfo &&I);
+  void insert(StringRef Key, EnumInfo &&I);
+  void insert(StringRef Key, FunctionInfo &&I);
+
+  /// Returns the info with a Key, if it exists. Valid until next insert().
+  template <typename T>
+  T *find(StringRef Key);
+
+  /// Populate the type references in all infos
+  void createReferences();
+
+  std::vector<NamespaceInfo> &getNamespaceInfos() { return NamespaceInfos; }
+  std::vector<FunctionInfo> &getFunctionInfos() { return FunctionInfos; }
+  std::vector<RecordInfo> &getRecordInfos() { return RecordInfos; }
+  std::vector<EnumInfo> &getEnumInfos() { return EnumInfos; }
+
+ private:
+  void resolveReferences(llvm::SmallVector<Reference, 4> &References,
+                         Reference &Caller);
+  void resolveReferences(llvm::SmallVector<TypeInfo, 4> &References,
+                         Reference &Caller);
+  void resolveReferences(llvm::SmallVector<FieldTypeInfo, 4> &References,
+                         Reference &Caller);
+  void resolveReferences(llvm::SmallVector<MemberTypeInfo, 4> &References,
+                         Reference &Caller);
+  void resolveReferences(TypeInfo &TI, Reference &Caller);
+  void resolveReferences(Reference &Ref, Reference &Caller);
+  void addCaller(Info *I, Reference &Caller);
+
+  std::vector<NamespaceInfo> NamespaceInfos;
+  std::vector<FunctionInfo> FunctionInfos;
+  std::vector<RecordInfo> RecordInfos;
+  std::vector<EnumInfo> EnumInfos;
+  llvm::DenseMap<StringRef, size_t> InfoIndex;
+};
+
 }  // namespace doc
 }  // namespace clang
 
Index: clang-doc/Representation.cpp
===================================================================
--- /dev/null
+++ clang-doc/Representation.cpp
@@ -0,0 +1,207 @@
+///===-- ClangDocRepresentation.cpp - ClangDocRepresenation -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Representation.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+static void mergeInfoBase(Info &L, Info &R) {
+  assert(L.USR == R.USR);
+  assert(L.Name == R.Name);
+  if (L.Namespace.empty()) std::move(R.Namespace);
+  std::move(R.Description.begin(), R.Description.end(),
+            std::back_inserter(L.Description));
+}
+
+static void mergeSymbolInfoBase(SymbolInfo &L, SymbolInfo &R) {
+  mergeInfoBase(L, R);
+  if (R.IsDefinition) {
+    L.IsDefinition = true;
+    L.DefLoc = std::move(R.DefLoc);
+  }
+  L.Loc.insert(L.Loc.end(), R.Loc.begin(), R.Loc.end());
+}
+
+static void mergeInfo(NamespaceInfo &L, NamespaceInfo &R) {
+  mergeInfoBase(L, R);
+}
+
+static void mergeInfo(RecordInfo &L, RecordInfo &R) {
+  mergeSymbolInfoBase(L, R);
+  assert(L.TagType == R.TagType);
+  if (L.Members.empty()) L.Members = std::move(R.Members);
+  if (L.Parents.empty()) L.Parents = std::move(R.Parents);
+  if (L.VirtualParents.empty()) L.VirtualParents = std::move(R.VirtualParents);
+}
+
+static void mergeInfo(EnumInfo &L, EnumInfo &R) {
+  mergeSymbolInfoBase(L, R);
+  assert(L.Scoped == R.Scoped);
+  if (L.Members.empty()) L.Members = std::move(R.Members);
+}
+
+static void mergeInfo(FunctionInfo &L, FunctionInfo &R) {
+  mergeSymbolInfoBase(L, R);
+  assert(L.ReturnType.Type.USR == R.ReturnType.Type.USR);
+  assert(L.Access == R.Access);
+  if (L.Parent.USR.empty()) {
+    L.Parent.USR = R.Parent.USR;
+    L.Parent.RefType = R.Parent.RefType;
+  }
+  if (L.Params.empty()) L.Params = std::move(R.Params);
+}
+
+#define FIND_FUNC(X)                          \
+  template <>                                 \
+  X *InfoSet::find(StringRef Key) {           \
+    auto I = InfoIndex.find(Key);             \
+    if (I == InfoIndex.end()) return nullptr; \
+    return &X##s[I->second];                  \
+  }
+
+FIND_FUNC(NamespaceInfo)
+FIND_FUNC(RecordInfo)
+FIND_FUNC(EnumInfo)
+FIND_FUNC(FunctionInfo)
+
+#undef FIND_FUNC
+
+#define INSERT_FUNC(X)                                \
+  void InfoSet::insert(StringRef Key, X &&I) {        \
+    auto R = InfoIndex.try_emplace(Key, X##s.size()); \
+    if (R.second)                                     \
+      X##s.push_back(std::move(I));                   \
+    else                                              \
+      mergeInfo(X##s[R.first->second], I);            \
+  }
+
+INSERT_FUNC(NamespaceInfo)
+INSERT_FUNC(RecordInfo)
+INSERT_FUNC(EnumInfo)
+INSERT_FUNC(FunctionInfo)
+
+#undef INSERT_FUNC
+
+void InfoSet::createReferences() {
+  Reference Caller;
+  for (auto &I : NamespaceInfos) {
+    Caller.USR = I.USR;
+    Caller.RefType = InfoType::IT_namespace;
+    Caller.Ref = &I;
+    resolveReferences(I.Namespace, Caller);
+  }
+  for (auto &I : FunctionInfos) {
+    Caller.USR = I.USR;
+    Caller.RefType = InfoType::IT_function;
+    Caller.Ref = &I;
+    resolveReferences(I.Namespace, Caller);
+    resolveReferences(I.Parent, Caller);
+    resolveReferences(I.ReturnType, Caller);
+    resolveReferences(I.Params, Caller);
+  }
+  for (auto &I : RecordInfos) {
+    Caller.USR = I.USR;
+    Caller.RefType = InfoType::IT_record;
+    Caller.Ref = &I;
+    resolveReferences(I.Namespace, Caller);
+    resolveReferences(I.Members, Caller);
+    resolveReferences(I.Parents, Caller);
+    resolveReferences(I.VirtualParents, Caller);
+  }
+  for (auto &I : EnumInfos) {
+    Caller.USR = I.USR;
+    Caller.RefType = InfoType::IT_enum;
+    Caller.Ref = &I;
+    resolveReferences(I.Namespace, Caller);
+    resolveReferences(I.Members, Caller);
+  }
+}
+
+void InfoSet::resolveReferences(llvm::SmallVector<Reference, 4> &References,
+                                Reference &Caller) {
+  for (auto &Ref : References) resolveReferences(Ref, Caller);
+}
+
+void InfoSet::resolveReferences(llvm::SmallVector<TypeInfo, 4> &References,
+                                Reference &Caller) {
+  for (auto &Ref : References) resolveReferences(Ref.Type, Caller);
+}
+
+void InfoSet::resolveReferences(llvm::SmallVector<FieldTypeInfo, 4> &References,
+                                Reference &Caller) {
+  for (auto &Ref : References) resolveReferences(Ref.Type, Caller);
+}
+
+void InfoSet::resolveReferences(
+    llvm::SmallVector<MemberTypeInfo, 4> &References, Reference &Caller) {
+  for (auto &Ref : References) resolveReferences(Ref.Type, Caller);
+}
+
+void InfoSet::resolveReferences(TypeInfo &TI, Reference &Caller) {
+  resolveReferences(TI.Type, Caller);
+}
+
+void InfoSet::resolveReferences(Reference &Ref, Reference &Caller) {
+  switch (Ref.RefType) {
+    case InfoType::IT_namespace:
+      if (auto *I = find<NamespaceInfo>(Ref.USR)) {
+        Ref.Ref = I;
+        addCaller(I, Caller);
+      }
+      return;
+    case InfoType::IT_record:
+      if (auto *I = find<RecordInfo>(Ref.USR)) {
+        Ref.Ref = I;
+        addCaller(I, Caller);
+      }
+      return;
+    case InfoType::IT_function:
+      if (auto *I = find<FunctionInfo>(Ref.USR)) {
+        Ref.Ref = I;
+        addCaller(I, Caller);
+      }
+      return;
+    case InfoType::IT_enum:
+      if (auto *I = find<EnumInfo>(Ref.USR)) {
+        Ref.Ref = I;
+        addCaller(I, Caller);
+      }
+      return;
+    case InfoType::IT_default:
+      // We don't resolve non-USR references.
+      return;
+  }
+}
+
+void InfoSet::addCaller(Info *I, Reference &Caller) {
+  switch (Caller.RefType) {
+    case InfoType::IT_namespace:
+      I->Namespaces.push_back(Caller);
+      return;
+    case InfoType::IT_record:
+      I->Records.push_back(Caller);
+      return;
+    case InfoType::IT_function:
+      I->Functions.push_back(Caller);
+      return;
+    case InfoType::IT_enum:
+      I->Enums.push_back(Caller);
+      return;
+    default:
+      // We don't resolve non-USR references.
+      return;
+  }
+}
+
+}  // namespace doc
+}  // namespace clang
Index: clang-doc/Reducer.h
===================================================================
--- /dev/null
+++ clang-doc/Reducer.h
@@ -0,0 +1,26 @@
+///===-- ClangDocReducer.h - ClangDocReducer -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REDUCER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REDUCER_H
+
+#include "Representation.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace doc {
+
+// Combine occurrences of the same info across translation units.
+std::unique_ptr<InfoSet> mergeInfos(tooling::ToolResults *Results);
+
+}  // namespace doc
+}  // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REDUCER_H
Index: clang-doc/Reducer.cpp
===================================================================
--- /dev/null
+++ clang-doc/Reducer.cpp
@@ -0,0 +1,33 @@
+///===-- ClangDocReducer.h - ClangDocReducer -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeReader.h"
+#include "Reducer.h"
+#include "Representation.h"
+
+namespace clang {
+namespace doc {
+
+std::unique_ptr<InfoSet> mergeInfos(tooling::ToolResults *Results) {
+  std::unique_ptr<InfoSet> UniqueInfos = llvm::make_unique<InfoSet>();
+  doc::ClangDocBitcodeReader Reader;
+  bool Err = false;
+  Results->forEachResult([&](StringRef Key, StringRef Value) {
+    if (!Reader.readBitstream(Value, UniqueInfos)) {
+      Err = true;
+      return;
+    }
+  });
+  if (Err) return nullptr;
+  UniqueInfos->createReferences();
+  return UniqueInfos;
+}
+
+}  // namespace doc
+}  // namespace clang
Index: clang-doc/CMakeLists.txt
===================================================================
--- clang-doc/CMakeLists.txt
+++ clang-doc/CMakeLists.txt
@@ -3,9 +3,12 @@
   )
 
 add_clang_library(clangDoc
+  BitcodeReader.cpp
   BitcodeWriter.cpp
   Mapper.cpp
   Serialize.cpp
+  Reducer.cpp
+  Representation.cpp
 
   LINK_LIBS
   clangAnalysis
Index: clang-doc/BitcodeWriter.h
===================================================================
--- clang-doc/BitcodeWriter.h
+++ clang-doc/BitcodeWriter.h
@@ -178,6 +178,7 @@
 
   template <typename T>
   void emitBlock(const T &I);
+  void emitInfoSet(std::unique_ptr<InfoSet> &ISet);
 
  private:
   class AbbreviationMap {
Index: clang-doc/BitcodeWriter.cpp
===================================================================
--- clang-doc/BitcodeWriter.cpp
+++ clang-doc/BitcodeWriter.cpp
@@ -450,5 +450,12 @@
 
 #undef EMITINFO
 
+void ClangDocBitcodeWriter::emitInfoSet(std::unique_ptr<InfoSet> &ISet) {
+  for (const auto &I : ISet->getNamespaceInfos()) emitBlock(I);
+  for (const auto &I : ISet->getFunctionInfos()) emitBlock(I);
+  for (const auto &I : ISet->getRecordInfos()) emitBlock(I);
+  for (const auto &I : ISet->getEnumInfos()) emitBlock(I);
+}
+
 }  // namespace doc
 }  // namespace clang
Index: clang-doc/BitcodeReader.h
===================================================================
--- /dev/null
+++ clang-doc/BitcodeReader.h
@@ -0,0 +1,104 @@
+//===--  BitcodeReader.h - ClangDoc Bitcode Reader --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a reader for parsing the clang-doc internal
+// representation to LLVM bitcode. The reader takes in a stream of bits and
+// generates the set of infos that it represents.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+
+#include "BitcodeWriter.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include <initializer_list>
+#include <vector>
+
+namespace clang {
+namespace doc {
+
+// Class to read bitstream into an InfoSet collection
+class ClangDocBitcodeReader {
+ public:
+  ClangDocBitcodeReader() = default;
+
+  bool readBitstream(llvm::SmallString<2048> Bits,
+                     std::unique_ptr<InfoSet> &IS);
+
+ private:
+  enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin };
+
+  // Top level parsing
+  bool validateStream(llvm::BitstreamCursor &Stream);
+  bool readVersion(llvm::BitstreamCursor &Stream);
+  bool readBlockInfoBlock(llvm::BitstreamCursor &Stream);
+  template <typename T>
+  bool readBlockToInfo(llvm::BitstreamCursor &Stream, unsigned ID,
+                       std::unique_ptr<InfoSet> &IS, T &&I);
+
+  // Reading records
+  template <typename T>
+  bool readRecord(llvm::BitstreamCursor &Stream, unsigned ID, T &I);
+
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, unsigned VersionNo);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, NamespaceInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, RecordInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, EnumInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, FunctionInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, TypeInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, FieldTypeInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, MemberTypeInfo &I);
+  bool parseRecord(unsigned ID, llvm::StringRef Blob, CommentInfo &I);
+
+  void storeData(llvm::SmallString<4> &Field, llvm::StringRef Blob);
+  void storeData(llvm::SmallString<16> &Field, llvm::StringRef Blob);
+  void storeData(llvm::SmallString<64> &Field, llvm::StringRef Blob);
+  void storeData(bool &Field, llvm::StringRef Blob);
+  void storeData(int &Field, llvm::StringRef Blob);
+  void storeData(AccessSpecifier &Field, llvm::StringRef Blob);
+  void storeData(TagTypeKind &Field, llvm::StringRef Blob);
+  void storeData(llvm::Optional<Location> &Field, llvm::StringRef Blob);
+  void storeData(Reference &Field, llvm::StringRef Blob);
+  void storeData(llvm::SmallVectorImpl<Location> &Field, llvm::StringRef Blob);
+  void storeData(llvm::SmallVectorImpl<Reference> &Field, llvm::StringRef Blob);
+  void storeData(llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
+                 llvm::StringRef Blob);
+
+  // Reading blocks
+  template <typename T>
+  bool readBlock(llvm::BitstreamCursor &Stream, unsigned ID, T &I);
+  template <typename T>
+  bool readSubBlock(llvm::BitstreamCursor &Stream, unsigned ID, T &I);
+  Cursor skipUntilRecordOrBlock(llvm::BitstreamCursor &Stream,
+                                unsigned &BlockOrRecordID);
+
+  // Helpers
+  CommentInfo &getCommentInfo(const unsigned int I);
+  CommentInfo &getCommentInfo(TypeInfo &I);
+  CommentInfo &getCommentInfo(Info &I);
+  CommentInfo &getCommentInfo(CommentInfo &I);
+  CommentInfo &getCommentInfo(std::unique_ptr<CommentInfo> &I);
+
+  template <typename Iy, typename Ty>
+  void addTypeInfo(Iy &I, Ty &&T);
+
+  llvm::SmallVector<uint64_t, 1024> Record;
+  Optional<llvm::BitstreamBlockInfo> BlockInfo;
+  std::map<unsigned, llvm::StringRef> RecordNames;
+};
+
+}  // namespace doc
+}  // namespace clang
+
+#endif  // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
Index: clang-doc/BitcodeReader.cpp
===================================================================
--- /dev/null
+++ clang-doc/BitcodeReader.cpp
@@ -0,0 +1,528 @@
+//===--  BitcodeReader.cpp - ClangDoc Bitcode Reader ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeReader.h"
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+namespace doc {
+
+// Store data
+
+void ClangDocBitcodeReader::storeData(llvm::SmallString<4> &Field,
+                                      llvm::StringRef Blob) {
+  Field = Blob;
+}
+
+void ClangDocBitcodeReader::storeData(llvm::SmallString<16> &Field,
+                                      llvm::StringRef Blob) {
+  Field = Blob;
+}
+
+void ClangDocBitcodeReader::storeData(llvm::SmallString<64> &Field,
+                                      llvm::StringRef Blob) {
+  Field = Blob;
+}
+
+void ClangDocBitcodeReader::storeData(bool &Field, llvm::StringRef Blob) {
+  Field = (bool)Record[0];
+}
+
+void ClangDocBitcodeReader::storeData(int &Field, llvm::StringRef Blob) {
+  Field = (int)Record[0];
+}
+
+void ClangDocBitcodeReader::storeData(AccessSpecifier &Field,
+                                      llvm::StringRef Blob) {
+  Field = (AccessSpecifier)Record[0];
+}
+
+void ClangDocBitcodeReader::storeData(TagTypeKind &Field,
+                                      llvm::StringRef Blob) {
+  Field = (TagTypeKind)Record[0];
+}
+
+void ClangDocBitcodeReader::storeData(llvm::Optional<Location> &Field,
+                                      llvm::StringRef Blob) {
+  Field.emplace((int)Record[0], Blob);
+}
+
+void ClangDocBitcodeReader::storeData(Reference &Field, llvm::StringRef Blob) {
+  Field = Reference{Blob, (InfoType)Record[0]};
+}
+
+void ClangDocBitcodeReader::storeData(
+    llvm::SmallVectorImpl<llvm::SmallString<16>> &Field, llvm::StringRef Blob) {
+  Field.push_back(Blob);
+}
+
+void ClangDocBitcodeReader::storeData(llvm::SmallVectorImpl<Location> &Field,
+                                      llvm::StringRef Blob) {
+  Field.emplace_back((int)Record[0], Blob);
+}
+
+void ClangDocBitcodeReader::storeData(llvm::SmallVectorImpl<Reference> &Field,
+                                      llvm::StringRef Blob) {
+  Field.emplace_back(Blob, (InfoType)Record[0]);
+}
+
+// Read records
+
+template <typename T>
+bool ClangDocBitcodeReader::readRecord(llvm::BitstreamCursor &Stream,
+                                       unsigned ID, T &I) {
+  Record.clear();
+  llvm::StringRef Blob;
+  unsigned RecID = Stream.readRecord(ID, Record, &Blob);
+  return parseRecord(RecID, Blob, I);
+  return false;
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        unsigned VersionNo) {
+  if (ID == VERSION && Record[0] == VersionNo) return true;
+  return false;
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        NamespaceInfo &I) {
+  switch (ID) {
+    case NAMESPACE_USR:
+      storeData(I.USR, Blob);
+      return true;
+    case NAMESPACE_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case NAMESPACE_NAMESPACE:
+      storeData(I.Namespace, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        RecordInfo &I) {
+  switch (ID) {
+    case RECORD_USR:
+      storeData(I.USR, Blob);
+      return true;
+    case RECORD_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case RECORD_NAMESPACE:
+      storeData(I.Namespace, Blob);
+      return true;
+    case RECORD_ISDEFINITION:
+      storeData(I.IsDefinition, Blob);
+      return true;
+    case RECORD_PARENT:
+      storeData(I.Parents, Blob);
+      return true;
+    case RECORD_VPARENT:
+      storeData(I.VirtualParents, Blob);
+      return true;
+    case RECORD_DEFLOCATION:
+      storeData(I.DefLoc, Blob);
+      return true;
+    case RECORD_LOCATION:
+      storeData(I.Loc, Blob);
+      return true;
+    case RECORD_TAG_TYPE:
+      storeData(I.TagType, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        EnumInfo &I) {
+  switch (ID) {
+    case ENUM_USR:
+      storeData(I.USR, Blob);
+      return true;
+    case ENUM_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case ENUM_NAMESPACE:
+      storeData(I.Namespace, Blob);
+      return true;
+    case ENUM_ISDEFINITION:
+      storeData(I.IsDefinition, Blob);
+      return true;
+    case ENUM_DEFLOCATION:
+      storeData(I.DefLoc, Blob);
+      return true;
+    case ENUM_LOCATION:
+      storeData(I.Loc, Blob);
+      return true;
+    case ENUM_SCOPED:
+      storeData(I.Scoped, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        FunctionInfo &I) {
+  switch (ID) {
+    case FUNCTION_USR:
+      storeData(I.USR, Blob);
+      return true;
+    case FUNCTION_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case FUNCTION_NAMESPACE:
+      storeData(I.Namespace, Blob);
+      return true;
+    case FUNCTION_PARENT:
+      storeData(I.Parent, Blob);
+      return true;
+    case FUNCTION_ISDEFINITION:
+      storeData(I.IsDefinition, Blob);
+      return true;
+    case FUNCTION_DEFLOCATION:
+      storeData(I.DefLoc, Blob);
+      return true;
+    case FUNCTION_LOCATION:
+      storeData(I.Loc, Blob);
+      return true;
+    case FUNCTION_ACCESS:
+      storeData(I.Access, Blob);
+      return true;
+    case FUNCTION_IS_METHOD:
+      storeData(I.IsMethod, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        TypeInfo &I) {
+  switch (ID) {
+    case TYPE_REF:
+      storeData(I.Type, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        FieldTypeInfo &I) {
+  switch (ID) {
+    case FIELD_TYPE_REF:
+      storeData(I.Type, Blob);
+      return true;
+    case FIELD_TYPE_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        MemberTypeInfo &I) {
+  switch (ID) {
+    case MEMBER_TYPE_REF:
+      storeData(I.Type, Blob);
+      return true;
+    case MEMBER_TYPE_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case MEMBER_TYPE_ACCESS:
+      storeData(I.Access, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool ClangDocBitcodeReader::parseRecord(unsigned ID, llvm::StringRef Blob,
+                                        CommentInfo &I) {
+  switch (ID) {
+    case COMMENT_KIND:
+      storeData(I.Kind, Blob);
+      return true;
+    case COMMENT_TEXT:
+      storeData(I.Text, Blob);
+      return true;
+    case COMMENT_NAME:
+      storeData(I.Name, Blob);
+      return true;
+    case COMMENT_DIRECTION:
+      storeData(I.Direction, Blob);
+      return true;
+    case COMMENT_PARAMNAME:
+      storeData(I.ParamName, Blob);
+      return true;
+    case COMMENT_CLOSENAME:
+      storeData(I.CloseName, Blob);
+      return true;
+    case COMMENT_ATTRKEY:
+      storeData(I.AttrKeys, Blob);
+      return true;
+    case COMMENT_ATTRVAL:
+      storeData(I.AttrValues, Blob);
+      return true;
+    case COMMENT_ARG:
+      storeData(I.Args, Blob);
+      return true;
+    case COMMENT_SELFCLOSING:
+      storeData(I.SelfClosing, Blob);
+      return true;
+    case COMMENT_EXPLICIT:
+      storeData(I.Explicit, Blob);
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Helpers
+CommentInfo &ClangDocBitcodeReader::getCommentInfo(const unsigned int I) {
+  llvm::errs() << "Cannot have comment subblock.\n";
+  exit(1);
+}
+
+CommentInfo &ClangDocBitcodeReader::getCommentInfo(TypeInfo &I) {
+  llvm::errs() << "Cannot have comment subblock.\n";
+  exit(1);
+}
+
+CommentInfo &ClangDocBitcodeReader::getCommentInfo(Info &I) {
+  I.Description.emplace_back();
+  return I.Description.back();
+}
+
+CommentInfo &ClangDocBitcodeReader::getCommentInfo(CommentInfo &I) {
+  I.Children.emplace_back(llvm::make_unique<CommentInfo>());
+  return *I.Children.back();
+}
+
+CommentInfo &ClangDocBitcodeReader::getCommentInfo(
+    std::unique_ptr<CommentInfo> &I) {
+  I->Children.emplace_back(llvm::make_unique<CommentInfo>());
+  return *I->Children.back();
+}
+
+template <typename Iy, typename Ty>
+void ClangDocBitcodeReader::addTypeInfo(Iy &I, Ty &&T) {
+  llvm::errs() << "Invalid type for info.\n";
+  exit(1);
+}
+
+template <>
+void ClangDocBitcodeReader::addTypeInfo(EnumInfo &I, TypeInfo &&T) {
+  I.Members.emplace_back(std::move(T));
+}
+
+template <>
+void ClangDocBitcodeReader::addTypeInfo(RecordInfo &I, MemberTypeInfo &&T) {
+  I.Members.emplace_back(std::move(T));
+}
+
+template <>
+void ClangDocBitcodeReader::addTypeInfo(FunctionInfo &I, TypeInfo &&T) {
+  I.ReturnType = std::move(T);
+}
+
+template <>
+void ClangDocBitcodeReader::addTypeInfo(FunctionInfo &I, FieldTypeInfo &&T) {
+  I.Params.emplace_back(std::move(T));
+}
+
+// Read blocks
+template <typename T>
+bool ClangDocBitcodeReader::readBlock(llvm::BitstreamCursor &Stream,
+                                      unsigned ID, T &I) {
+  if (Stream.EnterSubBlock(ID)) return false;
+
+  while (true) {
+    unsigned BlockOrCode = 0;
+    Cursor Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
+
+    switch (Res) {
+      case Cursor::BadBlock:
+        return false;
+      case Cursor::BlockEnd:
+        return true;
+      case Cursor::BlockBegin:
+        if (readSubBlock(Stream, BlockOrCode, I)) continue;
+        if (!Stream.SkipBlock()) return false;
+        continue;
+      case Cursor::Record:
+        break;
+    }
+    if (!readRecord(Stream, BlockOrCode, I)) return false;
+  }
+}
+
+template <typename Ty>
+bool ClangDocBitcodeReader::readSubBlock(llvm::BitstreamCursor &Stream,
+                                         unsigned ID, Ty &I) {
+  switch (ID) {
+    // Blocks can only have Comment or TypeInfo subblocks
+    case BI_COMMENT_BLOCK_ID:
+      if (readBlock(Stream, ID, getCommentInfo(I))) return true;
+      return false;
+    case BI_TYPE_BLOCK_ID: {
+      TypeInfo T;
+      if (readBlock(Stream, ID, T)) {
+        addTypeInfo(I, std::move(T));
+        return true;
+      }
+    }
+    case BI_FIELD_TYPE_BLOCK_ID: {
+      FieldTypeInfo T;
+      if (readBlock(Stream, ID, T)) {
+        addTypeInfo(I, std::move(T));
+        return true;
+      }
+    }
+    case BI_MEMBER_TYPE_BLOCK_ID: {
+      MemberTypeInfo T;
+      if (readBlock(Stream, ID, T)) {
+        addTypeInfo(I, std::move(T));
+        return true;
+      }
+      return false;
+    }
+    default:
+      llvm::errs() << "Invalid subblock type.\n";
+      return false;
+  }
+}
+
+ClangDocBitcodeReader::Cursor ClangDocBitcodeReader::skipUntilRecordOrBlock(
+    llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
+  BlockOrRecordID = 0;
+
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+
+    switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+      case llvm::bitc::ENTER_SUBBLOCK:
+        BlockOrRecordID = Stream.ReadSubBlockID();
+        return Cursor::BlockBegin;
+      case llvm::bitc::END_BLOCK:
+        if (Stream.ReadBlockEnd()) return Cursor::BadBlock;
+        return Cursor::BlockEnd;
+      case llvm::bitc::DEFINE_ABBREV:
+        Stream.ReadAbbrevRecord();
+        continue;
+      case llvm::bitc::UNABBREV_RECORD:
+        return Cursor::BadBlock;
+      default:
+        BlockOrRecordID = Code;
+        return Cursor::Record;
+    }
+  }
+  llvm_unreachable("Premature stream end.");
+}
+
+// Validation and overview
+
+bool ClangDocBitcodeReader::validateStream(llvm::BitstreamCursor &Stream) {
+  if (Stream.AtEndOfStream()) return false;
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'D' || Stream.Read(8) != 'O' || Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'S')
+    return false;
+  return true;
+}
+
+bool ClangDocBitcodeReader::readBlockInfoBlock(llvm::BitstreamCursor &Stream) {
+  BlockInfo = Stream.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
+  if (!BlockInfo) return false;
+  Stream.setBlockInfo(&*BlockInfo);
+  // Extract the record names associated with each field
+  for (unsigned I = BI_FIRST; I <= BI_LAST; ++I) {
+    for (const auto &N : (*BlockInfo).getBlockInfo(I)->RecordNames)
+      RecordNames[N.first] = N.second;
+  }
+  return true;
+}
+
+// Entry point
+
+bool ClangDocBitcodeReader::readBitstream(llvm::SmallString<2048> Bits,
+                                          std::unique_ptr<InfoSet> &IS) {
+  llvm::BitstreamCursor Stream(Bits);
+  if (!validateStream(Stream)) return false;
+
+  // Read the top level blocks.
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+    if (Code != llvm::bitc::ENTER_SUBBLOCK) return false;
+
+    unsigned ID = Stream.ReadSubBlockID();
+    switch (ID) {
+      // NamedType and Comment blocks should not appear at the top level
+      case BI_TYPE_BLOCK_ID:
+      case BI_FIELD_TYPE_BLOCK_ID:
+      case BI_MEMBER_TYPE_BLOCK_ID:
+      case BI_COMMENT_BLOCK_ID:
+        llvm::errs() << "Invalid top level block.\n";
+        return false;
+      case BI_VERSION_BLOCK_ID:
+        if (readBlock(Stream, ID, VersionNumber)) continue;
+        return false;
+      case llvm::bitc::BLOCKINFO_BLOCK_ID:
+        if (readBlockInfoBlock(Stream)) continue;
+        return false;
+      case BI_NAMESPACE_BLOCK_ID: {
+        NamespaceInfo I;
+        if (!readBlockToInfo(Stream, ID, IS, std::move(I))) return false;
+        continue;
+      }
+      case BI_RECORD_BLOCK_ID: {
+        RecordInfo I;
+        if (!readBlockToInfo(Stream, ID, IS, std::move(I))) return false;
+        continue;
+      }
+      case BI_ENUM_BLOCK_ID: {
+        EnumInfo I;
+        if (!readBlockToInfo(Stream, ID, IS, std::move(I))) return false;
+        continue;
+      }
+      case BI_FUNCTION_BLOCK_ID: {
+        FunctionInfo I;
+        if (!readBlockToInfo(Stream, ID, IS, std::move(I))) return false;
+        continue;
+      }
+      default:
+        if (!Stream.SkipBlock()) return false;
+        continue;
+    }
+  }
+  return true;
+}
+
+template <typename T>
+bool ClangDocBitcodeReader::readBlockToInfo(llvm::BitstreamCursor &Stream,
+                                            unsigned ID,
+                                            std::unique_ptr<InfoSet> &IS,
+                                            T &&I) {
+  if (!readBlock(Stream, ID, I)) {
+    llvm::errs() << "Error reading from block.\n";
+    return false;
+  }
+  IS->insert(I.USR, std::move(I));
+  return true;
+}
+
+}  // namespace doc
+}  // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to