From ad5056354d44b509d36c81651466f863b467ec6f Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Thu, 17 Jul 2014 15:09:53 +0200 Subject: [PATCH] data: parse variable usage * Implemented functions for parsing usages of fields and global variables in ASTBodyVisitor and ASTVisitor. * Storage adds TokenLocatons and Edges for usages. * Added tests for parsing usage of fields and global variables. fortune cookie message = Fame, riches and love are yours for the taking. --- bin/app/data/src/header.h | 23 +++---- bin/app/data/src/main.cpp | 2 +- src/lib/data/Storage.cpp | 23 +++++++ src/lib/data/Storage.h | 5 ++ src/lib/data/graph/Edge.cpp | 2 + src/lib/data/parser/ParserClient.h | 4 ++ src/lib/data/parser/cxx/ASTBodyVisitor.cpp | 18 +++++ src/lib/data/parser/cxx/ASTBodyVisitor.h | 2 + .../data/parser/cxx/ASTBodyVisitorClient.h | 2 + src/lib/data/parser/cxx/ASTVisitor.cpp | 44 +++++++++++++ src/lib/data/parser/cxx/ASTVisitor.h | 2 + src/test/CxxParserTestSuite.h | 65 +++++++++++++++++++ 12 files changed, 180 insertions(+), 12 deletions(-) diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index bd6cb688..05c6fbf2 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -35,29 +35,31 @@ public: , m_importantestValue(3.14159265359f) { } - + ~A() { } - + void doImportantStuff() { m_importantValue *= 1; } - + void doModeratelyImportantStuff() { m_importanterValue = 'R'; - + sum(21, 21); } - + private: int m_importantValue; char m_importanterValue; float m_importantestValue; }; +A globalA; + class B : public A {}; class C @@ -66,23 +68,22 @@ public: C() : m_valuable(0) { + globalA.doImportantStuff(); } - + ~C() { } - + void solveAllProblems() { A aInstance; aInstance.doImportantStuff(); aInstance.doModeratelyImportantStuff(); } - + private: int m_valuable; }; -A globalA; - -typedef A* C; +typedef A* D; diff --git a/bin/app/data/src/main.cpp b/bin/app/data/src/main.cpp index c122ff93..6857433c 100644 --- a/bin/app/data/src/main.cpp +++ b/bin/app/data/src/main.cpp @@ -22,7 +22,7 @@ int diff(int a, int b); void foo() { - std::string foo = "bar"; + const char* foo = "bar"; } int diff(int a, int b); diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index d95e308b..b7e89876 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -223,6 +223,29 @@ void Storage::onCallParsed(const ParseLocation& location, const std::string& cal addTokenLocation(edge, location); } +void Storage::onFieldUsageParsed(const ParseLocation& location, const std::string& userName, const std::string& usedName) +{ + log("usage", userName + " -> " + usedName, location); + + Node* userNode = m_graph.createNodeHierarchy(userName); + Node* usedNode = m_graph.createNodeHierarchy(usedName); + + Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode); + addTokenLocation(edge, location); +} + +void Storage::onGlobalVariableUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName +) +{ + log("usage", userName + " -> " + usedName, location); + + Node* userNode = m_graph.createNodeHierarchy(userName); + Node* usedNode = m_graph.createNodeHierarchy(usedName); + + Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode); + addTokenLocation(edge, location); +} Id Storage::getIdForNodeWithName(const std::string& name) const { diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 7f1bbc0e..8244060b 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -56,6 +56,11 @@ public: virtual void onCallParsed( const ParseLocation& location, const std::string& callerName, const std::string& calleeName ); + virtual void onFieldUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName + ); + virtual void onGlobalVariableUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName); // GraphAccess implementation virtual Id getIdForNodeWithName(const std::string& name) const; diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 51020de6..f34bc46e 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -103,6 +103,8 @@ std::string Edge::getTypeString() const return "is derived from"; case EDGE_CALL: return "calls"; + case EDGE_USAGE: + return "uses"; case EDGE_TYPEDEF_OF: return "is typedef of"; default: diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 871e91a3..bcbe841e 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -74,6 +74,10 @@ public: const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access) = 0; virtual void onCallParsed( const ParseLocation& location, const std::string& callerName, const std::string& calleeName) = 0; + virtual void onFieldUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName) = 0; + virtual void onGlobalVariableUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName) = 0; }; #endif // PARSER_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp index a282eeae..55fd9376 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp @@ -39,3 +39,21 @@ void ASTBodyVisitor::VisitCXXConstructExpr(clang::CXXConstructExpr* expr) VisitStmt(expr); } + +void ASTBodyVisitor::VisitMemberExpr(clang::make_ptr::type expr) +{ + if (expr->getMemberDecl()->getKind() == clang::Decl::Kind::Field) + { + m_client->VisitFieldUsageExprInDeclBody(m_parentDecl, expr); + } + VisitStmt(expr); +} + +void ASTBodyVisitor::VisitDeclRefExpr(clang::make_ptr::type expr) +{ + if (expr->getDecl()->getKind() == clang::Decl::Var && expr->getDecl()->isDefinedOutsideFunctionOrMethod()) + { + m_client->VisitGlobalVariableUsageExprInDeclBody(m_parentDecl, expr); + } + VisitStmt(expr); +} diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.h b/src/lib/data/parser/cxx/ASTBodyVisitor.h index b518812c..59ec600d 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.h @@ -14,6 +14,8 @@ public: void VisitChildren(clang::Stmt* stmt); void VisitCallExpr(clang::CallExpr* expr); void VisitCXXConstructExpr(clang::CXXConstructExpr* expr); + void VisitMemberExpr(clang::make_ptr::type expr); + void VisitDeclRefExpr(clang::make_ptr::type expr); private: ASTBodyVisitorClient* m_client; diff --git a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h index 3a98b3e7..994508dc 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h @@ -13,6 +13,8 @@ public: virtual void VisitCallExprInDeclBody(clang::NamedDecl* decl, clang::CallExpr* expr) = 0; virtual void VisitCXXConstructExprInDeclBody(clang::NamedDecl* decl, clang::CXXConstructExpr* expr) = 0; + virtual void VisitFieldUsageExprInDeclBody(clang::NamedDecl* decl, clang::MemberExpr* expr) = 0; + virtual void VisitGlobalVariableUsageExprInDeclBody(clang::NamedDecl* decl, clang::DeclRefExpr* expr) = 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 4385c39b..74c15934 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -278,6 +278,50 @@ void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::NamedDecl* decl, clang:: ); } +void ASTVisitor::VisitFieldUsageExprInDeclBody(clang::NamedDecl* decl, clang::MemberExpr* expr) +{ + const clang::SourceManager& sourceManager = m_context->getSourceManager(); + const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(expr->getSourceRange().getBegin()); + const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(expr->getSourceRange().getEnd()); + const std::string exprName = expr->getMemberNameInfo().getAsString(); + + ParseLocation parseLocation( + presumedBegin.getFilename(), + presumedBegin.getLine(), + presumedBegin.getColumn(), + presumedEnd.getLine(), + presumedEnd.getColumn() + exprName.size() - 1 + ); + + m_client->onFieldUsageParsed( + parseLocation, + decl->getQualifiedNameAsString(), + expr->getMemberDecl()->getQualifiedNameAsString() + ); +} + +void ASTVisitor::VisitGlobalVariableUsageExprInDeclBody(clang::NamedDecl* decl, clang::DeclRefExpr* expr) +{ + const clang::SourceManager& sourceManager = m_context->getSourceManager(); + const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(expr->getSourceRange().getBegin()); + const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(expr->getSourceRange().getEnd()); + const std::string exprName = expr->getNameInfo().getAsString(); + + ParseLocation parseLocation( + presumedBegin.getFilename(), + presumedBegin.getLine(), + presumedBegin.getColumn(), + presumedEnd.getLine(), + presumedEnd.getColumn() + exprName.size() - 1 + ); + + m_client->onGlobalVariableUsageParsed( + parseLocation, + decl->getQualifiedNameAsString(), + expr->getDecl()->getQualifiedNameAsString() + ); +} + 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 04273dfe..3492b7a2 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -41,6 +41,8 @@ public: // ASTBodyVisitorClient implementation virtual void VisitCallExprInDeclBody(clang::NamedDecl* decl, clang::CallExpr* expr); // calls virtual void VisitCXXConstructExprInDeclBody(clang::NamedDecl* decl, clang::CXXConstructExpr* expr); // constructor calls + virtual void VisitFieldUsageExprInDeclBody(clang::NamedDecl* decl, clang::MemberExpr* expr); // field usages + virtual void VisitGlobalVariableUsageExprInDeclBody(clang::NamedDecl* decl, clang::DeclRefExpr* expr); // global variable usage private: bool hasValidLocation(const clang::Decl* declaration) const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index df9f99ec..5104e404 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -675,6 +675,58 @@ public: TS_ASSERT_EQUALS(client->calls[1], "main -> App::operator+ <11:2 11:8>"); } + void test_cxx_parser_finds_usage_of_global_variable_in_function() + { + std::shared_ptr client = parseCode( + "int bar;\n" + "\n" + "int main()\n" + "{\n" + " bar = 1;\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->usages.size(), 1); + TS_ASSERT_EQUALS(client->usages[0], "main -> bar <5:2 5:4>"); + } + + void test_cxx_parser_finds_usage_of_global_variable_in_method() + { + std::shared_ptr client = parseCode( + "int bar;\n" + "\n" + "class App\n" + "{\n" + " void foo()\n" + " {\n" + " bar = 1;\n" + " }\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->usages.size(), 1); + TS_ASSERT_EQUALS(client->usages[0], "App::foo -> bar <7:3 7:5>"); + } + + void test_cxx_parser_finds_usage_of_field_in_method() + { + std::shared_ptr client = parseCode( + "class App\n" + "{\n" + " void foo()\n" + " {\n" + " bar = 1;\n" + " this->bar = 2;\n" + " }\n" + " int bar;\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->usages.size(), 2); + TS_ASSERT_EQUALS(client->usages[0], "App::foo -> App::bar <5:3 5:5>"); + TS_ASSERT_EQUALS(client->usages[1], "App::foo -> App::bar <6:3 6:11>"); + } + void test_cxx_parser_finds_return_type_use_in_function() { std::shared_ptr client = parseCode( @@ -834,6 +886,18 @@ private: calls.push_back(addLocationSuffix(callerName + " -> " + calleeName, location)); } + virtual void onFieldUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName) + { + usages.push_back(addLocationSuffix(userName + " -> " + usedName, location)); + } + + virtual void onGlobalVariableUsageParsed( + const ParseLocation& location, const std::string& userName, const std::string& usedName) + { + usages.push_back(addLocationSuffix(userName + " -> " + usedName, location)); + } + std::vector typedefs; std::vector classes; std::vector enums; @@ -846,6 +910,7 @@ private: std::vector structs; std::vector inheritances; std::vector calls; + std::vector usages; std::vector typeUses; private: