[clang] [clang][ExtractAPI] Correctly generate declaration fragments for non-type template parameters (PR #91958)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 13 06:09:39 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Daniel Grumberg (daniel-grumberg)
<details>
<summary>Changes</summary>
Previously we only generated declaration fragments for template type parameters/arguments, this adds supports for most other possible template parameters/arguments.
rdar://127732598
---
Patch is 31.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/91958.diff
15 Files Affected:
- (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+189-37)
- (modified) clang/test/ExtractAPI/class_template.cpp (+1-1)
- (modified) clang/test/ExtractAPI/class_template_param_inheritance.cpp (+1-1)
- (modified) clang/test/ExtractAPI/class_template_partial_spec.cpp (+2-2)
- (modified) clang/test/ExtractAPI/class_template_spec.cpp (+2-2)
- (modified) clang/test/ExtractAPI/concept.cpp (+1-1)
- (modified) clang/test/ExtractAPI/field_template.cpp (+1-1)
- (modified) clang/test/ExtractAPI/global_func_template.cpp (+2-2)
- (modified) clang/test/ExtractAPI/global_func_template_spec.cpp (+2-2)
- (modified) clang/test/ExtractAPI/global_var_template.cpp (+1-1)
- (modified) clang/test/ExtractAPI/global_var_template_partial_spec.cpp (+2-2)
- (modified) clang/test/ExtractAPI/global_var_template_spec.cpp (+2-2)
- (modified) clang/test/ExtractAPI/method_template.cpp (+1-1)
- (modified) clang/test/ExtractAPI/method_template_spec.cpp (+2-2)
- (added) clang/test/ExtractAPI/non_type_template.cpp (+313)
``````````diff
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 9bf7950888dbb..98b9343924a83 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,13 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang::extractapi;
using namespace llvm;
@@ -386,6 +392,25 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
getFragmentsForType(AT->getElementType(), Context, After));
}
+ if (const TemplateSpecializationType *TemplSpecTy =
+ dyn_cast<TemplateSpecializationType>(T)) {
+ const auto TemplName = TemplSpecTy->getTemplateName();
+ std::string Str;
+ raw_string_ostream Stream(Str);
+ TemplName.print(Stream, Context.getPrintingPolicy(),
+ TemplateName::Qualified::AsWritten);
+ SmallString<64> USR("");
+ if (const auto *TemplDecl = TemplName.getAsTemplateDecl())
+ index::generateUSRForDecl(TemplDecl, USR);
+
+ return Fragments
+ .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ TemplSpecTy->template_arguments(), Context, std::nullopt))
+ .append(">", DeclarationFragments::FragmentKind::Text);
+ }
+
// Everything we care about has been handled now, reduce to the canonical
// unqualified base type.
QualType Base = T->getCanonicalTypeUnqualified();
@@ -650,7 +675,6 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
DeclarationFragments Fragments;
- // FIXME: Handle template specialization
switch (Func->getStorageClass()) {
case SC_None:
case SC_PrivateExtern:
@@ -952,27 +976,84 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
.appendSpace();
- const auto *TemplateParam =
- dyn_cast<TemplateTypeParmDecl>(ParameterArray[i]);
- if (!TemplateParam)
- continue;
- if (TemplateParam->hasTypeConstraint())
- Fragments.append(TemplateParam->getTypeConstraint()
- ->getNamedConcept()
- ->getName()
- .str(),
- DeclarationFragments::FragmentKind::TypeIdentifier);
- else if (TemplateParam->wasDeclaredWithTypename())
- Fragments.append("typename", DeclarationFragments::FragmentKind::Keyword);
- else
- Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
-
- if (TemplateParam->isParameterPack())
- Fragments.append("...", DeclarationFragments::FragmentKind::Text);
-
- Fragments.appendSpace().append(
- TemplateParam->getName(),
- DeclarationFragments::FragmentKind::GenericParameter);
+ if (const auto *TemplateParam =
+ dyn_cast<TemplateTypeParmDecl>(ParameterArray[i])) {
+ if (TemplateParam->hasTypeConstraint())
+ Fragments.append(TemplateParam->getTypeConstraint()
+ ->getNamedConcept()
+ ->getName()
+ .str(),
+ DeclarationFragments::FragmentKind::TypeIdentifier);
+ else if (TemplateParam->wasDeclaredWithTypename())
+ Fragments.append("typename",
+ DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
+
+ if (TemplateParam->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!TemplateParam->getName().empty())
+ Fragments.appendSpace().append(
+ TemplateParam->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+
+ if (TemplateParam->hasDefaultArgument()) {
+ DeclarationFragments After;
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForType(TemplateParam->getDefaultArgument(),
+ TemplateParam->getASTContext(), After));
+ Fragments.append(std::move(After));
+ }
+ } else if (const auto *NTP =
+ dyn_cast<NonTypeTemplateParmDecl>(ParameterArray[i])) {
+ DeclarationFragments After;
+ const auto TyFragments =
+ getFragmentsForType(NTP->getType(), NTP->getASTContext(), After);
+ Fragments.append(std::move(TyFragments)).append(std::move(After));
+
+ if (NTP->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!NTP->getName().empty())
+ Fragments.appendSpace().append(
+ NTP->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+
+ if (NTP->hasDefaultArgument()) {
+ SmallString<8> ExprStr;
+ raw_svector_ostream Output(ExprStr);
+ NTP->getDefaultArgument()->printPretty(
+ Output, nullptr, NTP->getASTContext().getPrintingPolicy());
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(ExprStr, DeclarationFragments::FragmentKind::Text);
+ }
+ } else if (const auto *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(ParameterArray[i])) {
+ Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateParameters(
+ TTP->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(TTP->wasDeclaredWithTypename() ? "typename" : "class",
+ DeclarationFragments::FragmentKind::Keyword);
+
+ if (TTP->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!TTP->getName().empty())
+ Fragments.appendSpace().append(
+ TTP->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+ if (TTP->hasDefaultArgument()) {
+ const auto Default = TTP->getDefaultArgument();
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ {Default.getArgument()}, TTP->getASTContext(), {Default}));
+ }
+ }
}
return Fragments;
}
@@ -993,23 +1074,85 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateArguments(
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
.appendSpace();
- std::string Type = TemplateArguments[i].getAsType().getAsString();
- DeclarationFragments After;
- DeclarationFragments ArgumentFragment =
- getFragmentsForType(TemplateArguments[i].getAsType(), Context, After);
-
- if (StringRef(ArgumentFragment.begin()->Spelling)
- .starts_with("type-parameter")) {
- std::string ProperArgName = TemplateArgumentLocs.value()[i]
- .getTypeSourceInfo()
- ->getType()
- .getAsString();
- ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+ const auto &CTA = TemplateArguments[i];
+ switch (CTA.getKind()) {
+ case TemplateArgument::Type: {
+ DeclarationFragments After;
+ DeclarationFragments ArgumentFragment =
+ getFragmentsForType(CTA.getAsType(), Context, After);
+
+ if (StringRef(ArgumentFragment.begin()->Spelling)
+ .starts_with("type-parameter")) {
+ std::string ProperArgName = TemplateArgumentLocs.value()[i]
+ .getTypeSourceInfo()
+ ->getType()
+ .getAsString();
+ ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+ }
+ Fragments.append(std::move(ArgumentFragment));
+ break;
}
- Fragments.append(std::move(ArgumentFragment));
+ case TemplateArgument::Declaration: {
+ const auto *VD = CTA.getAsDecl();
+ SmallString<128> USR;
+ index::generateUSRForDecl(VD, USR);
+ Fragments.append(VD->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier, USR);
+ break;
+ }
+ case TemplateArgument::NullPtr:
+ Fragments.append("nullptr", DeclarationFragments::FragmentKind::Keyword);
+ break;
- if (TemplateArguments[i].isPackExpansion())
- Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+ case TemplateArgument::Integral: {
+ SmallString<4> Str;
+ CTA.getAsIntegral().toString(Str);
+ Fragments.append(Str, DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::StructuralValue: {
+ const auto SVTy = CTA.getStructuralValueType();
+ Fragments.append(CTA.getAsStructuralValue().getAsString(Context, SVTy),
+ DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Template: {
+ std::string Str;
+ raw_string_ostream Stream(Str);
+ CTA.getAsTemplate().print(Stream, Context.getPrintingPolicy());
+ SmallString<64> USR("");
+ if (const auto *TemplDecl =
+ CTA.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ index::generateUSRForDecl(TemplDecl, USR);
+ Fragments.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR);
+ if (CTA.getKind() == TemplateArgument::TemplateExpansion)
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ Fragments.append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(CTA.pack_elements(), Context,
+ {}))
+ .append(">", DeclarationFragments::FragmentKind::Text);
+ break;
+
+ case TemplateArgument::Expression: {
+ SmallString<8> ExprStr;
+ raw_svector_ostream Output(ExprStr);
+ CTA.getAsExpr()->printPretty(Output, nullptr,
+ Context.getPrintingPolicy());
+ Fragments.append(ExprStr, DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::Null:
+ break;
+ }
}
return Fragments;
}
@@ -1019,10 +1162,12 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
.append(getFragmentsForTemplateParameters(
Concept->getTemplateParameters()->asArray()))
.append("> ", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
.append("concept", DeclarationFragments::FragmentKind::Keyword)
.appendSpace()
.append(Concept->getName().str(),
@@ -1035,6 +1180,7 @@ DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
const RedeclarableTemplateDecl *RedeclarableTemplate) {
DeclarationFragments Fragments;
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
.append(getFragmentsForTemplateParameters(
RedeclarableTemplate->getTemplateParameters()->asArray()))
@@ -1057,6 +1203,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
.append(">", DeclarationFragments::FragmentKind::Text)
.appendSpace()
@@ -1077,6 +1224,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
.append(getFragmentsForTemplateParameters(
Decl->getTemplateParameters()->asArray()))
@@ -1099,6 +1247,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
.append(">", DeclarationFragments::FragmentKind::Text)
.appendSpace()
@@ -1118,6 +1267,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
// Partial specs may have new params.
.append(getFragmentsForTemplateParameters(
@@ -1140,6 +1290,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<", DeclarationFragments::FragmentKind::Text)
// Partial specs may have new params.
.append(getFragmentsForTemplateParameters(
@@ -1156,6 +1307,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(
DeclarationFragments Fragments;
return Fragments
.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
.append("<>", DeclarationFragments::FragmentKind::Text)
.appendSpace()
.append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl));
diff --git a/clang/test/ExtractAPI/class_template.cpp b/clang/test/ExtractAPI/class_template.cpp
index 4f2670d7b6997..203d47394dd60 100644
--- a/clang/test/ExtractAPI/class_template.cpp
+++ b/clang/test/ExtractAPI/class_template.cpp
@@ -51,7 +51,7 @@ template<typename T> class Foo {};
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_param_inheritance.cpp b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
index 3d7b09f93ed6d..53b331e0b460b 100644
--- a/clang/test/ExtractAPI/class_template_param_inheritance.cpp
+++ b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
@@ -58,7 +58,7 @@ template<typename T> class Foo : public T {};
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_partial_spec.cpp b/clang/test/ExtractAPI/class_template_partial_spec.cpp
index c8d9cc78d41c5..7d244f49c7359 100644
--- a/clang/test/ExtractAPI/class_template_partial_spec.cpp
+++ b/clang/test/ExtractAPI/class_template_partial_spec.cpp
@@ -53,7 +53,7 @@ template<typename Z> class Foo<Z, int> {};
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
@@ -161,7 +161,7 @@ template<typename Z> class Foo<Z, int> {};
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_spec.cpp b/clang/test/ExtractAPI/class_template_spec.cpp
index 06a95314dc4aa..9dbd887510c70 100644
--- a/clang/test/ExtractAPI/class_template_spec.cpp
+++ b/clang/test/ExtractAPI/class_template_spec.cpp
@@ -53,7 +53,7 @@ template<> class Foo<int> {};
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
@@ -140,7 +140,7 @@ template<> class Foo<int> {};
},
{
"kind": "text",
- "spelling": "<> "
+ "spelling": " <> "
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/concept.cpp b/clang/test/ExtractAPI/concept.cpp
index 443eac2971f0e..4396a39a63ef6 100644
--- a/clang/test/ExtractAPI/concept.cpp
+++ b/clang/test/ExtractAPI/concept.cpp
@@ -51,7 +51,7 @@ template<typename T> concept Foo = true;
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/field_template.cpp b/clang/test/ExtractAPI/field_template.cpp
index 2058ed008cfe4..973a9de5c9986 100644
--- a/clang/test/ExtractAPI/field_template.cpp
+++ b/clang/test/ExtractAPI/field_template.cpp
@@ -114,7 +114,7 @@ class Foo {
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_func_template.cpp b/clang/test/ExtractAPI/global_func_template.cpp
index f43a618ec0c36..044757c316d58 100644
--- a/clang/test/ExtractAPI/global_func_template.cpp
+++ b/clang/test/ExtractAPI/global_func_template.cpp
@@ -52,7 +52,7 @@ template<typename T> T Fizz(int Buzz);
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
@@ -186,7 +186,7 @@ template<typename T> T Fizz(int Buzz);
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_func_template_spec.cpp b/clang/test/ExtractAPI/global_func_template_spec.cpp
index fe046e9c3b9da..b88063aacfedc 100644
--- a/clang/test/ExtractAPI/global_func_template_spec.cpp
+++ b/clang/test/ExtractAPI/global_func_template_spec.cpp
@@ -52,7 +52,7 @@ template<> void Foo<int>(int Bar);
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
@@ -186,7 +186,7 @@ template<> void Foo<int>(int Bar);
},
{
"kind": "text",
- "spelling": "<> "
+ "spelling": " <> "
},
{
"kind": "typeIdentifier",
diff --git a/clang/test/ExtractAPI/global_var_template.cpp b/clang/test/ExtractAPI/global_var_template.cpp
index 94f3713cd3d31..5c9194141332b 100644
--- a/clang/test/ExtractAPI/global_var_template.cpp
+++ b/clang/test/ExtractAPI/global_var_template.cpp
@@ -50,7 +50,7 @@ template<typename T> T Foo = T(3.14);
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
index 91084f258878e..ffb1557fd7580 100644
--- a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
+++ b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
@@ -52,7 +52,7 @@ template<typename Z> int Foo<int, Z> = 0;
},
{
"kind": "text",
- "spelling": "<"
+ "spelling": " <"
},
{
"kind": "keyword",
@@ -161,7 +161,7 @@ template<typename Z> int Foo<...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/91958
More information about the cfe-commits
mailing list