341 lines · cpp
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-exception6//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 17namespace clang {18namespace doc {19 20template <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 28static 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 case InfoType::IT_typedef:39 return writeInfo(*static_cast<TypedefInfo *>(I));40 case InfoType::IT_concept:41 return writeInfo(*static_cast<ConceptInfo *>(I));42 case InfoType::IT_variable:43 return writeInfo(*static_cast<VarInfo *>(I));44 case InfoType::IT_friend:45 return writeInfo(*static_cast<FriendInfo *>(I));46 case InfoType::IT_default:47 return "";48 }49}50 51static std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode,52 size_t NumInfos) {53 llvm::BitstreamCursor Stream(Bitcode);54 doc::ClangDocBitcodeReader Reader(Stream);55 auto Infos = Reader.readBitcode();56 57 // Check that there was no error in the read.58 assert(Infos);59 EXPECT_EQ(Infos.get().size(), NumInfos);60 return std::move(Infos.get());61}62 63TEST(BitcodeTest, emitNamespaceInfoBitcode) {64 NamespaceInfo I;65 I.Name = "r";66 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);67 68 I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",69 InfoType::IT_namespace);70 I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);71 I.Children.Functions.emplace_back();72 I.Children.Enums.emplace_back();73 74 std::string WriteResult = writeInfo(&I);75 EXPECT_TRUE(WriteResult.size() > 0);76 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);77 78 CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));79}80 81TEST(BitcodeTest, emitRecordInfoBitcode) {82 RecordInfo I;83 I.Name = "r";84 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);85 86 I.DefLoc = Location(10, 10, "test.cpp");87 I.Loc.emplace_back(12, 12, "test.cpp");88 89 I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);90 I.TagType = TagTypeKind::Class;91 I.IsTypeDef = true;92 I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,93 AccessSpecifier::AS_public, true);94 I.Bases.back().Children.Functions.emplace_back();95 I.Bases.back().Members.emplace_back(TypeInfo("int"), "X",96 AccessSpecifier::AS_private);97 I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);98 I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);99 100 // Documentation for the data member.101 CommentInfo TopComment;102 TopComment.Kind = CommentKind::CK_FullComment;103 TopComment.Children.emplace_back(std::make_unique<CommentInfo>());104 CommentInfo *Brief = TopComment.Children.back().get();105 Brief->Kind = CommentKind::CK_ParagraphComment;106 Brief->Children.emplace_back(std::make_unique<CommentInfo>());107 Brief->Children.back()->Kind = CommentKind::CK_TextComment;108 Brief->Children.back()->Name = "ParagraphComment";109 Brief->Children.back()->Text = "Value of the thing.";110 I.Bases.back().Members.back().Description.emplace_back(std::move(TopComment));111 112 I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);113 I.Children.Functions.emplace_back();114 I.Children.Enums.emplace_back();115 116 std::string WriteResult = writeInfo(&I);117 EXPECT_TRUE(WriteResult.size() > 0);118 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);119 120 CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get()));121}122 123TEST(BitcodeTest, emitFunctionInfoBitcode) {124 FunctionInfo I;125 I.Name = "f";126 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);127 128 I.DefLoc = Location(10, 10, "test.cpp");129 I.Loc.emplace_back(12, 12, "test.cpp");130 131 I.ReturnType = TypeInfo("void");132 I.Params.emplace_back(TypeInfo("int"), "P");133 134 I.Access = AccessSpecifier::AS_none;135 136 std::string WriteResult = writeInfo(&I);137 EXPECT_TRUE(WriteResult.size() > 0);138 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);139 140 CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));141}142 143TEST(BitcodeTest, emitMethodInfoBitcode) {144 FunctionInfo I;145 I.Name = "f";146 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);147 148 I.DefLoc = Location(10, 10, "test.cpp");149 I.Loc.emplace_back(12, 12, "test.cpp");150 151 I.ReturnType = TypeInfo("void");152 I.Params.emplace_back(TypeInfo("int"), "P");153 I.IsMethod = true;154 I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);155 156 I.Access = AccessSpecifier::AS_public;157 158 std::string WriteResult = writeInfo(&I);159 EXPECT_TRUE(WriteResult.size() > 0);160 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);161 162 CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));163}164 165TEST(BitcodeTest, emitEnumInfoBitcode) {166 EnumInfo I;167 I.Name = "e";168 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);169 170 I.DefLoc = Location(10, 10, "test.cpp");171 I.Loc.emplace_back(12, 12, "test.cpp");172 173 I.Members.emplace_back("X");174 I.Scoped = true;175 176 std::string WriteResult = writeInfo(&I);177 EXPECT_TRUE(WriteResult.size() > 0);178 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);179 180 CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));181}182 183TEST(BitcodeTest, emitTypedefInfoBitcode) {184 TypedefInfo I;185 I.Name = "MyInt";186 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);187 188 I.DefLoc = Location(10, 10, "test.cpp");189 I.Underlying = TypeInfo("unsigned");190 I.IsUsing = true;191 192 CommentInfo Top;193 Top.Kind = CommentKind::CK_FullComment;194 195 Top.Children.emplace_back(std::make_unique<CommentInfo>());196 CommentInfo *BlankLine = Top.Children.back().get();197 BlankLine->Kind = CommentKind::CK_ParagraphComment;198 BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());199 BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;200 201 I.Description.emplace_back(std::move(Top));202 203 std::string WriteResult = writeInfo(&I);204 EXPECT_TRUE(WriteResult.size() > 0);205 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);206 207 CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0].get()));208 209 // Check one with no IsUsing set, no description, and no definition location.210 TypedefInfo I2;211 I2.Name = "SomethingElse";212 I2.IsUsing = false;213 I2.Underlying = TypeInfo("int");214 215 WriteResult = writeInfo(&I2);216 EXPECT_TRUE(WriteResult.size() > 0);217 ReadResults = readInfo(WriteResult, 1);218 CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0].get()));219}220 221TEST(SerializeTest, emitInfoWithCommentBitcode) {222 FunctionInfo F;223 F.Name = "F";224 F.ReturnType = TypeInfo("void");225 F.DefLoc = Location(0, 0, "test.cpp");226 F.Params.emplace_back(TypeInfo("int"), "I");227 228 CommentInfo Top;229 Top.Kind = CommentKind::CK_FullComment;230 231 Top.Children.emplace_back(std::make_unique<CommentInfo>());232 CommentInfo *BlankLine = Top.Children.back().get();233 BlankLine->Kind = CommentKind::CK_ParagraphComment;234 BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());235 BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;236 237 Top.Children.emplace_back(std::make_unique<CommentInfo>());238 CommentInfo *Brief = Top.Children.back().get();239 Brief->Kind = CommentKind::CK_ParagraphComment;240 Brief->Children.emplace_back(std::make_unique<CommentInfo>());241 Brief->Children.back()->Kind = CommentKind::CK_TextComment;242 Brief->Children.back()->Name = "ParagraphComment";243 Brief->Children.back()->Text = " Brief description.";244 245 Top.Children.emplace_back(std::make_unique<CommentInfo>());246 CommentInfo *Extended = Top.Children.back().get();247 Extended->Kind = CommentKind::CK_ParagraphComment;248 Extended->Children.emplace_back(std::make_unique<CommentInfo>());249 Extended->Children.back()->Kind = CommentKind::CK_TextComment;250 Extended->Children.back()->Text = " Extended description that";251 Extended->Children.emplace_back(std::make_unique<CommentInfo>());252 Extended->Children.back()->Kind = CommentKind::CK_TextComment;253 Extended->Children.back()->Text = " continues onto the next line.";254 255 Top.Children.emplace_back(std::make_unique<CommentInfo>());256 CommentInfo *HTML = Top.Children.back().get();257 HTML->Kind = CommentKind::CK_ParagraphComment;258 HTML->Children.emplace_back(std::make_unique<CommentInfo>());259 HTML->Children.back()->Kind = CommentKind::CK_TextComment;260 HTML->Children.emplace_back(std::make_unique<CommentInfo>());261 HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;262 HTML->Children.back()->Name = "ul";263 HTML->Children.back()->AttrKeys.emplace_back("class");264 HTML->Children.back()->AttrValues.emplace_back("test");265 HTML->Children.emplace_back(std::make_unique<CommentInfo>());266 HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;267 HTML->Children.back()->Name = "li";268 HTML->Children.emplace_back(std::make_unique<CommentInfo>());269 HTML->Children.back()->Kind = CommentKind::CK_TextComment;270 HTML->Children.back()->Text = " Testing.";271 HTML->Children.emplace_back(std::make_unique<CommentInfo>());272 HTML->Children.back()->Kind = CommentKind::CK_HTMLEndTagComment;273 HTML->Children.back()->Name = "ul";274 HTML->Children.back()->SelfClosing = true;275 276 Top.Children.emplace_back(std::make_unique<CommentInfo>());277 CommentInfo *Verbatim = Top.Children.back().get();278 Verbatim->Kind = CommentKind::CK_VerbatimBlockComment;279 Verbatim->Name = "verbatim";280 Verbatim->CloseName = "endverbatim";281 Verbatim->Children.emplace_back(std::make_unique<CommentInfo>());282 Verbatim->Children.back()->Kind = CommentKind::CK_VerbatimBlockLineComment;283 Verbatim->Children.back()->Text = " The description continues.";284 285 Top.Children.emplace_back(std::make_unique<CommentInfo>());286 CommentInfo *ParamOut = Top.Children.back().get();287 ParamOut->Kind = CommentKind::CK_ParamCommandComment;288 ParamOut->Direction = "[out]";289 ParamOut->ParamName = "I";290 ParamOut->Explicit = true;291 ParamOut->Children.emplace_back(std::make_unique<CommentInfo>());292 ParamOut->Children.back()->Kind = CommentKind::CK_ParagraphComment;293 ParamOut->Children.back()->Children.emplace_back(294 std::make_unique<CommentInfo>());295 ParamOut->Children.back()->Children.back()->Kind =296 CommentKind::CK_TextComment;297 ParamOut->Children.back()->Children.emplace_back(298 std::make_unique<CommentInfo>());299 ParamOut->Children.back()->Children.back()->Kind =300 CommentKind::CK_TextComment;301 ParamOut->Children.back()->Children.back()->Text = " is a parameter.";302 303 Top.Children.emplace_back(std::make_unique<CommentInfo>());304 CommentInfo *ParamIn = Top.Children.back().get();305 ParamIn->Kind = CommentKind::CK_ParamCommandComment;306 ParamIn->Direction = "[in]";307 ParamIn->ParamName = "J";308 ParamIn->Children.emplace_back(std::make_unique<CommentInfo>());309 ParamIn->Children.back()->Kind = CommentKind::CK_ParagraphComment;310 ParamIn->Children.back()->Children.emplace_back(311 std::make_unique<CommentInfo>());312 ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;313 ParamIn->Children.back()->Children.back()->Text = " is a parameter.";314 ParamIn->Children.back()->Children.emplace_back(315 std::make_unique<CommentInfo>());316 ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;317 318 Top.Children.emplace_back(std::make_unique<CommentInfo>());319 CommentInfo *Return = Top.Children.back().get();320 Return->Kind = CommentKind::CK_BlockCommandComment;321 Return->Name = "return";322 Return->Explicit = true;323 Return->Children.emplace_back(std::make_unique<CommentInfo>());324 Return->Children.back()->Kind = CommentKind::CK_ParagraphComment;325 Return->Children.back()->Children.emplace_back(326 std::make_unique<CommentInfo>());327 Return->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;328 Return->Children.back()->Children.back()->Text = "void";329 330 F.Description.emplace_back(std::move(Top));331 332 std::string WriteResult = writeInfo(&F);333 EXPECT_TRUE(WriteResult.size() > 0);334 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);335 336 CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get()));337}338 339} // namespace doc340} // namespace clang341