logic: skip traversing unspecialized template method of implicit template class specialization

This commit is contained in:
mlangkabel
2019-10-18 13:05:29 +02:00
committed by Eberhard Graether
parent ee7dcc2d83
commit cd731a3798
11 changed files with 100 additions and 676 deletions
+18 -1
View File
@@ -66,7 +66,7 @@ CanonicalFilePathCache* CxxAstVisitor::getCanonicalFilePathCache() const
void CxxAstVisitor::indexDecl(clang::Decl* d)
{
LOG_INFO("starting AST traversal");
//d->dump();
this->TraverseDecl(d);
}
@@ -236,6 +236,23 @@ bool CxxAstVisitor::traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d)
return ret;
}
bool CxxAstVisitor::TraverseCXXMethodDecl(clang::CXXMethodDecl* d)
{
if (d->getTemplatedKind() == clang::CXXMethodDecl::TK_FunctionTemplate)
{
if (clang::CXXRecordDecl* recordDecl = d->getParent())
{
if (!clang::isa<clang::ClassTemplatePartialSpecializationDecl>(recordDecl) &&
clang::isa<clang::ClassTemplateSpecializationDecl>(recordDecl) &&
!clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)->isExplicitSpecialization())
{
return true; // we skip visiting an implicit definition of a template method and its contents
}
}
}
return Base::TraverseCXXMethodDecl(d);
}
// same as Base::TraverseTemplateTypeParmDecl(..) but we need to integrate the setter for the context info.
bool CxxAstVisitor::TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d)
{
@@ -67,6 +67,7 @@ public:
virtual bool TraverseCXXRecordDecl(clang::CXXRecordDecl* d);
bool traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d);
virtual bool TraverseCXXMethodDecl(clang::CXXMethodDecl* d);
virtual bool TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d);
virtual bool TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d);
virtual bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc loc);
@@ -191,13 +191,12 @@ void CxxAstVisitorComponentIndexer::visitClassTemplateSpecializationDecl(clang::
{
if (getAstVisitor()->shouldVisitDecl(d))
{
clang::NamedDecl* specializedFromDecl = nullptr;
clang::CXXRecordDecl* specializedFromDecl = nullptr;
// todo: use context and childcontext!!
llvm::PointerUnion<clang::ClassTemplateDecl*, clang::ClassTemplatePartialSpecializationDecl*> pu = d->getSpecializedTemplateOrPartial();
if (pu.is<clang::ClassTemplateDecl*>())
{
specializedFromDecl = pu.get<clang::ClassTemplateDecl*>();
specializedFromDecl = pu.get<clang::ClassTemplateDecl*>()->getTemplatedDecl();
}
else if (pu.is<clang::ClassTemplatePartialSpecializationDecl*>())
{
@@ -330,14 +329,49 @@ void CxxAstVisitorComponentIndexer::visitFunctionDecl(clang::FunctionDecl* d)
if (d->isFunctionTemplateSpecialization())
{
Id templateId = getOrCreateSymbolId(d->getPrimaryTemplate()->getTemplatedDecl());
m_client->recordSymbolKind(templateId, SYMBOL_FUNCTION);
m_client->recordReference(
REFERENCE_TEMPLATE_SPECIALIZATION,
templateId,
symbolId,
getParseLocation(d->getLocation())
);
if (clang::isa<clang::ClassTemplateSpecializationDecl>(d->getParent()) &&
!clang::isa<clang::ClassTemplatePartialSpecializationDecl>(d->getParent()) &&
!clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(d->getParent())->isExplicitSpecialization())
{
// record edge from Foo<int>::bar<float>() to Foo<T>::bar<U>() instead of recording an edge from Foo<int>::bar<float>() to Foo<int>::bar<U>()
// because there is not "written" code for Foo<int>::bar<U>() if Foo<int> is an implicit template specialization.
if (clang::CXXRecordDecl* declaringRecordDecl = clang::dyn_cast_or_null<clang::CXXRecordDecl>(d->getParent()))
{
if (clang::CXXRecordDecl* declaringRecordTemplateDecl = declaringRecordDecl->getTemplateInstantiationPattern())
{
for (clang::Decl* templateMethodDecl : declaringRecordTemplateDecl->decls())
{
if (clang::FunctionTemplateDecl* functionTemplateDecl = clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(templateMethodDecl))
{
if (d->getName() == functionTemplateDecl->getName())
{
Id templateMethodId = getOrCreateSymbolId(functionTemplateDecl);
m_client->recordSymbolKind(templateMethodId, SYMBOL_METHOD);
m_client->recordReference(
REFERENCE_TEMPLATE_SPECIALIZATION,
templateMethodId,
symbolId,
getParseLocation(d->getLocation())
);
break;
}
}
}
}
}
}
else
{
// record edge from foo<int>() to foo<T>()
Id templateId = getOrCreateSymbolId(d->getPrimaryTemplate()->getTemplatedDecl());
m_client->recordSymbolKind(templateId, SYMBOL_FUNCTION);
m_client->recordReference(
REFERENCE_TEMPLATE_SPECIALIZATION,
templateId,
symbolId,
getParseLocation(d->getLocation())
);
}
}
}
}
@@ -363,6 +397,7 @@ void CxxAstVisitorComponentIndexer::visitCXXMethodDecl(clang::CXXMethodDecl* d)
);
}
// record edge from Foo::bar<int>() to Foo::bar<T>()
recordTemplateMemberSpecialization(
d->getMemberSpecializationInfo(),
symbolId,
+28 -1
View File
@@ -15,8 +15,35 @@
class CxxParserTestSuite: public CxxTest::TestSuite
{
public:
void test_cxx_parser_skips_implicit_template_method_definition_of_implicit_template_class_instantiation()
{
std::shared_ptr<TestIntermediateStorage> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
"public:\n"
" template <typename U>\n"
" void foo() {}\n"
"};\n"
"\n"
"int main()\n"
"{\n"
" A<int>().foo<float>();\n"
" return 0;\n"
"}\n"
);
void test_foofooofooofow()
TS_ASSERT( /*NOT!*/ !utility::containsElement<std::wstring>(
client->methods, L"public void A<int>::foo<typename U>() <6:2 <6:7 6:9> 6:14>"
));
TS_ASSERT(utility::containsElement<std::wstring>(
client->templateSpecializations, L"void A<int>::foo<float>() -> void A<typename T>::foo<typename U>() <6:7 6:9>"
));
}
void test_foofooofooofow1()
{
{
std::shared_ptr<TestIntermediateStorage> client = parseCode(