From 890575cd9063fa6b36ae95a1636c1ec5bca2b340 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Wed, 30 Jul 2014 22:35:30 +0200 Subject: [PATCH] data: Parsing type usages within function and method bodies This change parses type usages in function and method bodies and saves them with an edge of type EDGE_TYPE_USAGE. This also includes base class types used in initialization lists of derived class constructors. --- bin/app/data/src/header.h | 23 ++-- bin/app/data/src/main.cpp | 4 +- bin/test/data/CxxParserTestSuite/header.h | 4 + src/lib/data/Storage.cpp | 13 +- src/lib/data/Storage.h | 1 + src/lib/data/graph/Edge.cpp | 7 +- src/lib/data/graph/Edge.h | 1 + src/lib/data/parser/ParserClient.h | 1 + src/lib/data/parser/cxx/ASTBodyVisitor.cpp | 16 ++- src/lib/data/parser/cxx/ASTBodyVisitor.h | 1 + .../data/parser/cxx/ASTBodyVisitorClient.h | 5 +- src/lib/data/parser/cxx/ASTVisitor.cpp | 19 ++- src/lib/data/parser/cxx/ASTVisitor.h | 5 +- src/test/CxxParserTestSuite.h | 113 +++++++++++++++++- 14 files changed, 190 insertions(+), 23 deletions(-) diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index a23581e1..2f52d575 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -14,9 +14,9 @@ void funk(); class A { public: - A() + A(char c) : m_importantValue(42) - , m_importanterValue('r') + , m_importanterValue(c) , m_importantestValue(3.14159265359f) { } @@ -27,14 +27,14 @@ public: void doImportantStuff() { - m_importantValue *= 1; + int a = 1; + m_importantValue *= a; } void doModeratelyImportantStuff() { m_importanterValue = 'R'; - - sum(21, 21); + int answer = sum(21, 21); } private: @@ -43,9 +43,16 @@ private: float m_importantestValue; }; -A globalA; +A globalA(' '); -class B : public A {}; +class B : public A +{ +public: + B() + : A('b') + { + } +}; class C { @@ -62,7 +69,7 @@ public: void solveAllProblems() { - A aInstance; + A aInstance('a'); aInstance.doImportantStuff(); aInstance.doModeratelyImportantStuff(); } diff --git a/bin/app/data/src/main.cpp b/bin/app/data/src/main.cpp index 6857433c..f544cde2 100644 --- a/bin/app/data/src/main.cpp +++ b/bin/app/data/src/main.cpp @@ -7,7 +7,7 @@ int diff(int a, int b); int main() { - A aInstance; + A aInstance('m'); aInstance.doImportantStuff(); int a = sum(1, 2); @@ -39,6 +39,6 @@ int diff(int a, int b) void funk() { - A aInstance; + A aInstance('x'); aInstance.doModeratelyImportantStuff(); } diff --git a/bin/test/data/CxxParserTestSuite/header.h b/bin/test/data/CxxParserTestSuite/header.h index 5da2f00c..d59b1028 100644 --- a/bin/test/data/CxxParserTestSuite/header.h +++ b/bin/test/data/CxxParserTestSuite/header.h @@ -1,6 +1,10 @@ typedef unsigned int uint; +class G +{}; + class H + : public G { private: int width; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 79936524..a5f4d5df 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -238,7 +238,7 @@ void Storage::onCallParsed(const ParseLocation& location, const ParseVariable& c void Storage::onFieldUsageParsed(const ParseLocation& location, const ParseFunction& user, const std::string& usedName) { - log("usage", user.fullName + " -> " + usedName, location); + log("field usage", user.fullName + " -> " + usedName, location); Node* userNode = m_graph.createNodeHierarchyWithDistinctSignature(user.fullName, ParserClient::functionSignatureStr(user)); @@ -251,7 +251,7 @@ void Storage::onFieldUsageParsed(const ParseLocation& location, const ParseFunct void Storage::onGlobalVariableUsageParsed( const ParseLocation& location, const ParseFunction& user, const std::string& usedName ){ - log("usage", user.fullName + " -> " + usedName, location); + log("global usage", user.fullName + " -> " + usedName, location); Node* userNode = m_graph.createNodeHierarchyWithDistinctSignature(user.fullName, ParserClient::functionSignatureStr(user));; @@ -261,6 +261,15 @@ void Storage::onGlobalVariableUsageParsed( addTokenLocation(edge, location); } +void Storage::onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) +{ + log("type usage", function.fullName + " -> " + type.dataType.getRawTypeName(), type.location); + + Node* functionNode = + m_graph.createNodeHierarchyWithDistinctSignature(function.fullName, ParserClient::functionSignatureStr(function)); + addTypeEdge(functionNode, Edge::EDGE_TYPE_USAGE, type); +} + Id Storage::getIdForNodeWithName(const std::string& fullName) const { Node* node = m_graph.getNode(fullName); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 37814d43..5269f060 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -60,6 +60,7 @@ public: const ParseLocation& location, const ParseFunction& user, const std::string& usedName); virtual void onGlobalVariableUsageParsed( const ParseLocation& location, const ParseFunction& user, const std::string& usedName); + virtual void onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function); // GraphAccess implementation virtual Id getIdForNodeWithName(const std::string& fullName) const; diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index a19b5c89..d60055ec 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -90,8 +90,9 @@ void Edge::addComponentDataType(std::shared_ptr componen { LOG_ERROR("TokenComponentDataType has been set before!"); } - else if (m_type != EDGE_TYPEDEF_OF && m_type != EDGE_TYPE_OF - && m_type != EDGE_RETURN_TYPE_OF && m_type != EDGE_PARAMETER_TYPE_OF) + else if (m_type != EDGE_TYPEDEF_OF && m_type != EDGE_TYPE_OF && + m_type != EDGE_RETURN_TYPE_OF && m_type != EDGE_PARAMETER_TYPE_OF && + m_type != EDGE_TYPE_USAGE) { LOG_ERROR("TokenComponentDataType can't be set on edge of type: " + getTypeString()); } @@ -113,6 +114,8 @@ std::string Edge::getTypeString() const return "return type"; case EDGE_PARAMETER_TYPE_OF: return "parameter type"; + case EDGE_TYPE_USAGE: + return "type usage"; case EDGE_INHERITANCE: return "inheritance"; case EDGE_CALL: diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index 5eaca092..d200c873 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -19,6 +19,7 @@ public: EDGE_TYPE_OF, EDGE_RETURN_TYPE_OF, EDGE_PARAMETER_TYPE_OF, + EDGE_TYPE_USAGE, EDGE_USAGE, EDGE_CALL, EDGE_INHERITANCE, diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index c90c3c16..7e4b5e4d 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -79,6 +79,7 @@ public: const ParseLocation& location, const ParseFunction& user, const std::string& usedName) = 0; virtual void onGlobalVariableUsageParsed( const ParseLocation& location, const ParseFunction& user, const std::string& usedName) = 0; + virtual void onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) = 0; }; #endif // PARSER_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp index 1230c318..9d0d7fb0 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp @@ -66,7 +66,7 @@ void ASTBodyVisitor::VisitMemberExpr(clang::make_ptr::type ex { if (expr->getMemberDecl()->getKind() == clang::Decl::Kind::Field) { - m_client->VisitFieldUsageExprInDeclBody(m_functionDecl, expr); + m_client->VisitMemberExprInDeclBody(m_functionDecl, expr); } VisitStmt(expr); } @@ -75,7 +75,19 @@ void ASTBodyVisitor::VisitDeclRefExpr(clang::make_ptr::type { if (expr->getDecl()->getKind() == clang::Decl::Var && expr->getDecl()->isDefinedOutsideFunctionOrMethod()) { - m_client->VisitGlobalVariableUsageExprInDeclBody(m_functionDecl, expr); + m_client->VisitDeclRefExprInDeclBody(m_functionDecl, expr); } VisitStmt(expr); } + +void ASTBodyVisitor::VisitDeclStmt(clang::DeclStmt* stmt) +{ + for (clang::Decl* decl : stmt->decls()) + { + if (clang::isa(decl)) + { + m_client->VisitVarDeclInDeclBody(m_functionDecl, clang::dyn_cast(decl)); + } + } + VisitStmt(stmt); +} diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.h b/src/lib/data/parser/cxx/ASTBodyVisitor.h index 4c09302f..631febd1 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.h @@ -17,6 +17,7 @@ public: void VisitCXXConstructExpr(clang::CXXConstructExpr* expr); void VisitMemberExpr(clang::make_ptr::type expr); void VisitDeclRefExpr(clang::make_ptr::type expr); + void VisitDeclStmt(clang::DeclStmt* stmt); private: ASTBodyVisitorClient* m_client; diff --git a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h index 9f0f48e9..bd71eeda 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h @@ -15,8 +15,9 @@ public: virtual void VisitCallExprInDeclBody(clang::VarDecl* decl, clang::CallExpr* expr) = 0; virtual void VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clang::CXXConstructExpr* expr) = 0; virtual void VisitCXXConstructExprInDeclBody(clang::VarDecl* decl, clang::CXXConstructExpr* expr) = 0; - virtual void VisitFieldUsageExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) = 0; - virtual void VisitGlobalVariableUsageExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) = 0; + virtual void VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) = 0; + virtual void VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) = 0; + virtual void VisitVarDeclInDeclBody(clang::FunctionDecl* decl, clang::VarDecl* varDecl) = 0; }; #endif // AST_BODY_VISITOR_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index a8e6ab65..4ece8ce0 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -206,6 +206,13 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration) init->getMember()->getQualifiedNameAsString() ); } + else if (init->isBaseInitializer()) + { + m_client->onTypeUsageParsed( + getParseTypeUsage(init->getTypeSourceInfo()->getTypeLoc(), init->getTypeSourceInfo()->getType()), + getParseFunction(declaration) + ); + } ASTBodyVisitor bodyVisitor(this, declaration); bodyVisitor.Visit(init->getInit()); @@ -308,7 +315,7 @@ void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::VarDecl* decl, clang::CX ); } -void ASTVisitor::VisitFieldUsageExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) +void ASTVisitor::VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) { ParseLocation parseLocation = getParseLocation(expr->getSourceRange()); @@ -322,7 +329,7 @@ void ASTVisitor::VisitFieldUsageExprInDeclBody(clang::FunctionDecl* decl, clang: ); } -void ASTVisitor::VisitGlobalVariableUsageExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) +void ASTVisitor::VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) { ParseLocation parseLocation = getParseLocation(expr->getSourceRange()); @@ -336,6 +343,14 @@ void ASTVisitor::VisitGlobalVariableUsageExprInDeclBody(clang::FunctionDecl* dec ); } +void ASTVisitor::VisitVarDeclInDeclBody(clang::FunctionDecl* decl, clang::VarDecl* varDecl) +{ + m_client->onTypeUsageParsed( + getParseTypeUsage(varDecl->getTypeSourceInfo()->getTypeLoc(), varDecl->getType()), + getParseFunction(decl) + ); +} + bool ASTVisitor::hasValidLocation(const clang::Decl* declaration) const { const clang::SourceLocation& location = declaration->getLocStart(); diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 688fb145..26a583f3 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -43,8 +43,9 @@ public: virtual void VisitCallExprInDeclBody(clang::VarDecl* decl, clang::CallExpr* expr); // calls in initialization of global variables virtual void VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clang::CXXConstructExpr* expr); // constructor calls virtual void VisitCXXConstructExprInDeclBody(clang::VarDecl* decl, clang::CXXConstructExpr* expr); // constructor calls of global variables - virtual void VisitFieldUsageExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr); // field usages - virtual void VisitGlobalVariableUsageExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr); // global variable usage + virtual void VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr); // field usages + virtual void VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr); // global variable usage + virtual void VisitVarDeclInDeclBody(clang::FunctionDecl* decl, clang::VarDecl* varDecl); // type usages private: bool hasValidLocation(const clang::Decl* declaration) const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 56a2e5e5..8663dff6 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -871,6 +871,96 @@ public: TS_ASSERT_EQUALS(client->typeUses[3], "int <3:28 3:30>"); } + void test_cxx_parser_finds_type_uses_in_function_body() + { + std::shared_ptr client = parseCode( + "int main()\n" + "{\n" + " int a = 42;\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 2); + TS_ASSERT_EQUALS(client->typeUses[0], "int <1:1 1:3>"); + TS_ASSERT_EQUALS(client->typeUses[1], "int main() -> int <3:2 3:4>"); + } + + void test_cxx_parser_finds_type_uses_in_method_body() + { + std::shared_ptr client = parseCode( + "class A\n" + "{\n" + " int main()\n" + " {\n" + " int a = 42;\n" + " return a;\n" + " }\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 2); + TS_ASSERT_EQUALS(client->typeUses[0], "int <3:2 3:4>"); + TS_ASSERT_EQUALS(client->typeUses[1], "int A::main() -> int <5:3 5:5>"); + } + + void test_cxx_parser_finds_type_uses_in_loops_and_conditions() + { + std::shared_ptr client = parseCode( + "int main()\n" + "{\n" + " if (true)\n" + " {\n" + " int a = 42;\n" + " }\n" + " for (int i = 0; i < 10; i++)\n" + " {\n" + " int b = i * 2;\n" + " }\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 4); + TS_ASSERT_EQUALS(client->typeUses[0], "int <1:1 1:3>"); + TS_ASSERT_EQUALS(client->typeUses[1], "int main() -> int <5:3 5:5>"); + TS_ASSERT_EQUALS(client->typeUses[2], "int main() -> int <7:7 7:9>"); + TS_ASSERT_EQUALS(client->typeUses[3], "int main() -> int <9:3 9:5>"); + } + + void test_cxx_parser_finds_type_uses_of_classes_in_functions() + { + std::shared_ptr client = parseCode( + "class A {};\n" + "int main()\n" + "{\n" + " A a;\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 2); + TS_ASSERT_EQUALS(client->typeUses[0], "int <2:1 2:3>"); + TS_ASSERT_EQUALS(client->typeUses[1], "int main() -> A <4:2 4:2>"); + } + + void test_cxx_parser_finds_type_uses_of_base_class_in_derived_constructor() + { + std::shared_ptr client = parseCode( + "class A\n" + "{\n" + "public:\n" + " A(int n) {}" + "};\n" + "class B : public A\n" + "{\n" + "public:\n" + " B() : A(42) {}\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 2); + TS_ASSERT_EQUALS(client->typeUses[0], "int <4:4 4:6>"); + TS_ASSERT_EQUALS(client->typeUses[1], "void B::B() -> A <8:8 8:8>"); + } + void test_cxx_parser_parses_multiple_files() { std::shared_ptr client = std::make_shared(); @@ -882,7 +972,7 @@ public: parser.parseFiles(filePaths); TS_ASSERT_EQUALS(client->typedefs.size(), 1); - TS_ASSERT_EQUALS(client->classes.size(), 3); + TS_ASSERT_EQUALS(client->classes.size(), 4); TS_ASSERT_EQUALS(client->enums.size(), 1); TS_ASSERT_EQUALS(client->enumFields.size(), 2); TS_ASSERT_EQUALS(client->functions.size(), 2); @@ -891,6 +981,11 @@ public: TS_ASSERT_EQUALS(client->methods.size(), 5); TS_ASSERT_EQUALS(client->namespaces.size(), 2); TS_ASSERT_EQUALS(client->structs.size(), 1); + + TS_ASSERT_EQUALS(client->inheritances.size(), 1); + TS_ASSERT_EQUALS(client->calls.size(), 2); + TS_ASSERT_EQUALS(client->usages.size(), 3); + TS_ASSERT_EQUALS(client->typeUses.size(), 8); } private: @@ -1008,6 +1103,11 @@ private: usages.push_back(addLocationSuffix(functionStr(user) + " -> " + usedName, location)); } + virtual void onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) + { + addTypeUse(type, function); + } + std::vector typedefs; std::vector classes; std::vector enums; @@ -1018,6 +1118,7 @@ private: std::vector methods; std::vector namespaces; std::vector structs; + std::vector inheritances; std::vector calls; std::vector usages; @@ -1031,6 +1132,16 @@ private: typeUses.push_back(addLocationSuffix(use.dataType.getFullTypeName(), use.location)); } } + + void addTypeUse(const ParseTypeUsage& use, const ParseFunction& func) + { + if (use.location.isValid()) + { + typeUses.push_back( + addLocationSuffix(functionStr(func) + " -> " + use.dataType.getFullTypeName(), use.location) + ); + } + } }; std::shared_ptr parseCode(std::string code) const