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:
@@ -19,6 +19,8 @@ NameElement::Signature NameElement::Signature::deserialize(const std::string& se
|
||||
}
|
||||
|
||||
NameElement::Signature::Signature()
|
||||
: m_prefix("")
|
||||
, m_postfix("")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user