data: template argument fix

* improved context detection of template parameters.
* fixed case where declaration and definition of template function has 2 nodes in graph.
* removed code duplications: replaced individual cache classes in ASTVisitor with template based
This commit is contained in:
malte_langkabel
2016-03-04 11:13:13 +01:00
parent 8f1326e02a
commit 731c88dabd
5 changed files with 104 additions and 84 deletions
+56 -23
View File
@@ -38,10 +38,23 @@ ASTVisitor::ASTVisitor(clang::ASTContext* context, clang::Preprocessor* preproce
, m_typeContext(RT_Reference)
, m_contextAccess(ParserClient::ACCESS_NONE)
{
m_declNameCache = std::make_shared<DeclNameCache>();
m_typeNameCache = std::make_shared<TypeNameCache>();
m_contextNameGenerator = std::make_shared<ContextDeclNameGenerator>(nullptr, m_declNameCache);
m_childContextNameGenerator = std::make_shared<ContextDeclNameGenerator>(nullptr, m_declNameCache);
m_declNameCache = std::make_shared<DeclNameCache>([](const clang::NamedDecl* decl) -> NameHierarchy
{
if (decl)
{
return utility::getDeclNameHierarchy(decl);
}
return NameHierarchy("global");
});
m_typeNameCache = std::make_shared<TypeNameCache>([](const clang::Type* type) -> NameHierarchy
{
if (type)
{
CxxTypeNameResolver resolver;
return resolver.getTypeNameHierarchy(type);
}
return NameHierarchy("global");
});
}
ASTVisitor::~ASTVisitor()
@@ -50,7 +63,7 @@ ASTVisitor::~ASTVisitor()
bool ASTVisitor::VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl)
{
//decl->dump();
decl->dump();
return true;
}
@@ -152,8 +165,8 @@ bool ASTVisitor::TraverseVarDecl(clang::VarDecl *d)
{
std::shared_ptr<ScopedSwitcher<std::shared_ptr<ContextNameGenerator>>> switcher;
NameHierarchy contextNameHierarchy = m_contextNameGenerator->getName();
if (!(contextNameHierarchy.size() > 0 && contextNameHierarchy.back()->hasSignature())) // TODO: optimize this: remove requirement to get the name here!
NameHierarchy contextNameHierarchy = getContextName();
if (!(contextNameHierarchy.size() > 0 && contextNameHierarchy.back()->hasSignature())) // TODO: whle test if its a function. optimize this: remove requirement to get the name here!
{
switcher = std::make_shared<ScopedSwitcher<std::shared_ptr<ContextNameGenerator>>>(m_contextNameGenerator, std::make_shared<ContextDeclNameGenerator>(d, m_declNameCache));
}
@@ -166,6 +179,13 @@ bool ASTVisitor::TraverseClassTemplateDecl(clang::ClassTemplateDecl* d)
return base::TraverseClassTemplateDecl(d);
}
bool ASTVisitor::TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl* d)
{
// we need to use the templated decl here because name resolving for FunctionTemplateDecl is not returning a correct signature yet.
ScopedSwitcher<std::shared_ptr<ContextNameGenerator>> switcher(m_contextNameGenerator, std::make_shared<ContextDeclNameGenerator>(d->getTemplatedDecl(), m_declNameCache));
return base::TraverseFunctionTemplateDecl(d);
}
bool ASTVisitor::TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d)
{
// same as base::TraverseTemplateTypeParmDecl(..) but we need to integrate the setter for the context info.
@@ -194,7 +214,6 @@ bool ASTVisitor::TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDec
ScopedSwitcher<RefType> sw1(m_typeContext, RT_TemplateDefaultArgument);
ScopedSwitcher<std::shared_ptr<ContextNameGenerator>> sw2(m_contextNameGenerator, std::make_shared<ContextDeclNameGenerator>(d, m_declNameCache));
//d->getDefaultArgument
TraverseTemplateArgumentLoc(d->getDefaultArgument());
}
@@ -230,12 +249,22 @@ bool ASTVisitor::TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializa
return base::TraverseTemplateSpecializationTypeLoc(loc);
}
bool ASTVisitor::TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) // TODO: do this for unresolved and dependent stuff
{
std::shared_ptr<ContextNameGenerator> n;
ScopedSwitcher<std::shared_ptr<ContextNameGenerator>> sw(m_childContextNameGenerator, n);
return base::TraverseUnresolvedLookupExpr(e);
}
bool ASTVisitor::TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
std::shared_ptr<ScopedSwitcher<RefType>> sw1;
std::shared_ptr<ScopedSwitcher<std::shared_ptr<ContextNameGenerator>>> sw2;
if (m_typeContext != RT_TemplateDefaultArgument)
if (m_typeContext != RT_TemplateDefaultArgument
&&
m_childContextNameGenerator
)
{
sw1 = std::make_shared<ScopedSwitcher<RefType>>(m_typeContext, RT_TemplateArgument);
sw2 = std::make_shared<ScopedSwitcher<std::shared_ptr<ContextNameGenerator>>>(m_contextNameGenerator, m_childContextNameGenerator);
@@ -250,12 +279,6 @@ bool ASTVisitor::TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& l
return base::TraverseTemplateArgumentLoc(loc);
}
//bool ASTVisitor::TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl* d)
//{
// ScopedSwitcher<clang::Decl*> switcher(m_contextDecl, d);
// return base::TraverseFunctionTemplateDecl(d);
//}
///////////////////////////////////////////////////////////////////////////////
// Expression context propagation
@@ -1052,8 +1075,8 @@ void ASTVisitor::RecordTypeRef(
if (isLocatedInProjectFile(beginLoc))
{
ParseLocation parseLocation = getDeclRefRange(0, beginLoc);
NameHierarchy typeNameHierarchy = m_typeNameCache->getName(type);
NameHierarchy contextNameHierarchy = m_contextNameGenerator->getName();
NameHierarchy typeNameHierarchy = m_typeNameCache->getValue(type);
NameHierarchy contextNameHierarchy = getContextName();
if (refType == RT_TemplateArgument)
{
@@ -1112,7 +1135,8 @@ void ASTVisitor::RecordDeclRef(
}
ParseLocation parseLocation = getDeclRefRange(d, beginLoc);
NameHierarchy declNameHierarchy = m_declNameCache->getName(d);
//NameHierarchy declNameHierarchy = m_declNameCache->getValue(d);
NameHierarchy declNameHierarchy = utility::getDeclNameHierarchy(d);
bool fallback = false;
@@ -1192,7 +1216,7 @@ void ASTVisitor::RecordDeclRef(
{
m_client->onMethodOverrideParsed(
parseLocation,
m_declNameCache->getName(*it),
m_declNameCache->getValue(*it),
declNameHierarchy);
}
@@ -1205,7 +1229,7 @@ void ASTVisitor::RecordDeclRef(
m_client->onTemplateMemberFunctionSpecializationParsed(
parseLocation,
declNameHierarchy,
m_declNameCache->getName(specializedNamedDecl));
m_declNameCache->getValue(specializedNamedDecl));
}
}
}
@@ -1266,7 +1290,7 @@ void ASTVisitor::RecordDeclRef(
m_client->onTemplateSpecializationParsed(
parseLocation,
declNameHierarchy,
m_declNameCache->getName(specializedFromDecl)); // use context and childcontext!!
m_declNameCache->getValue(specializedFromDecl)); // use context and childcontext!!
}
break;
case ST_FunctionTemplateSpecialization:
@@ -1275,7 +1299,7 @@ void ASTVisitor::RecordDeclRef(
m_client->onTemplateSpecializationParsed(
parseLocation,
declNameHierarchy,
m_declNameCache->getName(functionDecl->getPrimaryTemplate()->getTemplatedDecl())); // TODO: use contect and childcontext!!
m_declNameCache->getValue(functionDecl->getPrimaryTemplate()->getTemplatedDecl())); // TODO: use contect and childcontext!!
}
break;
case ST_LocalVariable:
@@ -1289,7 +1313,7 @@ void ASTVisitor::RecordDeclRef(
}
else
{
const NameHierarchy contextNameHierarchy = m_contextNameGenerator->getName();
const NameHierarchy contextNameHierarchy = getContextName();
switch (symbolType)
{
case ST_Field:
@@ -1570,3 +1594,12 @@ ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange
presumedEnd.getColumn()
);
}
NameHierarchy ASTVisitor::getContextName()
{
if (m_contextNameGenerator)
{
return m_contextNameGenerator->getName();
}
return NameHierarchy("global");
}
+13 -59
View File
@@ -10,6 +10,7 @@
#include "data/parser/ParserClient.h"
#include "utility/file/FileRegister.h"
#include "utility/Cache.h"
@@ -19,61 +20,8 @@
class ASTVisitor: clang::RecursiveASTVisitor<ASTVisitor>
{
public:
class TypeNameCache
{
public:
NameHierarchy getName(const clang::Type* type)
{
if (type)
{
NameHierarchy nameHierarchy;
std::unordered_map<const clang::Type*, NameHierarchy>::const_iterator it = m_typeNameMap.find(type);
if (it != m_typeNameMap.end())
{
nameHierarchy = it->second;
}
else
{
CxxTypeNameResolver resolver;
nameHierarchy = resolver.getTypeNameHierarchy(type);
m_typeNameMap[type] = nameHierarchy;
}
return nameHierarchy;
}
return NameHierarchy("global");
}
private:
std::unordered_map<const clang::Type*, NameHierarchy> m_typeNameMap;
};
class DeclNameCache
{
public:
NameHierarchy getName(const clang::NamedDecl* decl)
{
if (decl)
{
NameHierarchy nameHierarchy;
std::unordered_map<const clang::Decl*, NameHierarchy>::const_iterator it = m_declNameCache.find(decl);
if (it != m_declNameCache.end())
{
nameHierarchy = it->second;
}
else
{
nameHierarchy = utility::getDeclNameHierarchy(decl);
m_declNameCache[decl] = nameHierarchy;
}
return nameHierarchy;
}
return NameHierarchy("global");
}
private:
std::unordered_map<const clang::Decl*, NameHierarchy> m_declNameCache;
};
typedef Cache<const clang::NamedDecl*, NameHierarchy> DeclNameCache;
typedef Cache<const clang::Type*, NameHierarchy> TypeNameCache;
class ContextNameGenerator
{
@@ -94,8 +42,9 @@ public:
virtual NameHierarchy getName() const
{
return m_nameCache->getName(m_decl);
return m_nameCache->getValue(m_decl);
}
private:
const clang::NamedDecl* m_decl;
std::shared_ptr<DeclNameCache> m_nameCache;
@@ -113,8 +62,9 @@ public:
virtual NameHierarchy getName() const
{
return m_nameCache->getName(m_type);
return m_nameCache->getValue(m_type);
}
private:
const clang::Type* m_type;
std::shared_ptr<TypeNameCache> m_nameCache;
@@ -225,11 +175,13 @@ private:
bool TraverseFieldDecl(clang::FieldDecl *d);
bool TraverseVarDecl(clang::VarDecl *d);
bool TraverseClassTemplateDecl(clang::ClassTemplateDecl* d);
bool TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl* d);
bool TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d);
bool TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d);
bool TraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d);
bool TraverseDeclRefExpr(clang::DeclRefExpr* expr);
bool TraverseDeclRefExpr(clang::DeclRefExpr* e);
bool TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc);
bool TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e);
bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
// Expression context propagation
@@ -302,6 +254,8 @@ private:
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
NameHierarchy getContextName();
struct FileIdHash {
size_t operator()(clang::FileID fileID) const {
return fileID.getHashValue();
@@ -312,7 +266,7 @@ private:
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inProjectFileMap;
std::shared_ptr<ContextNameGenerator> m_contextNameGenerator;
std::shared_ptr<ContextNameGenerator> m_childContextNameGenerator;
std::shared_ptr<ContextNameGenerator> m_childContextNameGenerator; // TODO: rename templateArgumentContextNameGenerator
std::shared_ptr<DeclNameCache> m_declNameCache;
std::shared_ptr<TypeNameCache> m_typeNameCache;
@@ -10,14 +10,24 @@
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration)
: CxxNameResolver(std::vector<const clang::Decl*>())
, m_declaration(declaration)
{
const clang::Decl* prev = declaration;
while (prev)
{
m_declaration = prev;
prev = prev->getPreviousDecl();
}
}
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration, std::vector<const clang::Decl*> ignoredContextDecls)
: CxxNameResolver(ignoredContextDecls)
, m_declaration(declaration)
{
const clang::Decl* prev = declaration;
while (prev)
{
m_declaration = prev;
prev = prev->getPreviousDecl();
}
}
CxxDeclNameResolver::~CxxDeclNameResolver()
@@ -23,6 +23,8 @@ CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver()
std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
{
// This doesn't work correctly if the template argument is dependent.
// If that's required: build name from depth and index of template arg.
const clang::TemplateArgument::ArgKind kind = argument.getKind();
switch (kind)
{
+21
View File
@@ -2625,6 +2625,27 @@ public:
TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller::lambda at 4:2() -> void func() <6:3 6:6>");
}
void test_cxx_parser_finds_template_argument_of_unresolved_lookup_expression_as_type_use()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"void a()\n"
"{\n"
"}\n"
"\n"
"template<typename MessageType>\n"
"void dispatch()\n"
"{\n"
" a<MessageType>();\n"
"}\n"
);
TS_ASSERT_EQUALS(client->typeUses.size(), 3);
TS_ASSERT_EQUALS(client->typeUses[0], "void a<typename T>() -> void <2:1 2:4>");
TS_ASSERT_EQUALS(client->typeUses[1], "void dispatch<typename MessageType>() -> void <7:1 7:4>");
TS_ASSERT_EQUALS(client->typeUses[2], "void dispatch<typename MessageType>() -> dispatch<typename MessageType>::MessageType <9:4 9:14>");
}
///////////////////////////////////////////////////////////////////////////////
// test finding symbol locations