logic: skip traversing unspecialized template method of implicit template class specialization
This commit is contained in:
committed by
Eberhard Graether
parent
ee7dcc2d83
commit
cd731a3798
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user