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.
This commit is contained in:
+12
-11
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,3 +39,21 @@ void ASTBodyVisitor::VisitCXXConstructExpr(clang::CXXConstructExpr* expr)
|
||||
|
||||
VisitStmt(expr);
|
||||
}
|
||||
|
||||
void ASTBodyVisitor::VisitMemberExpr(clang::make_ptr<clang::MemberExpr>::type expr)
|
||||
{
|
||||
if (expr->getMemberDecl()->getKind() == clang::Decl::Kind::Field)
|
||||
{
|
||||
m_client->VisitFieldUsageExprInDeclBody(m_parentDecl, expr);
|
||||
}
|
||||
VisitStmt(expr);
|
||||
}
|
||||
|
||||
void ASTBodyVisitor::VisitDeclRefExpr(clang::make_ptr<clang::DeclRefExpr>::type expr)
|
||||
{
|
||||
if (expr->getDecl()->getKind() == clang::Decl::Var && expr->getDecl()->isDefinedOutsideFunctionOrMethod())
|
||||
{
|
||||
m_client->VisitGlobalVariableUsageExprInDeclBody(m_parentDecl, expr);
|
||||
}
|
||||
VisitStmt(expr);
|
||||
}
|
||||
|
||||
@@ -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<clang::MemberExpr>::type expr);
|
||||
void VisitDeclRefExpr(clang::make_ptr<clang::DeclRefExpr>::type expr);
|
||||
|
||||
private:
|
||||
ASTBodyVisitorClient* m_client;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<TestParserClient> 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<TestParserClient> 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<TestParserClient> 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<TestParserClient> 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<std::string> typedefs;
|
||||
std::vector<std::string> classes;
|
||||
std::vector<std::string> enums;
|
||||
@@ -846,6 +910,7 @@ private:
|
||||
std::vector<std::string> structs;
|
||||
std::vector<std::string> inheritances;
|
||||
std::vector<std::string> calls;
|
||||
std::vector<std::string> usages;
|
||||
std::vector<std::string> typeUses;
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user