logic: improved indexer coverage for using decls, using directives

* moved source code for solving names of NestedNameSpecifiers to new CxxSpecifierNameResolver.
* implemented recording of UsingDirectives.
* implemented using file as context for using directives and using directive decls if no other context is available.
* re-implemented recording of the auto keyword
This commit is contained in:
malte_langkabel
2016-11-14 13:16:20 +01:00
parent 2b830fd2c0
commit 9ba3cf165c
11 changed files with 191 additions and 61 deletions
+2
View File
@@ -19,6 +19,8 @@ NameElement::Signature NameElement::Signature::deserialize(const std::string& se
}
NameElement::Signature::Signature()
: m_prefix("")
, m_postfix("")
{
}
+2
View File
@@ -6,6 +6,8 @@ add_files(
data/parser/cxx/name_resolver/CxxDeclNameResolver.h
data/parser/cxx/name_resolver/CxxNameResolver.cpp
data/parser/cxx/name_resolver/CxxNameResolver.h
data/parser/cxx/name_resolver/CxxSpecifierNameResolver.cpp
data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h
data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp
+25 -13
View File
@@ -68,7 +68,7 @@ bool CxxAstVisitor::TraverseDecl(clang::Decl* d)
!clang::isa<clang::ParmVarDecl>(d) && // no parameter
!(clang::isa<clang::VarDecl>(d) && d->getParentFunctionOrMethod() != NULL) && // no local variable
!clang::isa<clang::UsingDirectiveDecl>(d) && // no using directive decl
//!clang::isa<clang::UsingDecl>(d) && // no using decl
!clang::isa<clang::UsingDecl>(d) && // no using decl
!clang::isa<clang::NamespaceDecl>(d) // no namespace
){
clang::NamedDecl* nd = clang::dyn_cast<clang::NamedDecl>(d);
@@ -588,11 +588,12 @@ bool CxxAstVisitor::VisitUsingDirectiveDecl(clang::UsingDirectiveDecl* d)
{
if (shouldVisitDecl(d))
{
ParseLocation loc = getParseLocation(d->getLocation());
m_client->recordReference(
REFERENCE_USAGE,
m_declNameCache->getValue(d->getNominatedNamespaceAsWritten()),
getContextName(), // TODO: use file here, if no context available
getParseLocation(d->getLocation())
getContextName(NameHierarchy(loc.filePath.fileName())),
loc
);
}
return true;
@@ -600,15 +601,16 @@ bool CxxAstVisitor::VisitUsingDirectiveDecl(clang::UsingDirectiveDecl* d)
bool CxxAstVisitor::VisitUsingDecl(clang::UsingDecl* d)
{
//if (shouldVisitDecl(d))
//{
//m_client->recordReference(
// REFERENCE_USAGE,
// m_declNameCache->getValue(d),
// getContextName(), // TODO: use file here, if no context available
// getParseLocation(d->getLocation())
//);
//}
if (shouldVisitDecl(d))
{
ParseLocation loc = getParseLocation(d->getLocation());
m_client->recordReference(
REFERENCE_USAGE,
m_declNameCache->getValue(d),
getContextName(NameHierarchy(loc.filePath.fileName())),
loc
);
}
return true;
}
@@ -1178,6 +1180,15 @@ NameHierarchy CxxAstVisitor::getContextName(const size_t skip) const
return m_contextStack[m_contextStack.size() - 1 - skip]->getName(); // todo: performance optimize this
}
NameHierarchy CxxAstVisitor::getContextName(const NameHierarchy& fallback, const size_t skip) const
{
if (m_contextStack.size() <= skip)
{
return fallback;
}
return m_contextStack[m_contextStack.size() - 1 - skip]->getName(); // todo: performance optimize this
}
bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl)
{
if ((!tl.getAs<clang::TagTypeLoc>().isNull()) ||
@@ -1185,7 +1196,8 @@ bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl)
(!tl.getAs<clang::TemplateTypeParmTypeLoc>().isNull()) ||
(!tl.getAs<clang::TemplateSpecializationTypeLoc>().isNull()) ||
(!tl.getAs<clang::DependentNameTypeLoc>().isNull()) ||
(!tl.getAs<clang::BuiltinTypeLoc>().isNull())
(!tl.getAs<clang::BuiltinTypeLoc>().isNull()) ||
(!tl.getAs<clang::AutoTypeLoc>().isNull())
){
return false;
}
@@ -134,6 +134,7 @@ private:
const clang::NamedDecl* getTopmostContextDecl() const;
NameHierarchy getContextName(const size_t skip = 0) const;
NameHierarchy getContextName(const NameHierarchy& fallback, const size_t skip = 0) const;
bool checkIgnoresTypeLoc(const clang::TypeLoc& tl);
struct FileIdHash
@@ -3,6 +3,7 @@
#include <clang/AST/DeclTemplate.h>
#include <clang/AST/ASTContext.h>
#include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h"
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
#include "utility/file/FilePath.h"
@@ -50,7 +51,15 @@ NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy()
// LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName()));
}
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
if (const clang::UsingDecl* usingDecl = clang::dyn_cast_or_null<clang::UsingDecl>(m_declaration))
{
CxxSpecifierNameResolver specifierNameResolver(getIgnoredContextDecls());
contextNameHierarchy = specifierNameResolver.getNameHierarchy(usingDecl->getQualifier());
}
else
{
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
}
if (declName)
{
@@ -16,6 +16,7 @@ public:
private:
NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration);
NameHierarchy getContextNameHierarchy(const clang::NestedNameSpecifier* specifier);
std::shared_ptr<NameElement> getDeclName(const clang::NamedDecl* declaration);
std::shared_ptr<NameElement> getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::PresumedLoc& presumedBegin);
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
@@ -0,0 +1,70 @@
#include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h"
#include <clang/AST/PrettyPrinter.h>
#include <clang/AST/DeclTemplate.h>
#include <clang/AST/ASTContext.h>
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
CxxSpecifierNameResolver::CxxSpecifierNameResolver()
: CxxNameResolver(std::vector<const clang::Decl*>())
{
}
CxxSpecifierNameResolver::CxxSpecifierNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
: CxxNameResolver(ignoredContextDecls)
{
}
CxxSpecifierNameResolver::~CxxSpecifierNameResolver()
{
}
NameHierarchy CxxSpecifierNameResolver::getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier)
{
clang::NestedNameSpecifier::SpecifierKind nnsKind = nestedNameSpecifier->getKind();
NameHierarchy typeNameHerarchy;
switch (nnsKind)
{
case clang::NestedNameSpecifier::Identifier:
{
const clang::NestedNameSpecifier* prefix = nestedNameSpecifier->getPrefix();
if (prefix)
{
typeNameHerarchy = getNameHierarchy(prefix);
}
typeNameHerarchy.push(std::make_shared<NameElement>(nestedNameSpecifier->getAsIdentifier()->getName()));
}
break;
case clang::NestedNameSpecifier::Namespace:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespace(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
case clang::NestedNameSpecifier::NamespaceAlias:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespaceAlias(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
case clang::NestedNameSpecifier::TypeSpec:
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
{
CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls());
typeNameHerarchy = typeNameResolver.getTypeNameHierarchy(nestedNameSpecifier->getAsType());
}
break;
case clang::NestedNameSpecifier::Global:
// no context name hierarchy needed.
break;
case clang::NestedNameSpecifier::Super:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsRecordDecl(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
}
return typeNameHerarchy;
}
@@ -0,0 +1,17 @@
#ifndef CXX_SPECIFIER_NAME_RESOLVER_H
#define CXX_SPECIFIER_NAME_RESOLVER_H
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
#include "data/type/DataType.h"
class CxxSpecifierNameResolver: public CxxNameResolver
{
public:
CxxSpecifierNameResolver();
CxxSpecifierNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
virtual ~CxxSpecifierNameResolver();
NameHierarchy getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier);
};
#endif // CXX_SPECIFIER_NAME_RESOLVER_H
@@ -5,6 +5,7 @@
#include <clang/AST/ASTContext.h>
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
#include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h"
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
#include "data/type/DataType.h"
#include "data/type/NamedDataType.h"
@@ -163,7 +164,8 @@ std::shared_ptr<DataType> CxxTypeNameResolver::typeToDataType(const clang::Type*
{
const clang::DependentNameType* dependentNameType = clang::dyn_cast<clang::DependentNameType>(type);
NameHierarchy typeNameHerarchy = getNameHierarchy(dependentNameType->getQualifier());
CxxSpecifierNameResolver specifierNameResolver(getIgnoredContextDecls());
NameHierarchy typeNameHerarchy = specifierNameResolver.getNameHierarchy(dependentNameType->getQualifier());
typeNameHerarchy.push(std::make_shared<NameElement>(dependentNameType->getIdentifier()->getName().str()));
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
@@ -223,48 +225,3 @@ NameHierarchy CxxTypeNameResolver::getTypeNameHierarchy(const clang::Type* type)
{
return typeToDataType(type)->getTypeNameHierarchy();
}
NameHierarchy CxxTypeNameResolver::getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier)
{
clang::NestedNameSpecifier::SpecifierKind nnsKind = nestedNameSpecifier->getKind();
NameHierarchy typeNameHerarchy;
switch (nnsKind)
{
case clang::NestedNameSpecifier::Identifier:
{
const clang::NestedNameSpecifier* prefix = nestedNameSpecifier->getPrefix();
if (prefix)
{
typeNameHerarchy = getNameHierarchy(prefix);
}
typeNameHerarchy.push(std::make_shared<NameElement>(nestedNameSpecifier->getAsIdentifier()->getName()));
}
break;
case clang::NestedNameSpecifier::Namespace:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespace(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
case clang::NestedNameSpecifier::NamespaceAlias:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespaceAlias(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
case clang::NestedNameSpecifier::TypeSpec:
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
typeNameHerarchy = typeToDataType(nestedNameSpecifier->getAsType())->getTypeNameHierarchy();
break;
case clang::NestedNameSpecifier::Global:
// no context name hierarchy needed.
break;
case clang::NestedNameSpecifier::Super:
{
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsRecordDecl(), getIgnoredContextDecls());
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
}
break;
}
return typeNameHerarchy;
}
@@ -16,7 +16,6 @@ public:
private:
std::shared_ptr<DataType> typeToDataType(const clang::Type* type);
NameHierarchy getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier);
};
#endif // CXX_TYPE_NAME_RESOLVER_H
+60
View File
@@ -1457,6 +1457,66 @@ public:
TS_ASSERT_EQUALS(client->overrides.size(), 0);
}
void test_cxx_parser_finds_using_directive_decl_in_function_context()
{
std::shared_ptr<TestParserClient> client = parseCode(
"void foo()\n"
"{\n"
" using namespace std;\n"
"}\n"
);
TS_ASSERT_EQUALS(client->usages.size(), 1);
TS_ASSERT_EQUALS(client->usages[0], "void foo() -> std <3:18 3:20>");
}
void test_cxx_parser_finds_using_directive_decl_in_file_context()
{
std::shared_ptr<TestParserClient> client = parseCode(
"using namespace std;\n"
"void foo()\n"
"{\n"
"}\n"
);
TS_ASSERT_EQUALS(client->usages.size(), 1);
TS_ASSERT_EQUALS(client->usages[0], "input.cc -> std <1:17 1:19>");
}
void test_cxx_parser_finds_using_decl_in_function_context()
{
std::shared_ptr<TestParserClient> client = parseCode(
"namespace foo\n"
"{\n"
" int a;\n"
"}\n"
"void bar()\n"
"{\n"
" using foo::a;\n"
"}\n"
);
TS_ASSERT_EQUALS(client->usages.size(), 1);
TS_ASSERT_EQUALS(client->usages[0], "void bar() -> foo::a <7:13 7:13>");
}
void test_cxx_parser_finds_using_decl_in_file_context()
{
std::shared_ptr<TestParserClient> client = parseCode(
"namespace foo\n"
"{\n"
" int a;\n"
"}\n"
"using foo::a;\n"
"void bar()\n"
"{\n"
"}\n"
);
TS_ASSERT_EQUALS(client->usages.size(), 1);
TS_ASSERT_EQUALS(client->usages[0], "input.cc -> foo::a <5:12 5:12>");
}
void test_cxx_parser_finds_call_in_function()
{
std::shared_ptr<TestParserClient> client = parseCode(