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