juliehockett created this revision.
juliehockett added reviewers: ioeric, lebedev.ri.
juliehockett added a project: clang-tools-extra.

The first reduce pass combines all duplicate info data into one representation 
of that declaration info. This second pass iterates through the output of that 
first pass in order to streamline the outputted documentation.

The result of this pass is that all Function and Enum infos are absorbed into 
the info of their enclosing scope (i.e. the class or namespace in which they 
are defined). Namespace and Record infos are passed along to the final output, 
but the second pass creates a reference to each in its parent scope. As a 
result, the top-level final outputs are Namespaces and Records (and any 
declarations internal to functions are discarded).


https://reviews.llvm.org/D48341

Files:
  clang-tools-extra/clang-doc/Representation.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/YAMLGenerator.cpp
  clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
  clang-tools-extra/test/clang-doc/yaml-comments.cpp
  clang-tools-extra/test/clang-doc/yaml-namespace.cpp
  clang-tools-extra/test/clang-doc/yaml-record.cpp

Index: clang-tools-extra/test/clang-doc/yaml-record.cpp
===================================================================
--- clang-tools-extra/test/clang-doc/yaml-record.cpp
+++ clang-tools-extra/test/clang-doc/yaml-record.cpp
@@ -1,250 +1,301 @@
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "" > %t/compile_flags.txt
-// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: cat %t/docs/A.yaml | FileCheck %s --check-prefix=CHECK-A
-// RUN: cat %t/docs/Bc.yaml | FileCheck %s --check-prefix=CHECK-BC
-// RUN: cat %t/docs/B.yaml | FileCheck %s --check-prefix=CHECK-B
-// RUN: cat %t/docs/C.yaml | FileCheck %s --check-prefix=CHECK-C
-// RUN: cat %t/docs/D.yaml | FileCheck %s --check-prefix=CHECK-D
-// RUN: cat %t/docs/E.yaml | FileCheck %s --check-prefix=CHECK-E
-// RUN: cat %t/docs/E/ProtectedMethod.yaml | FileCheck %s --check-prefix=CHECK-EPM
-// RUN: cat %t/docs/E/E.yaml | FileCheck %s --check-prefix=CHECK-ECON
-// RUN: cat %t/docs/E/'~E.yaml' | FileCheck %s --check-prefix=CHECK-EDES
-// RUN: cat %t/docs/F.yaml | FileCheck %s --check-prefix=CHECK-F
-// RUN: cat %t/docs/X.yaml | FileCheck %s --check-prefix=CHECK-X
-// RUN: cat %t/docs/X/Y.yaml | FileCheck %s --check-prefix=CHECK-Y
-// RUN: cat %t/docs/H.yaml | FileCheck %s --check-prefix=CHECK-H
-// RUN: cat %t/docs/H/I.yaml | FileCheck %s --check-prefix=CHECK-I
-
-union A { int X; int Y; };
-
-// CHECK-A: ---
-// CHECK-A-NEXT: USR:             'ACE81AFA6627B4CEF2B456FB6E1252925674AF7E'
-// CHECK-A-NEXT: Name:            'A'
-// CHECK-A-NEXT: DefLocation:     
-// CHECK-A-NEXT:   LineNumber:      21
-// CHECK-A-NEXT:   Filename:        '{{.*}}'
-// CHECK-A-NEXT: TagType:         Union
-// CHECK-A-NEXT: Members:         
-// CHECK-A-NEXT:   - Type:            
-// CHECK-A-NEXT:       Name:            'int'
-// CHECK-A-NEXT:     Name:            'X'
-// CHECK-A-NEXT:   - Type:            
-// CHECK-A-NEXT:       Name:            'int'
-// CHECK-A-NEXT:     Name:            'Y'
-// CHECK-A-NEXT: ...
+// RUN: cp "%s" "%t/{{.*}}.cpp"
+// RUN: clang-doc -doxygen -p %t %t/{{.*}}.cpp -output=%t/docs
+// RUN: cat %t/docs/GlobalNamespace.yaml | FileCheck %s --check-prefix=CHECK-G
+// RUN: cat %t/docs/Records.yaml | FileCheck %s --check-prefix=CHECK-R
+// RUN: cat %t/docs/Records/A.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/Records/C.yaml | FileCheck %s --check-prefix=CHECK-C
+// RUN: cat %t/docs/Records/D.yaml | FileCheck %s --check-prefix=CHECK-D
+// RUN: cat %t/docs/Records/E.yaml | FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/Records/F.yaml | FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/Records/X.yaml | FileCheck %s --check-prefix=CHECK-X
+// RUN: cat %t/docs/Records/X/Y.yaml | FileCheck %s --check-prefix=CHECK-Y
 
+namespace Records {
 
-enum B { X, Y };
+union A {
+  int X;
+  int Y;
+};
 
-// CHECK-B: ---
-// CHECK-B-NEXT: USR:             'FC07BD34D5E77782C263FA944447929EA8753740'
-// CHECK-B-NEXT: Name:            'B'
-// CHECK-B-NEXT: DefLocation:     
-// CHECK-B-NEXT:   LineNumber:      40
-// CHECK-B-NEXT:   Filename:        '{{.*}}'
-// CHECK-B-NEXT: Members:         
-// CHECK-B-NEXT:   - 'X'
-// CHECK-B-NEXT:   - 'Y'
-// CHECK-B-NEXT: ...
+//CHECK-A: ---
+//CHECK-A-NEXT: USR:             '4CEF2DF0745C555B511A58908105E0C50EADA718'
+//CHECK-A-NEXT: Name:            'A'
+//CHECK-A-NEXT: Namespace:       
+//CHECK-A-NEXT:   - Type:            Namespace
+//CHECK-A-NEXT:     Name:            'Records'
+//CHECK-A-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-A-NEXT: DefLocation:     
+//CHECK-A-NEXT:   LineNumber:      18
+//CHECK-A-NEXT:   Filename:        '{{.*}}'
+//CHECK-A-NEXT: TagType:         Union
+//CHECK-A-NEXT: Members:         
+//CHECK-A-NEXT:   - Type:            
+//CHECK-A-NEXT:       Name:            'int'
+//CHECK-A-NEXT:     Name:            'X'
+//CHECK-A-NEXT:   - Type:            
+//CHECK-A-NEXT:       Name:            'int'
+//CHECK-A-NEXT:     Name:            'Y'
+//CHECK-A-NEXT: ...
 
-enum class Bc { A, B };
+struct C {
+  int i;
+};
+
+//CHECK-C: ---
+//CHECK-C-NEXT: USR:             '4EE7D72B3FDB5E3960C3B6B57011CCE41A64858B'
+//CHECK-C-NEXT: Name:            'C'
+//CHECK-C-NEXT: Namespace:       
+//CHECK-C-NEXT:   - Type:            Namespace
+//CHECK-C-NEXT:     Name:            'Records'
+//CHECK-C-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-C-NEXT: DefLocation:     
+//CHECK-C-NEXT:   LineNumber:      43
+//CHECK-C-NEXT:   Filename:        '{{.*}}'
+//CHECK-C-NEXT: Members:         
+//CHECK-C-NEXT:   - Type:            
+//CHECK-C-NEXT:       Name:            'int'
+//CHECK-C-NEXT:     Name:            'i'
+//CHECK-C-NEXT: ...
 
-// CHECK-BC: ---
-// CHECK-BC-NEXT: USR:             '1E3438A08BA22025C0B46289FF0686F92C8924C5'
-// CHECK-BC-NEXT: Name:            'Bc'
-// CHECK-BC-NEXT: DefLocation:     
-// CHECK-BC-NEXT:   LineNumber:      53
-// CHECK-BC-NEXT:   Filename:        '{{.*}}'
-// CHECK-BC-NEXT: Scoped:          true
-// CHECK-BC-NEXT: Members:         
-// CHECK-BC-NEXT:   - 'A'
-// CHECK-BC-NEXT:   - 'B'
-// CHECK-BC-NEXT: ...
-
-struct C { int i; };
-
-// CHECK-C: ---
-// CHECK-C-NEXT: USR:             '06B5F6A19BA9F6A832E127C9968282B94619B210'
-// CHECK-C-NEXT: Name:            'C'
-// CHECK-C-NEXT: DefLocation:     
-// CHECK-C-NEXT:   LineNumber:      67
-// CHECK-C-NEXT:   Filename:        '{{.*}}'
-// CHECK-C-NEXT: Members:         
-// CHECK-C-NEXT:   - Type:            
-// CHECK-C-NEXT:       Name:            'int'
-// CHECK-C-NEXT:     Name:            'i'
-// CHECK-C-NEXT: ...
 
 class D {};
 
-// CHECK-D: ---
-// CHECK-D-NEXT: USR:             '0921737541208B8FA9BB42B60F78AC1D779AA054'
-// CHECK-D-NEXT: Name:            'D'
-// CHECK-D-NEXT: DefLocation:     
-// CHECK-D-NEXT:   LineNumber:      81
-// CHECK-D-NEXT:   Filename:        '{{.*}}'
-// CHECK-D-NEXT: TagType:         Class
-// CHECK-D-NEXT: ...
+//CHECK-D: ---
+//CHECK-D-NEXT: USR:             '46338D046036E1CA878745D9245396CE05815B31'
+//CHECK-D-NEXT: Name:            'D'
+//CHECK-D-NEXT: Namespace:       
+//CHECK-D-NEXT:   - Type:            Namespace
+//CHECK-D-NEXT:     Name:            'Records'
+//CHECK-D-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-D-NEXT: DefLocation:     
+//CHECK-D-NEXT:   LineNumber:      64
+//CHECK-D-NEXT:   Filename:        '{{.*}}'
+//CHECK-D-NEXT: TagType:         Class
+//CHECK-D-NEXT: ...
+
 
 class E {
 public:
   E() {}
-
-// CHECK-ECON: ---
-// CHECK-ECON-NEXT: USR:             'DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4'
-// CHECK-ECON-NEXT: Name:            'E'
-// CHECK-ECON-NEXT: Namespace:       
-// CHECK-ECON-NEXT:   - Type:            Record
-// CHECK-ECON-NEXT:     Name:            'E'
-// CHECK-ECON-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-ECON-NEXT: DefLocation:
-// CHECK-ECON-NEXT:   LineNumber:      94
-// CHECK-ECON-NEXT:   Filename:        '{{.*}}'
-// CHECK-ECON-NEXT: IsMethod:        true
-// CHECK-ECON-NEXT: Parent:          
-// CHECK-ECON-NEXT:   Type:            Record
-// CHECK-ECON-NEXT:   Name:            'E'
-// CHECK-ECON-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-ECON-NEXT: ReturnType:      
-// CHECK-ECON-NEXT:   Type:            
-// CHECK-ECON-NEXT:     Name:            'void'
-// CHECK-ECON-NEXT: ...
-  
   ~E() {}
-  
-// CHECK-EDES: ---
-// CHECK-EDES-NEXT: USR:             'BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17'
-// CHECK-EDES-NEXT: Name:            '~E'
-// CHECK-EDES-NEXT: Namespace:       
-// CHECK-EDES-NEXT:   - Type:            Record
-// CHECK-EDES-NEXT:     Name:            'E'
-// CHECK-EDES-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-EDES-NEXT: DefLocation:     
-// CHECK-EDES-NEXT:   LineNumber:      116
-// CHECK-EDES-NEXT:   Filename:        '{{.*}}'
-// CHECK-EDES-NEXT: IsMethod:        true
-// CHECK-EDES-NEXT: Parent:          
-// CHECK-EDES-NEXT:   Type:            Record
-// CHECK-EDES-NEXT:   Name:            'E'
-// CHECK-EDES-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-EDES-NEXT: ReturnType:      
-// CHECK-EDES-NEXT:   Type:            
-// CHECK-EDES-NEXT:     Name:            'void'
-// CHECK-EDES-NEXT: ...
-
 
 protected:
   void ProtectedMethod();
 };
 
-// CHECK-E: ---
-// CHECK-E-NEXT: USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-E-NEXT: Name:            'E'
-// CHECK-E-NEXT: DefLocation:     
-// CHECK-E-NEXT:   LineNumber:      92
-// CHECK-E-NEXT:   Filename:        '{{.*}}'
-// CHECK-E-NEXT: TagType:         Class
-// CHECK-E-NEXT: ...
-
 void E::ProtectedMethod() {}
 
-// CHECK-EPM: ---
-// CHECK-EPM-NEXT: USR:             '5093D428CDC62096A67547BA52566E4FB9404EEE'
-// CHECK-EPM-NEXT: Name:            'ProtectedMethod'
-// CHECK-EPM-NEXT: Namespace:       
-// CHECK-EPM-NEXT:   - Type:            Record
-// CHECK-EPM-NEXT:     Name:            'E'
-// CHECK-EPM-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-EPM-NEXT: DefLocation:     
-// CHECK-EPM-NEXT:   LineNumber:      152
-// CHECK-EPM-NEXT:   Filename:        '{{.*}}'
-// CHECK-EPM-NEXT: Location:        
-// CHECK-EPM-NEXT:   - LineNumber:      140
-// CHECK-EPM-NEXT:     Filename:        '{{.*}}'
-// CHECK-EPM-NEXT: IsMethod:        true
-// CHECK-EPM-NEXT: Parent:          
-// CHECK-EPM-NEXT:   Type:            Record
-// CHECK-EPM-NEXT:   Name:            'E'
-// CHECK-EPM-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-EPM-NEXT: ReturnType:      
-// CHECK-EPM-NEXT:   Type:            
-// CHECK-EPM-NEXT:     Name:            'void'
-// CHECK-EPM-NEXT: ...
+//CHECK-E: ---
+//CHECK-E-NEXT: USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT: Name:            'E'
+//CHECK-E-NEXT: Namespace:       
+//CHECK-E-NEXT:   - Type:            Namespace
+//CHECK-E-NEXT:     Name:            'Records'
+//CHECK-E-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-E-NEXT: DefLocation:     
+//CHECK-E-NEXT:   LineNumber:      80
+//CHECK-E-NEXT:   Filename:        '{{.*}}'
+//CHECK-E-NEXT: TagType:         Class
+//CHECK-E-NEXT: ChildFunctions:  
+//CHECK-E-NEXT:   - USR:             '27891438584F9D4524AC344014F9EDF9210BBD97'
+//CHECK-E-NEXT:     Name:            '~E'
+//CHECK-E-NEXT:     Namespace:       
+//CHECK-E-NEXT:       - Type:            Record
+//CHECK-E-NEXT:         Name:            'E'
+//CHECK-E-NEXT:         USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:       - Type:            Namespace
+//CHECK-E-NEXT:         Name:            'Records'
+//CHECK-E-NEXT:         USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-E-NEXT:     DefLocation:     
+//CHECK-E-NEXT:       LineNumber:      83
+//CHECK-E-NEXT:       Filename:        '{{.*}}'
+//CHECK-E-NEXT:     IsMethod:        true
+//CHECK-E-NEXT:     Parent:          
+//CHECK-E-NEXT:       Type:            Record
+//CHECK-E-NEXT:       Name:            'E'
+//CHECK-E-NEXT:       USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:     ReturnType:      
+//CHECK-E-NEXT:       Type:            
+//CHECK-E-NEXT:         Name:            'void'
+//CHECK-E-NEXT:   - USR:             'E9F0209D569A0C2409D4CBDD39D0A09FA50B91FF'
+//CHECK-E-NEXT:     Name:            'ProtectedMethod'
+//CHECK-E-NEXT:     Namespace:       
+//CHECK-E-NEXT:       - Type:            Record
+//CHECK-E-NEXT:         Name:            'E'
+//CHECK-E-NEXT:         USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:       - Type:            Namespace
+//CHECK-E-NEXT:         Name:            'Records'
+//CHECK-E-NEXT:         USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-E-NEXT:     DefLocation:     
+//CHECK-E-NEXT:       LineNumber:      89
+//CHECK-E-NEXT:       Filename:        '{{.*}}'
+//CHECK-E-NEXT:     Location:        
+//CHECK-E-NEXT:       - LineNumber:      86
+//CHECK-E-NEXT:         Filename:        '{{.*}}'
+//CHECK-E-NEXT:     IsMethod:        true
+//CHECK-E-NEXT:     Parent:          
+//CHECK-E-NEXT:       Type:            Record
+//CHECK-E-NEXT:       Name:            'E'
+//CHECK-E-NEXT:       USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:     ReturnType:      
+//CHECK-E-NEXT:       Type:            
+//CHECK-E-NEXT:         Name:            'void'
+//CHECK-E-NEXT:   - USR:             'F0E5D0D6B95740D966BA04F8412D760CA2525640'
+//CHECK-E-NEXT:     Name:            'E'
+//CHECK-E-NEXT:     Namespace:       
+//CHECK-E-NEXT:       - Type:            Record
+//CHECK-E-NEXT:         Name:            'E'
+//CHECK-E-NEXT:         USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:       - Type:            Namespace
+//CHECK-E-NEXT:         Name:            'Records'
+//CHECK-E-NEXT:         USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-E-NEXT:     DefLocation:     
+//CHECK-E-NEXT:       LineNumber:      82
+//CHECK-E-NEXT:       Filename:        '{{.*}}'
+//CHECK-E-NEXT:     IsMethod:        true
+//CHECK-E-NEXT:     Parent:          
+//CHECK-E-NEXT:       Type:            Record
+//CHECK-E-NEXT:       Name:            'E'
+//CHECK-E-NEXT:       USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-E-NEXT:     ReturnType:      
+//CHECK-E-NEXT:       Type:            
+//CHECK-E-NEXT:         Name:            'void'
+//CHECK-E-NEXT: ...
 
 class F : virtual private D, public E {};
 
-// CHECK-F: ---
-// CHECK-F-NEXT: USR:             'E3B54702FABFF4037025BA194FC27C47006330B5'
-// CHECK-F-NEXT: Name:            'F'
-// CHECK-F-NEXT: DefLocation:     
-// CHECK-F-NEXT:   LineNumber:      177
-// CHECK-F-NEXT:   Filename:        '{{.*}}'
-// CHECK-F-NEXT: TagType:         Class
-// CHECK-F-NEXT: Parents:         
-// CHECK-F-NEXT:   - Type:            Record
-// CHECK-F-NEXT:     Name:            'E'
-// CHECK-F-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
-// CHECK-F-NEXT: VirtualParents:  
-// CHECK-F-NEXT:   - Type:            Record
-// CHECK-F-NEXT:     Name:            'D'
-// CHECK-F-NEXT:     USR:             '0921737541208B8FA9BB42B60F78AC1D779AA054'
-// CHECK-F-NEXT: ...
+//CHECK-F: ---
+//CHECK-F-NEXT: USR:             '02E91F603621631ADB210A166EFB74C7B217BFE1'
+//CHECK-F-NEXT: Name:            'F'
+//CHECK-F-NEXT: Namespace:       
+//CHECK-F-NEXT:   - Type:            Namespace
+//CHECK-F-NEXT:     Name:            'Records'
+//CHECK-F-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-F-NEXT: DefLocation:     
+//CHECK-F-NEXT:   LineNumber:      168
+//CHECK-F-NEXT:   Filename:        '{{.*}}'
+//CHECK-F-NEXT: TagType:         Class
+//CHECK-F-NEXT: Parents:         
+//CHECK-F-NEXT:   - Type:            Record
+//CHECK-F-NEXT:     Name:            'E'
+//CHECK-F-NEXT:     USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-F-NEXT: VirtualParents:  
+//CHECK-F-NEXT:   - Type:            Record
+//CHECK-F-NEXT:     Name:            'D'
+//CHECK-F-NEXT:     USR:             '46338D046036E1CA878745D9245396CE05815B31'
+//CHECK-F-NEXT: ...
 
 class X {
   class Y {};
   
-// CHECK-Y: ---
-// CHECK-Y-NEXT: USR:             '641AB4A3D36399954ACDE29C7A8833032BF40472'
-// CHECK-Y-NEXT: Name:            'Y'
-// CHECK-Y-NEXT: Namespace:       
-// CHECK-Y-NEXT:   - Type:            Record
-// CHECK-Y-NEXT:     Name:            'X'
-// CHECK-Y-NEXT:     USR:             'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
-// CHECK-Y-NEXT: DefLocation:     
-// CHECK-Y-NEXT:   LineNumber:      197
-// CHECK-Y-NEXT:   Filename:        '{{.*}}'
-// CHECK-Y-NEXT: TagType:         Class
-// CHECK-Y-NEXT: ...
+//CHECK-Y: ---
+//CHECK-Y-NEXT: USR:             '09B9080AF84CC90D1A19DF25282AFFA8335490D0'
+//CHECK-Y-NEXT: Name:            'Y'
+//CHECK-Y-NEXT: Namespace:       
+//CHECK-Y-NEXT:   - Type:            Record
+//CHECK-Y-NEXT:     Name:            'X'
+//CHECK-Y-NEXT:     USR:             '456785191D5B1F0EDA2ABA8D89070D5C398BE2C2'
+//CHECK-Y-NEXT:   - Type:            Namespace
+//CHECK-Y-NEXT:     Name:            'Records'
+//CHECK-Y-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-Y-NEXT: DefLocation:     
+//CHECK-Y-NEXT:   LineNumber:      192
+//CHECK-Y-NEXT:   Filename:        '{{.*}}'
+//CHECK-Y-NEXT: TagType:         Class
+//CHECK-Y-NEXT: ...
 
 };
 
-// CHECK-X: ---
-// CHECK-X-NEXT: USR:             'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
-// CHECK-X-NEXT: Name:            'X'
-// CHECK-X-NEXT: DefLocation:     
-// CHECK-X-NEXT:   LineNumber:      196
-// CHECK-X-NEXT:   Filename:        '{{.*}}'
-// CHECK-X-NEXT: TagType:         Class
-// CHECK-X-NEXT: ...
+//CHECK-X: ---
+//CHECK-X-NEXT: USR:             '456785191D5B1F0EDA2ABA8D89070D5C398BE2C2'
+//CHECK-X-NEXT: Name:            'X'
+//CHECK-X-NEXT: Namespace:       
+//CHECK-X-NEXT:   - Type:            Namespace
+//CHECK-X-NEXT:     Name:            'Records'
+//CHECK-X-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-X-NEXT: DefLocation:     
+//CHECK-X-NEXT:   LineNumber:      191
+//CHECK-X-NEXT:   Filename:        '{{.*}}'
+//CHECK-X-NEXT: TagType:         Class
+//CHECK-X-NEXT: ChildRecords:    
+//CHECK-X-NEXT:   - Type:            Record
+//CHECK-X-NEXT:     Name:            'Y'
+//CHECK-X-NEXT:     USR:             '09B9080AF84CC90D1A19DF25282AFFA8335490D0'
+//CHECK-X-NEXT: ...
 
 void H() {
   class I {};
-  
-// CHECK-I: ---
-// CHECK-I-NEXT: USR:             '{{.*}}'
-// CHECK-I-NEXT: Name:            'I'
-// CHECK-I-NEXT: Namespace:       
-// CHECK-I-NEXT:   - Type:            Function
-// CHECK-I-NEXT:     Name:            'H'
-// CHECK-I-NEXT:     USR:             'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
-// CHECK-I-NEXT: DefLocation:     
-// CHECK-I-NEXT:   LineNumber:      224
-// CHECK-I-NEXT:   Filename:        'test'
-// CHECK-I-NEXT: TagType:         Class
-// CHECK-I-NEXT: ...
-
 }
 
-// CHECK-H: ---
-// CHECK-H-NEXT: USR:             'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
-// CHECK-H-NEXT: Name:            'H'
-// CHECK-H-NEXT: DefLocation:     
-// CHECK-H-NEXT:   LineNumber:      223
-// CHECK-H-NEXT:   Filename:        'test'
-// CHECK-H-NEXT: ReturnType:      
-// CHECK-H-NEXT:   Type:            
-// CHECK-H-NEXT:     Name:            'void'
-// CHECK-H-NEXT: ...
+} // namespace Records
+
+//CHECK-R: ---
+//CHECK-R-NEXT: USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-R-NEXT: Name:            'Records'
+//CHECK-R-NEXT: ChildRecords:    
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'F'
+//CHECK-R-NEXT:     USR:             '02E91F603621631ADB210A166EFB74C7B217BFE1'
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'D'
+//CHECK-R-NEXT:     USR:             '46338D046036E1CA878745D9245396CE05815B31'
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'E'
+//CHECK-R-NEXT:     USR:             '879C0D9A894E1E702C54B5CBC71279091D9C85AA'
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'X'
+//CHECK-R-NEXT:     USR:             '456785191D5B1F0EDA2ABA8D89070D5C398BE2C2'
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'A'
+//CHECK-R-NEXT:     USR:             '4CEF2DF0745C555B511A58908105E0C50EADA718'
+//CHECK-R-NEXT:   - Type:            Record
+//CHECK-R-NEXT:     Name:            'C'
+//CHECK-R-NEXT:     USR:             '4EE7D72B3FDB5E3960C3B6B57011CCE41A64858B'
+//CHECK-R-NEXT: ChildFunctions:  
+//CHECK-R-NEXT:   - USR:             'C73C0024A05478DB46EBDBBA2F50400ACB5F99D9'
+//CHECK-R-NEXT:     Name:            'H'
+//CHECK-R-NEXT:     Namespace:       
+//CHECK-R-NEXT:       - Type:            Namespace
+//CHECK-R-NEXT:         Name:            'Records'
+//CHECK-R-NEXT:         USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-R-NEXT:     DefLocation:     
+//CHECK-R-NEXT:       LineNumber:      229
+//CHECK-R-NEXT:       Filename:        '{{.*}}'
+//CHECK-R-NEXT:     ReturnType:      
+//CHECK-R-NEXT:       Type:            
+//CHECK-R-NEXT:         Name:            'void'
+//CHECK-R-NEXT: ...
+
+
+enum B { X, Y };
+
+enum class Bc { A, B };
+
+//CHECK-G: ---
+//CHECK-G-NEXT: USR:             '0000000000000000000000000000000000000000'
+//CHECK-G-NEXT: ChildNamespaces: 
+//CHECK-G-NEXT:   - Type:            Namespace
+//CHECK-G-NEXT:     Name:            'Records'
+//CHECK-G-NEXT:     USR:             '910F55DBF9BF4C7A75A12A4AB871C1B2AE4E7F48'
+//CHECK-G-NEXT: ChildEnums:      
+//CHECK-G-NEXT:   - USR:             'FC07BD34D5E77782C263FA944447929EA8753740'
+//CHECK-G-NEXT:     Name:            'B'
+//CHECK-G-NEXT:     DefLocation:     
+//CHECK-G-NEXT:       LineNumber:      273
+//CHECK-G-NEXT:       Filename:        '{{.*}}'
+//CHECK-G-NEXT:     Members:         
+//CHECK-G-NEXT:       - 'X'
+//CHECK-G-NEXT:       - 'Y'
+//CHECK-G-NEXT:   - USR:             '1E3438A08BA22025C0B46289FF0686F92C8924C5'
+//CHECK-G-NEXT:     Name:            'Bc'
+//CHECK-G-NEXT:     DefLocation:     
+//CHECK-G-NEXT:       LineNumber:      275
+//CHECK-G-NEXT:       Filename:        '{{.*}}'
+//CHECK-G-NEXT:     Scoped:          true
+//CHECK-G-NEXT:     Members:         
+//CHECK-G-NEXT:       - 'A'
+//CHECK-G-NEXT:       - 'B'
+//CHECK-G-NEXT: ...
Index: clang-tools-extra/test/clang-doc/yaml-namespace.cpp
===================================================================
--- clang-tools-extra/test/clang-doc/yaml-namespace.cpp
+++ clang-tools-extra/test/clang-doc/yaml-namespace.cpp
@@ -3,100 +3,104 @@
 // RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
 // RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/GlobalNamespace.yaml | FileCheck %s --check-prefix=CHECK-G
 // RUN: cat %t/docs/A.yaml | FileCheck %s --check-prefix=CHECK-A
 // RUN: cat %t/docs/A/B.yaml | FileCheck %s --check-prefix=CHECK-B
-// RUN: cat %t/docs/A/f.yaml | FileCheck %s --check-prefix=CHECK-F
-// RUN: cat %t/docs/A/B/E.yaml | FileCheck %s --check-prefix=CHECK-E
-// RUN: cat %t/docs/A/B/func.yaml | FileCheck %s --check-prefix=CHECK-FUNC
+
+// CHECK-G: ---
+// CHECK-G-NEXT: USR:             '0000000000000000000000000000000000000000'
+// CHECK-G-NEXT: ChildNamespaces: 
+// CHECK-G-NEXT:   - Type:            Namespace
+// CHECK-G-NEXT:     Name:            'A'
+// CHECK-G-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-G-NEXT: ...
+
 
 namespace A {
-  
+
+void f();
+
+}  // namespace A
+
 // CHECK-A: ---
 // CHECK-A-NEXT: USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
 // CHECK-A-NEXT: Name:            'A'
+// CHECK-A-NEXT: ChildNamespaces: 
+// CHECK-A-NEXT:   - Type:            Namespace
+// CHECK-A-NEXT:     Name:            'B'
+// CHECK-A-NEXT:     USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-A-NEXT: ChildFunctions:  
+// CHECK-A-NEXT:   - USR:             '39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC'
+// CHECK-A-NEXT:     Name:            'f'
+// CHECK-A-NEXT:     Namespace:       
+// CHECK-A-NEXT:       - Type:            Namespace
+// CHECK-A-NEXT:         Name:            'A'
+// CHECK-A-NEXT:         USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-A-NEXT:     DefLocation:     
+// CHECK-A-NEXT:       LineNumber:      52
+// CHECK-A-NEXT:       Filename:        '{{.*}}'
+// CHECK-A-NEXT:     Location:        
+// CHECK-A-NEXT:       - LineNumber:      21
+// CHECK-A-NEXT:         Filename:        '{{.*}}'
+// CHECK-A-NEXT:     ReturnType:      
+// CHECK-A-NEXT:       Type:            
+// CHECK-A-NEXT:         Name:            'void'
 // CHECK-A-NEXT: ...
 
+namespace A {
 
-void f();
+void f(){};
 
-}  // namespace A
+namespace B {
 
-namespace A {
+enum E { X };
 
-void f(){};
+E func(int i) { return X; }
 
-// CHECK-F: ---
-// CHECK-F-NEXT: USR:             '39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC'
-// CHECK-F-NEXT: Name:            'f'
-// CHECK-F-NEXT: Namespace:       
-// CHECK-F-NEXT:   - Type:            Namespace
-// CHECK-F-NEXT:     Name:            'A'
-// CHECK-F-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
-// CHECK-F-NEXT: DefLocation:     
-// CHECK-F-NEXT:   LineNumber:      26
-// CHECK-F-NEXT:   Filename:        '{{.*}}'
-// CHECK-F-NEXT: Location:        
-// CHECK-F-NEXT:   - LineNumber:      20
-// CHECK-F-NEXT:     Filename:        'test'
-// CHECK-F-NEXT: ReturnType:      
-// CHECK-F-NEXT:   Type:            
-// CHECK-F-NEXT:     Name:            'void'
-// CHECK-F-NEXT: ...
+}  // namespace B
+}  // namespace A
 
-namespace B {
-  
 // CHECK-B: ---
 // CHECK-B-NEXT: USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
 // CHECK-B-NEXT: Name:            'B'
 // CHECK-B-NEXT: Namespace:       
 // CHECK-B-NEXT:   - Type:            Namespace
 // CHECK-B-NEXT:     Name:            'A'
 // CHECK-B-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-B-NEXT: ChildFunctions:  
+// CHECK-B-NEXT:   - USR:             '9A82CB33ED0FDF81EE383D31CD0957D153C5E840'
+// CHECK-B-NEXT:     Name:            'func'
+// CHECK-B-NEXT:     Namespace:       
+// CHECK-B-NEXT:       - Type:            Namespace
+// CHECK-B-NEXT:         Name:            'B'
+// CHECK-B-NEXT:         USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-B-NEXT:       - Type:            Namespace
+// CHECK-B-NEXT:         Name:            'A'
+// CHECK-B-NEXT:         USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-B-NEXT:     DefLocation:     
+// CHECK-B-NEXT:       LineNumber:      58
+// CHECK-B-NEXT:       Filename:        '{{.*}}'
+// CHECK-B-NEXT:     Params:          
+// CHECK-B-NEXT:       - Type:            
+// CHECK-B-NEXT:           Name:            'int'
+// CHECK-B-NEXT:         Name:            'i'
+// CHECK-B-NEXT:     ReturnType:      
+// CHECK-B-NEXT:       Type:            
+// CHECK-B-NEXT:         Name:            'enum A::B::E'
+// CHECK-B-NEXT: ChildEnums:      
+// CHECK-B-NEXT:   - USR:             'E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775'
+// CHECK-B-NEXT:     Name:            'E'
+// CHECK-B-NEXT:     Namespace:       
+// CHECK-B-NEXT:       - Type:            Namespace
+// CHECK-B-NEXT:         Name:            'B'
+// CHECK-B-NEXT:         USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-B-NEXT:       - Type:            Namespace
+// CHECK-B-NEXT:         Name:            'A'
+// CHECK-B-NEXT:         USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-B-NEXT:     DefLocation:     
+// CHECK-B-NEXT:       LineNumber:      56
+// CHECK-B-NEXT:       Filename:        '{{.*}}'
+// CHECK-B-NEXT:     Members:         
+// CHECK-B-NEXT:       - 'X'
 // CHECK-B-NEXT: ...
 
-
-enum E { X };
-
-// CHECK-E: ---
-// CHECK-E-NEXT: USR:             'E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775'
-// CHECK-E-NEXT: Name:            'E'
-// CHECK-E-NEXT: Namespace:       
-// CHECK-E-NEXT:   - Type:            Namespace
-// CHECK-E-NEXT:     Name:            'B'
-// CHECK-E-NEXT:     USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
-// CHECK-E-NEXT:   - Type:            Namespace
-// CHECK-E-NEXT:     Name:            'A'
-// CHECK-E-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
-// CHECK-E-NEXT: DefLocation:     
-// CHECK-E-NEXT:   LineNumber:      58
-// CHECK-E-NEXT:   Filename:        '{{.*}}'
-// CHECK-E-NEXT: Members:         
-// CHECK-E-NEXT:   - 'X'
-// CHECK-E-NEXT: ...
-
-E func(int i) { return X; }
-
-// CHECK-FUNC: ---
-// CHECK-FUNC-NEXT: USR:             '9A82CB33ED0FDF81EE383D31CD0957D153C5E840'
-// CHECK-FUNC-NEXT: Name:            'func'
-// CHECK-FUNC-NEXT: Namespace:       
-// CHECK-FUNC-NEXT:   - Type:            Namespace
-// CHECK-FUNC-NEXT:     Name:            'B'
-// CHECK-FUNC-NEXT:     USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
-// CHECK-FUNC-NEXT:   - Type:            Namespace
-// CHECK-FUNC-NEXT:     Name:            'A'
-// CHECK-FUNC-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
-// CHECK-FUNC-NEXT: DefLocation:     
-// CHECK-FUNC-NEXT:   LineNumber:      77
-// CHECK-FUNC-NEXT:   Filename:        '{{.*}}'
-// CHECK-FUNC-NEXT: Params:          
-// CHECK-FUNC-NEXT:   - Type:            
-// CHECK-FUNC-NEXT:       Name:            'int'
-// CHECK-FUNC-NEXT:     Name:            'i'
-// CHECK-FUNC-NEXT: ReturnType:      
-// CHECK-FUNC-NEXT:   Type:            
-// CHECK-FUNC-NEXT:     Name:            'enum A::B::E'
-// CHECK-FUNC-NEXT: ...
-
-}  // namespace B
-}  // namespace A
Index: clang-tools-extra/test/clang-doc/yaml-comments.cpp
===================================================================
--- clang-tools-extra/test/clang-doc/yaml-comments.cpp
+++ clang-tools-extra/test/clang-doc/yaml-comments.cpp
@@ -3,7 +3,7 @@
 // RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
 // RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
-// RUN: cat %t/docs/F.yaml | FileCheck %s
+// RUN: cat %t/docs/GlobalNamespace.yaml | FileCheck %s
 
 /// \brief Brief description.
 ///
@@ -26,8 +26,10 @@
 /// Bonus comment on definition
 void F(int I, int J) {}
 
-// CHECK: ---
-// CHECK-NEXT: USR:             '7574630614A535710E5A6ABCFFF98BCA2D06A4CA'
+// CHECK: ---  
+// CHECK-NEXT: USR:             '0000000000000000000000000000000000000000'
+// CHECK-NEXT: ChildFunctions:  
+// CHECK-NEXT:  - USR:             '7574630614A535710E5A6ABCFFF98BCA2D06A4CA'
 // CHECK-NEXT: Name:            'F'
 // CHECK-NEXT: Description:     
 // CHECK-NEXT:   - Kind:            'FullComment'
Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -130,6 +130,8 @@
     return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
                                                llvm::inconvertibleErrorCode());
 
+  if (Name.empty())
+    Name = "GlobalNamespace";
   llvm::sys::path::append(Path, Name + Ext);
   return Path;
 }
@@ -142,6 +144,13 @@
   llvm_unreachable("Unknown OutputFormatTy");
 }
 
+void addToOutput(
+    StringRef Key, std::unique_ptr<doc::Info> &&I,
+    llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> &Output) {
+  auto R = Output.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
+  R.first->second.emplace_back(std::move(I));
+}
+
 int main(int argc, const char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   std::error_code OK;
@@ -196,25 +205,25 @@
 
   // In ToolResults, the Key is the hashed USR and the value is the
   // bitcode-encoded representation of the Info object.
-  Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
-                                                   StringRef Value) {
-    llvm::BitstreamCursor Stream(Value);
-    doc::ClangDocBitcodeReader Reader(Stream);
-    auto Infos = Reader.readBitcode();
-    for (auto &I : Infos) {
-      auto R =
-          MapOutput.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
-      R.first->second.emplace_back(std::move(I));
-    }
-  });
+  Exec->get()->getToolResults()->forEachResult(
+      [&](StringRef Key, StringRef Value) {
+        llvm::BitstreamCursor Stream(Value);
+        doc::ClangDocBitcodeReader Reader(Stream);
+        auto Infos = Reader.readBitcode();
+        for (auto &I : Infos) {
+          addToOutput(Key, std::move(I), MapOutput);
+        }
+      });
 
-  // Reducing and generation phases
+  // First reducing phase (by key)
   llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
-  llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
+  llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> ReduceOutput;
   for (auto &Group : MapOutput) {
     auto Reduced = doc::mergeInfos(Group.getValue());
-    if (!Reduced)
+    if (!Reduced) {
       llvm::errs() << llvm::toString(Reduced.takeError());
+      continue;
+    }
 
     if (DumpIntermediateResult) {
       SmallString<4096> Buffer;
@@ -225,9 +234,88 @@
         llvm::errs() << "Error dumping to bitcode.\n";
       continue;
     }
+    
+    // Prepare for second reduce pass.
+    
+    // Get the enclosing scope of this decl.
+    auto EnclosingScope = Reduced.get()->getEnclosingScope();
+    if (!EnclosingScope) {
+      llvm::errs() << llvm::toString(Reduced.takeError());
+      continue;
+    }
+    
+    // Pass over things declared internally to functions.
+    if (EnclosingScope.get().RefType == doc::InfoType::IT_function)
+      continue;
+    
+    std::string EnclosingScopeKey;
+    if (EnclosingScope.get().USR == doc::SymbolID())
+      EnclosingScopeKey = "";
+    else
+      EnclosingScopeKey =
+          llvm::toHex(llvm::toStringRef(EnclosingScope.get().USR));
+
+    switch (Reduced.get()->IT) {
+    case doc::InfoType::IT_namespace: {
+      // Wrap a reference in the type of the enclosing scope.
+      std::unique_ptr<doc::Info> Ref = llvm::make_unique<doc::NamespaceInfo>(
+          Reduced.get()->USR, Reduced.get()->Name);
+      auto Enclosing = doc::getEnclosingTypeInfo(EnclosingScope.get().RefType,
+                                                 std::move(Ref));
+      if (!Enclosing) {
+        llvm::errs() << llvm::toString(Reduced.takeError());
+        continue;
+      }
+      // Add this reference to the enclosing scope's key.
+      addToOutput(EnclosingScopeKey, std::move(Enclosing.get()), ReduceOutput);
+      // Add the actual info to its own key.
+      addToOutput(Group.getKey(), std::move(Reduced.get()), ReduceOutput);
+      break;
+    }
+    case doc::InfoType::IT_record: {
+      // Wrap a reference in the type of the enclosing scope.
+      std::unique_ptr<doc::Info> Ref = llvm::make_unique<doc::RecordInfo>(
+          Reduced.get()->USR, Reduced.get()->Name);
+      auto Enclosing = doc::getEnclosingTypeInfo(EnclosingScope.get().RefType,
+                                                 std::move(Ref));
+      if (!Enclosing) {
+        llvm::errs() << llvm::toString(Reduced.takeError());
+        continue;
+      }
+      // Add this reference to the enclosing scope's key.
+      addToOutput(EnclosingScopeKey, std::move(Enclosing.get()), ReduceOutput);
+      // Add the actual info to its own key.
+      addToOutput(Group.getKey(), std::move(Reduced.get()), ReduceOutput);
+      break;
+    }
+    case doc::InfoType::IT_enum:
+    case doc::InfoType::IT_function: {
+      // Add this info to the enclosing scope's key.
+      auto Enclosing = doc::getEnclosingTypeInfo(EnclosingScope.get().RefType,
+                                                 std::move(Reduced.get()));
+      if (!Enclosing) {
+        llvm::errs() << llvm::toString(Reduced.takeError());
+        continue;
+      }
+      addToOutput(EnclosingScopeKey, std::move(Enclosing.get()), ReduceOutput);
+      break;
+    }
+    default:
+      llvm::errs() << "Error sorting for second reduce pass.\n";
+    }
+  }
 
+  // Second reducing phase (by scope) and docs generation phase
+  llvm::outs() << "Further reducing " << ReduceOutput.size() << " infos...\n";
+  for (auto &Group : ReduceOutput) {
     // Create the relevant ostream and emit the documentation for this decl.
+    auto Reduced = doc::mergeInfos(Group.getValue());
+    if (!Reduced) {
+      llvm::errs() << llvm::toString(Reduced.takeError());
+      continue;
+    }
     doc::Info *I = Reduced.get().get();
+
     auto InfoPath = getPath(OutDirectory, "." + Format, I->Name, I->Namespace);
     if (!InfoPath) {
       llvm::errs() << toString(InfoPath.takeError()) << "\n";
Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -20,6 +20,8 @@
 LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
 LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
 LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
 
@@ -175,7 +177,14 @@
 };
 
 template <> struct MappingTraits<NamespaceInfo> {
-  static void mapping(IO &IO, NamespaceInfo &I) { InfoMapping(IO, I); }
+  static void mapping(IO &IO, NamespaceInfo &I) {
+    InfoMapping(IO, I);
+    IO.mapOptional("ChildNamespaces", I.ChildNamespaces,
+                   std::vector<Reference>());
+    IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
+    IO.mapOptional("ChildFunctions", I.ChildFunctions);
+    IO.mapOptional("ChildEnums", I.ChildEnums);
+  }
 };
 
 template <> struct MappingTraits<RecordInfo> {
@@ -186,6 +195,11 @@
     IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
     IO.mapOptional("VirtualParents", I.VirtualParents,
                    llvm::SmallVector<Reference, 4>());
+    IO.mapOptional("ChildNamespaces", I.ChildNamespaces,
+                   std::vector<Reference>());
+    IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
+    IO.mapOptional("ChildFunctions", I.ChildFunctions);
+    IO.mapOptional("ChildEnums", I.ChildEnums);
   }
 };
 
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -30,6 +30,9 @@
 using SymbolID = std::array<uint8_t, 20>;
 
 struct Info;
+struct FunctionInfo;
+struct EnumInfo;
+
 enum class InfoType {
   IT_default,
   IT_namespace,
@@ -151,6 +154,8 @@
 /// A base struct for Infos.
 struct Info {
   Info() = default;
+  Info(InfoType IT, SymbolID USR, StringRef Name)
+      : USR(USR), IT(IT), Name(Name) {}
   Info(InfoType IT) : IT(IT) {}
   Info(const Info &Other) = delete;
   Info(Info &&Other) = default;
@@ -165,18 +170,28 @@
 
   void mergeBase(Info &&I);
   bool mergeable(const Info &Other);
+  llvm::Expected<Reference> getEnclosingScope();
 };
 
 // Info for namespaces.
 struct NamespaceInfo : public Info {
   NamespaceInfo() : Info(InfoType::IT_namespace) {}
+  NamespaceInfo(SymbolID USR, StringRef Name)
+      : Info(InfoType::IT_namespace, USR, Name) {}
 
   void merge(NamespaceInfo &&I);
+
+  std::vector<Reference> ChildNamespaces;
+  std::vector<Reference> ChildRecords;
+  std::vector<FunctionInfo> ChildFunctions;
+  std::vector<EnumInfo> ChildEnums;
 };
 
 // Info for symbols.
 struct SymbolInfo : public Info {
   SymbolInfo(InfoType IT) : Info(IT) {}
+  SymbolInfo(InfoType IT, SymbolID USR, StringRef Name)
+      : Info(IT, USR, Name) {}
 
   void merge(SymbolInfo &&I);
 
@@ -204,6 +219,8 @@
 // Info for types.
 struct RecordInfo : public SymbolInfo {
   RecordInfo() : SymbolInfo(InfoType::IT_record) {}
+  RecordInfo(SymbolID USR, StringRef Name)
+      : SymbolInfo(InfoType::IT_record, USR, Name) {}
 
   void merge(RecordInfo &&I);
 
@@ -217,6 +234,11 @@
                                            // parents).
   llvm::SmallVector<Reference, 4>
       VirtualParents; // List of virtual base/parent records.
+
+  std::vector<Reference> ChildNamespaces;
+  std::vector<Reference> ChildRecords;
+  std::vector<FunctionInfo> ChildFunctions;
+  std::vector<EnumInfo> ChildEnums;
 };
 
 // TODO: Expand to allow for documenting templating.
@@ -239,6 +261,11 @@
 llvm::Expected<std::unique_ptr<Info>>
 mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
 
+// A standalone function to wrap a reference in an Info of the appropriate
+// enclosing scope.
+llvm::Expected<std::unique_ptr<Info>>
+getEnclosingTypeInfo(InfoType EnclosingType, std::unique_ptr<Info> &&Info);
+
 } // namespace doc
 } // namespace clang
 
Index: clang-tools-extra/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/clang-doc/Representation.cpp
+++ clang-tools-extra/clang-doc/Representation.cpp
@@ -42,7 +42,7 @@
 mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
   if (Values.empty())
     return llvm::make_error<llvm::StringError>("No info values to merge.\n",
-                                             llvm::inconvertibleErrorCode());
+                                               llvm::inconvertibleErrorCode());
 
   switch (Values[0]->IT) {
   case InfoType::IT_namespace:
@@ -59,21 +59,94 @@
   }
 }
 
+template <typename T>
+bool addInfoToEnclosing(T *Enclosing, std::unique_ptr<Info> &&I) {
+  switch (I->IT) {
+  case InfoType::IT_namespace:
+    Enclosing->ChildNamespaces.emplace_back(I->USR, I->Name, I->IT);
+    return true;
+  case InfoType::IT_record:
+    Enclosing->ChildRecords.emplace_back(I->USR, I->Name, I->IT);
+    return true;
+  case InfoType::IT_function: {
+    FunctionInfo *Info = static_cast<FunctionInfo *>(I.release());
+    Enclosing->ChildFunctions.emplace_back(std::move(*Info));
+    return true;
+  }
+  case InfoType::IT_enum: {
+    EnumInfo *Info = static_cast<EnumInfo *>(I.release());
+    Enclosing->ChildEnums.emplace_back(std::move(*Info));
+    return true;
+  }
+  default:
+    return false;
+  }
+}
+
+llvm::Expected<std::unique_ptr<Info>>
+getEnclosingTypeInfo(InfoType EnclosingType, std::unique_ptr<Info> &&I) {
+  switch (EnclosingType) {
+  case InfoType::IT_namespace: {
+    std::unique_ptr<Info> EnclosingInfo = llvm::make_unique<NamespaceInfo>();
+    NamespaceInfo *Enclosing =
+        static_cast<NamespaceInfo *>(EnclosingInfo.get());
+    if (!addInfoToEnclosing(Enclosing, std::move(I)))
+      return llvm::make_error<llvm::StringError>(
+          "Unexpected reference type.\n", llvm::inconvertibleErrorCode());
+    return EnclosingInfo;
+  }
+  case InfoType::IT_record: {
+    std::unique_ptr<Info> EnclosingInfo = llvm::make_unique<RecordInfo>();
+    RecordInfo *Enclosing = static_cast<RecordInfo *>(EnclosingInfo.get());
+    if (!addInfoToEnclosing(Enclosing, std::move(I)))
+      return llvm::make_error<llvm::StringError>(
+          "Unexpected reference type.\n", llvm::inconvertibleErrorCode());
+    return EnclosingInfo;
+  }
+  default:
+    return llvm::make_error<llvm::StringError>("Unexpected enclosing type.\n",
+                                               llvm::inconvertibleErrorCode());
+  }
+}
+
+llvm::Expected<Reference> Info::getEnclosingScope() {
+  // If this is top level, the enclosing scope is the global namespace.
+  if (Namespace.empty()) {
+    auto R = Reference();
+    R.RefType = InfoType::IT_namespace;
+    return R;
+  }
+
+  switch (Namespace[0].RefType) {
+  // Enclosing scopes should only be namespaces, functions, or records.
+  case InfoType::IT_namespace:
+  case InfoType::IT_record:
+  case InfoType::IT_function:
+    return Namespace[0];
+  case InfoType::IT_enum:
+  case InfoType::IT_default:
+    return llvm::make_error<llvm::StringError>("Unexpected scope type.\n",
+                                               llvm::inconvertibleErrorCode());
+  }
+}
+
 void Info::mergeBase(Info &&Other) {
   assert(mergeable(Other));
   if (USR == EmptySID)
     USR = Other.USR;
   if (Name == "")
     Name = Other.Name;
   if (Namespace.empty())
     Namespace = std::move(Other.Namespace);
-  // Unconditionally extend the description, since each decl may have a comment.
+  // Unconditionally extend the description, since each decl may have a
+  // comment.
   std::move(Other.Description.begin(), Other.Description.end(),
             std::back_inserter(Description));
 }
 
 bool Info::mergeable(const Info &Other) {
-  return IT == Other.IT && (USR == EmptySID || USR == Other.USR);
+  return IT == Other.IT &&
+         (USR == EmptySID || USR == Other.USR || Other.USR == EmptySID);
 }
 
 void SymbolInfo::merge(SymbolInfo &&Other) {
@@ -87,6 +160,16 @@
 
 void NamespaceInfo::merge(NamespaceInfo &&Other) {
   assert(mergeable(Other));
+  // Unconditionally extend the children, since they're added after the
+  // initial reduce and therefore there can only be one.
+  std::move(Other.ChildNamespaces.begin(), Other.ChildNamespaces.end(),
+            std::back_inserter(ChildNamespaces));
+  std::move(Other.ChildRecords.begin(), Other.ChildRecords.end(),
+            std::back_inserter(ChildRecords));
+  std::move(Other.ChildFunctions.begin(), Other.ChildFunctions.end(),
+            std::back_inserter(ChildFunctions));
+  std::move(Other.ChildEnums.begin(), Other.ChildEnums.end(),
+            std::back_inserter(ChildEnums));
   mergeBase(std::move(Other));
 }
 
@@ -100,6 +183,16 @@
     Parents = std::move(Other.Parents);
   if (VirtualParents.empty())
     VirtualParents = std::move(Other.VirtualParents);
+  // Unconditionally extend the children, since they're added after the
+  // initial reduce and therefore there can only be one.
+  std::move(Other.ChildNamespaces.begin(), Other.ChildNamespaces.end(),
+            std::back_inserter(ChildNamespaces));
+  std::move(Other.ChildRecords.begin(), Other.ChildRecords.end(),
+            std::back_inserter(ChildRecords));
+  std::move(Other.ChildFunctions.begin(), Other.ChildFunctions.end(),
+            std::back_inserter(ChildFunctions));
+  std::move(Other.ChildEnums.begin(), Other.ChildEnums.end(),
+            std::back_inserter(ChildEnums));
   SymbolInfo::merge(std::move(Other));
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to