From 5b47d195ff997704b3871219c315c29e0054abd7 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Thu, 3 Nov 2016 09:08:35 +0100 Subject: [PATCH] data: fixed anonymous symbol name conflicts (issue #241) * added start location to symbol name string * added tests for this case --- src/lib/utility/utilityString.cpp | 12 ++++- src/lib/utility/utilityString.h | 3 +- .../cxx/name_resolver/CxxDeclNameResolver.cpp | 21 ++++++--- .../cxx/name_resolver/CxxDeclNameResolver.h | 1 + src/test/CxxParserTestSuite.h | 37 +++++++++++++-- src/test/UtilityStringTestSuite.h | 45 ++++++++++++++----- 6 files changed, 97 insertions(+), 22 deletions(-) diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index eb03f5a0..8b26d02e 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -100,7 +100,7 @@ namespace utility return c; } - std::string substrBefore(const std::string& str, char delimiter) + std::string substrBeforeFirst(const std::string& str, char delimiter) { size_t pos = str.find(delimiter); if (pos != std::string::npos) @@ -110,6 +110,16 @@ namespace utility return str; } + std::string substrBeforeLast(const std::string& str, char delimiter) + { + size_t pos = str.rfind(delimiter); + if (pos != std::string::npos) + { + return str.substr(0, pos); + } + return str; + } + std::string substrAfter(const std::string& str, char delimiter) { size_t pos = str.find(delimiter); diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 501d89a3..9ca841e6 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -29,7 +29,8 @@ namespace utility std::deque tokenize(const std::deque& list, char delimiter); std::deque tokenize(const std::deque& list, const std::string& delimiter); - std::string substrBefore(const std::string& str, char delimiter); + std::string substrBeforeFirst(const std::string& str, char delimiter); + std::string substrBeforeLast(const std::string& str, char delimiter); std::string substrAfter(const std::string& str, char delimiter); std::string substrBetween(const std::string& str, const std::string& delimiter1, const std::string& delimiter2); 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 af484043..dc83d2bc 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -163,8 +163,8 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); - const std::string recordType = (recordDecl->isStruct() ? "struct" : "class"); - return std::make_shared("anonymous " + recordType + " (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + const std::string symbolKindName = (recordDecl->isStruct() ? "struct" : "class"); + return getNameForAnonymousSymbol(symbolKindName, presumedBegin); } } else if (clang::isa(declaration)) @@ -252,13 +252,13 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); - return std::make_shared("anonymous namespace (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + return getNameForAnonymousSymbol("namespace", presumedBegin); } else if (clang::isa(declaration) && declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); - return std::make_shared("anonymous enum (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + return getNameForAnonymousSymbol("enum", presumedBegin); } else if ( ( @@ -269,13 +269,13 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); - return std::make_shared("anonymous template parameter (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + return getNameForAnonymousSymbol("template parameter", presumedBegin); } else if (clang::isa(declaration) && declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); - return std::make_shared("anonymous parameter (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + return getNameForAnonymousSymbol("parameter", presumedBegin); } if (declNameString.size() > 0) @@ -286,7 +286,7 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); // LOG_ERROR("could not resolve name of decl at: " + declaration->getLocation().printToString(sourceManager)); - return std::make_shared("anonymous symbol (" + FilePath(presumedBegin.getFilename()).fileName() + ")"); + return getNameForAnonymousSymbol("symbol", presumedBegin); } std::shared_ptr CxxDeclNameResolver::getDeclName(const clang::NamedDecl* declaration) @@ -295,6 +295,13 @@ std::shared_ptr CxxDeclNameResolver::getDeclName(const clang::Named return resolver.getDeclName(); } +std::shared_ptr CxxDeclNameResolver::getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::PresumedLoc& presumedBegin) +{ + return std::make_shared("anonymous " + symbolKindName + + " (" + FilePath(presumedBegin.getFilename()).fileName() + "<" + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn()) + ">)" + ); +} + std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter) { std::string templateParameterTypeString = ""; 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 57bdb945..92b315f7 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h @@ -17,6 +17,7 @@ public: private: NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration); 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); std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter); std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter); diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index ec8ea2e7..3e32379c 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -221,7 +221,38 @@ public: ); TS_ASSERT_EQUALS(client->namespaces.size(), 1); - TS_ASSERT_EQUALS(client->namespaces[0], "anonymous namespace (input.cc) <1:1 3:1>"); + TS_ASSERT_EQUALS(client->namespaces[0], "anonymous namespace (input.cc<1:1>) <1:1 3:1>"); + } + + void test_cxx_parser_finds_anonymous_struct_declaration() + { + std::shared_ptr client = parseCode( + "typedef struct\n" + "{\n" + " int x;\n" + "} Foo;\n" + ); + + TS_ASSERT_EQUALS(client->structs.size(), 1); + TS_ASSERT_EQUALS(client->structs[0], "anonymous struct (input.cc<1:9>) <1:9 <1:9 1:14> 4:1>"); + } + + void test_cxx_parser_finds_multiple_anonymous_struct_declarations_as_distinct_elements() + { + std::shared_ptr client = parseCode( + "typedef struct\n" + "{\n" + " int x;\n" + "} Foo;\n" + "typedef struct\n" + "{\n" + " float x;\n" + "} Bar;\n" + ); + + TS_ASSERT_EQUALS(client->structs.size(), 2); + TS_ASSERT_EQUALS(client->fields.size(), 2); + TS_ASSERT_DIFFERS(utility::substrBeforeLast(client->fields[0], '<'), utility::substrBeforeLast(client->fields[1], '<')); } void test_cxx_parser_finds_enum_defined_in_global_namespace() @@ -282,7 +313,7 @@ public: ); TS_ASSERT_EQUALS(client->typedefs.size(), 1); - TS_ASSERT_EQUALS(client->typedefs[0], "anonymous namespace (input.cc)::uint <3:23 3:26>"); + TS_ASSERT_EQUALS(client->typedefs[0], "anonymous namespace (input.cc<1:1>)::uint <3:23 3:26>"); } void test_cxx_parser_finds_type_alias_in_class() @@ -1019,7 +1050,7 @@ public: ); TS_ASSERT_EQUALS(client->functions.size(), 1); - TS_ASSERT_EQUALS(client->functions[0], "int anonymous namespace (input.cc)::sum(int, int) <3:6 3:8>"); + TS_ASSERT_EQUALS(client->functions[0], "int anonymous namespace (input.cc<1:1>)::sum(int, int) <3:6 3:8>"); } void test_cxx_parser_finds_method_declared_in_nested_class() diff --git a/src/test/UtilityStringTestSuite.h b/src/test/UtilityStringTestSuite.h index 1dd468b2..16b7a34c 100644 --- a/src/test/UtilityStringTestSuite.h +++ b/src/test/UtilityStringTestSuite.h @@ -156,29 +156,54 @@ public: TS_ASSERT_EQUALS(result.at(6), "D"); } - void test_substr_before_with_single_delimiter_occurence() + void test_substr_before_first_with_single_delimiter_occurence() { - TS_ASSERT_EQUALS(utility::substrBefore("foo bar", ' '), "foo"); + TS_ASSERT_EQUALS(utility::substrBeforeFirst("foo bar", ' '), "foo"); } - void test_substr_before_with_multiple_delimiter_occurences() + void test_substr_before_first_with_multiple_delimiter_occurences() { - TS_ASSERT_EQUALS(utility::substrBefore("foo bar foo", ' '), "foo"); + TS_ASSERT_EQUALS(utility::substrBeforeFirst("foo bar foo", ' '), "foo"); } - void test_substr_before_with_no_delimiter_occurence() + void test_substr_before_first_with_no_delimiter_occurence() { - TS_ASSERT_EQUALS(utility::substrBefore("foobar", ' '), "foobar"); + TS_ASSERT_EQUALS(utility::substrBeforeFirst("foobar", ' '), "foobar"); } - void test_substr_before_with_delimiter_at_start() + void test_substr_before_first_with_delimiter_at_start() { - TS_ASSERT_EQUALS(utility::substrBefore(" foobar", ' '), ""); + TS_ASSERT_EQUALS(utility::substrBeforeFirst(" foobar", ' '), ""); } - void test_substr_before_with_delimiter_at_end() + void test_substr_before_first_with_delimiter_at_end() { - TS_ASSERT_EQUALS(utility::substrBefore("foobar ", ' '), "foobar"); + TS_ASSERT_EQUALS(utility::substrBeforeFirst("foobar ", ' '), "foobar"); + } + + void test_substr_before_last_with_single_delimiter_occurence() + { + TS_ASSERT_EQUALS(utility::substrBeforeLast("foo bar", ' '), "foo"); + } + + void test_substr_before_last_with_multiple_delimiter_occurences() + { + TS_ASSERT_EQUALS(utility::substrBeforeLast("foo bar foo", ' '), "foo bar"); + } + + void test_substr_before_last_with_no_delimiter_occurence() + { + TS_ASSERT_EQUALS(utility::substrBeforeLast("foobar", ' '), "foobar"); + } + + void test_substr_before_last_with_delimiter_at_start() + { + TS_ASSERT_EQUALS(utility::substrBeforeLast(" foobar", ' '), ""); + } + + void test_substr_before_last_with_delimiter_at_end() + { + TS_ASSERT_EQUALS(utility::substrBeforeLast("foobar ", ' '), "foobar"); } void test_substr_after_with_single_delimiter_occurence()