forked from OSchip/llvm-project
[clang][Index] Introduce a TemplateParm SymbolKind
Summary: Currently template parameters has symbolkind `Unknown`. This patch introduces a new kind `TemplateParm` for templatetemplate, templatetype and nontypetemplate parameters. Also adds tests in clangd hover feature. Reviewers: sammccall Subscribers: kristof.beyls, ilya-biryukov, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73696
This commit is contained in:
parent
c45fb35b5e
commit
84240e0db8
|
@ -108,6 +108,7 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
|
|||
return CompletionItemKind::Function;
|
||||
case SK::Variable:
|
||||
case SK::Parameter:
|
||||
case SK::NonTypeTemplateParm:
|
||||
return CompletionItemKind::Variable;
|
||||
case SK::Field:
|
||||
return CompletionItemKind::Field;
|
||||
|
@ -125,6 +126,9 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
|
|||
return CompletionItemKind::Property;
|
||||
case SK::Constructor:
|
||||
return CompletionItemKind::Constructor;
|
||||
case SK::TemplateTypeParm:
|
||||
case SK::TemplateTemplateParm:
|
||||
return CompletionItemKind::TypeParameter;
|
||||
}
|
||||
llvm_unreachable("Unhandled clang::index::SymbolKind.");
|
||||
}
|
||||
|
|
|
@ -115,15 +115,6 @@ std::string printDefinition(const Decl *D) {
|
|||
return Definition;
|
||||
}
|
||||
|
||||
void printParams(llvm::raw_ostream &OS,
|
||||
const std::vector<HoverInfo::Param> &Params) {
|
||||
for (size_t I = 0, E = Params.size(); I != E; ++I) {
|
||||
if (I)
|
||||
OS << ", ";
|
||||
OS << Params.at(I);
|
||||
}
|
||||
}
|
||||
|
||||
std::string printType(QualType QT, const PrintingPolicy &Policy) {
|
||||
// TypePrinter doesn't resolve decltypes, so resolve them here.
|
||||
// FIXME: This doesn't handle composite types that contain a decltype in them.
|
||||
|
@ -133,6 +124,43 @@ std::string printType(QualType QT, const PrintingPolicy &Policy) {
|
|||
return QT.getAsString(Policy);
|
||||
}
|
||||
|
||||
std::string printType(const TemplateTypeParmDecl *TTP) {
|
||||
std::string Res = TTP->wasDeclaredWithTypename() ? "typename" : "class";
|
||||
if (TTP->isParameterPack())
|
||||
Res += "...";
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::string printType(const NonTypeTemplateParmDecl *NTTP,
|
||||
const PrintingPolicy &PP) {
|
||||
std::string Res = printType(NTTP->getType(), PP);
|
||||
if (NTTP->isParameterPack())
|
||||
Res += "...";
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::string printType(const TemplateTemplateParmDecl *TTP,
|
||||
const PrintingPolicy &PP) {
|
||||
std::string Res;
|
||||
llvm::raw_string_ostream OS(Res);
|
||||
OS << "template <";
|
||||
llvm::StringRef Sep = "";
|
||||
for (const Decl *Param : *TTP->getTemplateParameters()) {
|
||||
OS << Sep;
|
||||
Sep = ", ";
|
||||
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
|
||||
OS << printType(TTP);
|
||||
else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
|
||||
OS << printType(NTTP, PP);
|
||||
else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param))
|
||||
OS << printType(TTPD, PP);
|
||||
}
|
||||
// FIXME: TemplateTemplateParameter doesn't store the info on whether this
|
||||
// param was a "typename" or "class".
|
||||
OS << "> class";
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
std::vector<HoverInfo::Param>
|
||||
fetchTemplateParameters(const TemplateParameterList *Params,
|
||||
const PrintingPolicy &PP) {
|
||||
|
@ -142,38 +170,30 @@ fetchTemplateParameters(const TemplateParameterList *Params,
|
|||
for (const Decl *Param : *Params) {
|
||||
HoverInfo::Param P;
|
||||
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
|
||||
P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
|
||||
if (TTP->isParameterPack())
|
||||
*P.Type += "...";
|
||||
P.Type = printType(TTP);
|
||||
|
||||
if (!TTP->getName().empty())
|
||||
P.Name = TTP->getNameAsString();
|
||||
|
||||
if (TTP->hasDefaultArgument())
|
||||
P.Default = TTP->getDefaultArgument().getAsString(PP);
|
||||
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
|
||||
P.Type = printType(NTTP, PP);
|
||||
|
||||
if (IdentifierInfo *II = NTTP->getIdentifier())
|
||||
P.Name = II->getName().str();
|
||||
|
||||
P.Type = printType(NTTP->getType(), PP);
|
||||
if (NTTP->isParameterPack())
|
||||
*P.Type += "...";
|
||||
|
||||
if (NTTP->hasDefaultArgument()) {
|
||||
P.Default.emplace();
|
||||
llvm::raw_string_ostream Out(*P.Default);
|
||||
NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
|
||||
}
|
||||
} else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
|
||||
P.Type.emplace();
|
||||
llvm::raw_string_ostream OS(*P.Type);
|
||||
OS << "template <";
|
||||
printParams(OS,
|
||||
fetchTemplateParameters(TTPD->getTemplateParameters(), PP));
|
||||
OS << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
|
||||
// info on whether this param was a "typename" or
|
||||
// "class".
|
||||
P.Type = printType(TTPD, PP);
|
||||
|
||||
if (!TTPD->getName().empty())
|
||||
P.Name = TTPD->getNameAsString();
|
||||
|
||||
if (TTPD->hasDefaultArgument()) {
|
||||
P.Default.emplace();
|
||||
llvm::raw_string_ostream Out(*P.Default);
|
||||
|
@ -385,6 +405,10 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) {
|
|||
fillFunctionTypeAndParams(HI, D, FD, Policy);
|
||||
else if (const auto *VD = dyn_cast<ValueDecl>(D))
|
||||
HI.Type = printType(VD->getType(), Policy);
|
||||
else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
|
||||
HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
|
||||
else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D))
|
||||
HI.Type = printType(TTP, Policy);
|
||||
|
||||
// Fill in value with evaluated initializer if possible.
|
||||
if (const auto *Var = dyn_cast<VarDecl>(D)) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Logger.h"
|
||||
#include "URI.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Index/IndexSymbol.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
@ -261,9 +262,13 @@ SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
|
|||
case index::SymbolKind::ConversionFunction:
|
||||
return SymbolKind::Function;
|
||||
case index::SymbolKind::Parameter:
|
||||
case index::SymbolKind::NonTypeTemplateParm:
|
||||
return SymbolKind::Variable;
|
||||
case index::SymbolKind::Using:
|
||||
return SymbolKind::Namespace;
|
||||
case index::SymbolKind::TemplateTemplateParm:
|
||||
case index::SymbolKind::TemplateTypeParm:
|
||||
return SymbolKind::TypeParameter;
|
||||
}
|
||||
llvm_unreachable("invalid symbol kind");
|
||||
}
|
||||
|
|
|
@ -129,6 +129,8 @@ categorize(const index::SymbolInfo &D) {
|
|||
case index::SymbolKind::Extension:
|
||||
case index::SymbolKind::Union:
|
||||
case index::SymbolKind::TypeAlias:
|
||||
case index::SymbolKind::TemplateTypeParm:
|
||||
case index::SymbolKind::TemplateTemplateParm:
|
||||
return SymbolQualitySignals::Type;
|
||||
case index::SymbolKind::Function:
|
||||
case index::SymbolKind::ClassMethod:
|
||||
|
@ -147,6 +149,7 @@ categorize(const index::SymbolInfo &D) {
|
|||
case index::SymbolKind::Field:
|
||||
case index::SymbolKind::EnumConstant:
|
||||
case index::SymbolKind::Parameter:
|
||||
case index::SymbolKind::NonTypeTemplateParm:
|
||||
return SymbolQualitySignals::Variable;
|
||||
case index::SymbolKind::Using:
|
||||
case index::SymbolKind::Module:
|
||||
|
|
|
@ -573,6 +573,42 @@ class Foo {})cpp";
|
|||
// pattern.
|
||||
HI.Documentation = "comment from primary";
|
||||
}},
|
||||
{// Template Type Parameter
|
||||
R"cpp(
|
||||
template <typename [[^T]] = int> void foo();
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "T";
|
||||
HI.Kind = index::SymbolKind::TemplateTypeParm;
|
||||
HI.NamespaceScope = "";
|
||||
HI.Definition = "typename T = int";
|
||||
HI.LocalScope = "foo::";
|
||||
HI.Type = "typename";
|
||||
}},
|
||||
{// TemplateTemplate Type Parameter
|
||||
R"cpp(
|
||||
template <template<typename> class [[^T]]> void foo();
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "T";
|
||||
HI.Kind = index::SymbolKind::TemplateTemplateParm;
|
||||
HI.NamespaceScope = "";
|
||||
HI.Definition = "template <typename> class T";
|
||||
HI.LocalScope = "foo::";
|
||||
HI.Type = "template <typename> class";
|
||||
}},
|
||||
{// NonType Template Parameter
|
||||
R"cpp(
|
||||
template <int [[^T]] = 5> void foo();
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "T";
|
||||
HI.Kind = index::SymbolKind::NonTypeTemplateParm;
|
||||
HI.NamespaceScope = "";
|
||||
HI.Definition = "int T = 5";
|
||||
HI.LocalScope = "foo::";
|
||||
HI.Type = "int";
|
||||
}},
|
||||
};
|
||||
for (const auto &Case : Cases) {
|
||||
SCOPED_TRACE(Case.Code);
|
||||
|
|
|
@ -54,6 +54,9 @@ enum class SymbolKind : uint8_t {
|
|||
|
||||
Parameter,
|
||||
Using,
|
||||
TemplateTypeParm,
|
||||
TemplateTemplateParm,
|
||||
NonTypeTemplateParm,
|
||||
};
|
||||
|
||||
enum class SymbolLanguage : uint8_t {
|
||||
|
|
|
@ -357,6 +357,15 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
|
|||
case Decl::VarTemplate:
|
||||
llvm_unreachable("variables handled before");
|
||||
break;
|
||||
case Decl::TemplateTypeParm:
|
||||
Info.Kind = SymbolKind::TemplateTypeParm;
|
||||
break;
|
||||
case Decl::TemplateTemplateParm:
|
||||
Info.Kind = SymbolKind::TemplateTemplateParm;
|
||||
break;
|
||||
case Decl::NonTypeTemplateParm:
|
||||
Info.Kind = SymbolKind::NonTypeTemplateParm;
|
||||
break;
|
||||
// Other decls get the 'unknown' kind.
|
||||
default:
|
||||
break;
|
||||
|
@ -517,6 +526,9 @@ StringRef index::getSymbolKindString(SymbolKind K) {
|
|||
case SymbolKind::ConversionFunction: return "conversion-func";
|
||||
case SymbolKind::Parameter: return "param";
|
||||
case SymbolKind::Using: return "using";
|
||||
case SymbolKind::TemplateTypeParm: return "template-type-param";
|
||||
case SymbolKind::TemplateTemplateParm: return "template-template-param";
|
||||
case SymbolKind::NonTypeTemplateParm: return "non-type-template-param";
|
||||
}
|
||||
llvm_unreachable("invalid symbol kind");
|
||||
}
|
||||
|
|
|
@ -1245,6 +1245,9 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
|
|||
case SymbolKind::Macro:
|
||||
case SymbolKind::ClassProperty:
|
||||
case SymbolKind::Using:
|
||||
case SymbolKind::TemplateTypeParm:
|
||||
case SymbolKind::TemplateTemplateParm:
|
||||
case SymbolKind::NonTypeTemplateParm:
|
||||
return CXIdxEntity_Unexposed;
|
||||
|
||||
case SymbolKind::Enum: return CXIdxEntity_Enum;
|
||||
|
|
|
@ -249,8 +249,13 @@ TEST(IndexTest, IndexTypeParmDecls) {
|
|||
Index->Symbols.clear();
|
||||
tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
|
||||
EXPECT_THAT(Index->Symbols,
|
||||
AllOf(Contains(QName("Foo::T")), Contains(QName("Foo::I")),
|
||||
Contains(QName("Foo::C")), Contains(QName("Foo::NoRef"))));
|
||||
AllOf(Contains(AllOf(QName("Foo::T"),
|
||||
Kind(SymbolKind::TemplateTypeParm))),
|
||||
Contains(AllOf(QName("Foo::I"),
|
||||
Kind(SymbolKind::NonTypeTemplateParm))),
|
||||
Contains(AllOf(QName("Foo::C"),
|
||||
Kind(SymbolKind::TemplateTemplateParm))),
|
||||
Contains(QName("Foo::NoRef"))));
|
||||
}
|
||||
|
||||
TEST(IndexTest, UsingDecls) {
|
||||
|
|
Loading…
Reference in New Issue