https://github.com/evelez7 updated https://github.com/llvm/llvm-project/pull/146165
>From 318f0c85b9f984ba22873ee76a0e610b07d443e9 Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Thu, 26 Jun 2025 20:54:03 -0700 Subject: [PATCH] [clang-doc] serialize friends --- clang-tools-extra/clang-doc/BitcodeReader.cpp | 46 +++++++++++ clang-tools-extra/clang-doc/BitcodeWriter.cpp | 27 ++++++- clang-tools-extra/clang-doc/BitcodeWriter.h | 6 +- clang-tools-extra/clang-doc/HTMLGenerator.cpp | 3 + .../clang-doc/HTMLMustacheGenerator.cpp | 1 + clang-tools-extra/clang-doc/JSONGenerator.cpp | 23 +++++- clang-tools-extra/clang-doc/MDGenerator.cpp | 4 + .../clang-doc/Representation.cpp | 16 ++++ clang-tools-extra/clang-doc/Representation.h | 21 ++++- clang-tools-extra/clang-doc/Serialize.cpp | 55 ++++++++++++++ clang-tools-extra/clang-doc/YAMLGenerator.cpp | 1 + .../test/clang-doc/json/class.cpp | 76 +++++++++---------- .../unittests/clang-doc/BitcodeTest.cpp | 2 + 13 files changed, 236 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index fd6f40cff1a4e..2cbf8bf6b2879 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -94,6 +94,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field, case InfoType::IT_typedef: case InfoType::IT_concept: case InfoType::IT_variable: + case InfoType::IT_friend: Field = IT; return llvm::Error::success(); } @@ -111,6 +112,7 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field, case FieldId::F_child_namespace: case FieldId::F_child_record: case FieldId::F_concept: + case FieldId::F_friend: case FieldId::F_default: Field = F; return llvm::Error::success(); @@ -450,6 +452,15 @@ static llvm::Error parseRecord(const Record &R, unsigned ID, } } +static llvm::Error parseRecord(const Record &R, unsigned ID, StringRef Blob, + FriendInfo *F) { + if (ID == FRIEND_IS_CLASS) { + return decodeRecord(R, F->IsClass, Blob); + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for Friend"); +} + template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain CommentInfo"); @@ -525,6 +536,18 @@ template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) { return llvm::Error::success(); } +template <> llvm::Error addTypeInfo(FriendInfo *I, FieldTypeInfo &&T) { + if (!I->Params) + I->Params.emplace(); + I->Params->emplace_back(std::move(T)); + return llvm::Error::success(); +} + +template <> llvm::Error addTypeInfo(FriendInfo *I, TypeInfo &&T) { + I->ReturnType.emplace(std::move(T)); + return llvm::Error::success(); +} + template <> llvm::Error addTypeInfo(EnumInfo *I, TypeInfo &&T) { I->BaseType = std::move(T); return llvm::Error::success(); @@ -667,6 +690,16 @@ llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) { "ConstraintInfo cannot contain this Reference"); } +template <> +llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F) { + if (F == FieldId::F_friend) { + Friend->Ref = std::move(R); + return llvm::Error::success(); + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Friend cannot contain this Reference"); +} + template <typename T, typename ChildInfoType> static void addChild(T I, ChildInfoType &&R) { llvm::errs() << "invalid child type for info"; @@ -700,6 +733,9 @@ template <> void addChild(RecordInfo *I, EnumInfo &&R) { template <> void addChild(RecordInfo *I, TypedefInfo &&R) { I->Children.Typedefs.emplace_back(std::move(R)); } +template <> void addChild(RecordInfo *I, FriendInfo &&R) { + I->Friends.emplace_back(std::move(R)); +} // Other types of children: template <> void addChild(EnumInfo *I, EnumValueInfo &&R) { @@ -741,6 +777,9 @@ template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) { template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) { I->Template = std::move(P); } +template <> void addTemplate(FriendInfo *I, TemplateInfo &&P) { + I->Template.emplace(std::move(P)); +} // Template specializations go only into template records. template <typename T> @@ -921,6 +960,10 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { case BI_VAR_BLOCK_ID: { return handleSubBlock<VarInfo>(ID, I, CreateAddFunc(addChild<T, VarInfo>)); } + case BI_FRIEND_BLOCK_ID: { + return handleSubBlock<FriendInfo>(ID, I, + CreateAddFunc(addChild<T, FriendInfo>)); + } default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid subblock type"); @@ -1032,6 +1075,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { return createInfo<FunctionInfo>(ID); case BI_VAR_BLOCK_ID: return createInfo<VarInfo>(ID); + case BI_FRIEND_BLOCK_ID: + return createInfo<FriendInfo>(ID); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "cannot create info"); @@ -1072,6 +1117,7 @@ ClangDocBitcodeReader::readBitcode() { case BI_TYPEDEF_BLOCK_ID: case BI_CONCEPT_BLOCK_ID: case BI_VAR_BLOCK_ID: + case BI_FRIEND_BLOCK_ID: case BI_FUNCTION_BLOCK_ID: { auto InfoOrErr = readBlockToInfo(ID); if (!InfoOrErr) diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index 006ddda1b75e7..3cc0d4ad332f0 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -131,7 +131,8 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}, {BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"}, {BI_CONCEPT_BLOCK_ID, "ConceptBlock"}, - {BI_VAR_BLOCK_ID, "VarBlock"}}; + {BI_VAR_BLOCK_ID, "VarBlock"}, + {BI_FRIEND_BLOCK_ID, "FriendBlock"}}; assert(Inits.size() == BlockIdCount); for (const auto &Init : Inits) BlockIdNameMap[Init.first] = Init.second; @@ -224,7 +225,8 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> {VAR_USR, {"USR", &genSymbolIdAbbrev}}, {VAR_NAME, {"Name", &genStringAbbrev}}, {VAR_DEFLOCATION, {"DefLocation", &genLocationAbbrev}}, - {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}}}; + {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}}, + {FRIEND_IS_CLASS, {"IsClass", &genBoolAbbrev}}}; assert(Inits.size() == RecordIdCount); for (const auto &Init : Inits) { @@ -293,7 +295,8 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>> CONCEPT_CONSTRAINT_EXPRESSION}}, // Constraint Block {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}}, - {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}}}; + {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}}, + {BI_FRIEND_BLOCK_ID, {FRIEND_IS_CLASS}}}; // AbbreviationMap @@ -476,6 +479,19 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { emitRecord((unsigned)Field, REFERENCE_FIELD); } +void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) { + StreamSubBlockGuard Block(Stream, BI_FRIEND_BLOCK_ID); + emitBlock(R.Ref, FieldId::F_friend); + emitRecord(R.IsClass, FRIEND_IS_CLASS); + if (R.Template) + emitBlock(*R.Template); + if (R.Params) + for (const auto &P : *R.Params) + emitBlock(P); + if (R.ReturnType) + emitBlock(*R.ReturnType); +} + void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) { StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID); emitBlock(T.Type, FieldId::F_type); @@ -628,6 +644,8 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) { emitBlock(C); if (I.Template) emitBlock(*I.Template); + for (const auto &C : I.Friends) + emitBlock(C); } void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) { @@ -744,6 +762,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { case InfoType::IT_variable: emitBlock(*static_cast<VarInfo *>(I)); break; + case InfoType::IT_friend: + emitBlock(*static_cast<FriendInfo *>(I)); + break; case InfoType::IT_default: llvm::errs() << "Unexpected info, unable to write.\n"; return true; diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h index f1325094f957a..d09ec4ca34006 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -70,6 +70,7 @@ enum BlockId { BI_TYPEDEF_BLOCK_ID, BI_CONCEPT_BLOCK_ID, BI_VAR_BLOCK_ID, + BI_FRIEND_BLOCK_ID, BI_LAST, BI_FIRST = BI_VERSION_BLOCK_ID }; @@ -153,6 +154,7 @@ enum RecordId { VAR_NAME, VAR_DEFLOCATION, VAR_IS_STATIC, + FRIEND_IS_CLASS, RI_LAST, RI_FIRST = VERSION }; @@ -169,7 +171,8 @@ enum class FieldId { F_type, F_child_namespace, F_child_record, - F_concept + F_concept, + F_friend }; class ClangDocBitcodeWriter { @@ -201,6 +204,7 @@ class ClangDocBitcodeWriter { void emitBlock(const ConceptInfo &T); void emitBlock(const ConstraintInfo &T); void emitBlock(const Reference &B, FieldId F); + void emitBlock(const FriendInfo &R); void emitBlock(const VarInfo &B); private: diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index c4303d287da9e..8294ff9118558 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -987,6 +987,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, break; case InfoType::IT_concept: case InfoType::IT_variable: + case InfoType::IT_friend: break; case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), @@ -1018,6 +1019,8 @@ static std::string getRefType(InfoType IT) { return "concept"; case InfoType::IT_variable: return "variable"; + case InfoType::IT_friend: + return "friend"; } llvm_unreachable("Unknown InfoType"); } diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index c611c946b3937..7aeaa1b7cf67d 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -588,6 +588,7 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, case InfoType::IT_concept: break; case InfoType::IT_variable: + case InfoType::IT_friend: break; case InfoType::IT_default: return createStringError(inconvertibleErrorCode(), "unexpected InfoType"); diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 1f6167f7f9b8d..0e1a0cc347e45 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -39,8 +39,7 @@ static void serializeArray(const Container &Records, Object &Obj, static auto SerializeInfoLambda = [](const auto &Info, Object &Object) { serializeInfo(Info, Object); }; -static auto SerializeReferenceLambda = [](const Reference &Ref, - Object &Object) { +static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) { serializeReference(Ref, Object); }; @@ -365,6 +364,22 @@ static void serializeInfo(const BaseRecordInfo &I, Object &Obj, Obj["IsParent"] = I.IsParent; } +static void serializeInfo(const FriendInfo &I, Object &Obj) { + auto FriendRef = Object(); + serializeReference(I.Ref, FriendRef); + Obj["Reference"] = std::move(FriendRef); + Obj["IsClass"] = I.IsClass; + if (I.Template) + serializeInfo(I.Template.value(), Obj); + if (I.Params) + serializeArray(I.Params.value(), Obj, "Params", SerializeInfoLambda); + if (I.ReturnType) { + auto ReturnTypeObj = Object(); + serializeInfo(I.ReturnType.value(), ReturnTypeObj); + Obj["ReturnType"] = std::move(ReturnTypeObj); + } +} + static void serializeInfo(const RecordInfo &I, json::Object &Obj, const std::optional<StringRef> &RepositoryUrl) { serializeCommonAttributes(I, Obj, RepositoryUrl); @@ -436,6 +451,9 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, if (I.Template) serializeInfo(I.Template.value(), Obj); + if (!I.Friends.empty()) + serializeArray(I.Friends, Obj, "Friends", SerializeInfoLambda); + serializeCommonChildren(I.Children, Obj, RepositoryUrl); } @@ -525,6 +543,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS, case InfoType::IT_function: case InfoType::IT_typedef: case InfoType::IT_variable: + case InfoType::IT_friend: break; case InfoType::IT_default: return createStringError(inconvertibleErrorCode(), "unexpected info type"); diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp index 608a7f6d4a9d3..6f16f5bd2f528 100644 --- a/clang-tools-extra/clang-doc/MDGenerator.cpp +++ b/clang-tools-extra/clang-doc/MDGenerator.cpp @@ -378,6 +378,9 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) { case InfoType::IT_variable: Type = "Variable"; break; + case InfoType::IT_friend: + Type = "Friend"; + break; case InfoType::IT_default: Type = "Other"; } @@ -472,6 +475,7 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, break; case InfoType::IT_concept: case InfoType::IT_variable: + case InfoType::IT_friend: break; case InfoType::IT_default: return createStringError(llvm::inconvertibleErrorCode(), diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 5b94d37d868b4..422a76d99e5b3 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -147,6 +147,8 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values) { return reduce<ConceptInfo>(Values); case InfoType::IT_variable: return reduce<VarInfo>(Values); + case InfoType::IT_friend: + return reduce<FriendInfo>(Values); case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "unexpected info type"); @@ -247,6 +249,15 @@ void Reference::merge(Reference &&Other) { Path = Other.Path; } +bool FriendInfo::mergeable(const FriendInfo &Other) { + return Ref.USR == Other.Ref.USR && Ref.Name == Other.Ref.Name; +} + +void FriendInfo::merge(FriendInfo &&Other) { + assert(mergeable(Other)); + Ref.merge(std::move(Other.Ref)); +} + void Info::mergeBase(Info &&Other) { assert(mergeable(Other)); if (USR == EmptySID) @@ -313,6 +324,8 @@ void RecordInfo::merge(RecordInfo &&Other) { Parents = std::move(Other.Parents); if (VirtualParents.empty()) VirtualParents = std::move(Other.VirtualParents); + if (Friends.empty()) + Friends = std::move(Other.Friends); // Reduce children if necessary. reduceChildren(Children.Records, std::move(Other.Children.Records)); reduceChildren(Children.Functions, std::move(Other.Children.Functions)); @@ -422,6 +435,9 @@ llvm::SmallString<16> Info::extractName() const { case InfoType::IT_variable: return llvm::SmallString<16>("@nonymous_variable_" + toHex(llvm::toStringRef(USR))); + case InfoType::IT_friend: + return llvm::SmallString<16>("@nonymous_friend_" + + toHex(llvm::toStringRef(USR))); case InfoType::IT_default: return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR))); } diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 59874f0cfcedf..fe5cc48069d58 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -46,7 +46,8 @@ enum class InfoType { IT_enum, IT_typedef, IT_concept, - IT_variable + IT_variable, + IT_friend }; enum class CommentKind { @@ -379,6 +380,22 @@ struct SymbolInfo : public Info { bool IsStatic = false; }; +struct FriendInfo : SymbolInfo { + FriendInfo() : SymbolInfo(InfoType::IT_friend) {} + FriendInfo(SymbolID USR) : SymbolInfo(InfoType::IT_friend, USR) {} + FriendInfo(const InfoType IT, const SymbolID &USR, + const StringRef Name = StringRef()) + : SymbolInfo(IT, USR, Name) {} + bool mergeable(const FriendInfo &Other); + void merge(FriendInfo &&Other); + + Reference Ref; + std::optional<TemplateInfo> Template; + std::optional<TypeInfo> ReturnType; + std::optional<SmallVector<FieldTypeInfo, 4>> Params; + bool IsClass = false; +}; + struct VarInfo : SymbolInfo { VarInfo() : SymbolInfo(InfoType::IT_variable) {} explicit VarInfo(SymbolID USR) : SymbolInfo(InfoType::IT_variable, USR) {} @@ -454,6 +471,8 @@ struct RecordInfo : public SymbolInfo { Bases; // List of base/parent records; this includes inherited methods and // attributes + std::vector<FriendInfo> Friends; + ScopeChildren Children; }; diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 7a9cb8a1eddb9..83c97b9270cf5 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -7,9 +7,12 @@ //===----------------------------------------------------------------------===// #include "Serialize.h" +#include "../clangd/CodeCompletionStrings.h" #include "BitcodeWriter.h" + #include "clang/AST/Attr.h" #include "clang/AST/Comment.h" +#include "clang/AST/DeclFriend.h" #include "clang/Index/USRGeneration.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringExtras.h" @@ -403,6 +406,7 @@ std::string serialize(std::unique_ptr<Info> &I) { return serialize(*static_cast<ConceptInfo *>(I.get())); case InfoType::IT_variable: return serialize(*static_cast<VarInfo *>(I.get())); + case InfoType::IT_friend: case InfoType::IT_typedef: case InfoType::IT_default: return ""; @@ -556,6 +560,7 @@ static std::unique_ptr<Info> makeAndInsertIntoParent(ChildType Child) { case InfoType::IT_typedef: case InfoType::IT_concept: case InfoType::IT_variable: + case InfoType::IT_friend: break; } llvm_unreachable("Invalid reference type for parent namespace"); @@ -947,6 +952,55 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, return {std::move(NSI), makeAndInsertIntoParent<const NamespaceInfo &>(*NSI)}; } +static void parseFriends(RecordInfo &RI, const CXXRecordDecl *D) { + if (!D->hasDefinition() || !D->hasFriends()) + return; + + for (const FriendDecl *FD : D->friends()) { + if (FD->isUnsupportedFriend()) + continue; + + FriendInfo F(InfoType::IT_friend, getUSRForDecl(FD)); + const auto *ActualDecl = FD->getFriendDecl(); + if (!ActualDecl) { + const auto *FriendTypeInfo = FD->getFriendType(); + if (!FriendTypeInfo) + continue; + ActualDecl = FriendTypeInfo->getType()->getAsCXXRecordDecl(); + + if (!ActualDecl) + continue; + F.IsClass = true; + } + + if (const auto *ActualTD = dyn_cast_or_null<TemplateDecl>(ActualDecl)) { + if (isa<RecordDecl>(ActualTD->getTemplatedDecl())) + F.IsClass = true; + F.Template.emplace(); + for (const auto *Param : ActualTD->getTemplateParameters()->asArray()) + F.Template->Params.emplace_back( + getSourceCode(Param, Param->getSourceRange())); + ActualDecl = ActualTD->getTemplatedDecl(); + } + + if (auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(ActualDecl)) { + FunctionInfo TempInfo; + parseParameters(TempInfo, FuncDecl); + F.Params.emplace(); + F.Params = std::move(TempInfo.Params); + F.ReturnType = getTypeInfoForType(FuncDecl->getReturnType(), + FuncDecl->getLangOpts()); + } + + F.Ref = + Reference(getUSRForDecl(ActualDecl), ActualDecl->getNameAsString(), + InfoType::IT_default, ActualDecl->getQualifiedNameAsString(), + getInfoRelativePath(ActualDecl)); + + RI.Friends.push_back(std::move(F)); + } +} + std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc, bool PublicOnly) { @@ -970,6 +1024,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc, // TODO: remove first call to parseBases, that function should be deleted parseBases(*RI, C); parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true); + parseFriends(*RI, C); } RI->Path = getInfoRelativePath(RI->Namespace); diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp index 3ca4d4947fa97..eeccdd804b669 100644 --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -410,6 +410,7 @@ llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, break; case InfoType::IT_concept: case InfoType::IT_variable: + case InfoType::IT_friend: break; case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index 0715fcefbb785..ae47da75edccb 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -89,44 +89,44 @@ struct MyClass { // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } // CHECK-NEXT: ], -// CHECK-NOT: "Friends": [ -// CHECK-NOT: { -// CHECK-NOT: "IsClass": false, -// CHECK-NOT: "Params": [ -// CHECK-NOT: { -// CHECK-NOT: "Name": "", -// CHECK-NOT: "Type": "int" -// CHECK-NOT: } -// CHECK-NOT: ], -// CHECK-NOT: "Reference": { -// CHECK-NOT: "Name": "friendFunction", -// CHECK-NOT: "Path": "", -// CHECK-NOT: "QualName": "friendFunction", -// CHECK-NOT: "USR": "{{[0-9A-F]*}}" -// CHECK-NOT: }, -// CHECK-NOT: "ReturnType": { -// CHECK-NOT: "IsBuiltIn": true, -// CHECK-NOT: "IsTemplate": false, -// CHECK-NOT: "Name": "void", -// CHECK-NOT: "QualName": "void", -// CHECK-NOT: "USR": "0000000000000000000000000000000000000000" -// CHECK-NOT: }, -// CHECK-NOT: "Template": { -// CHECK-NOT: "Parameters": [ -// CHECK-NOT: "typename T" -// CHECK-NOT: ] -// CHECK-NOT: } -// CHECK-NOT: }, -// CHECK-NOT: { -// CHECK-NOT: "IsClass": true, -// CHECK-NOT: "Reference": { -// CHECK-NOT: "Name": "Foo", -// CHECK-NOT: "Path": "GlobalNamespace", -// CHECK-NOT: "QualName": "Foo", -// CHECK-NOT: "USR": "{{[0-9A-F]*}}" -// CHECK-NOT: }, -// CHECK-NOT: }, -// CHECK-NOT: ], +// CHECK-NEXT: "Friends": [ +// CHECK-NEXT: { +// CHECK-NEXT: "IsClass": false, +// CHECK-NEXT: "Params": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "", +// CHECK-NEXT: "Type": "int" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Reference": { +// CHECK-NEXT: "Name": "friendFunction", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "friendFunction", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: "ReturnType": { +// CHECK-NEXT: "IsBuiltIn": true, +// CHECK-NEXT: "IsTemplate": false, +// CHECK-NEXT: "Name": "void", +// CHECK-NEXT: "QualName": "void", +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NEXT: }, +// CHECK-NEXT: "Template": { +// CHECK-NEXT: "Parameters": [ +// CHECK-NEXT: "typename T" +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "IsClass": true, +// CHECK-NEXT: "Reference": { +// CHECK-NEXT: "Name": "Foo", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "QualName": "Foo", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ], // COM: FIXME: FullName is not emitted correctly. // CHECK-NEXT: "FullName": "", // CHECK-NEXT: "IsTypedef": false, diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp index 323431c4fc9e0..d88b0c91bb9a9 100644 --- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp @@ -41,6 +41,8 @@ static std::string writeInfo(Info *I) { return writeInfo(*static_cast<ConceptInfo *>(I)); case InfoType::IT_variable: return writeInfo(*static_cast<VarInfo *>(I)); + case InfoType::IT_friend: + return writeInfo(*static_cast<FriendInfo *>(I)); case InfoType::IT_default: return ""; } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits