llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Erick Velez (evelez7) <details> <summary>Changes</summary> This patch contains changes for the JSON generator that will enable compatibility with Mustache templates, like booleans to check for the existence and bounds of arrays to avoid duplication. --- Patch is 28.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/149588.diff 17 Files Affected: - (modified) clang-tools-extra/clang-doc/BitcodeReader.cpp (+2) - (modified) clang-tools-extra/clang-doc/BitcodeWriter.cpp (+3-1) - (modified) clang-tools-extra/clang-doc/BitcodeWriter.h (+1) - (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+49-10) - (modified) clang-tools-extra/clang-doc/Representation.cpp (+2) - (modified) clang-tools-extra/clang-doc/Representation.h (+10) - (modified) clang-tools-extra/clang-doc/Serialize.cpp (+6-2) - (modified) clang-tools-extra/test/clang-doc/json/class-requires.cpp (+1) - (modified) clang-tools-extra/test/clang-doc/json/class-template.cpp (+1) - (modified) clang-tools-extra/test/clang-doc/json/class.cpp (+18) - (modified) clang-tools-extra/test/clang-doc/json/compound-constraints.cpp (+4) - (modified) clang-tools-extra/test/clang-doc/json/concept.cpp (+2) - (modified) clang-tools-extra/test/clang-doc/json/function-requires.cpp (+7) - (modified) clang-tools-extra/test/clang-doc/json/method-template.cpp (+2) - (modified) clang-tools-extra/test/clang-doc/json/namespace.cpp (+17) - (modified) clang-tools-extra/test/clang-doc/json/nested-namespace.cpp (+4) - (modified) clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp (+25) ``````````diff diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index dce34a8434ff8..4efbbd34730cf 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -384,6 +384,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID, return decodeRecord(R, I->Path, Blob); case REFERENCE_FIELD: return decodeRecord(R, F, Blob); + case REFERENCE_FILE: + return decodeRecord(R, I->DocumentationFileName, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for Reference"); diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index eed23726e17bf..e23511bf63690 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -210,6 +210,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> {REFERENCE_TYPE, {"RefType", &genIntAbbrev}}, {REFERENCE_PATH, {"Path", &genStringAbbrev}}, {REFERENCE_FIELD, {"Field", &genIntAbbrev}}, + {REFERENCE_FILE, {"File", &genStringAbbrev}}, {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}}, {TEMPLATE_SPECIALIZATION_OF, {"SpecializationOf", &genSymbolIdAbbrev}}, @@ -286,7 +287,7 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>> // Reference Block {BI_REFERENCE_BLOCK_ID, {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE, - REFERENCE_PATH, REFERENCE_FIELD}}, + REFERENCE_PATH, REFERENCE_FIELD, REFERENCE_FILE}}, // Template Blocks. {BI_TEMPLATE_BLOCK_ID, {}}, {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}}, @@ -479,6 +480,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { emitRecord((unsigned)R.RefType, REFERENCE_TYPE); emitRecord(R.Path, REFERENCE_PATH); emitRecord((unsigned)Field, REFERENCE_FIELD); + emitRecord(R.DocumentationFileName, REFERENCE_FILE); } void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) { diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h index 501af12582a8e..688f886b45308 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -140,6 +140,7 @@ enum RecordId { REFERENCE_TYPE, REFERENCE_PATH, REFERENCE_FIELD, + REFERENCE_FILE, TEMPLATE_PARAM_CONTENTS, TEMPLATE_SPECIALIZATION_OF, TYPEDEF_USR, diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index cc4c68346ec53..908e23d24d079 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -43,6 +43,30 @@ static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) { serializeReference(Ref, Object); }; +static std::string infoTypeToString(InfoType IT) { + switch (IT) { + case InfoType::IT_default: + return "default"; + case InfoType::IT_namespace: + return "namespace"; + case InfoType::IT_record: + return "record"; + case InfoType::IT_function: + return "function"; + case InfoType::IT_enum: + return "enum"; + case InfoType::IT_typedef: + return "typedef"; + case InfoType::IT_concept: + return "concept"; + case InfoType::IT_variable: + return "variable"; + case InfoType::IT_friend: + return "friend"; + } + llvm_unreachable("Unknown InfoType encountered."); +} + static json::Object serializeLocation(const Location &Loc, const std::optional<StringRef> RepositoryUrl) { @@ -172,6 +196,9 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, const std::optional<StringRef> RepositoryUrl) { Obj["Name"] = I.Name; Obj["USR"] = toHex(toStringRef(I.USR)); + Obj["InfoType"] = infoTypeToString(I.IT); + if (!I.DocumentationFileName.empty()) + Obj["DocumentationFileName"] = I.DocumentationFileName; if (!I.Path.empty()) Obj["Path"] = I.Path; @@ -205,6 +232,8 @@ static void serializeReference(const Reference &Ref, Object &ReferenceObj) { ReferenceObj["Name"] = Ref.Name; ReferenceObj["QualName"] = Ref.QualName; ReferenceObj["USR"] = toHex(toStringRef(Ref.USR)); + if (!Ref.DocumentationFileName.empty()) + ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName; } // Although namespaces and records both have ScopeChildren, they serialize them @@ -217,14 +246,18 @@ serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, serializeInfo(Info, Object, RepositoryUrl); }; - if (!Children.Enums.empty()) + if (!Children.Enums.empty()) { serializeArray(Children.Enums, Obj, "Enums", SerializeInfo); + Obj["HasEnums"] = true; + } if (!Children.Typedefs.empty()) serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo); - if (!Children.Records.empty()) + if (!Children.Records.empty()) { serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda); + Obj["HasRecords"] = true; + } } template <typename Container, typename SerializationFunc> @@ -234,10 +267,12 @@ static void serializeArray(const Container &Records, Object &Obj, json::Value RecordsArray = Array(); auto &RecordsArrayRef = *RecordsArray.getAsArray(); RecordsArrayRef.reserve(Records.size()); - for (const auto &Item : Records) { + for (size_t Index = 0; Index < Records.size(); ++Index) { json::Value ItemVal = Object(); auto &ItemObj = *ItemVal.getAsObject(); - SerializeInfo(Item, ItemObj); + SerializeInfo(Records[Index], ItemObj); + if (Index == Records.size() - 1) + ItemObj["End"] = true; RecordsArrayRef.push_back(ItemVal); } Obj[Key] = RecordsArray; @@ -405,8 +440,10 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, ProtFunctionsArrayRef.push_back(FunctionVal); } - if (!PubFunctionsArrayRef.empty()) + if (!PubFunctionsArrayRef.empty()) { Obj["PublicFunctions"] = PubFunctionsArray; + Obj["HasPublicFunctions"] = true; + } if (!ProtFunctionsArrayRef.empty()) Obj["ProtectedFunctions"] = ProtFunctionsArray; } @@ -429,8 +466,10 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, ProtMembersArrayRef.push_back(MemberVal); } - if (!PubMembersArrayRef.empty()) + if (!PubMembersArrayRef.empty()) { Obj["PublicMembers"] = PublicMembersArray; + Obj["HasPublicMembers"] = true; + } if (!ProtMembersArrayRef.empty()) Obj["ProtectedMembers"] = ProtectedMembersArray; } @@ -496,10 +535,7 @@ static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) { SmallString<16> FileName; if (I->IT == InfoType::IT_record) { auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I); - if (RecordSymbolInfo->MangledName.size() < 255) - FileName = RecordSymbolInfo->MangledName; - else - FileName = toStringRef(toHex(RecordSymbolInfo->USR)); + FileName = RecordSymbolInfo->MangledName; } else if (I->IT == InfoType::IT_namespace && I->Name != "") // Serialize the global namespace as index.json FileName = I->Name; @@ -527,7 +563,10 @@ Error JSONGenerator::generateDocs( } SmallString<16> FileName = determineFileName(Info, Path); + if (FileToInfos.contains(Path)) + continue; FileToInfos[Path].push_back(Info); + Info->DocumentationFileName = FileName; } for (const auto &Group : FileToInfos) { diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index beaf314a04ae1..79850e1f90253 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -247,6 +247,8 @@ void Reference::merge(Reference &&Other) { Name = Other.Name; if (Path.empty()) Path = Other.Path; + if (DocumentationFileName.empty()) + DocumentationFileName = Other.DocumentationFileName; } bool FriendInfo::mergeable(const FriendInfo &Other) { diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 23f0e90daa27f..2a75f89696b7d 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -121,6 +121,10 @@ struct Reference { Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, StringRef Path = StringRef()) : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {} + Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, + StringRef Path, SmallString<16> DocumentationFileName) + : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path), + DocumentationFileName(DocumentationFileName) {} bool operator==(const Reference &Other) const { return std::tie(USR, Name, QualName, RefType) == @@ -155,6 +159,7 @@ struct Reference { // Path of directory where the clang-doc generated file will be saved // (possibly unresolved) llvm::SmallString<128> Path; + SmallString<16> DocumentationFileName; }; // Holds the children of a record or namespace. @@ -331,6 +336,11 @@ struct Info { llvm::SmallString<128> Path; // Path of directory where the clang-doc // generated file will be saved + // The name used for the file that this info is documented in. + // In the JSON generator, infos are documented in files with mangled names. + // Thus, we keep track of the physical filename for linking purposes. + SmallString<16> DocumentationFileName; + void mergeBase(Info &&I); bool mergeable(const Info &Other); diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 7a0e00c6d9c2d..3e0e54bf53419 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -495,7 +495,8 @@ static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) { static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) { Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record, - Info.Name, getInfoRelativePath(Info.Namespace)); + Info.Name, getInfoRelativePath(Info.Namespace), + Info.MangledName); } static void InsertChild(ScopeChildren &Scope, EnumInfo Info) { @@ -777,7 +778,10 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, Mangler->mangleCXXVTable(CXXD, MangledStream); else MangledStream << D->getNameAsString(); - I.MangledName = MangledName; + if (MangledName.size() > 255) + I.MangledName = llvm::toStringRef(llvm::toHex(I.USR)); + else + I.MangledName = MangledName; delete Mangler; } diff --git a/clang-tools-extra/test/clang-doc/json/class-requires.cpp b/clang-tools-extra/test/clang-doc/json/class-requires.cpp index 213da93a1adfa..bf6c889849a70 100644 --- a/clang-tools-extra/test/clang-doc/json/class-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp @@ -20,6 +20,7 @@ struct MyClass; // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Addable<T>", // CHECK-NEXT: "Name": "Addable", // CHECK-NEXT: "Path": "", diff --git a/clang-tools-extra/test/clang-doc/json/class-template.cpp b/clang-tools-extra/test/clang-doc/json/class-template.cpp index 6cdc3e9175278..149248c772055 100644 --- a/clang-tools-extra/test/clang-doc/json/class-template.cpp +++ b/clang-tools-extra/test/clang-doc/json/class-template.cpp @@ -11,6 +11,7 @@ template<typename T> struct MyClass { // CHECK: "Name": "method", // CHECK: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "Param", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index d8317eafea91a..a36358982b019 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -60,8 +60,11 @@ struct MyClass { // CHECK-NEXT: "TextComment": " This is a brief description." // CHECK-NEXT: } // CHECK: "Command": "brief" +// CHECK: "DocumentationFileName": "_ZTV7MyClass", // CHECK: "Enums": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "enum", // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", // CHECK-NEXT: "LineNumber": 17 @@ -76,6 +79,7 @@ struct MyClass { // CHECK-NEXT: "Value": "1" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "BLUE", // CHECK-NEXT: "ValueExpr": "5" // CHECK-NEXT: } @@ -94,6 +98,7 @@ struct MyClass { // CHECK-NEXT: "IsClass": false, // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -118,6 +123,7 @@ struct MyClass { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "IsClass": true, // CHECK-NEXT: "Reference": { // CHECK-NEXT: "Name": "Foo", @@ -129,6 +135,11 @@ struct MyClass { // CHECK-NEXT: ], // COM: FIXME: FullName is not emitted correctly. // CHECK-NEXT: "FullName": "", +// CHECK-NEXT: "HasEnums": true, +// CHECK-NEXT: "HasPublicFunctions": true, +// CHECK-NEXT: "HasPublicMembers": true, +// CHECK-NEXT: "HasRecords": true, +// CHECK-NEXT: "InfoType": "record", // CHECK-NEXT: "IsTypedef": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", @@ -142,6 +153,7 @@ struct MyClass { // CHECK-NEXT: "Path": "GlobalNamespace", // CHECK-NEXT: "ProtectedFunctions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "protectedMethod", // CHECK-NEXT: "Namespace": [ @@ -166,6 +178,7 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "PublicFunctions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "myMethod", // CHECK-NEXT: "Namespace": [ @@ -174,6 +187,7 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "MyParam", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -204,6 +218,8 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "Records": [ // CHECK-NEXT: { +// CHECK-NEXT: "DocumentationFileName": "_ZTVN7MyClass11NestedClassE", +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "NestedClass", // CHECK-NEXT: "Path": "GlobalNamespace{{[\/]+}}MyClass", // CHECK-NEXT: "QualName": "NestedClass", @@ -213,6 +229,8 @@ struct MyClass { // CHECK-NEXT: "TagType": "struct", // CHECK-NEXT: "Typedefs": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "typedef", // CHECK-NEXT: "IsUsing": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp index 34acb6808409d..bb2b4ca770fc0 100644 --- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp +++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp @@ -37,6 +37,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable<T>", // CHECK-NEXT: "Name": "Decrementable", // CHECK-NEXT: "Path": "", @@ -55,6 +56,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable<T>", // CHECK-NEXT: "Name": "Decrementable", // CHECK-NEXT: "Path": "", @@ -87,6 +89,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreDecrementable<T>", // CHECK-NEXT: "Name": "PreDecrementable", // CHECK-NEXT: "Path": "", @@ -112,6 +115,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreIncrementable<T>", // CHECK-NEXT: "Name": "PreIncrementable", // CHECK-NEXT: "Path": "", diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp index b946393274c85..766415bbbeecd 100644 --- a/clang-tools-extra/test/clang-doc/json/concept.cpp +++ b/clang-tools-extra/test/clang-doc/json/concept.cpp @@ -23,6 +23,8 @@ concept Incrementable = requires(T x) { // CHECK-NEXT: { // CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." // CHECK: ], +// CHECK: "End": true, +// CHECK-NEXT: "InfoType": "concept", // CHECK-NEXT: "IsType": true, // CHECK-NEXT: "Name": "Incrementable", // CHECK-NEXT: "Template": { diff --git a/clang-tools-extra/test/clang-doc/json/function-requires.cpp b/clang-tools-extra/test/clang-doc/json/function-requires.cpp index 08ac4c7ed2ca3..59ed39ee61fda 100644 --- a/clang-tools-extra/test/clang-doc/json/function-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp @@ -14,10 +14,12 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK: "Functions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "increment", // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "t", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } @@ -32,6 +34,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Incrementable<T>", // CHECK-NEXT: "Name": "Incrementable", // CHECK-NEXT: "Path": "", @@ -46,10 +49,13 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "incrementTwo", // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "t", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } @@ -64,6 +70,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/149588 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits