juliehockett updated this revision to Diff 148678. juliehockett marked 11 inline comments as done. juliehockett added a comment.
Reworking the reducer interface a bit to address comments. 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 docs/ReleaseNotes.rst test/clang-doc/bc-comment.cpp test/clang-doc/bc-namespace.cpp test/clang-doc/bc-record.cpp
Index: test/clang-doc/bc-record.cpp =================================================================== --- /dev/null +++ test/clang-doc/bc-record.cpp @@ -0,0 +1,254 @@ +// This test requires Linux due to the system-dependent USR for the +// inner class in function H. +// REQUIRES: system-linux +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "" > %t/compile_flags.txt +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs +// RUN: llvm-bcanalyzer %t/docs/bc/ACE81AFA6627B4CEF2B456FB6E1252925674AF7E.bc --dump | FileCheck %s --check-prefix CHECK-A +// RUN: llvm-bcanalyzer %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc --dump | FileCheck %s --check-prefix CHECK-B +// RUN: llvm-bcanalyzer %t/docs/bc/1E3438A08BA22025C0B46289FF0686F92C8924C5.bc --dump | FileCheck %s --check-prefix CHECK-BC +// RUN: llvm-bcanalyzer %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc --dump | FileCheck %s --check-prefix CHECK-C +// RUN: llvm-bcanalyzer %t/docs/bc/0921737541208B8FA9BB42B60F78AC1D779AA054.bc --dump | FileCheck %s --check-prefix CHECK-D +// RUN: llvm-bcanalyzer %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc --dump | FileCheck %s --check-prefix CHECK-E +// RUN: llvm-bcanalyzer %t/docs/bc/DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4.bc --dump | FileCheck %s --check-prefix CHECK-ECON +// RUN: llvm-bcanalyzer %t/docs/bc/BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17.bc --dump | FileCheck %s --check-prefix CHECK-EDES +// RUN: llvm-bcanalyzer %t/docs/bc/E3B54702FABFF4037025BA194FC27C47006330B5.bc --dump | FileCheck %s --check-prefix CHECK-F +// RUN: llvm-bcanalyzer %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc --dump | FileCheck %s --check-prefix CHECK-H +// RUN: llvm-bcanalyzer %t/docs/bc/6BA1EE2B3DAEACF6E4306F10AF44908F4807927C.bc --dump | FileCheck %s --check-prefix CHECK-I +// RUN: llvm-bcanalyzer %t/docs/bc/5093D428CDC62096A67547BA52566E4FB9404EEE.bc --dump | FileCheck %s --check-prefix CHECK-PM +// RUN: llvm-bcanalyzer %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc --dump | FileCheck %s --check-prefix CHECK-X +// RUN: llvm-bcanalyzer %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc --dump | FileCheck %s --check-prefix CHECK-Y + +void H() { + class I {}; +} +// CHECK-H: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-H-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/> + // CHECK-H-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H' + // CHECK-H-NEXT: <DefLocation abbrevid=6 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-H-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-H-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-H-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-H-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-H-NEXT: </ReferenceBlock> + // CHECK-H-NEXT: </TypeBlock> +// CHECK-H-NEXT: </FunctionBlock> + + +// CHECK-I: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-I-NEXT: <USR abbrevid=4 op0=20 op1=107 op2=161 op3=238 op4=43 op5=61 op6=174 op7=172 op8=246 op9=228 op10=48 op11=111 op12=16 op13=175 op14=68 op15=144 op16=143 op17=72 op18=7 op19=146 op20=124/> + // CHECK-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I' + // CHECK-I-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-I-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/> + // CHECK-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H' + // CHECK-I-NEXT: <RefType abbrevid=6 op0=3/> + // CHECK-I-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-I-NEXT: </ReferenceBlock> + // CHECK-I-NEXT: <DefLocation abbrevid=6 op0=25 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-I-NEXT: <TagType abbrevid=8 op0=3/> +// CHECK-I-NEXT: </RecordBlock> + +union A { int X; int Y; }; +// CHECK-A: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <USR abbrevid=4 op0=20 op1=172 op2=232 op3=26 op4=250 op5=102 op6=39 op7=180 op8=206 op9=242 op10=180 op11=86 op12=251 op13=110 op14=18 op15=82 op16=146 op17=86 op18=116 op19=175 op20=126/> + // CHECK-A-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' + // CHECK-A-NEXT: <DefLocation abbrevid=6 op0=53 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-A-NEXT: <TagType abbrevid=8 op0=2/> + // CHECK-A-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-A-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-A-NEXT: </ReferenceBlock> + // CHECK-A-NEXT: <Name abbrevid=4 op0=1/> blob data = 'X' + // CHECK-A-NEXT: <Access abbrevid=5 op0=3/> + // CHECK-A-NEXT: </MemberTypeBlock> + // CHECK-A-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-A-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-A-NEXT: </ReferenceBlock> + // CHECK-A-NEXT: <Name abbrevid=4 op0=1/> blob data = 'Y' + // CHECK-A-NEXT: <Access abbrevid=5 op0=3/> + // CHECK-A-NEXT: </MemberTypeBlock> +// CHECK-A-NEXT: </RecordBlock> + +enum B { X, Y }; +// CHECK-B: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=252 op2=7 op3=189 op4=52 op5=213 op6=231 op7=119 op8=130 op9=194 op10=99 op11=250 op12=148 op13=68 op14=71 op15=146 op16=158 op17=168 op18=117 op19=55 op20=64/> + // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B' + // CHECK-B-NEXT: <DefLocation abbrevid=6 op0=77 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-B-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X' + // CHECK-B-NEXT: <Member abbrevid=8 op0=1/> blob data = 'Y' +// CHECK-B-NEXT: </EnumBlock> + +enum class Bc { A, B }; +// CHECK-BC: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-BC-NEXT: <USR abbrevid=4 op0=20 op1=30 op2=52 op3=56 op4=160 op5=139 op6=162 op7=32 op8=37 op9=192 op10=180 op11=98 op12=137 op13=255 op14=6 op15=134 op16=249 op17=44 op18=137 op19=36 op20=197/> + // CHECK-BC-NEXT: <Name abbrevid=5 op0=2/> blob data = 'Bc' + // CHECK-BC-NEXT: <DefLocation abbrevid=6 op0=86 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-BC-NEXT: <Scoped abbrevid=9 op0=1/> + // CHECK-BC-NEXT: <Member abbrevid=8 op0=1/> blob data = 'A' + // CHECK-BC-NEXT: <Member abbrevid=8 op0=1/> blob data = 'B' +// CHECK-BC-NEXT: </EnumBlock> + +struct C { int i; }; +// CHECK-C: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-C-NEXT: <USR abbrevid=4 op0=20 op1=6 op2=181 op3=246 op4=161 op5=155 op6=169 op7=246 op8=168 op9=50 op10=225 op11=39 op12=201 op13=150 op14=130 op15=130 op16=185 op17=70 op18=25 op19=178 op20=16/> + // CHECK-C-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C' + // CHECK-C-NEXT: <DefLocation abbrevid=6 op0=96 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-C-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-C-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-C-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-C-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-C-NEXT: </ReferenceBlock> + // CHECK-C-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i' + // CHECK-C-NEXT: <Access abbrevid=5 op0=3/> + // CHECK-C-NEXT: </MemberTypeBlock> +// CHECK-C-NEXT: </RecordBlock> + +class D {}; +// CHECK-D: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-D-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/> + // CHECK-D-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D' + // CHECK-D-NEXT: <DefLocation abbrevid=6 op0=111 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-D-NEXT: <TagType abbrevid=8 op0=3/> +// CHECK-D-NEXT: </RecordBlock> + +class E { +public: + E() {} + ~E() {} + +protected: + void ProtectedMethod(); +}; +// CHECK-E: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-E-NEXT: <DefLocation abbrevid=6 op0=119 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-E-NEXT: <TagType abbrevid=8 op0=3/> +// CHECK-E-NEXT: </RecordBlock> + +// CHECK-ECON: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=222 op2=180 op3=172 op4=28 op5=217 op6=37 op7=60 op8=217 op9=239 op10=127 op11=190 op12=107 op13=202 op14=197 op15=6 op16=215 op17=121 op18=132 op19=171 op20=212/> + // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-ECON-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-ECON-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-ECON-NEXT: </ReferenceBlock> + // CHECK-ECON-NEXT: <IsMethod abbrevid=9 op0=1/> + // CHECK-ECON-NEXT: <DefLocation abbrevid=6 op0=121 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-ECON-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-ECON-NEXT: <Field abbrevid=7 op0=2/> + // CHECK-ECON-NEXT: </ReferenceBlock> + // CHECK-ECON-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-ECON-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-ECON-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-ECON-NEXT: </ReferenceBlock> + // CHECK-ECON-NEXT: </TypeBlock> +// CHECK-ECON-NEXT: </FunctionBlock> + +// CHECK-EDES: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=189 op2=43 op3=222 op4=189 op5=66 op6=63 op7=128 op8=186 op9=204 op10=234 op11=117 op12=222 op13=109 op14=102 op15=34 op16=211 op17=85 op18=252 op19=45 op20=23/> + // CHECK-EDES-NEXT: <Name abbrevid=5 op0=2/> blob data = '~E' + // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-EDES-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-EDES-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-EDES-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-EDES-NEXT: </ReferenceBlock> + // CHECK-EDES-NEXT: <IsMethod abbrevid=9 op0=1/> + // CHECK-EDES-NEXT: <DefLocation abbrevid=6 op0=122 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-EDES-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-EDES-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-EDES-NEXT: <Field abbrevid=7 op0=2/> + // CHECK-EDES-NEXT: </ReferenceBlock> + // CHECK-EDES-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-EDES-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-EDES-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-EDES-NEXT: </ReferenceBlock> + // CHECK-EDES-NEXT: </TypeBlock> +// CHECK-EDES-NEXT: </FunctionBlock> + +void E::ProtectedMethod() {} +// CHECK-PM: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=80 op2=147 op3=212 op4=40 op5=205 op6=198 op7=32 op8=150 op9=166 op10=117 op11=71 op12=186 op13=82 op14=86 op15=110 op16=79 op17=185 op18=64 op19=78 op20=238/> + // CHECK-PM-NEXT: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod' + // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-PM-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-PM-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-PM-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-PM-NEXT: </ReferenceBlock> + // CHECK-PM-NEXT: <IsMethod abbrevid=9 op0=1/> + // CHECK-PM-NEXT: <DefLocation abbrevid=6 op0=184 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-PM-NEXT: <Location abbrevid=7 op0=125 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-PM-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-PM-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-PM-NEXT: <Field abbrevid=7 op0=2/> + // CHECK-PM-NEXT: </ReferenceBlock> + // CHECK-PM-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-PM-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-PM-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-PM-NEXT: </ReferenceBlock> + // CHECK-PM-NEXT: </TypeBlock> +// CHECK-PM-NEXT: </FunctionBlock> + + + +class F : virtual private D, public E {}; +// CHECK-F: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=227 op2=181 op3=71 op4=2 op5=250 op6=191 op7=244 op8=3 op9=112 op10=37 op11=186 op12=25 op13=79 op14=194 op15=124 op16=71 op17=0 op18=99 op19=48 op20=181/> + // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F' + // CHECK-F-NEXT: <DefLocation abbrevid=6 op0=213 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-F-NEXT: <TagType abbrevid=8 op0=3/> + // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/> + // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-F-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-F-NEXT: <Field abbrevid=7 op0=2/> + // CHECK-F-NEXT: </ReferenceBlock> + // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/> + // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D' + // CHECK-F-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-F-NEXT: <Field abbrevid=7 op0=3/> + // CHECK-F-NEXT: </ReferenceBlock> +// CHECK-F-NEXT: </RecordBlock> + +class X { + class Y {}; +}; +// CHECK-X: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-X-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/> + // CHECK-X-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X' + // CHECK-X-NEXT: <DefLocation abbrevid=6 op0=233 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-X-NEXT: <TagType abbrevid=8 op0=3/> +// CHECK-X-NEXT: </RecordBlock> + +// CHECK-Y: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-Y-NEXT: <USR abbrevid=4 op0=20 op1=100 op2=26 op3=180 op4=163 op5=211 op6=99 op7=153 op8=149 op9=74 op10=205 op11=226 op12=156 op13=122 op14=136 op15=51 op16=3 op17=43 op18=244 op19=4 op20=114/> + // CHECK-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y' + // CHECK-Y-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-Y-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/> + // CHECK-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X' + // CHECK-Y-NEXT: <RefType abbrevid=6 op0=2/> + // CHECK-Y-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-Y-NEXT: </ReferenceBlock> + // CHECK-Y-NEXT: <DefLocation abbrevid=6 op0=234 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-Y-NEXT: <TagType abbrevid=8 op0=3/> +// CHECK-Y-NEXT: </RecordBlock> Index: test/clang-doc/bc-namespace.cpp =================================================================== --- /dev/null +++ test/clang-doc/bc-namespace.cpp @@ -0,0 +1,119 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "" > %t/compile_flags.txt +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs +// RUN: llvm-bcanalyzer %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc --dump | FileCheck %s --check-prefix CHECK-A +// RUN: llvm-bcanalyzer %t/docs/bc/E21AF79E2A9D02554BA090D10DF39FE273F5CDB5.bc --dump | FileCheck %s --check-prefix CHECK-B +// RUN: llvm-bcanalyzer %t/docs/bc/39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC.bc --dump | FileCheck %s --check-prefix CHECK-F +// RUN: llvm-bcanalyzer %t/docs/bc/9A82CB33ED0FDF81EE383D31CD0957D153C5E840.bc --dump | FileCheck %s --check-prefix CHECK-FUNC +// RUN: llvm-bcanalyzer %t/docs/bc/E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775.bc --dump | FileCheck %s --check-prefix CHECK-E + +namespace A { +// CHECK-A: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-A-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/> + // CHECK-A-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' +// CHECK-A-NEXT: </NamespaceBlock> + +void f(); + +} // namespace A + +namespace A { + +void f(){}; +// CHECK-F: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=57 op2=211 op3=201 op4=90 op5=95 op6=124 op7=226 op8=186 op9=73 op10=55 op11=189 op12=123 op13=1 op14=186 op15=224 op16=158 op17=188 op18=42 op19=216 op20=172/> + // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'f' + // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/> + // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' + // CHECK-F-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-F-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-F-NEXT: </ReferenceBlock> + // CHECK-F-NEXT: <DefLocation abbrevid=6 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-F-NEXT: <Location abbrevid=7 op0=18 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-F-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-F-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-F-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-F-NEXT: </ReferenceBlock> + // CHECK-F-NEXT: </TypeBlock> +// CHECK-F-NEXT: </FunctionBlock> + +namespace B { +// CHECK-B: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/> + // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B' + // CHECK-B-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/> + // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' + // CHECK-B-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-B-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-B-NEXT: </ReferenceBlock> +// CHECK-B-NEXT: </NamespaceBlock> + +enum E { X }; +// CHECK-E: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=233 op2=171 op3=247 op4=231 op5=226 op6=66 op7=91 op8=98 op9=103 op10=35 op11=212 op12=30 op13=118 op14=228 op15=188 op16=126 op17=122 op18=91 op19=215 op20=117/> + // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E' + // CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/> + // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B' + // CHECK-E-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-E-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-E-NEXT: </ReferenceBlock> + // CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/> + // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' + // CHECK-E-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-E-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-E-NEXT: </ReferenceBlock> + // CHECK-E-NEXT: <DefLocation abbrevid=6 op0=56 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-E-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X' +// CHECK-E-NEXT: </EnumBlock> + +E func(int i) { return X; } +// CHECK-FUNC: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=154 op2=130 op3=203 op4=51 op5=237 op6=15 op7=223 op8=129 op9=238 op10=56 op11=61 op12=49 op13=205 op14=9 op15=87 op16=209 op17=83 op18=197 op19=232 op20=64/> + // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=4/> blob data = 'func' + // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/> + // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B' + // CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-FUNC-NEXT: </ReferenceBlock> + // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/> + // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A' + // CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/> + // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/> + // CHECK-FUNC-NEXT: </ReferenceBlock> + // CHECK-FUNC-NEXT: <DefLocation abbrevid=6 op0=76 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-FUNC-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=12/> blob data = 'enum A::B::E' + // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-FUNC-NEXT: </ReferenceBlock> + // CHECK-FUNC-NEXT: </TypeBlock> + // CHECK-FUNC-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-FUNC-NEXT: </ReferenceBlock> + // CHECK-FUNC-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i' + // CHECK-FUNC-NEXT: </FieldTypeBlock> +// CHECK-FUNC-NEXT: </FunctionBlock> + +} // namespace B +} // namespace A + + + + + + + + + + Index: test/clang-doc/bc-comment.cpp =================================================================== --- /dev/null +++ test/clang-doc/bc-comment.cpp @@ -0,0 +1,197 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "" > %t/compile_flags.txt +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs +// RUN: llvm-bcanalyzer %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc --dump | FileCheck %s + +/// \brief Brief description. +/// +/// Extended description that +/// continues onto the next line. +/// +/// <ul class="test"> +/// <li> Testing. +/// </ul> +/// +/// \verbatim +/// The description continues. +/// \endverbatim +/// -- +/// \param [out] I is a parameter. +/// \param J is a parameter. +/// \return void +void F(int I, int J); + +/// Bonus comment on definition +void F(int I, int J) {} + +// CHECK: <BLOCKINFO_BLOCK/> +// CHECK-NEXT: <VersionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Version abbrevid=4 op0=2/> +// CHECK-NEXT: </VersionBlock> +// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/> + // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment' + // CHECK-NEXT: <Name abbrevid=6 op0=5/> blob data = 'brief' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=19/> blob data = ' Brief description.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=26/> blob data = ' Extended description that' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=30/> blob data = ' continues onto the next line.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment' + // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul' + // CHECK-NEXT: <AttrKey abbrevid=12 op0=5/> blob data = 'class' + // CHECK-NEXT: <AttrVal abbrevid=13 op0=4/> blob data = 'test' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment' + // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'li' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=9/> blob data = ' Testing.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=17/> blob data = 'HTMLEndTagComment' + // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul' + // CHECK-NEXT: <SelfClosing abbrevid=10 op0=1/> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=20/> blob data = 'VerbatimBlockComment' + // CHECK-NEXT: <Name abbrevid=6 op0=8/> blob data = 'verbatim' + // CHECK-NEXT: <CloseName abbrevid=9 op0=11/> blob data = 'endverbatim' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=24/> blob data = 'VerbatimBlockLineComment' + // CHECK-NEXT: <Text abbrevid=5 op0=27/> blob data = ' The description continues.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=3/> blob data = ' --' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment' + // CHECK-NEXT: <Direction abbrevid=7 op0=5/> blob data = '[out]' + // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'I' + // CHECK-NEXT: <Explicit abbrevid=11 op0=1/> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment' + // CHECK-NEXT: <Direction abbrevid=7 op0=4/> blob data = '[in]' + // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'J' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment' + // CHECK-NEXT: <Name abbrevid=6 op0=6/> blob data = 'return' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=5/> blob data = ' void' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment' + // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment' + // CHECK-NEXT: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition' + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: </CommentBlock> + // CHECK-NEXT: <DefLocation abbrevid=6 op0=27 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-NEXT: <Location abbrevid=7 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}' + // CHECK-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void' + // CHECK-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-NEXT: </ReferenceBlock> + // CHECK-NEXT: </TypeBlock> + // CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-NEXT: </ReferenceBlock> + // CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'I' + // CHECK-NEXT: </FieldTypeBlock> + // CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4> + // CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int' + // CHECK-NEXT: <Field abbrevid=7 op0=4/> + // CHECK-NEXT: </ReferenceBlock> + // CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'J' + // CHECK-NEXT: </FieldTypeBlock> +// CHECK-NEXT: </FunctionBlock> Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -42,7 +42,8 @@ Major New Features ------------------ -... +New tool :doc:`clang-doc <clang-doc>`, a tool for generating C and C++ +documenation from source code and comments. Improvements to clang-query --------------------------- Index: clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-doc/tool/ClangDocMain.cpp +++ clang-doc/tool/ClangDocMain.cpp @@ -18,7 +18,10 @@ // //===----------------------------------------------------------------------===// +#include "BitcodeReader.h" #include "ClangDoc.h" +#include "Reducer.h" +#include "Representation.h" #include "clang/AST/AST.h" #include "clang/AST/Decl.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -54,14 +57,62 @@ llvm::cl::desc("Dump mapper results to bitcode file."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt<bool> DumpIntermediateResult( + "dump-intermediate", + llvm::cl::desc("Dump intermediate results to bitcode file."), + llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); + +static llvm::cl::opt<std::string> Format( + "format", + llvm::cl::desc("Format for outputted docs (Current options are yaml)."), + llvm::cl::init("yaml"), llvm::cl::cat(ClangDocCategory)); + static llvm::cl::opt<bool> DoxygenOnly( "doxygen", llvm::cl::desc("Use only doxygen-style comments to generate docs."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); +bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) { + std::error_code OK; + llvm::SmallString<128> DocsRootPath; + if (ClearDirectory) { + std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName); + if (RemoveStatus != OK) { + llvm::errs() << "Unable to remove existing documentation directory for " + << DirName << ".\n"; + return true; + } + } + std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName); + if (DirectoryStatus != OK) { + llvm::errs() << "Unable to create documentation directories.\n"; + return true; + } + return false; +} + +bool DumpResultToFile(const Twine &DirName, const Twine &FileName, + StringRef Buffer, bool ClearDirectory = false) { + std::error_code OK; + llvm::SmallString<128> IRRootPath; + llvm::sys::path::native(OutDirectory, IRRootPath); + llvm::sys::path::append(IRRootPath, DirName); + if (CreateDirectory(IRRootPath, ClearDirectory)) + return true; + llvm::sys::path::append(IRRootPath, FileName); + 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 true; + } + OS << Buffer; + OS.close(); + return false; +} + int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - std::error_code OK; auto Exec = clang::tooling::createExecutorFromCommandLineArgs( argc, argv, ClangDocCategory); @@ -80,34 +131,57 @@ // Mapping phase llvm::outs() << "Mapping decls...\n"; - auto Err = Exec->get()->execute(doc::newMapperActionFactory( - Exec->get()->getExecutionContext()), - ArgAdjuster); - if (Err) + auto Err = Exec->get()->execute( + doc::newMapperActionFactory(Exec->get()->getExecutionContext()), + ArgAdjuster); + if (Err) { llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } if (DumpMapperResult) { - Exec->get()->getToolResults()->forEachResult([&](StringRef Key, - StringRef Value) { - SmallString<128> IRRootPath; - llvm::sys::path::native(OutDirectory, IRRootPath); - llvm::sys::path::append(IRRootPath, "bc"); - 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(); - }); + bool Err = false; + Exec->get()->getToolResults()->forEachResult( + [&](StringRef Key, StringRef Value) { + Err = DumpResultToFile("bc", Key + ".bc", Value); + }); + if (Err) + llvm::errs() << "Error dumping map results.\n"; + return Err; + } + + // Collect values into output by key. + llvm::outs() << "Collecting infos...\n"; + llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> MapOutput; + + // 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)); + } + }); + + // Reducing phase + llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n"; + for (auto &Group : MapOutput) { + auto Reduced = doc::reduceInfos(Group.getValue()); + Group.getValue().clear(); + Group.getValue().emplace_back(std::move(Reduced)); + + if (DumpIntermediateResult) { + SmallString<4096> Buffer; + for (const auto &I : Group.getValue()) + doc::writeInfo(I.get(), Buffer); + if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer)) + return 1; + } } return 0; Index: clang-doc/Representation.h =================================================================== --- clang-doc/Representation.h +++ clang-doc/Representation.h @@ -1,4 +1,4 @@ -///===-- Representation.h - ClangDoc Represenation --------------*- C++ -*-===// +///===-- Representation.h - ClangDoc Representation -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -26,6 +26,7 @@ namespace clang { namespace doc { +// SHA1'd hash of a USR. using SymbolID = std::array<uint8_t, 20>; struct Info; @@ -40,7 +41,8 @@ // A representation of a parsed comment. struct CommentInfo { CommentInfo() = default; - CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {} + CommentInfo(CommentInfo &Other) = delete; + CommentInfo(CommentInfo &&Other) = default; SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment, // HTMLStartTagComment, HTMLEndTagComment, @@ -128,61 +130,92 @@ /// A base struct for Infos. struct Info { Info() = default; - Info(Info &&Other) : Description(std::move(Other.Description)) {} - virtual ~Info() = default; - - SymbolID USR; // Unique identifier for the decl described by this Info. - SmallString<16> Name; // Unqualified name of the decl. + Info(InfoType IT) : IT(IT) {} + Info(const Info &Other) = delete; + Info(Info &&Other) = default; + + SymbolID USR = + SymbolID(); // Unique identifier for the decl described by this Info. + const InfoType IT = InfoType::IT_default; // InfoType of this particular Info. + SmallString<16> Name; // Unqualified name of the decl. llvm::SmallVector<Reference, 4> Namespace; // List of parent namespaces for this decl. std::vector<CommentInfo> Description; // Comment description of this decl. + + void mergeBase(Info &&I); }; // Info for namespaces. -struct NamespaceInfo : public Info {}; +struct NamespaceInfo : public Info { + NamespaceInfo() : Info(InfoType::IT_namespace) {} + + void merge(NamespaceInfo &&I); +}; // Info for symbols. struct SymbolInfo : public Info { + SymbolInfo(InfoType IT) : Info(IT) {} + + void merge(SymbolInfo &&I); + llvm::Optional<Location> DefLoc; // Location where this decl is defined. llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared. }; // TODO: Expand to allow for documenting templating and default args. // Info for functions. struct FunctionInfo : public SymbolInfo { + FunctionInfo() : SymbolInfo(InfoType::IT_function) {} + + void merge(FunctionInfo &&I); + bool IsMethod = false; // Indicates whether this function is a class method. Reference Parent; // Reference to the parent class decl for this method. TypeInfo ReturnType; // Info about the return type of this function. llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters. AccessSpecifier Access = AccessSpecifier::AS_none; // Access level for this - // method (public, private, - // protected, none). + // method (public, + // private, protected, + // none). }; // TODO: Expand to allow for documenting templating, inheritance access, // friend classes // Info for types. struct RecordInfo : public SymbolInfo { - TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record (struct, - // class, union, interface). + RecordInfo() : SymbolInfo(InfoType::IT_record) {} + + void merge(RecordInfo &&I); + + TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record + // (struct, class, union, + // interface). llvm::SmallVector<MemberTypeInfo, 4> Members; // List of info about record members. - llvm::SmallVector<Reference, 4> Parents; // List of base/parent records (does - // not include virtual parents). + llvm::SmallVector<Reference, 4> Parents; // List of base/parent records + // (does not include virtual + // parents). llvm::SmallVector<Reference, 4> VirtualParents; // List of virtual base/parent records. }; // TODO: Expand to allow for documenting templating. // Info for types. struct EnumInfo : public SymbolInfo { + EnumInfo() : SymbolInfo(InfoType::IT_enum) {} + + void merge(EnumInfo &&I); + bool Scoped = false; // Indicates whether this enum is scoped (e.g. enum class). llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members. }; // TODO: Add functionality to include separate markdown pages. +// A standalone function to call to merge a vector of infos into one. +std::unique_ptr<Info> mergeInfos(std::vector<std::unique_ptr<Info>> &Value); + } // namespace doc } // namespace clang Index: clang-doc/Representation.cpp =================================================================== --- /dev/null +++ clang-doc/Representation.cpp @@ -0,0 +1,129 @@ +///===-- Representation.cpp - ClangDoc Representation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the merging of different types of infos. The data in the +// calling Info is preserved during a merge unless that field is empty or +// default. In that case, the data from the parameter Info is used to replace +// the empty or default data. +// +// For most fields, the first decl seen provides the data. Exceptions to this +// include the location and description fields, which are collections of data on +// all decls related to a given definition. All other fields are ignored in new +// decls unless the first seen decl didn't, for whatever reason, incorporate +// data on that field (e.g. a forward declared class wouldn't have information +// on members on the forward declaration, but would have the class name). +// +//===----------------------------------------------------------------------===// +#include "Representation.h" + +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace doc { + +#define ASSERT_MERGEABLE \ + assert(IT == Other.IT && (USR == EmptySID || USR == Other.USR)) + +static const SymbolID EmptySID = SymbolID(); + +template <typename T> +std::unique_ptr<Info> reduce(std::vector<std::unique_ptr<Info>> &Values) { + std::unique_ptr<Info> Merged = llvm::make_unique<T>(); + T *Tmp = static_cast<T *>(Merged.get()); + for (auto &I : Values) + Tmp->merge(std::move(*static_cast<T *>(I.get()))); + return Merged; +} + +// Dispatch function. +std::unique_ptr<Info> mergeInfos(std::vector<std::unique_ptr<Info>> &Values) { + if (Values.empty()) + return nullptr; + + switch (Values[0]->IT) { + case InfoType::IT_namespace: + return reduce<NamespaceInfo>(Values); + case InfoType::IT_record: + return reduce<RecordInfo>(Values); + case InfoType::IT_enum: + return reduce<EnumInfo>(Values); + case InfoType::IT_function: + return reduce<FunctionInfo>(Values); + case InfoType::IT_default: + llvm::errs() << "Unexpected info type in index.\n"; + return nullptr; + } +} + +void Info::mergeBase(Info &&Other) { + ASSERT_MERGEABLE; + 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. + std::move(Other.Description.begin(), Other.Description.end(), + std::back_inserter(Description)); +} + +void SymbolInfo::merge(SymbolInfo &&Other) { + ASSERT_MERGEABLE; + if (!DefLoc) + DefLoc = std::move(Other.DefLoc); + // Unconditionally extend the list of locations, since we want all of them. + std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc)); + mergeBase(std::move(Other)); +} + +void NamespaceInfo::merge(NamespaceInfo &&Other) { + ASSERT_MERGEABLE; + mergeBase(std::move(Other)); +} + +void RecordInfo::merge(RecordInfo &&Other) { + ASSERT_MERGEABLE; + if (!TagType) + TagType = Other.TagType; + if (Members.empty()) + Members = std::move(Other.Members); + if (Parents.empty()) + Parents = std::move(Other.Parents); + if (VirtualParents.empty()) + VirtualParents = std::move(Other.VirtualParents); + SymbolInfo::merge(std::move(Other)); +} + +void EnumInfo::merge(EnumInfo &&Other) { + ASSERT_MERGEABLE; + if (!Scoped) + Scoped = Other.Scoped; + if (Members.empty()) + Members = std::move(Other.Members); + SymbolInfo::merge(std::move(Other)); +} + +void FunctionInfo::merge(FunctionInfo &&Other) { + ASSERT_MERGEABLE; + if (!IsMethod) + IsMethod = Other.IsMethod; + if (!Access) + Access = Other.Access; + if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "") + ReturnType = std::move(Other.ReturnType); + if (Parent.USR == EmptySID && Parent.Name == "") + Parent = std::move(Other.Parent); + if (Params.empty()) + Params = std::move(Other.Params); + SymbolInfo::merge(std::move(Other)); +} + +} // namespace doc +} // namespace clang \ No newline at end of file Index: clang-doc/Reducer.h =================================================================== --- /dev/null +++ clang-doc/Reducer.h @@ -0,0 +1,30 @@ +///===-- 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 (prefering the left in case of +// conflict, and collecting all data from both into the left). +std::unique_ptr<Info> reduceInfos(std::vector<std::unique_ptr<Info>> &Values); + +// Write a given Info out to a bitcode string. +bool writeInfo(Info *I, SmallVectorImpl<char> &Buffer); + +} // 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,47 @@ +///===-- 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 "Reducer.h" +#include "BitcodeReader.h" +#include "BitcodeWriter.h" +#include "Representation.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace doc { + +std::unique_ptr<Info> reduceInfos(std::vector<std::unique_ptr<Info>> &Values) { + return mergeInfos(Values); +} + +bool writeInfo(Info *I, SmallVectorImpl<char> &Buffer) { + llvm::BitstreamWriter Stream(Buffer); + ClangDocBitcodeWriter Writer(Stream); + switch (I->IT) { + case InfoType::IT_namespace: + Writer.emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I)); + break; + case InfoType::IT_record: + Writer.emitBlock(*static_cast<clang::doc::RecordInfo *>(I)); + break; + case InfoType::IT_enum: + Writer.emitBlock(*static_cast<clang::doc::EnumInfo *>(I)); + break; + case InfoType::IT_function: + Writer.emitBlock(*static_cast<clang::doc::FunctionInfo *>(I)); + break; + default: + llvm::errs() << "Unexpected info in index.\n"; + return true; + } + return false; +} + +} // 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 ClangDoc.cpp Mapper.cpp + Reducer.cpp + Representation.cpp Serialize.cpp LINK_LIBS Index: clang-doc/BitcodeWriter.h =================================================================== --- clang-doc/BitcodeWriter.h +++ clang-doc/BitcodeWriter.h @@ -34,7 +34,7 @@ static const unsigned VersionNumber = 2; struct BitCodeConstants { - static constexpr unsigned RecordSize = 16U; + static constexpr unsigned RecordSize = 32U; static constexpr unsigned SignatureBitSize = 8U; static constexpr unsigned SubblockIDSize = 4U; static constexpr unsigned BoolSize = 1U; @@ -45,6 +45,8 @@ static constexpr unsigned ReferenceTypeSize = 8U; static constexpr unsigned USRLengthSize = 6U; static constexpr unsigned USRBitLengthSize = 8U; + static constexpr char Signature[4] = {'D', 'O', 'C', 'S'}; + static constexpr int USRHashSize = 20; }; // New Ids need to be added to both the enum here and the relevant IdNameMap in @@ -113,7 +115,7 @@ #undef INFORECORDS // Identifiers for differentiating between subblocks -enum class FieldId { F_namespace = 1, F_parent, F_vparent, F_type }; +enum class FieldId { F_default, F_namespace, F_parent, F_vparent, F_type }; class ClangDocBitcodeWriter { public: @@ -123,13 +125,6 @@ emitVersionBlock(); } -#ifndef NDEBUG // Don't want explicit dtor unless needed. - ~ClangDocBitcodeWriter() { - // Check that the static size is large-enough. - assert(Record.capacity() > BitCodeConstants::RecordSize); - } -#endif - // Block emission of different info types. void emitBlock(const NamespaceInfo &I); void emitBlock(const RecordInfo &I); Index: clang-doc/BitcodeWriter.cpp =================================================================== --- clang-doc/BitcodeWriter.cpp +++ clang-doc/BitcodeWriter.cpp @@ -214,6 +214,8 @@ // AbbreviationMap +constexpr char BitCodeConstants::Signature[]; + void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID, unsigned AbbrevID) { assert(RecordIdNameMap[RID] && "Unknown RecordId."); @@ -232,7 +234,7 @@ /// \brief Emits the magic number header to check that its the right format, /// in this case, 'DOCS'. void ClangDocBitcodeWriter::emitHeader() { - for (char C : llvm::StringRef("DOCS")) + for (char C : BitCodeConstants::Signature) Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize); } Index: clang-doc/BitcodeReader.h =================================================================== --- /dev/null +++ clang-doc/BitcodeReader.h @@ -0,0 +1,70 @@ +//===-- 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 from 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" + +namespace clang { +namespace doc { + +// Class to read bitstream into an InfoSet collection +class ClangDocBitcodeReader { +public: + ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {} + + // Main entry point, calls readBlock to read each block in the given stream. + std::vector<std::unique_ptr<Info>> readBitcode(); + +private: + enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin }; + + // Top level parsing + bool validateStream(); + bool readVersion(); + bool readBlockInfoBlock(); + + // Read a block of records into a single Info struct, calls readRecord on each + // record found. + template <typename T> bool readBlock(unsigned ID, T I); + + // Step through a block of records to find the next data field. + template <typename T> bool readSubBlock(unsigned ID, T I); + + // Read record data into the given Info data field, calling the appropriate + // parseRecord functions to parse and store the data. + template <typename T> bool readRecord(unsigned ID, T I); + + // Helper function to step through blocks to find and dispatch the next record + // or block to be read. + Cursor skipUntilRecordOrBlock(unsigned &BlockOrRecordID); + + // Helper function to set up the approriate type of Info. + std::unique_ptr<Info> readBlockToInfo(unsigned ID); + + llvm::BitstreamCursor &Stream; + Optional<llvm::BitstreamBlockInfo> BlockInfo; + FieldId CurrentReferenceField; +}; + +} // 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,627 @@ +//===-- 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" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace doc { + +using Record = llvm::SmallVector<uint64_t, 1024>; + +bool decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field, + llvm::StringRef Blob) { + Field.assign(Blob.begin(), Blob.end()); + return true; +} + +bool decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) { + if (R[0] != BitCodeConstants::USRHashSize) + return false; + + // First position in the record is the length of the following array, so we + // copy the following elements to the field. + for (int I = 0, E = R[0]; I < E; ++I) + Field[I] = R[I + 1]; + return true; +} + +bool decodeRecord(Record R, bool &Field, llvm::StringRef Blob) { + Field = R[0] != 0; + return true; +} + +bool decodeRecord(Record R, int &Field, llvm::StringRef Blob) { + if (R[0] > INT_MAX) + return false; + Field = (int)R[0]; + return true; +} + +bool decodeRecord(Record R, AccessSpecifier &Field, llvm::StringRef Blob) { + switch (R[0]) { + case AS_public: + case AS_private: + case AS_protected: + case AS_none: + Field = (AccessSpecifier)R[0]; + return true; + default: + return false; + } +} + +bool decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) { + switch (R[0]) { + case TTK_Struct: + case TTK_Interface: + case TTK_Union: + case TTK_Class: + case TTK_Enum: + Field = (TagTypeKind)R[0]; + return true; + default: + return false; + } +} + +bool decodeRecord(Record R, llvm::Optional<Location> &Field, + llvm::StringRef Blob) { + if (R[0] > INT_MAX) + return false; + Field.emplace((int)R[0], Blob); + return true; +} + +bool decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) { + switch (auto IT = static_cast<InfoType>(R[0])) { + case InfoType::IT_namespace: + case InfoType::IT_record: + case InfoType::IT_function: + case InfoType::IT_default: + case InfoType::IT_enum: + Field = IT; + return true; + } + return false; +} + +bool decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) { + switch (auto F = static_cast<FieldId>(R[0])) { + case FieldId::F_namespace: + case FieldId::F_parent: + case FieldId::F_vparent: + case FieldId::F_type: + case FieldId::F_default: + Field = F; + return true; + } + return false; +} + +bool decodeRecord(Record R, llvm::SmallVectorImpl<llvm::SmallString<16>> &Field, + llvm::StringRef Blob) { + Field.push_back(Blob); + return true; +} + +bool decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field, + llvm::StringRef Blob) { + if (R[0] > INT_MAX) + return false; + Field.emplace_back((int)R[0], Blob); + return true; +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + const unsigned VersionNo) { + if (ID == VERSION && R[0] == VersionNo) + return true; + return false; +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + NamespaceInfo *I) { + switch (ID) { + case NAMESPACE_USR: + return decodeRecord(R, I->USR, Blob); + case NAMESPACE_NAME: + return decodeRecord(R, I->Name, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, RecordInfo *I) { + switch (ID) { + case RECORD_USR: + return decodeRecord(R, I->USR, Blob); + case RECORD_NAME: + return decodeRecord(R, I->Name, Blob); + case RECORD_DEFLOCATION: + return decodeRecord(R, I->DefLoc, Blob); + case RECORD_LOCATION: + return decodeRecord(R, I->Loc, Blob); + case RECORD_TAG_TYPE: + return decodeRecord(R, I->TagType, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, EnumInfo *I) { + switch (ID) { + case ENUM_USR: + return decodeRecord(R, I->USR, Blob); + case ENUM_NAME: + return decodeRecord(R, I->Name, Blob); + case ENUM_DEFLOCATION: + return decodeRecord(R, I->DefLoc, Blob); + case ENUM_LOCATION: + return decodeRecord(R, I->Loc, Blob); + case ENUM_MEMBER: + return decodeRecord(R, I->Members, Blob); + case ENUM_SCOPED: + return decodeRecord(R, I->Scoped, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, FunctionInfo *I) { + switch (ID) { + case FUNCTION_USR: + return decodeRecord(R, I->USR, Blob); + case FUNCTION_NAME: + return decodeRecord(R, I->Name, Blob); + case FUNCTION_DEFLOCATION: + return decodeRecord(R, I->DefLoc, Blob); + case FUNCTION_LOCATION: + return decodeRecord(R, I->Loc, Blob); + case FUNCTION_ACCESS: + return decodeRecord(R, I->Access, Blob); + case FUNCTION_IS_METHOD: + return decodeRecord(R, I->IsMethod, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) { + switch (ID) { + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + FieldTypeInfo *I) { + switch (ID) { + case FIELD_TYPE_NAME: + return decodeRecord(R, I->Name, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + MemberTypeInfo *I) { + switch (ID) { + case MEMBER_TYPE_NAME: + return decodeRecord(R, I->Name, Blob); + case MEMBER_TYPE_ACCESS: + return decodeRecord(R, I->Access, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) { + switch (ID) { + case COMMENT_KIND: + return decodeRecord(R, I->Kind, Blob); + case COMMENT_TEXT: + return decodeRecord(R, I->Text, Blob); + case COMMENT_NAME: + return decodeRecord(R, I->Name, Blob); + case COMMENT_DIRECTION: + return decodeRecord(R, I->Direction, Blob); + case COMMENT_PARAMNAME: + return decodeRecord(R, I->ParamName, Blob); + case COMMENT_CLOSENAME: + return decodeRecord(R, I->CloseName, Blob); + case COMMENT_ATTRKEY: + return decodeRecord(R, I->AttrKeys, Blob); + case COMMENT_ATTRVAL: + return decodeRecord(R, I->AttrValues, Blob); + case COMMENT_ARG: + return decodeRecord(R, I->Args, Blob); + case COMMENT_SELFCLOSING: + return decodeRecord(R, I->SelfClosing, Blob); + case COMMENT_EXPLICIT: + return decodeRecord(R, I->Explicit, Blob); + default: + return false; + } +} + +bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, Reference *I, + FieldId &F) { + switch (ID) { + case REFERENCE_USR: + return decodeRecord(R, I->USR, Blob); + case REFERENCE_NAME: + return decodeRecord(R, I->Name, Blob); + case REFERENCE_TYPE: + return decodeRecord(R, I->RefType, Blob); + case REFERENCE_FIELD: + return decodeRecord(R, F, Blob); + default: + return false; + } +} + +template <typename T> CommentInfo *getCommentInfo(T I) { + llvm::errs() << "Cannot have comment subblock.\n"; + exit(1); +} + +template <> CommentInfo *getCommentInfo(FunctionInfo *I) { + I->Description.emplace_back(); + return &I->Description.back(); +} + +template <> CommentInfo *getCommentInfo(NamespaceInfo *I) { + I->Description.emplace_back(); + return &I->Description.back(); +} + +template <> CommentInfo *getCommentInfo(RecordInfo *I) { + I->Description.emplace_back(); + return &I->Description.back(); +} + +template <> CommentInfo *getCommentInfo(EnumInfo *I) { + I->Description.emplace_back(); + return &I->Description.back(); +} + +template <> CommentInfo *getCommentInfo(CommentInfo *I) { + I->Children.emplace_back(llvm::make_unique<CommentInfo>()); + return I->Children.back().get(); +} + +template <> CommentInfo *getCommentInfo(std::unique_ptr<CommentInfo> &I) { + return getCommentInfo(I.get()); +} + +template <typename T, typename TTypeInfo> +void addTypeInfo(T I, TTypeInfo &&TI) { + llvm::errs() << "Invalid type for info.\n"; + exit(1); +} + +template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) { + I->Members.emplace_back(std::move(T)); +} + +template <> void addTypeInfo(FunctionInfo *I, TypeInfo &&T) { + I->ReturnType = std::move(T); +} + +template <> void addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) { + I->Params.emplace_back(std::move(T)); +} + +template <typename T> void addReference(T I, Reference &&R, FieldId F) { + llvm::errs() << "Invalid field type for info.\n"; + exit(1); +} + +template <> void addReference(TypeInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_type: + I->Type = std::move(R); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(FieldTypeInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_type: + I->Type = std::move(R); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(MemberTypeInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_type: + I->Type = std::move(R); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(EnumInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_namespace: + I->Namespace.emplace_back(std::move(R)); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(NamespaceInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_namespace: + I->Namespace.emplace_back(std::move(R)); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(FunctionInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_namespace: + I->Namespace.emplace_back(std::move(R)); + break; + case FieldId::F_parent: + I->Parent = std::move(R); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +template <> void addReference(RecordInfo *I, Reference &&R, FieldId F) { + switch (F) { + case FieldId::F_namespace: + I->Namespace.emplace_back(std::move(R)); + break; + case FieldId::F_parent: + I->Parents.emplace_back(std::move(R)); + break; + case FieldId::F_vparent: + I->VirtualParents.emplace_back(std::move(R)); + break; + default: + llvm::errs() << "Invalid field type for info.\n"; + exit(1); + } +} + +// Read records from bitcode into a given info. +template <typename T> bool ClangDocBitcodeReader::readRecord(unsigned ID, T I) { + Record R; + llvm::StringRef Blob; + unsigned RecID = Stream.readRecord(ID, R, &Blob); + return parseRecord(R, RecID, Blob, I); +} + +template <> bool ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) { + Record R; + llvm::StringRef Blob; + unsigned RecID = Stream.readRecord(ID, R, &Blob); + return parseRecord(R, RecID, Blob, I, CurrentReferenceField); +} + +// Read a block of records into a single info. +template <typename T> bool ClangDocBitcodeReader::readBlock(unsigned ID, T I) { + if (Stream.EnterSubBlock(ID)) + return false; + + while (true) { + unsigned BlockOrCode = 0; + Cursor Res = skipUntilRecordOrBlock(BlockOrCode); + + switch (Res) { + case Cursor::BadBlock: + return false; + case Cursor::BlockEnd: + return true; + case Cursor::BlockBegin: + if (readSubBlock(BlockOrCode, I)) + continue; + if (!Stream.SkipBlock()) + return false; + continue; + case Cursor::Record: + break; + } + if (!readRecord(BlockOrCode, I)) + return false; + } +} + +template <typename T> +bool ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { + switch (ID) { + // Blocks can only have Comment, Reference, or TypeInfo subblocks + case BI_COMMENT_BLOCK_ID: + if (readBlock(ID, getCommentInfo(I))) + return true; + return false; + case BI_TYPE_BLOCK_ID: { + TypeInfo TI; + if (readBlock(ID, &TI)) { + addTypeInfo(I, std::move(TI)); + return true; + } + return false; + } + case BI_FIELD_TYPE_BLOCK_ID: { + FieldTypeInfo TI; + if (readBlock(ID, &TI)) { + addTypeInfo(I, std::move(TI)); + return true; + } + return false; + } + case BI_MEMBER_TYPE_BLOCK_ID: { + MemberTypeInfo TI; + if (readBlock(ID, &TI)) { + addTypeInfo(I, std::move(TI)); + return true; + } + return false; + } + case BI_REFERENCE_BLOCK_ID: { + Reference R; + if (readBlock(ID, &R)) { + addReference(I, std::move(R), CurrentReferenceField); + return true; + } + return false; + } + default: + llvm::errs() << "Invalid subblock type.\n"; + return false; + } +} + +ClangDocBitcodeReader::Cursor +ClangDocBitcodeReader::skipUntilRecordOrBlock(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."); +} + +bool ClangDocBitcodeReader::validateStream() { + if (Stream.AtEndOfStream()) + return false; + + // Sniff for the signature. + if (Stream.Read(8) != BitCodeConstants::Signature[0] || + Stream.Read(8) != BitCodeConstants::Signature[1] || + Stream.Read(8) != BitCodeConstants::Signature[2] || + Stream.Read(8) != BitCodeConstants::Signature[3]) + return false; + return true; +} + +bool ClangDocBitcodeReader::readBlockInfoBlock() { + BlockInfo = Stream.ReadBlockInfoBlock(); + if (!BlockInfo) + return false; + Stream.setBlockInfo(&*BlockInfo); + return true; +} + +#define READINFO(INFO) \ + { \ + std::unique_ptr<Info> I = llvm::make_unique<INFO>(); \ + if (readBlock(ID, static_cast<INFO *>(I.get()))) \ + return I; \ + break; \ + } + +std::unique_ptr<Info> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { + switch (ID) { + case BI_NAMESPACE_BLOCK_ID: + READINFO(NamespaceInfo) + case BI_RECORD_BLOCK_ID: + READINFO(RecordInfo) + case BI_ENUM_BLOCK_ID: + READINFO(EnumInfo) + case BI_FUNCTION_BLOCK_ID: + READINFO(FunctionInfo) + default: + break; + } + llvm::errs() << "Error reading from block.\n"; + return nullptr; +} + +#undef READINFO + +// Entry point +std::vector<std::unique_ptr<Info>> ClangDocBitcodeReader::readBitcode() { + std::vector<std::unique_ptr<Info>> Infos; + if (!validateStream()) + return Infos; + + // Read the top level blocks. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code != llvm::bitc::ENTER_SUBBLOCK) + return Infos; + + 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: + case BI_REFERENCE_BLOCK_ID: + llvm::errs() << "Invalid top level block.\n"; + return Infos; + case BI_NAMESPACE_BLOCK_ID: + case BI_RECORD_BLOCK_ID: + case BI_ENUM_BLOCK_ID: + case BI_FUNCTION_BLOCK_ID: + if (std::unique_ptr<Info> I = readBlockToInfo(ID)) { + Infos.emplace_back(std::move(I)); + } + return Infos; + case BI_VERSION_BLOCK_ID: + if (readBlock(ID, VersionNumber)) + continue; + return Infos; + case llvm::bitc::BLOCKINFO_BLOCK_ID: + if (readBlockInfoBlock()) + continue; + return Infos; + default: + if (!Stream.SkipBlock()) + continue; + } + } + return Infos; +} + +} // namespace doc +} // namespace clang
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits