1 //===-- clang-doc/BitcodeTest.cpp -----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "BitcodeReader.h" 10 #include "BitcodeWriter.h" 11 #include "ClangDocTest.h" 12 #include "Representation.h" 13 #include "llvm/Bitstream/BitstreamReader.h" 14 #include "llvm/Bitstream/BitstreamWriter.h" 15 #include "gtest/gtest.h" 16 17 namespace clang { 18 namespace doc { 19 20 template <typename T> static std::string writeInfo(T &I) { 21 SmallString<2048> Buffer; 22 llvm::BitstreamWriter Stream(Buffer); 23 ClangDocBitcodeWriter Writer(Stream); 24 Writer.emitBlock(I); 25 return Buffer.str().str(); 26 } 27 28 std::string writeInfo(Info *I) { 29 switch (I->IT) { 30 case InfoType::IT_namespace: 31 return writeInfo(*static_cast<NamespaceInfo *>(I)); 32 case InfoType::IT_record: 33 return writeInfo(*static_cast<RecordInfo *>(I)); 34 case InfoType::IT_enum: 35 return writeInfo(*static_cast<EnumInfo *>(I)); 36 case InfoType::IT_function: 37 return writeInfo(*static_cast<FunctionInfo *>(I)); 38 default: 39 return ""; 40 } 41 } 42 43 std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode, 44 size_t NumInfos) { 45 llvm::BitstreamCursor Stream(Bitcode); 46 doc::ClangDocBitcodeReader Reader(Stream); 47 auto Infos = Reader.readBitcode(); 48 49 // Check that there was no error in the read. 50 assert(Infos); 51 EXPECT_EQ(Infos.get().size(), NumInfos); 52 return std::move(Infos.get()); 53 } 54 55 TEST(BitcodeTest, emitNamespaceInfoBitcode) { 56 NamespaceInfo I; 57 I.Name = "r"; 58 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); 59 60 I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace", 61 InfoType::IT_namespace); 62 I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record); 63 I.ChildFunctions.emplace_back(); 64 I.ChildEnums.emplace_back(); 65 66 std::string WriteResult = writeInfo(&I); 67 EXPECT_TRUE(WriteResult.size() > 0); 68 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 69 70 CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get())); 71 } 72 73 TEST(BitcodeTest, emitRecordInfoBitcode) { 74 RecordInfo I; 75 I.Name = "r"; 76 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); 77 78 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); 79 I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); 80 81 I.Members.emplace_back("int", "X", AccessSpecifier::AS_private); 82 I.TagType = TagTypeKind::TTK_Class; 83 I.IsTypeDef = true; 84 I.Bases.emplace_back(EmptySID, "F", "path/to/F", true, 85 AccessSpecifier::AS_public, true); 86 I.Bases.back().ChildFunctions.emplace_back(); 87 I.Bases.back().Members.emplace_back("int", "X", AccessSpecifier::AS_private); 88 I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record); 89 I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record); 90 91 I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record); 92 I.ChildFunctions.emplace_back(); 93 I.ChildEnums.emplace_back(); 94 95 std::string WriteResult = writeInfo(&I); 96 EXPECT_TRUE(WriteResult.size() > 0); 97 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 98 99 CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get())); 100 } 101 102 TEST(BitcodeTest, emitFunctionInfoBitcode) { 103 FunctionInfo I; 104 I.Name = "f"; 105 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); 106 107 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); 108 I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); 109 110 I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); 111 I.Params.emplace_back("int", "P"); 112 113 I.Access = AccessSpecifier::AS_none; 114 115 std::string WriteResult = writeInfo(&I); 116 EXPECT_TRUE(WriteResult.size() > 0); 117 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 118 119 CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get())); 120 } 121 122 TEST(BitcodeTest, emitMethodInfoBitcode) { 123 FunctionInfo I; 124 I.Name = "f"; 125 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); 126 127 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); 128 I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); 129 130 I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); 131 I.Params.emplace_back("int", "P"); 132 I.IsMethod = true; 133 I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record); 134 135 I.Access = AccessSpecifier::AS_public; 136 137 std::string WriteResult = writeInfo(&I); 138 EXPECT_TRUE(WriteResult.size() > 0); 139 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 140 141 CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get())); 142 } 143 144 TEST(BitcodeTest, emitEnumInfoBitcode) { 145 EnumInfo I; 146 I.Name = "e"; 147 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); 148 149 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); 150 I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); 151 152 I.Members.emplace_back("X"); 153 I.Scoped = true; 154 155 std::string WriteResult = writeInfo(&I); 156 EXPECT_TRUE(WriteResult.size() > 0); 157 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 158 159 CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get())); 160 } 161 162 TEST(SerializeTest, emitInfoWithCommentBitcode) { 163 FunctionInfo F; 164 F.Name = "F"; 165 F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); 166 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 167 F.Params.emplace_back("int", "I"); 168 169 CommentInfo Top; 170 Top.Kind = "FullComment"; 171 172 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 173 CommentInfo *BlankLine = Top.Children.back().get(); 174 BlankLine->Kind = "ParagraphComment"; 175 BlankLine->Children.emplace_back(std::make_unique<CommentInfo>()); 176 BlankLine->Children.back()->Kind = "TextComment"; 177 178 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 179 CommentInfo *Brief = Top.Children.back().get(); 180 Brief->Kind = "ParagraphComment"; 181 Brief->Children.emplace_back(std::make_unique<CommentInfo>()); 182 Brief->Children.back()->Kind = "TextComment"; 183 Brief->Children.back()->Name = "ParagraphComment"; 184 Brief->Children.back()->Text = " Brief description."; 185 186 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 187 CommentInfo *Extended = Top.Children.back().get(); 188 Extended->Kind = "ParagraphComment"; 189 Extended->Children.emplace_back(std::make_unique<CommentInfo>()); 190 Extended->Children.back()->Kind = "TextComment"; 191 Extended->Children.back()->Text = " Extended description that"; 192 Extended->Children.emplace_back(std::make_unique<CommentInfo>()); 193 Extended->Children.back()->Kind = "TextComment"; 194 Extended->Children.back()->Text = " continues onto the next line."; 195 196 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 197 CommentInfo *HTML = Top.Children.back().get(); 198 HTML->Kind = "ParagraphComment"; 199 HTML->Children.emplace_back(std::make_unique<CommentInfo>()); 200 HTML->Children.back()->Kind = "TextComment"; 201 HTML->Children.emplace_back(std::make_unique<CommentInfo>()); 202 HTML->Children.back()->Kind = "HTMLStartTagComment"; 203 HTML->Children.back()->Name = "ul"; 204 HTML->Children.back()->AttrKeys.emplace_back("class"); 205 HTML->Children.back()->AttrValues.emplace_back("test"); 206 HTML->Children.emplace_back(std::make_unique<CommentInfo>()); 207 HTML->Children.back()->Kind = "HTMLStartTagComment"; 208 HTML->Children.back()->Name = "li"; 209 HTML->Children.emplace_back(std::make_unique<CommentInfo>()); 210 HTML->Children.back()->Kind = "TextComment"; 211 HTML->Children.back()->Text = " Testing."; 212 HTML->Children.emplace_back(std::make_unique<CommentInfo>()); 213 HTML->Children.back()->Kind = "HTMLEndTagComment"; 214 HTML->Children.back()->Name = "ul"; 215 HTML->Children.back()->SelfClosing = true; 216 217 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 218 CommentInfo *Verbatim = Top.Children.back().get(); 219 Verbatim->Kind = "VerbatimBlockComment"; 220 Verbatim->Name = "verbatim"; 221 Verbatim->CloseName = "endverbatim"; 222 Verbatim->Children.emplace_back(std::make_unique<CommentInfo>()); 223 Verbatim->Children.back()->Kind = "VerbatimBlockLineComment"; 224 Verbatim->Children.back()->Text = " The description continues."; 225 226 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 227 CommentInfo *ParamOut = Top.Children.back().get(); 228 ParamOut->Kind = "ParamCommandComment"; 229 ParamOut->Direction = "[out]"; 230 ParamOut->ParamName = "I"; 231 ParamOut->Explicit = true; 232 ParamOut->Children.emplace_back(std::make_unique<CommentInfo>()); 233 ParamOut->Children.back()->Kind = "ParagraphComment"; 234 ParamOut->Children.back()->Children.emplace_back( 235 std::make_unique<CommentInfo>()); 236 ParamOut->Children.back()->Children.back()->Kind = "TextComment"; 237 ParamOut->Children.back()->Children.emplace_back( 238 std::make_unique<CommentInfo>()); 239 ParamOut->Children.back()->Children.back()->Kind = "TextComment"; 240 ParamOut->Children.back()->Children.back()->Text = " is a parameter."; 241 242 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 243 CommentInfo *ParamIn = Top.Children.back().get(); 244 ParamIn->Kind = "ParamCommandComment"; 245 ParamIn->Direction = "[in]"; 246 ParamIn->ParamName = "J"; 247 ParamIn->Children.emplace_back(std::make_unique<CommentInfo>()); 248 ParamIn->Children.back()->Kind = "ParagraphComment"; 249 ParamIn->Children.back()->Children.emplace_back( 250 std::make_unique<CommentInfo>()); 251 ParamIn->Children.back()->Children.back()->Kind = "TextComment"; 252 ParamIn->Children.back()->Children.back()->Text = " is a parameter."; 253 ParamIn->Children.back()->Children.emplace_back( 254 std::make_unique<CommentInfo>()); 255 ParamIn->Children.back()->Children.back()->Kind = "TextComment"; 256 257 Top.Children.emplace_back(std::make_unique<CommentInfo>()); 258 CommentInfo *Return = Top.Children.back().get(); 259 Return->Kind = "BlockCommandComment"; 260 Return->Name = "return"; 261 Return->Explicit = true; 262 Return->Children.emplace_back(std::make_unique<CommentInfo>()); 263 Return->Children.back()->Kind = "ParagraphComment"; 264 Return->Children.back()->Children.emplace_back( 265 std::make_unique<CommentInfo>()); 266 Return->Children.back()->Children.back()->Kind = "TextComment"; 267 Return->Children.back()->Children.back()->Text = "void"; 268 269 F.Description.emplace_back(std::move(Top)); 270 271 std::string WriteResult = writeInfo(&F); 272 EXPECT_TRUE(WriteResult.size() > 0); 273 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1); 274 275 CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get())); 276 } 277 278 } // namespace doc 279 } // namespace clang 280