From 9ba3cf165c37bca20060b75d61eec6ff53a69d19 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Mon, 14 Nov 2016 13:16:20 +0100 Subject: [PATCH] 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 --- src/lib/data/name/NameElement.cpp | 2 + src/lib_cxx/CMakeLists.txt | 2 + src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp | 38 ++++++---- src/lib_cxx/data/parser/cxx/CxxAstVisitor.h | 1 + .../cxx/name_resolver/CxxDeclNameResolver.cpp | 11 ++- .../cxx/name_resolver/CxxDeclNameResolver.h | 1 + .../CxxSpecifierNameResolver.cpp | 70 +++++++++++++++++++ .../name_resolver/CxxSpecifierNameResolver.h | 17 +++++ .../cxx/name_resolver/CxxTypeNameResolver.cpp | 49 +------------ .../cxx/name_resolver/CxxTypeNameResolver.h | 1 - src/test/CxxParserTestSuite.h | 60 ++++++++++++++++ 11 files changed, 191 insertions(+), 61 deletions(-) create mode 100644 src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.cpp create mode 100644 src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h diff --git a/src/lib/data/name/NameElement.cpp b/src/lib/data/name/NameElement.cpp index 9ccae680..a34a9118 100644 --- a/src/lib/data/name/NameElement.cpp +++ b/src/lib/data/name/NameElement.cpp @@ -19,6 +19,8 @@ NameElement::Signature NameElement::Signature::deserialize(const std::string& se } NameElement::Signature::Signature() + : m_prefix("") + , m_postfix("") { } diff --git a/src/lib_cxx/CMakeLists.txt b/src/lib_cxx/CMakeLists.txt index 53f9150a..ee9daf0f 100644 --- a/src/lib_cxx/CMakeLists.txt +++ b/src/lib_cxx/CMakeLists.txt @@ -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 diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp index d1f94e3f..33d87dbf 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp @@ -68,7 +68,7 @@ bool CxxAstVisitor::TraverseDecl(clang::Decl* d) !clang::isa(d) && // no parameter !(clang::isa(d) && d->getParentFunctionOrMethod() != NULL) && // no local variable !clang::isa(d) && // no using directive decl - //!clang::isa(d) && // no using decl + !clang::isa(d) && // no using decl !clang::isa(d) // no namespace ){ clang::NamedDecl* nd = clang::dyn_cast(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().isNull()) || @@ -1185,7 +1196,8 @@ bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl) (!tl.getAs().isNull()) || (!tl.getAs().isNull()) || (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) ){ return false; } diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h index 41732acc..8336548d 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h @@ -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 diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp index dc83d2bc..a3416dc0 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -3,6 +3,7 @@ #include #include +#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(m_declaration)) + { + CxxSpecifierNameResolver specifierNameResolver(getIgnoredContextDecls()); + contextNameHierarchy = specifierNameResolver.getNameHierarchy(usingDecl->getQualifier()); + } + else + { + contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext()); + } if (declName) { diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h index 92b315f7..53e5d033 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h @@ -16,6 +16,7 @@ public: private: NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration); + NameHierarchy getContextNameHierarchy(const clang::NestedNameSpecifier* specifier); std::shared_ptr getDeclName(const clang::NamedDecl* declaration); std::shared_ptr getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::PresumedLoc& presumedBegin); std::string getTemplateParameterString(const clang::NamedDecl* parameter); diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.cpp new file mode 100644 index 00000000..39e33a2e --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.cpp @@ -0,0 +1,70 @@ +#include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h" + +#include +#include +#include + +#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" +#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h" + +CxxSpecifierNameResolver::CxxSpecifierNameResolver() + : CxxNameResolver(std::vector()) +{ +} + +CxxSpecifierNameResolver::CxxSpecifierNameResolver(std::vector 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(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; +} diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h b/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h new file mode 100644 index 00000000..bdb36707 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h @@ -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 ignoredContextDecls); + virtual ~CxxSpecifierNameResolver(); + + NameHierarchy getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier); +}; + +#endif // CXX_SPECIFIER_NAME_RESOLVER_H diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp index d8dfcb17..3ef91032 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp @@ -5,6 +5,7 @@ #include #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 CxxTypeNameResolver::typeToDataType(const clang::Type* { const clang::DependentNameType* dependentNameType = clang::dyn_cast(type); - NameHierarchy typeNameHerarchy = getNameHierarchy(dependentNameType->getQualifier()); + CxxSpecifierNameResolver specifierNameResolver(getIgnoredContextDecls()); + NameHierarchy typeNameHerarchy = specifierNameResolver.getNameHierarchy(dependentNameType->getQualifier()); typeNameHerarchy.push(std::make_shared(dependentNameType->getIdentifier()->getName().str())); dataType = std::make_shared(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(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; -} diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.h b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.h index 0c94e9c1..6741fabc 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.h +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTypeNameResolver.h @@ -16,7 +16,6 @@ public: private: std::shared_ptr typeToDataType(const clang::Type* type); - NameHierarchy getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier); }; #endif // CXX_TYPE_NAME_RESOLVER_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index ac1b9a06..0e7af31d 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.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 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 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 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 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 client = parseCode(