Skip to content

Commit 465c790

Browse files
[clang][ExtractAPI] Correctly generate declaration fragments for non-type template parameters (llvm#91958)
Previously we only generated declaration fragments for template type parameters/arguments, this adds supports for most other possible template parameters/arguments. rdar://127732598
1 parent 05439d3 commit 465c790

15 files changed

+512
-95
lines changed

clang/lib/ExtractAPI/DeclarationFragments.cpp

Lines changed: 179 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "clang/ExtractAPI/DeclarationFragments.h"
15+
#include "clang/AST/ASTFwd.h"
1516
#include "clang/AST/Decl.h"
1617
#include "clang/AST/DeclCXX.h"
18+
#include "clang/AST/TemplateBase.h"
19+
#include "clang/AST/TemplateName.h"
1720
#include "clang/AST/Type.h"
1821
#include "clang/AST/TypeLoc.h"
1922
#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
2023
#include "clang/Index/USRGeneration.h"
2124
#include "llvm/ADT/StringSwitch.h"
25+
#include "llvm/Support/ErrorHandling.h"
26+
#include "llvm/Support/raw_ostream.h"
27+
#include <optional>
2228

2329
using namespace clang::extractapi;
2430
using namespace llvm;
@@ -386,46 +392,24 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
386392
getFragmentsForType(AT->getElementType(), Context, After));
387393
}
388394

389-
// An ElaboratedType is a sugar for types that are referred to using an
390-
// elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a
391-
// qualified name, e.g., `N::M::type`, or both.
392-
if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
393-
ElaboratedTypeKeyword Keyword = ET->getKeyword();
394-
if (Keyword != ElaboratedTypeKeyword::ETK_None) {
395-
Fragments
396-
.append(ElaboratedType::getKeywordName(Keyword),
397-
DeclarationFragments::FragmentKind::Keyword)
398-
.appendSpace();
399-
}
400-
401-
if (const NestedNameSpecifier *NNS = ET->getQualifier())
402-
Fragments.append(getFragmentsForNNS(NNS, Context, After));
403-
404-
// After handling the elaborated keyword or qualified name, build
405-
// declaration fragments for the desugared underlying type.
406-
return Fragments.append(getFragmentsForType(ET->desugar(), Context, After));
407-
}
395+
if (const TemplateSpecializationType *TemplSpecTy =
396+
dyn_cast<TemplateSpecializationType>(T)) {
397+
const auto TemplName = TemplSpecTy->getTemplateName();
398+
std::string Str;
399+
raw_string_ostream Stream(Str);
400+
TemplName.print(Stream, Context.getPrintingPolicy(),
401+
TemplateName::Qualified::AsWritten);
402+
SmallString<64> USR("");
403+
if (const auto *TemplDecl = TemplName.getAsTemplateDecl())
404+
index::generateUSRForDecl(TemplDecl, USR);
408405

409-
// If the type is a typedefed type, get the underlying TypedefNameDecl for a
410-
// direct reference to the typedef instead of the wrapped type.
411-
412-
// 'id' type is a typedef for an ObjCObjectPointerType
413-
// we treat it as a typedef
414-
if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
415-
const TypedefNameDecl *Decl = TypedefTy->getDecl();
416-
TypedefUnderlyingTypeResolver TypedefResolver(Context);
417-
std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
418-
419-
if (T->isObjCIdType()) {
420-
return Fragments.append(Decl->getName(),
421-
DeclarationFragments::FragmentKind::Keyword);
422-
}
423-
424-
return Fragments.append(
425-
Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
426-
USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
406+
return Fragments
407+
.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
408+
.append("<", DeclarationFragments::FragmentKind::Text)
409+
.append(getFragmentsForTemplateArguments(
410+
TemplSpecTy->template_arguments(), Context, std::nullopt))
411+
.append(">", DeclarationFragments::FragmentKind::Text);
427412
}
428-
429413
// Everything we care about has been handled now, reduce to the canonical
430414
// unqualified base type.
431415
QualType Base = T->getCanonicalTypeUnqualified();
@@ -689,7 +673,6 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
689673
DeclarationFragments
690674
DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
691675
DeclarationFragments Fragments;
692-
// FIXME: Handle template specialization
693676
switch (Func->getStorageClass()) {
694677
case SC_None:
695678
case SC_PrivateExtern:
@@ -983,27 +966,84 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
983966
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
984967
.appendSpace();
985968

986-
const auto *TemplateParam =
987-
dyn_cast<TemplateTypeParmDecl>(ParameterArray[i]);
988-
if (!TemplateParam)
989-
continue;
990-
if (TemplateParam->hasTypeConstraint())
991-
Fragments.append(TemplateParam->getTypeConstraint()
992-
->getNamedConcept()
993-
->getName()
994-
.str(),
995-
DeclarationFragments::FragmentKind::TypeIdentifier);
996-
else if (TemplateParam->wasDeclaredWithTypename())
997-
Fragments.append("typename", DeclarationFragments::FragmentKind::Keyword);
998-
else
999-
Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
1000-
1001-
if (TemplateParam->isParameterPack())
1002-
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
1003-
1004-
Fragments.appendSpace().append(
1005-
TemplateParam->getName(),
1006-
DeclarationFragments::FragmentKind::GenericParameter);
969+
if (const auto *TemplateParam =
970+
dyn_cast<TemplateTypeParmDecl>(ParameterArray[i])) {
971+
if (TemplateParam->hasTypeConstraint())
972+
Fragments.append(TemplateParam->getTypeConstraint()
973+
->getNamedConcept()
974+
->getName()
975+
.str(),
976+
DeclarationFragments::FragmentKind::TypeIdentifier);
977+
else if (TemplateParam->wasDeclaredWithTypename())
978+
Fragments.append("typename",
979+
DeclarationFragments::FragmentKind::Keyword);
980+
else
981+
Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
982+
983+
if (TemplateParam->isParameterPack())
984+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
985+
986+
if (!TemplateParam->getName().empty())
987+
Fragments.appendSpace().append(
988+
TemplateParam->getName(),
989+
DeclarationFragments::FragmentKind::GenericParameter);
990+
991+
if (TemplateParam->hasDefaultArgument()) {
992+
DeclarationFragments After;
993+
Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
994+
.append(getFragmentsForType(TemplateParam->getDefaultArgument(),
995+
TemplateParam->getASTContext(), After));
996+
Fragments.append(std::move(After));
997+
}
998+
} else if (const auto *NTP =
999+
dyn_cast<NonTypeTemplateParmDecl>(ParameterArray[i])) {
1000+
DeclarationFragments After;
1001+
auto TyFragments =
1002+
getFragmentsForType(NTP->getType(), NTP->getASTContext(), After);
1003+
Fragments.append(std::move(TyFragments)).append(std::move(After));
1004+
1005+
if (NTP->isParameterPack())
1006+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
1007+
1008+
if (!NTP->getName().empty())
1009+
Fragments.appendSpace().append(
1010+
NTP->getName(),
1011+
DeclarationFragments::FragmentKind::GenericParameter);
1012+
1013+
if (NTP->hasDefaultArgument()) {
1014+
SmallString<8> ExprStr;
1015+
raw_svector_ostream Output(ExprStr);
1016+
NTP->getDefaultArgument()->printPretty(
1017+
Output, nullptr, NTP->getASTContext().getPrintingPolicy());
1018+
Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
1019+
.append(ExprStr, DeclarationFragments::FragmentKind::Text);
1020+
}
1021+
} else if (const auto *TTP =
1022+
dyn_cast<TemplateTemplateParmDecl>(ParameterArray[i])) {
1023+
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
1024+
.appendSpace()
1025+
.append("<", DeclarationFragments::FragmentKind::Text)
1026+
.append(getFragmentsForTemplateParameters(
1027+
TTP->getTemplateParameters()->asArray()))
1028+
.append(">", DeclarationFragments::FragmentKind::Text)
1029+
.appendSpace()
1030+
.append("typename",
1031+
DeclarationFragments::FragmentKind::Keyword);
1032+
1033+
if (TTP->isParameterPack())
1034+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
1035+
1036+
if (!TTP->getName().empty())
1037+
Fragments.appendSpace().append(
1038+
TTP->getName(),
1039+
DeclarationFragments::FragmentKind::GenericParameter);
1040+
if (TTP->hasDefaultArgument()) {
1041+
const auto Default = TTP->getDefaultArgument();
1042+
Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
1043+
.append(getFragmentsForTemplateArguments(
1044+
{Default.getArgument()}, TTP->getASTContext(), {Default}));
1045+
}
1046+
}
10071047
}
10081048
return Fragments;
10091049
}
@@ -1024,23 +1064,78 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateArguments(
10241064
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
10251065
.appendSpace();
10261066

1027-
std::string Type = TemplateArguments[i].getAsType().getAsString();
1028-
DeclarationFragments After;
1029-
DeclarationFragments ArgumentFragment =
1030-
getFragmentsForType(TemplateArguments[i].getAsType(), Context, After);
1031-
1032-
if (StringRef(ArgumentFragment.begin()->Spelling)
1033-
.starts_with("type-parameter")) {
1034-
std::string ProperArgName = TemplateArgumentLocs.value()[i]
1035-
.getTypeSourceInfo()
1036-
->getType()
1037-
.getAsString();
1038-
ArgumentFragment.begin()->Spelling.swap(ProperArgName);
1067+
const auto &CTA = TemplateArguments[i];
1068+
switch (CTA.getKind()) {
1069+
case TemplateArgument::Type: {
1070+
DeclarationFragments After;
1071+
DeclarationFragments ArgumentFragment =
1072+
getFragmentsForType(CTA.getAsType(), Context, After);
1073+
1074+
if (StringRef(ArgumentFragment.begin()->Spelling)
1075+
.starts_with("type-parameter")) {
1076+
std::string ProperArgName = TemplateArgumentLocs.value()[i]
1077+
.getTypeSourceInfo()
1078+
->getType()
1079+
.getAsString();
1080+
ArgumentFragment.begin()->Spelling.swap(ProperArgName);
1081+
}
1082+
Fragments.append(std::move(ArgumentFragment));
1083+
break;
1084+
}
1085+
case TemplateArgument::Declaration: {
1086+
const auto *VD = CTA.getAsDecl();
1087+
SmallString<128> USR;
1088+
index::generateUSRForDecl(VD, USR);
1089+
Fragments.append(VD->getNameAsString(),
1090+
DeclarationFragments::FragmentKind::Identifier, USR);
1091+
break;
10391092
}
1040-
Fragments.append(std::move(ArgumentFragment));
1093+
case TemplateArgument::NullPtr:
1094+
Fragments.append("nullptr", DeclarationFragments::FragmentKind::Keyword);
1095+
break;
10411096

1042-
if (TemplateArguments[i].isPackExpansion())
1043-
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
1097+
case TemplateArgument::Integral: {
1098+
SmallString<4> Str;
1099+
CTA.getAsIntegral().toString(Str);
1100+
Fragments.append(Str, DeclarationFragments::FragmentKind::Text);
1101+
break;
1102+
}
1103+
1104+
case TemplateArgument::TemplateExpansion:
1105+
case TemplateArgument::Template: {
1106+
std::string Str;
1107+
raw_string_ostream Stream(Str);
1108+
CTA.getAsTemplate().print(Stream, Context.getPrintingPolicy());
1109+
SmallString<64> USR("");
1110+
if (const auto *TemplDecl =
1111+
CTA.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
1112+
index::generateUSRForDecl(TemplDecl, USR);
1113+
Fragments.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier,
1114+
USR);
1115+
if (CTA.getKind() == TemplateArgument::TemplateExpansion)
1116+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
1117+
break;
1118+
}
1119+
1120+
case TemplateArgument::Pack:
1121+
Fragments.append("<", DeclarationFragments::FragmentKind::Text)
1122+
.append(getFragmentsForTemplateArguments(CTA.pack_elements(), Context,
1123+
{}))
1124+
.append(">", DeclarationFragments::FragmentKind::Text);
1125+
break;
1126+
1127+
case TemplateArgument::Expression: {
1128+
SmallString<8> ExprStr;
1129+
raw_svector_ostream Output(ExprStr);
1130+
CTA.getAsExpr()->printPretty(Output, nullptr,
1131+
Context.getPrintingPolicy());
1132+
Fragments.append(ExprStr, DeclarationFragments::FragmentKind::Text);
1133+
break;
1134+
}
1135+
1136+
case TemplateArgument::Null:
1137+
break;
1138+
}
10441139
}
10451140
return Fragments;
10461141
}
@@ -1050,10 +1145,12 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept(
10501145
DeclarationFragments Fragments;
10511146
return Fragments
10521147
.append("template", DeclarationFragments::FragmentKind::Keyword)
1148+
.appendSpace()
10531149
.append("<", DeclarationFragments::FragmentKind::Text)
10541150
.append(getFragmentsForTemplateParameters(
10551151
Concept->getTemplateParameters()->asArray()))
10561152
.append("> ", DeclarationFragments::FragmentKind::Text)
1153+
.appendSpace()
10571154
.append("concept", DeclarationFragments::FragmentKind::Keyword)
10581155
.appendSpace()
10591156
.append(Concept->getName().str(),
@@ -1066,6 +1163,7 @@ DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
10661163
const RedeclarableTemplateDecl *RedeclarableTemplate) {
10671164
DeclarationFragments Fragments;
10681165
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
1166+
.appendSpace()
10691167
.append("<", DeclarationFragments::FragmentKind::Text)
10701168
.append(getFragmentsForTemplateParameters(
10711169
RedeclarableTemplate->getTemplateParameters()->asArray()))
@@ -1088,6 +1186,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
10881186
DeclarationFragments Fragments;
10891187
return Fragments
10901188
.append("template", DeclarationFragments::FragmentKind::Keyword)
1189+
.appendSpace()
10911190
.append("<", DeclarationFragments::FragmentKind::Text)
10921191
.append(">", DeclarationFragments::FragmentKind::Text)
10931192
.appendSpace()
@@ -1108,6 +1207,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization(
11081207
DeclarationFragments Fragments;
11091208
return Fragments
11101209
.append("template", DeclarationFragments::FragmentKind::Keyword)
1210+
.appendSpace()
11111211
.append("<", DeclarationFragments::FragmentKind::Text)
11121212
.append(getFragmentsForTemplateParameters(
11131213
Decl->getTemplateParameters()->asArray()))
@@ -1130,6 +1230,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization(
11301230
DeclarationFragments Fragments;
11311231
return Fragments
11321232
.append("template", DeclarationFragments::FragmentKind::Keyword)
1233+
.appendSpace()
11331234
.append("<", DeclarationFragments::FragmentKind::Text)
11341235
.append(">", DeclarationFragments::FragmentKind::Text)
11351236
.appendSpace()
@@ -1149,6 +1250,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization(
11491250
DeclarationFragments Fragments;
11501251
return Fragments
11511252
.append("template", DeclarationFragments::FragmentKind::Keyword)
1253+
.appendSpace()
11521254
.append("<", DeclarationFragments::FragmentKind::Text)
11531255
// Partial specs may have new params.
11541256
.append(getFragmentsForTemplateParameters(
@@ -1171,6 +1273,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
11711273
DeclarationFragments Fragments;
11721274
return Fragments
11731275
.append("template", DeclarationFragments::FragmentKind::Keyword)
1276+
.appendSpace()
11741277
.append("<", DeclarationFragments::FragmentKind::Text)
11751278
// Partial specs may have new params.
11761279
.append(getFragmentsForTemplateParameters(
@@ -1187,6 +1290,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(
11871290
DeclarationFragments Fragments;
11881291
return Fragments
11891292
.append("template", DeclarationFragments::FragmentKind::Keyword)
1293+
.appendSpace()
11901294
.append("<>", DeclarationFragments::FragmentKind::Text)
11911295
.appendSpace()
11921296
.append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl));

clang/test/ExtractAPI/class_template.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ template<typename T> class Foo {};
5151
},
5252
{
5353
"kind": "text",
54-
"spelling": "<"
54+
"spelling": " <"
5555
},
5656
{
5757
"kind": "keyword",

clang/test/ExtractAPI/class_template_param_inheritance.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ template<typename T> class Foo : public T {};
5858
},
5959
{
6060
"kind": "text",
61-
"spelling": "<"
61+
"spelling": " <"
6262
},
6363
{
6464
"kind": "keyword",

clang/test/ExtractAPI/class_template_partial_spec.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ template<typename Z> class Foo<Z, int> {};
5353
},
5454
{
5555
"kind": "text",
56-
"spelling": "<"
56+
"spelling": " <"
5757
},
5858
{
5959
"kind": "keyword",
@@ -161,7 +161,7 @@ template<typename Z> class Foo<Z, int> {};
161161
},
162162
{
163163
"kind": "text",
164-
"spelling": "<"
164+
"spelling": " <"
165165
},
166166
{
167167
"kind": "keyword",

0 commit comments

Comments
 (0)