From a44af5112263d04054c8c15530902d23f68d2d14 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Wed, 16 Dec 2015 11:27:29 +0100 Subject: [PATCH] data: function signature handling * functions will only display their names in the graph view. hovering the nodes shows the signature as a tooltip. However, nodes in the database will be created and used regarding their signature. * improved lambda handling. All calls to generated lambda functions (constructor, call operator) will now point to the lambda class instead. * implemented handling of the "auto" type. * improved the CxxParserTestSuite to use function strings instead of function names for template related functions. --- src/lib/data/SqliteStorage.cpp | 30 ++++---- src/lib/data/SqliteStorage.h | 4 +- src/lib/data/Storage.cpp | 68 ++++++++++++++++--- src/lib/data/parser/ParserClient.cpp | 5 +- .../cxx/name_resolver/CxxDeclNameResolver.cpp | 25 +++---- .../cxx/name_resolver/CxxTypeNameResolver.cpp | 6 ++ src/test/CxxParserTestSuite.h | 45 ++++++------ src/test/StorageTestSuite.h | 6 +- 8 files changed, 118 insertions(+), 71 deletions(-) diff --git a/src/lib/data/SqliteStorage.cpp b/src/lib/data/SqliteStorage.cpp index 7dff1986..7211d795 100644 --- a/src/lib/data/SqliteStorage.cpp +++ b/src/lib/data/SqliteStorage.cpp @@ -433,24 +433,20 @@ std::vector SqliteStorage::getEdgesByTargetType(Id targetId, int ty StorageNode SqliteStorage::getNodeById(Id id) const { - std::vector nodes = getAllNodes("WHERE id == " + std::to_string(id)); - if (nodes.size()) + if (id != 0) { - return nodes[0]; + std::vector nodes = getAllNodes("WHERE id == " + std::to_string(id)); + if (nodes.size()) + { + return nodes[0]; + } } - return StorageNode(0, 0, 0, false); } -StorageNode SqliteStorage::getNodeByNameId(Id nameId) const +std::vector SqliteStorage::getNodesByNameId(Id nameId) const { - std::vector nodes = getAllNodes("WHERE name_id == " + std::to_string(nameId)); - if (nodes.size()) - { - return nodes[0]; - } - - return StorageNode(0, 0, 0, false); + return getAllNodes("WHERE name_id == " + std::to_string(nameId)); } std::vector SqliteStorage::getNodesByIds(const std::vector& nodeIds) const @@ -736,18 +732,20 @@ std::vector SqliteStorage::getComponentAccessByMemberEdg return accesses; } -Id SqliteStorage::getNodeIdBySignature(const std::string& signature) const +std::vector SqliteStorage::getNodeIdsBySignature(const std::string& signature) const { CppSQLite3Query q = m_database.execQuery(( - "SELECT id, signature FROM function_signature WHERE signature == '" + signature + "';" + "SELECT id FROM function_signature WHERE signature == '" + signature + "';" ).c_str()); + std::vector ids; while (!q.eof()) { - return q.getIntField(0, 0); + ids.push_back(q.getIntField(0, 0)); + q.nextRow(); } - return 0; + return ids; } std::string SqliteStorage::getSignatureByNodeId(Id nodeId) const diff --git a/src/lib/data/SqliteStorage.h b/src/lib/data/SqliteStorage.h index f1e39ed7..973980fa 100644 --- a/src/lib/data/SqliteStorage.h +++ b/src/lib/data/SqliteStorage.h @@ -78,7 +78,7 @@ public: std::vector getEdgesByTargetType(Id targetId, int type) const; StorageNode getNodeById(Id id) const; - StorageNode getNodeByNameId(Id nameId) const; + std::vector getNodesByNameId(Id nameId) const; std::vector getNodesByIds(const std::vector& nodeIds) const; StorageFile getFileById(const Id id) const; @@ -107,7 +107,7 @@ public: StorageComponentAccess getComponentAccessByMemberEdgeId(Id memberEdgeId) const; std::vector getComponentAccessByMemberEdgeIds(const std::vector& memberEdgeIds) const; - Id getNodeIdBySignature(const std::string& signature) const; + std::vector getNodeIdsBySignature(const std::string& signature) const; std::string getSignatureByNodeId(Id nodeId) const; std::vector getCommentLocationsInFile(const FilePath& filePath) const; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index b238a34a..96fcffa1 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -772,7 +772,12 @@ Id Storage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) co currentId = m_sqliteStorage.getNameHierarchyElementIdByName(nameHierarchy[i]->getFullName(), currentId); } - return m_sqliteStorage.getNodeByNameId(currentId).id; + std::vector nodes = m_sqliteStorage.getNodesByNameId(currentId); + if (nodes.size() > 0) // TODO: make it impossible that one name id referrs to n nodes. + { + return nodes[0].id; + } + return 0; } Id Storage::getIdForEdge( @@ -1307,24 +1312,64 @@ Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarch for (size_t i = 0; i < nameIds.size(); i++) { Id nameId = nameIds[i]; - bool lastName = (i == nameHierarchy.size() - 1); + const bool isLastElement = (i == nameHierarchy.size() - 1); + const std::string& signature = nameHierarchy[i]->getFullSignature(); + const bool hasSignature = (signature.size() > 0); - Node::NodeType type = (lastName ? nodeType : Node::NODE_UNDEFINED); + Node::NodeType type = (isLastElement ? nodeType : Node::NODE_UNDEFINED); + + StorageNode node(0, 0, 0, false); + if (hasSignature) + { + std::vector potentialIds = m_sqliteStorage.getNodeIdsBySignature(signature); + if (parentNodeId != 0) + { + for (size_t i = 0; i < potentialIds.size(); i++) + { + if (m_sqliteStorage.getEdgeBySourceTargetType(parentNodeId, potentialIds[i], Edge::EDGE_MEMBER).id != 0) + { + node = m_sqliteStorage.getNodeById(potentialIds[i]); + break; + } + } + } + else if (potentialIds.size() > 0) + { + node = m_sqliteStorage.getNodeById(potentialIds[0]); + } + } + else + { + std::vector potentialIds = m_sqliteStorage.getNodesByNameId(nameId); + if (parentNodeId != 0) + { + for (size_t i = 0; i < potentialIds.size(); i++) + { + if (m_sqliteStorage.getEdgeBySourceTargetType(parentNodeId, potentialIds[i].id, Edge::EDGE_MEMBER).id != 0) + { + node = potentialIds[i]; + break; + } + } + } + else if (potentialIds.size() > 0) + { + node = potentialIds[0]; + } + } - const StorageNode node = m_sqliteStorage.getNodeByNameId(nameId); Id nodeId = node.id; - if (nodeId && !node.defined && lastName && defined) + if (nodeId && !node.defined && isLastElement && defined) { m_sqliteStorage.setNodeDefined(true, nodeId); } if (nodeId == 0) { - nodeId = m_sqliteStorage.addNode(Node::typeToInt(type), nameId, lastName && defined); + nodeId = m_sqliteStorage.addNode(Node::typeToInt(type), nameId, isLastElement && defined); - std::string signature = nameHierarchy[i]->getFullSignature(); - if (signature.size() != 0) + if (hasSignature) { m_sqliteStorage.addSignature(nodeId, signature); } @@ -1334,7 +1379,7 @@ Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarch addEdge(parentNodeId, nodeId, Edge::EDGE_MEMBER); } } - else if (lastName) // Update the type of the last node if the new type is more specific. + else if (isLastElement) // Update the type of the last node if the new type is more specific. { Node::NodeType storedType = Node::intToType(node.type); if (type > storedType) @@ -1433,6 +1478,11 @@ Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type) Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type, ParseLocation location) { + if (!sourceNodeId || !targetNodeId) + { + return 0; + } + Id edgeId = addEdge(sourceNodeId, targetNodeId, type); addSourceLocation(edgeId, location, false); diff --git a/src/lib/data/parser/ParserClient.cpp b/src/lib/data/parser/ParserClient.cpp index a877c870..3fd0f637 100644 --- a/src/lib/data/parser/ParserClient.cpp +++ b/src/lib/data/parser/ParserClient.cpp @@ -107,10 +107,9 @@ std::string ParserClient::parameterStr(const std::vector paramet std::string ParserClient::functionStr(const ParseFunction& function) { - //return function.getFullName(); std::string str = - function.returnType.dataType->getFullTypeName() + " " + function.getFullName(); - return addStaticPrefix(str, function.isStatic); + function.returnType.dataType->getFullTypeName() + " " + function.getFullName() + parameterStr(function.parameters); + return addConstPrefix(addStaticPrefix(str, function.isStatic), function.isConst, false); } ParserClient::ParserClient() diff --git a/src/lib_parser/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp b/src/lib_parser/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp index fd694fc9..78e838ab 100644 --- a/src/lib_parser/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp +++ b/src/lib_parser/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -40,10 +40,10 @@ NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy() LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName())); } + contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext()); + if (declName) { - contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext()); - if ((clang::isa(m_declaration) || clang::isa(m_declaration) || clang::isa(m_declaration)) && @@ -58,11 +58,6 @@ NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy() contextNameHierarchy.push(declName); } } - else - { - const clang::SourceManager& sourceManager = m_declaration->getASTContext().getSourceManager(); - LOG_ERROR("could not resolve name of decl at: " + m_declaration->getLocation().printToString(sourceManager)); - } } return contextNameHierarchy; } @@ -153,10 +148,12 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() } else if (recordDecl->isLambda()) { - // return empty pointer since lambdas will be handled at the level of the individual functions... not optimal. - return std::shared_ptr(); + const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); + const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(recordDecl->getLocStart()); + std::string lambdaName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn()); + return std::make_shared(lambdaName, lambdaName); } - else if (!recordDecl->isLambda() && declNameString.size() == 0) + else if (declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); @@ -170,10 +167,8 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() { if (methodDecl->getParent()->isLambda()) { - const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); - const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(methodDecl->getParent()->getLocStart()); - std::string lambdaName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn()); - return std::make_shared(lambdaName, lambdaName); + // return empty pointer since lambdas will be handled at the level of the parent class... not optimal. + return std::shared_ptr(); } } @@ -229,7 +224,7 @@ std::shared_ptr CxxDeclNameResolver::getDeclName() parameterString += ")"; return std::make_shared( - functionName + parameterString + (isConst ? "const" : ""), + functionName, (isStatic ? "static " : "") + returnTypeString + " " + functionName + parameterString + (isConst ? " const" : "")); } diff --git a/src/lib_parser/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp b/src/lib_parser/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp index a78e2275..93873380 100644 --- a/src/lib_parser/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp +++ b/src/lib_parser/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp @@ -178,6 +178,12 @@ std::shared_ptr CxxTypeNameResolver::typeToDataType(const clang::Type* dataType = qualTypeToDataType(packExpansionType->getPattern()); break; } + case clang::Type::Auto: + { + const clang::AutoType* autoType = clang::dyn_cast(type); + dataType = qualTypeToDataType(autoType->getDeducedType()); + break; + } default: { LOG_INFO(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName()); diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 1f471991..da90660a 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -138,8 +138,8 @@ public: ); TS_ASSERT_EQUALS(client->structs.size(), 2); - TS_ASSERT_EQUALS(client->structs[0], "foo(int)::B <3:2 <3:9 3:9> 5:2>"); - TS_ASSERT_EQUALS(client->structs[1], "foo(float)::B <9:2 <9:9 9:9> 11:2>"); + TS_ASSERT_EQUALS(client->structs[0], "foo::B <3:2 <3:9 3:9> 5:2>"); + TS_ASSERT_EQUALS(client->structs[1], "foo::B <9:2 <9:9 9:9> 11:2>"); } void test_cxx_parser_finds_variable_definitions_in_global_scope() @@ -328,7 +328,7 @@ public: ); TS_ASSERT_EQUALS(client->methods.size(), 1); - TS_ASSERT_EQUALS(client->methods[0], "private bool B::C::isGreat()const <5:8 5:14>"); + TS_ASSERT_EQUALS(client->methods[0], "private bool B::C::isGreat() const <5:8 5:14>"); } void test_cxx_parser_finds_named_namespace() @@ -1810,7 +1810,7 @@ public: "}\n" ); TS_ASSERT_EQUALS(client->templateMemberSpecializations.size(), 1); - TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "A::foo() -> A::foo() <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "int A::foo() -> A::T A::foo() <0:0 0:0>"); } void test_cxx_parser_finds_explicit_template_specialization() @@ -2529,7 +2529,7 @@ public: ); TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - TS_ASSERT_EQUALS(client->templateSpecializations[0], "test(int) -> test <2:3 2:6>"); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "int test(int) -> test::T test(test::T) <2:3 2:6>"); } void test_cxx_parser_finds_explicit_specialization_of_template_function() @@ -2549,7 +2549,7 @@ public: ); TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - TS_ASSERT_EQUALS(client->templateSpecializations[0], "test(int) -> test <8:5 8:8>"); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "int test(int) -> test::T test(test::T) <8:5 8:8>"); } void test_cxx_parser_finds_explicit_type_template_argument_of_explicit_specialization_of_template_function() @@ -2566,7 +2566,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test()->int <7:11 7:11>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test()->int <7:11 7:11>"); } void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_function() @@ -2582,7 +2582,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test()->int <6:7 6:7>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test()->int <6:7 6:7>"); } void test_cxx_parser_finds_explicit_non_type_template_argument_of_function_call_in_function() @@ -2598,7 +2598,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<33>()->int <6:7 6:7>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<33>()->int <6:7 6:7>"); } void test_cxx_parser_finds_explicit_template_template_argument_of_function_call_in_function() @@ -2615,7 +2615,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test()->A <7:7 7:7>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test()->A <7:7 7:7>"); } void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_function() @@ -2631,7 +2631,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test(int)->int <6:5 6:5>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test(int)->int <6:5 6:5>"); } void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_var_decl() @@ -2646,7 +2646,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test()->int <6:17 6:17>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "int test()->int <6:17 6:17>"); } void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_var_decl() @@ -2661,7 +2661,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test(int)->int <6:15 6:15>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "int test(int)->int <6:15 6:15>"); } @@ -2726,9 +2726,9 @@ public: TS_ASSERT_EQUALS(client->functions.size(), 2); TS_ASSERT_EQUALS(client->functions[0], "void lambdaCaller() <1:1 <1:6 1:17> 4:1>"); - TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller()::lambda at 3:2 <3:5 <3:2 3:2> 3:7>"); + TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller::lambda at 3:2() const <3:5 <3:2 3:2> 3:7>"); TS_ASSERT_EQUALS(client->calls.size(), 1); - TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller()::lambda at 3:2 <3:2 3:9>"); + TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller::lambda at 3:2() const <3:2 3:9>"); } void test_cxx_parser_ignores_lambda_in_function_but_still_finds_call_within() @@ -2747,10 +2747,10 @@ public: TS_ASSERT_EQUALS(client->functions.size(), 3); TS_ASSERT_EQUALS(client->functions[0], "void func() <1:1 <1:6 1:9> 1:14>"); TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller() <2:1 <2:6 2:17> 8:1>"); - TS_ASSERT_EQUALS(client->functions[2], "void lambdaCaller()::lambda at 4:2 <4:5 <4:2 4:2> 7:2>"); + TS_ASSERT_EQUALS(client->functions[2], "void lambdaCaller::lambda at 4:2() const <4:5 <4:2 4:2> 7:2>"); TS_ASSERT_EQUALS(client->calls.size(), 2); - TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller()::lambda at 4:2 <4:2 7:4>"); - TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller()::lambda at 4:2 -> void func() <6:3 6:8>"); + TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller::lambda at 4:2() const <4:2 7:4>"); + TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller::lambda at 4:2() const -> void func() <6:3 6:8>"); } void test_cxx_parser_parses_multiple_files() @@ -3056,7 +3056,7 @@ private: const ParseFunction& templateFunction) { templateArgumentTypes.push_back( - addLocationSuffix(templateFunction.getFullName() + "->" + argumentTypeNameHierarchy.getFullName(), location) + addLocationSuffix(functionStr(templateFunction) + "->" + argumentTypeNameHierarchy.getFullName(), location) ); return 0; } @@ -3094,9 +3094,8 @@ private: virtual Id onTemplateMemberFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction) { - // needs to be implemented templateMemberSpecializations.push_back(addLocationSuffix( - instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(), location + functionStr(instantiatedFunction) + " -> " + functionStr(specializedFunction), location )); return 0; } @@ -3106,7 +3105,7 @@ private: const ParseFunction function) { templateParameterTypes.push_back( - addLocationSuffix(templateParameterTypeNameHierarchy.getFullName(), location) + addLocationSuffix(templateParameterTypeNameHierarchy.getFullName(), location) // TODO: add template function! ); return 0; } @@ -3115,7 +3114,7 @@ private: const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) { templateSpecializations.push_back( - addLocationSuffix(specializedFunction.getFullName() + " -> " + templateFunction.getFullName(), location) + addLocationSuffix(functionStr(specializedFunction) + " -> " + functionStr(templateFunction), location) ); return 0; } diff --git a/src/test/StorageTestSuite.h b/src/test/StorageTestSuite.h index da130d5e..743c9481 100644 --- a/src/test/StorageTestSuite.h +++ b/src/test/StorageTestSuite.h @@ -310,15 +310,15 @@ public: { TestStorage storage; - ParseFunction a(typeUsage("void"), createNameHierarchy("A::isMethod(bool)"), parameters("bool")); - ParseFunction b(typeUsage("void"), createNameHierarchy("B::isMethod(bool)"), parameters("bool")); + ParseFunction a(typeUsage("void"), createNameHierarchy("A::isMethod"), parameters("bool")); + ParseFunction b(typeUsage("void"), createNameHierarchy("B::isMethod"), parameters("bool")); storage.onMethodParsed(validLocation(9), a, ParserClient::ACCESS_PRIVATE, ParserClient::ABSTRACTION_VIRTUAL, validLocation(4)); storage.onMethodParsed(validLocation(7), b, ParserClient::ACCESS_PRIVATE, ParserClient::ABSTRACTION_NONE, validLocation(3)); storage.onMethodOverrideParsed(validLocation(4), a, b); - TS_ASSERT(storage.getEdgeId(Edge::EDGE_OVERRIDE, "B::isMethod(bool)", "A::isMethod(bool)") != 0); + TS_ASSERT(storage.getEdgeId(Edge::EDGE_OVERRIDE, "B::isMethod", "A::isMethod") != 0); } void test_storage_saves_call()