logic: fixed getting the parent of a Cxx template parameter's declaration
* switched to getting the template parameter's parent from the ASTContext instead of using the DeclContext
This commit is contained in:
@@ -475,14 +475,12 @@ void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext* d)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse children.
|
for (auto* child : d->decls()) {
|
||||||
for (clang::DeclContext::decl_iterator it = d->decls_begin(),
|
// BlockDecls and CapturedDecls are traversed through BlockExprs and
|
||||||
itEnd = d->decls_end(); it != itEnd; ++it)
|
// CapturedStmts respectively.
|
||||||
{
|
if (!llvm::isa<clang::BlockDecl>(child) && !llvm::isa<clang::CapturedDecl>(child))
|
||||||
// BlockDecls are traversed through BlockExprs.
|
|
||||||
if (!llvm::isa<clang::BlockDecl>(*it))
|
|
||||||
{
|
{
|
||||||
TraverseDecl(*it);
|
TraverseDecl(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,17 +36,9 @@ CxxDeclNameResolver::~CxxDeclNameResolver()
|
|||||||
|
|
||||||
std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getName(const clang::NamedDecl* declaration)
|
std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getName(const clang::NamedDecl* declaration)
|
||||||
{
|
{
|
||||||
{
|
declaration = utility::getFirstDecl(declaration);
|
||||||
const clang::Decl* prev = declaration;
|
|
||||||
while (prev)
|
|
||||||
{
|
|
||||||
declaration = clang::dyn_cast_or_null<clang::NamedDecl>(prev);
|
|
||||||
prev = prev->getPreviousDecl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CxxDeclName> declName;
|
std::shared_ptr<CxxDeclName> declName;
|
||||||
|
|
||||||
if ((declaration) &&
|
if ((declaration) &&
|
||||||
(clang::isa<clang::CXXRecordDecl>(declaration)) &&
|
(clang::isa<clang::CXXRecordDecl>(declaration)) &&
|
||||||
(clang::dyn_cast<clang::CXXRecordDecl>(declaration)->isLambda()))
|
(clang::dyn_cast<clang::CXXRecordDecl>(declaration)->isLambda()))
|
||||||
@@ -77,6 +69,60 @@ std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getName(const clang::NamedDecl
|
|||||||
CxxSpecifierNameResolver specifierNameResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
CxxSpecifierNameResolver specifierNameResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||||
declName->setParent(specifierNameResolver.getName(usingDecl->getQualifier()));
|
declName->setParent(specifierNameResolver.getName(usingDecl->getQualifier()));
|
||||||
}
|
}
|
||||||
|
else if (
|
||||||
|
clang::isa<clang::TemplateTypeParmDecl>(declaration) ||
|
||||||
|
clang::isa<clang::NonTypeTemplateParmDecl>(declaration) ||
|
||||||
|
clang::isa<clang::TemplateTemplateParmDecl>(declaration)
|
||||||
|
) {
|
||||||
|
clang::ASTContext& context = declaration->getASTContext();
|
||||||
|
|
||||||
|
clang::ASTContext::DynTypedNodeList parents = context.getParents(*declaration);
|
||||||
|
for (const clang::ast_type_traits::DynTypedNode* parent = parents.begin(); parent != parents.end(); parent++)
|
||||||
|
{
|
||||||
|
const clang::Decl* parentDecl = parent->get<clang::Decl>();
|
||||||
|
while (parentDecl != nullptr)
|
||||||
|
{
|
||||||
|
parentDecl = utility::getFirstDecl(parentDecl);
|
||||||
|
|
||||||
|
if (const clang::TemplateDecl* parentTemplateDecl = clang::dyn_cast_or_null<clang::TemplateDecl>(parentDecl))
|
||||||
|
{
|
||||||
|
if (!ignoresContext(parentTemplateDecl) && !ignoresContext(parentTemplateDecl->getTemplatedDecl()))
|
||||||
|
{
|
||||||
|
declName->setParent(getName(parentTemplateDecl));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (const clang::ClassTemplatePartialSpecializationDecl* parentTemplateDecl = clang::dyn_cast_or_null<clang::ClassTemplatePartialSpecializationDecl>(parentDecl))
|
||||||
|
{
|
||||||
|
if (!ignoresContext(parentDecl))
|
||||||
|
{
|
||||||
|
declName->setParent(getName(parentTemplateDecl));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const clang::DeclContext* parentDeclContext = parentDecl->getDeclContext())
|
||||||
|
{
|
||||||
|
if (ignoresContext(parentDeclContext))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parentDecl = clang::dyn_cast_or_null<clang::Decl>(parentDeclContext);
|
||||||
|
if (parentDecl)
|
||||||
|
{
|
||||||
|
if (clang::TemplateDecl* describedTemplate = parentDecl->getDescribedTemplate())
|
||||||
|
{
|
||||||
|
parentDecl = describedTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
declName->setParent(getContextName(declaration->getDeclContext()));
|
declName->setParent(getContextName(declaration->getDeclContext()));
|
||||||
@@ -215,20 +261,15 @@ std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getDeclName(const clang::Named
|
|||||||
}
|
}
|
||||||
else if (clang::FunctionTemplateDecl* templateFunctionDeclaration = functionDecl->getDescribedFunctionTemplate())
|
else if (clang::FunctionTemplateDecl* templateFunctionDeclaration = functionDecl->getDescribedFunctionTemplate())
|
||||||
{
|
{
|
||||||
std::shared_ptr<CxxDeclName> templateDeclName = getDeclName(templateFunctionDeclaration);
|
templateArguments = getTemplateParameterStrings(templateFunctionDeclaration);
|
||||||
functionName = templateDeclName->getName();
|
|
||||||
templateArguments = templateDeclName->getTemplateParameterNames();
|
|
||||||
}
|
}
|
||||||
else
|
else if (functionDecl->isFunctionTemplateSpecialization())
|
||||||
{
|
{
|
||||||
if (functionDecl->isFunctionTemplateSpecialization())
|
const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs();
|
||||||
|
for (size_t i = 0; i < templateArgumentList->size(); i++)
|
||||||
{
|
{
|
||||||
const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs();
|
const clang::TemplateArgument& templateArgument = templateArgumentList->get(i);
|
||||||
for (size_t i = 0; i < templateArgumentList->size(); i++)
|
templateArguments.push_back(getTemplateArgumentName(templateArgument));
|
||||||
{
|
|
||||||
const clang::TemplateArgument& templateArgument = templateArgumentList->get(i);
|
|
||||||
templateArguments.push_back(getTemplateArgumentName(templateArgument));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,15 +317,14 @@ std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getDeclName(const clang::Named
|
|||||||
isStatic
|
isStatic
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else if (clang::isa<clang::FunctionTemplateDecl>(declaration))
|
||||||
|
{
|
||||||
|
const clang::FunctionTemplateDecl* functionTemplateDecl = clang::dyn_cast<clang::FunctionTemplateDecl>(declaration);
|
||||||
|
return getDeclName(functionTemplateDecl->getTemplatedDecl());
|
||||||
|
}
|
||||||
else if (clang::isa<clang::TemplateDecl>(declaration)) // also triggers on TemplateTemplateParmDecl
|
else if (clang::isa<clang::TemplateDecl>(declaration)) // also triggers on TemplateTemplateParmDecl
|
||||||
{
|
{
|
||||||
std::vector<std::string> templateParameters;
|
return std::make_shared<CxxDeclName>(declNameString, getTemplateParameterStrings(clang::dyn_cast<clang::TemplateDecl>(declaration)));
|
||||||
clang::TemplateParameterList* parameterList = clang::dyn_cast<clang::TemplateDecl>(declaration)->getTemplateParameters();
|
|
||||||
for (size_t i = 0; i < parameterList->size(); i++)
|
|
||||||
{
|
|
||||||
templateParameters.push_back(getTemplateParameterString(parameterList->getParam(i)));
|
|
||||||
}
|
|
||||||
return std::make_shared<CxxDeclName>(declNameString, templateParameters);
|
|
||||||
}
|
}
|
||||||
else if (clang::isa<clang::FieldDecl>(declaration))
|
else if (clang::isa<clang::FieldDecl>(declaration))
|
||||||
{
|
{
|
||||||
@@ -410,6 +450,17 @@ std::string CxxDeclNameResolver::getNameForAnonymousSymbol(const std::string& sy
|
|||||||
return "anonymous " + symbolKindName;
|
return "anonymous " + symbolKindName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> CxxDeclNameResolver::getTemplateParameterStrings(const clang::TemplateDecl* templateDecl)
|
||||||
|
{
|
||||||
|
std::vector<std::string> templateParameterStrings;
|
||||||
|
clang::TemplateParameterList* parameterList = templateDecl->getTemplateParameters();
|
||||||
|
for (size_t i = 0; i < parameterList->size(); i++)
|
||||||
|
{
|
||||||
|
templateParameterStrings.push_back(getTemplateParameterString(parameterList->getParam(i)));
|
||||||
|
}
|
||||||
|
return templateParameterStrings;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter)
|
std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter)
|
||||||
{
|
{
|
||||||
std::string templateParameterTypeString;
|
std::string templateParameterTypeString;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ private:
|
|||||||
std::string getTranslationUnitMainFileName(const clang::Decl* declaration);
|
std::string getTranslationUnitMainFileName(const clang::Decl* declaration);
|
||||||
std::string getDeclarationFileName(const clang::Decl* declaration);
|
std::string getDeclarationFileName(const clang::Decl* declaration);
|
||||||
std::string getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::Decl* declaration);
|
std::string getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::Decl* declaration);
|
||||||
|
std::vector<std::string> getTemplateParameterStrings(const clang::TemplateDecl* templateDecl);
|
||||||
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
|
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||||
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||||
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||||
|
|||||||
@@ -21,15 +21,26 @@ void CxxNameResolver::ignoreContextDecl(const clang::Decl* decl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CxxNameResolver::ignoresContext(const clang::Decl* decl)
|
||||||
|
{
|
||||||
|
if (decl)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_ignoredContextDecls.size(); i++)
|
||||||
|
{
|
||||||
|
if (decl == m_ignoredContextDecls[i])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CxxNameResolver::ignoresContext(const clang::DeclContext* declContext)
|
bool CxxNameResolver::ignoresContext(const clang::DeclContext* declContext)
|
||||||
{
|
{
|
||||||
const clang::Decl* decl = clang::dyn_cast<clang::Decl>(declContext);
|
if (const clang::Decl* decl = clang::dyn_cast_or_null<clang::Decl>(declContext))
|
||||||
for (size_t i = 0; i < m_ignoredContextDecls.size(); i++)
|
|
||||||
{
|
{
|
||||||
if (decl == m_ignoredContextDecls[i])
|
return ignoresContext(decl);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public:
|
|||||||
virtual ~CxxNameResolver();
|
virtual ~CxxNameResolver();
|
||||||
|
|
||||||
void ignoreContextDecl(const clang::Decl* decl);
|
void ignoreContextDecl(const clang::Decl* decl);
|
||||||
|
bool ignoresContext(const clang::Decl* decl);
|
||||||
bool ignoresContext(const clang::DeclContext* declContext);
|
bool ignoresContext(const clang::DeclContext* declContext);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace utility
|
namespace utility
|
||||||
{
|
{
|
||||||
|
template <typename T>
|
||||||
|
const T* getFirstDecl(const T* decl);
|
||||||
bool isImplicit(const clang::Decl* d);
|
bool isImplicit(const clang::Decl* d);
|
||||||
AccessKind convertAccessSpecifier(clang::AccessSpecifier access);
|
AccessKind convertAccessSpecifier(clang::AccessSpecifier access);
|
||||||
SymbolKind convertTagKind(const clang::TagTypeKind tagKind);
|
SymbolKind convertTagKind(const clang::TagTypeKind tagKind);
|
||||||
@@ -15,4 +17,19 @@ namespace utility
|
|||||||
std::string getFileNameOfFileEntry(const clang::FileEntry* entry);
|
std::string getFileNameOfFileEntry(const clang::FileEntry* entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T* utility::getFirstDecl(const T* decl)
|
||||||
|
{
|
||||||
|
const clang::Decl* ret = decl;
|
||||||
|
{
|
||||||
|
const clang::Decl* prev = ret;
|
||||||
|
while (prev)
|
||||||
|
{
|
||||||
|
ret = prev;
|
||||||
|
prev = prev->getPreviousDecl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clang::dyn_cast_or_null<T>(ret);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // UTILITY_CLANG_H
|
#endif // UTILITY_CLANG_H
|
||||||
|
|||||||
@@ -677,14 +677,18 @@ public:
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
//void _test_cxx_parser_finds_template_argument_of_dependent_non_type_template_parameter()
|
void test_cxx_parser_finds_template_argument_of_dependent_non_type_template_parameter()
|
||||||
//{
|
{
|
||||||
// std::shared_ptr<TestParserClient> client = parseCode(
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
// "template <template<typename> class T1, T1<int>& T2>\n" // test that t1<int> uses int
|
"template <template<typename> class T1, T1<int>& T2>\n"
|
||||||
// "class A\n"
|
"class A\n"
|
||||||
// "{};\n"
|
"{};\n"
|
||||||
// );
|
);
|
||||||
//}
|
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->templateArgumentTypes, "A<template<typename> typename T1, T1<int> & T2>::T1<int> -> int <1:43 1:45>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
void test_cxx_parser_finds_template_template_parameter_of_template_class()
|
void test_cxx_parser_finds_template_template_parameter_of_template_class()
|
||||||
{
|
{
|
||||||
@@ -2431,7 +2435,77 @@ public:
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_concrete_type()
|
void test_cxx_parser_finds_usage_of_template_parameter_of_template_member_variable_declaration()
|
||||||
|
{
|
||||||
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
|
"template <typename T>\n"
|
||||||
|
" struct IsBaseType {\n"
|
||||||
|
" static const bool value = true;\n"
|
||||||
|
"};\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"const bool IsBaseType<T>::value;\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->templateParameterTypes, "IsBaseType<typename T>::T <1:20 1:20>"
|
||||||
|
));
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->templateParameterTypes, "IsBaseType<typename T>::T <5:20 5:20>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_cxx_parser_finds_usage_of_template_parameters_with_different_depth_of_template_function()
|
||||||
|
{
|
||||||
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
|
"template <typename T>\n"
|
||||||
|
"class A\n"
|
||||||
|
"{\n"
|
||||||
|
" template <typename Q>\n"
|
||||||
|
" void foo(Q q)\n"
|
||||||
|
" {\n"
|
||||||
|
" T t;\n"
|
||||||
|
" t.run(q);\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->typeUses, "void A<typename T>::foo<typename Q>(Q) -> A<typename T>::T <7:3 7:3>"
|
||||||
|
));
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->typeUses, "void A<typename T>::foo<typename Q>(Q) -> A<typename T>::foo<typename Q>::Q <5:11 5:11>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_cxx_parser_finds_usage_of_template_parameters_with_different_depth_of_partial_template_specialization()
|
||||||
|
{
|
||||||
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
|
"template <typename T>\n"
|
||||||
|
"class A\n"
|
||||||
|
"{\n"
|
||||||
|
" template <typename Q, typename R>\n"
|
||||||
|
" class B\n"
|
||||||
|
" {\n"
|
||||||
|
" T foo(Q q, R r);\n"
|
||||||
|
" };\n"
|
||||||
|
"\n"
|
||||||
|
" template <typename R>\n"
|
||||||
|
" class B<int, R>\n"
|
||||||
|
" {\n"
|
||||||
|
" T foo(R r);\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->typeUses, "A<typename T>::T A<typename T>::B<int, typename R>::foo(A<typename T>::B<int, typename R>::R) -> A<typename T>::T <13:3 13:3>"
|
||||||
|
));
|
||||||
|
TS_ASSERT(utility::containsElement<std::string>(
|
||||||
|
client->typeUses, "A<typename T>::T A<typename T>::B<int, typename R>::foo(A<typename T>::B<int, typename R>::R) -> A<typename T>::B<int, typename R>::R <13:9 13:9>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_explicitly_instantiated_with_concrete_type_argument()
|
||||||
{
|
{
|
||||||
std::shared_ptr<TestParserClient> client = parseCode(
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
"template <typename T>\n"
|
"template <typename T>\n"
|
||||||
@@ -2450,7 +2524,7 @@ public:
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_template_type()
|
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_explicitly_instantiated_with_template_type()
|
||||||
{
|
{
|
||||||
std::shared_ptr<TestParserClient> client = parseCode(
|
std::shared_ptr<TestParserClient> client = parseCode(
|
||||||
"template <typename T>\n"
|
"template <typename T>\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user