llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Erick Velez (evelez7) <details> <summary>Changes</summary> Most of the JSONGenerator functionality was provided by a series of static functions. This made it unwieldy to access useful properties of ClangDocContext. As methods, they can now access a pointer to CDCtx. --- Patch is 23.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/184663.diff 1 Files Affected: - (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+116-138) ``````````diff diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 773dc3a205e1c..fa5fba43a8a8f 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -8,51 +8,69 @@ using namespace llvm::json; namespace clang { namespace doc { -// FIXME: These static methods should be refactored into methods for -// `JSONGenerator`. It's cumbersome to pass around important properties from -// ClangDocContext using these static methods. +template <typename Container, typename SerializationFunc> +static void serializeArray( + const Container &Records, Object &Obj, const StringRef Key, + SerializationFunc SerializeInfo, const StringRef EndKey = "End", + function_ref<void(Object &)> UpdateJson = [](Object &Obj) {}); + +// TODO(issue URL): Wrapping logic for HTML should probably use a more +// sophisticated heuristic than number of parameters. +constexpr static unsigned getMaxParamWrapLimit() { return 2; } + class JSONGenerator : public Generator { + json::Object serializeLocation(const Location &Loc); + void serializeCommonAttributes(const Info &I, json::Object &Obj); + void serializeCommonChildren(const ScopeChildren &Children, + json::Object &Obj); + void serializeInfo(const ConstraintInfo &I, Object &Obj); + void serializeInfo(const TemplateInfo &Template, Object &Obj); + void serializeInfo(const ConceptInfo &I, Object &Obj); + void serializeInfo(const TypeInfo &I, Object &Obj); + void serializeInfo(const FieldTypeInfo &I, Object &Obj); + void serializeInfo(const FunctionInfo &F, json::Object &Obj); + void serializeInfo(const EnumValueInfo &I, Object &Obj); + void serializeInfo(const EnumInfo &I, json::Object &Obj); + void serializeInfo(const TypedefInfo &I, json::Object &Obj); + void serializeInfo(const BaseRecordInfo &I, Object &Obj); + void serializeInfo(const FriendInfo &I, Object &Obj); + void serializeInfo(const RecordInfo &I, json::Object &Obj); + void serializeInfo(const VarInfo &I, json::Object &Obj); + void serializeInfo(const NamespaceInfo &I, json::Object &Obj); + SmallString<16> determineFileName(Info *I, SmallString<128> &Path); + Error serializeIndex(StringRef RootDir); + void generateContext(const Info &I, Object &Obj); + void serializeReference(const Reference &Ref, Object &ReferenceObj); + + // Convenience lambdas to pass to serializeArray. + auto serializeInfoLambda() { + return [this](const auto &Info, Object &Object) { + serializeInfo(Info, Object); + }; + } + auto serializeReferenceLambda() { + return [this](const auto &Ref, Object &Object) { + serializeReference(Ref, Object); + }; + } + public: static const char *Format; + const ClangDocContext *CDCtx; Error generateDocumentation(StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos, const ClangDocContext &CDCtx, std::string DirName) override; Error createResources(ClangDocContext &CDCtx) override; + // FIXME: Once legacy generators are removed, we can refactor the Generator + // interface to sto passing CDCtx here since we hold a pointer to it. Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override; }; const char *JSONGenerator::Format = "json"; -static void serializeInfo(const ConstraintInfo &I, Object &Obj); -static void serializeInfo(const RecordInfo &I, Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLinePrefix); - -static void serializeReference(const Reference &Ref, Object &ReferenceObj); - -template <typename Container, typename SerializationFunc> -static void serializeArray( - const Container &Records, Object &Obj, const StringRef Key, - SerializationFunc SerializeInfo, const StringRef EndKey = "End", - function_ref<void(Object &)> UpdateJson = [](Object &Obj) {}); - -// TODO(issue URL): Wrapping logic for HTML should probably use a more -// sophisticated heuristic than number of parameters. -constexpr static unsigned getMaxParamWrapLimit() { return 2; } - -// Convenience lambda to pass to serializeArray. -// If a serializeInfo needs a RepositoryUrl, create a local lambda that captures -// the optional. -static auto SerializeInfoLambda = [](const auto &Info, Object &Object) { - serializeInfo(Info, Object); -}; -static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) { - serializeReference(Ref, Object); -}; - static void insertNonEmpty(StringRef Key, StringRef Value, Object &Obj) { if (!Value.empty()) Obj[Key] = Value; @@ -82,24 +100,21 @@ static std::string infoTypeToString(InfoType IT) { llvm_unreachable("Unknown InfoType encountered."); } -static json::Object -serializeLocation(const Location &Loc, - const std::optional<StringRef> RepositoryUrl, - const std::optional<StringRef> RepositoryLinePrefix) { +json::Object JSONGenerator::serializeLocation(const Location &Loc) { Object LocationObj = Object(); LocationObj["LineNumber"] = Loc.StartLineNumber; LocationObj["Filename"] = Loc.Filename; - if (!Loc.IsFileInRootDir || !RepositoryUrl) + if (!Loc.IsFileInRootDir || !CDCtx->RepositoryUrl) return LocationObj; - SmallString<128> FileURL(*RepositoryUrl); + SmallString<128> FileURL(*CDCtx->RepositoryUrl); sys::path::append(FileURL, sys::path::Style::posix, Loc.Filename); std::string LinePrefix; - if (!RepositoryLinePrefix) + if (!CDCtx->RepositoryLinePrefix) LinePrefix = "#L"; else - LinePrefix = *RepositoryLinePrefix; + LinePrefix = *CDCtx->RepositoryLinePrefix; FileURL += LinePrefix + std::to_string(Loc.StartLineNumber); LocationObj["FileURL"] = FileURL; @@ -296,7 +311,7 @@ static Object serializeComment(const CommentInfo &I, Object &Description) { } /// Creates Contexts for namespaces and records to allow for navigation. -static void generateContext(const Info &I, Object &Obj) { +void JSONGenerator::generateContext(const Info &I, Object &Obj) { json::Value ContextArray = json::Array(); auto &ContextArrayRef = *ContextArray.getAsArray(); ContextArrayRef.reserve(I.Contexts.size()); @@ -353,10 +368,8 @@ static void generateContext(const Info &I, Object &Obj) { Obj["HasContexts"] = true; } -static void -serializeCommonAttributes(const Info &I, json::Object &Obj, - const std::optional<StringRef> RepositoryUrl, - const std::optional<StringRef> RepositoryLinePrefix) { +void JSONGenerator::serializeCommonAttributes(const Info &I, + json::Object &Obj) { insertNonEmpty("Name", I.Name, Obj); Obj["USR"] = toHex(toStringRef(I.USR)); Obj["InfoType"] = infoTypeToString(I.IT); @@ -396,15 +409,15 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, if (I.IT != InfoType::IT_namespace) { const auto *Symbol = static_cast<const SymbolInfo *>(&I); if (Symbol->DefLoc) - Obj["Location"] = serializeLocation(Symbol->DefLoc.value(), RepositoryUrl, - RepositoryLinePrefix); + Obj["Location"] = serializeLocation(Symbol->DefLoc.value()); } if (!I.Contexts.empty()) generateContext(I, Obj); } -static void serializeReference(const Reference &Ref, Object &ReferenceObj) { +void JSONGenerator::serializeReference(const Reference &Ref, + Object &ReferenceObj) { insertNonEmpty("Path", Ref.Path, ReferenceObj); ReferenceObj["Name"] = Ref.Name; ReferenceObj["QualName"] = Ref.QualName; @@ -421,27 +434,21 @@ static void serializeReference(const Reference &Ref, Object &ReferenceObj) { // Although namespaces and records both have ScopeChildren, they serialize them // differently. Only enums, records, and typedefs are handled here. -static void -serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, - const std::optional<StringRef> RepositoryUrl, - const std::optional<StringRef> RepositoryLinePrefix) { - static auto SerializeInfo = - [RepositoryUrl, RepositoryLinePrefix](const auto &Info, Object &Object) { - serializeInfo(Info, Object, RepositoryUrl, RepositoryLinePrefix); - }; - +void JSONGenerator::serializeCommonChildren(const ScopeChildren &Children, + json::Object &Obj) { if (!Children.Enums.empty()) { - serializeArray(Children.Enums, Obj, "Enums", SerializeInfo); + serializeArray(Children.Enums, Obj, "Enums", serializeInfoLambda()); Obj["HasEnums"] = true; } if (!Children.Typedefs.empty()) { - serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo); + serializeArray(Children.Typedefs, Obj, "Typedefs", serializeInfoLambda()); Obj["HasTypedefs"] = true; } if (!Children.Records.empty()) { - serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda); + serializeArray(Children.Records, Obj, "Records", + serializeReferenceLambda()); Obj["HasRecords"] = true; } } @@ -465,12 +472,12 @@ static void serializeArray(const Container &Records, Object &Obj, StringRef Key, UpdateJson(Obj); } -static void serializeInfo(const ConstraintInfo &I, Object &Obj) { +void JSONGenerator::serializeInfo(const ConstraintInfo &I, Object &Obj) { serializeReference(I.ConceptRef, Obj); Obj["Expression"] = I.ConstraintExpr; } -static void serializeInfo(const TemplateInfo &Template, Object &Obj) { +void JSONGenerator::serializeInfo(const TemplateInfo &Template, Object &Obj) { json::Value TemplateVal = Object(); auto &TemplateObj = *TemplateVal.getAsObject(); auto SerializeTemplateParam = [](const TemplateParamInfo &Param, @@ -506,21 +513,19 @@ static void serializeInfo(const TemplateInfo &Template, Object &Obj) { if (!Template.Constraints.empty()) serializeArray(Template.Constraints, TemplateObj, "Constraints", - SerializeInfoLambda); + serializeInfoLambda()); Obj["Template"] = TemplateVal; } -static void serializeInfo(const ConceptInfo &I, Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLine) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryLine); +void JSONGenerator::serializeInfo(const ConceptInfo &I, Object &Obj) { + serializeCommonAttributes(I, Obj); Obj["IsType"] = I.IsType; Obj["ConstraintExpression"] = I.ConstraintExpression; serializeInfo(I.Template, Obj); } -static void serializeInfo(const TypeInfo &I, Object &Obj) { +void JSONGenerator::serializeInfo(const TypeInfo &I, Object &Obj) { Obj["Name"] = I.Type.Name; Obj["QualName"] = I.Type.QualName; Obj["USR"] = toHex(toStringRef(I.Type.USR)); @@ -528,7 +533,7 @@ static void serializeInfo(const TypeInfo &I, Object &Obj) { Obj["IsBuiltIn"] = I.IsBuiltIn; } -static void serializeInfo(const FieldTypeInfo &I, Object &Obj) { +void JSONGenerator::serializeInfo(const FieldTypeInfo &I, Object &Obj) { Obj["Name"] = I.Name; insertNonEmpty("DefaultValue", I.DefaultValue, Obj); json::Value ReferenceVal = Object(); @@ -537,10 +542,8 @@ static void serializeInfo(const FieldTypeInfo &I, Object &Obj) { Obj["Type"] = ReferenceVal; } -static void serializeInfo(const FunctionInfo &F, json::Object &Obj, - const std::optional<StringRef> RepositoryURL, - const std::optional<StringRef> RepositoryLine) { - serializeCommonAttributes(F, Obj, RepositoryURL, RepositoryLine); +void JSONGenerator::serializeInfo(const FunctionInfo &F, json::Object &Obj) { + serializeCommonAttributes(F, Obj); Obj["IsStatic"] = F.IsStatic; auto ReturnTypeObj = Object(); @@ -549,7 +552,7 @@ static void serializeInfo(const FunctionInfo &F, json::Object &Obj, if (!F.Params.empty()) { const bool VerticalDisplay = F.Params.size() > getMaxParamWrapLimit(); - serializeArray(F.Params, Obj, "Params", SerializeInfoLambda, "ParamEnd", + serializeArray(F.Params, Obj, "Params", serializeInfoLambda(), "ParamEnd", [VerticalDisplay](Object &JsonObj) { JsonObj["VerticalDisplay"] = VerticalDisplay; }); @@ -559,7 +562,7 @@ static void serializeInfo(const FunctionInfo &F, json::Object &Obj, serializeInfo(F.Template.value(), Obj); } -static void serializeInfo(const EnumValueInfo &I, Object &Obj) { +void JSONGenerator::serializeInfo(const EnumValueInfo &I, Object &Obj) { Obj["Name"] = I.Name; if (!I.ValueExpr.empty()) Obj["ValueExpr"] = I.ValueExpr; @@ -567,10 +570,8 @@ static void serializeInfo(const EnumValueInfo &I, Object &Obj) { Obj["Value"] = I.Value; } -static void serializeInfo(const EnumInfo &I, json::Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLine) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryLine); +void JSONGenerator::serializeInfo(const EnumInfo &I, json::Object &Obj) { + serializeCommonAttributes(I, Obj); Obj["Scoped"] = I.Scoped; if (I.BaseType) { @@ -583,14 +584,11 @@ static void serializeInfo(const EnumInfo &I, json::Object &Obj, } if (!I.Members.empty()) - serializeArray(I.Members, Obj, "Members", SerializeInfoLambda); + serializeArray(I.Members, Obj, "Members", serializeInfoLambda()); } -static void -serializeInfo(const TypedefInfo &I, json::Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLinePrefix) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryLinePrefix); +void JSONGenerator::serializeInfo(const TypedefInfo &I, json::Object &Obj) { + serializeCommonAttributes(I, Obj); Obj["TypeDeclaration"] = I.TypeDeclaration; Obj["IsUsing"] = I.IsUsing; json::Value TypeVal = Object(); @@ -601,18 +599,14 @@ serializeInfo(const TypedefInfo &I, json::Object &Obj, serializeInfo(I.Template.value(), Obj); } -static void -serializeInfo(const BaseRecordInfo &I, Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLinePrefix) { - serializeInfo(static_cast<const RecordInfo &>(I), Obj, RepositoryUrl, - RepositoryLinePrefix); +void JSONGenerator::serializeInfo(const BaseRecordInfo &I, Object &Obj) { + serializeInfo(static_cast<const RecordInfo &>(I), Obj); Obj["IsVirtual"] = I.IsVirtual; Obj["Access"] = getAccessSpelling(I.Access); Obj["IsParent"] = I.IsParent; } -static void serializeInfo(const FriendInfo &I, Object &Obj) { +void JSONGenerator::serializeInfo(const FriendInfo &I, Object &Obj) { auto FriendRef = Object(); serializeReference(I.Ref, FriendRef); Obj["Reference"] = std::move(FriendRef); @@ -620,13 +614,13 @@ static void serializeInfo(const FriendInfo &I, Object &Obj) { if (I.Template) serializeInfo(I.Template.value(), Obj); if (I.Params) - serializeArray(I.Params.value(), Obj, "Params", SerializeInfoLambda); + serializeArray(I.Params.value(), Obj, "Params", serializeInfoLambda()); if (I.ReturnType) { auto ReturnTypeObj = Object(); serializeInfo(I.ReturnType.value(), ReturnTypeObj); Obj["ReturnType"] = std::move(ReturnTypeObj); } - serializeCommonAttributes(I, Obj, std::nullopt, std::nullopt); + serializeCommonAttributes(I, Obj); } static void insertArray(Object &Obj, json::Value &Array, StringRef Key) { @@ -634,11 +628,8 @@ static void insertArray(Object &Obj, json::Value &Array, StringRef Key) { Obj["Has" + Key.str()] = true; } -static void -serializeInfo(const RecordInfo &I, json::Object &Obj, - const std::optional<StringRef> &RepositoryUrl, - const std::optional<StringRef> &RepositoryLinePrefix) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryLinePrefix); +void JSONGenerator::serializeInfo(const RecordInfo &I, json::Object &Obj) { + serializeCommonAttributes(I, Obj); Obj["TagType"] = getTagType(I.TagType); Obj["IsTypedef"] = I.IsTypeDef; Obj["MangledName"] = I.MangledName; @@ -652,7 +643,7 @@ serializeInfo(const RecordInfo &I, json::Object &Obj, for (const auto &Function : I.Children.Functions) { json::Value FunctionVal = Object(); auto &FunctionObj = *FunctionVal.getAsObject(); - serializeInfo(Function, FunctionObj, RepositoryUrl, RepositoryLinePrefix); + serializeInfo(Function, FunctionObj); AccessSpecifier Access = Function.Access; if (Access == AccessSpecifier::AS_public) PubFunctionsArrayRef.push_back(FunctionVal); @@ -698,21 +689,16 @@ serializeInfo(const RecordInfo &I, json::Object &Obj, } if (!I.Bases.empty()) - serializeArray(I.Bases, Obj, "Bases", - [&RepositoryUrl, &RepositoryLinePrefix]( - const BaseRecordInfo &Base, Object &BaseObj) { - serializeInfo(Base, BaseObj, RepositoryUrl, - RepositoryLinePrefix); - }); + serializeArray(I.Bases, Obj, "Bases", serializeInfoLambda()); if (!I.Parents.empty()) { - serializeArray(I.Parents, Obj, "Parents", SerializeReferenceLambda); + serializeArray(I.Parents, Obj, "Parents", serializeReferenceLambda()); Obj["HasParents"] = true; } if (!I.VirtualParents.empty()) { serializeArray(I.VirtualParents, Obj, "VirtualParents", - SerializeReferenceLambda); + serializeReferenceLambda()); Obj["HasVirtualParents"] = true; } @@ -720,61 +706,54 @@ serializeInfo(const RecordInfo &I, json::Object &Obj, serializeInfo(I.Template.value(), Obj); if (!I.Friends.empty()) { - serializeArray(I.Friends, Obj, "Friends", SerializeInfoLambda); + serializeArray(I.Friends, Obj, "Friends", serializeInfoLambda()); Obj["HasFriends"] = true; } - serializeCommonChildren(I.Children, Obj, RepositoryUrl, RepositoryLinePrefix); + serializeCommonChildren(I.Children, Obj); } -static void -serializeInfo(const VarInfo &I, json::Object &Obj, - const std::optional<StringRef> RepositoryUrl, - const std::optional<StringRef> RepositoryUrlLinePrefix) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryUrlLinePrefix); +void JSONGenerator::serializeInfo(const VarInfo &I, json::Object &Obj) { + serializeCommonAttributes(I, Obj); Obj["IsStatic"] = I.IsStatic; auto TypeObj = Object(); serializeInfo(I.Type, TypeObj); Obj["Type"] = std::move(TypeObj); } -static void serializeInfo(const NamespaceInfo &I, json::Object &Obj, - const std::optional<StringRef> RepositoryUrl, - const std::optional<StringRef> RepositoryLinePrefix) { - serializeCommonAttributes(I, Obj, RepositoryUrl, RepositoryLinePrefix); +void JSONGenerator::serializeInfo(const NamespaceInfo &I, json::Object &Obj) { + serializeCommonAttributes(I, Obj); if (I.USR == GlobalNamespaceID) Obj["Name"] = "Global Namespace"; if (!I.Children.Namespaces.empty()) { serializeArray(I.Children.Namespaces, Obj, "Namespaces", - SerializeReferenceLambda); + serializeReferenceLambda()); Obj["HasNamespaces"] = true; } - static auto SerializeInfo = - [RepositoryUrl, RepositoryLinePrefix](const auto &Info, Object &Object) { - serializeInfo(Info, Object, RepositoryUrl, RepositoryLinePrefix); - }; - if (!I.Children.Functions.empty()) { - serializeArray(I.Children.Functions, Obj, "Functions", SerializeInfo); + serializeArray(I.Children.Functions, Obj, "Functions", + serializeInfoLambda()); Obj["HasFunctions"] = true; } if (!I.Children.Concepts.empty()) { - serializeArray(I.Children.Concepts, Obj, "Concepts", SerializeInfo); + serializeArray(I.Children.Concepts, Obj, "Concepts", serializeInfoLambda()); Obj["HasConcepts"] = true; } if (!I.Children.Variables.emp... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/184663 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
