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.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
typedef unsigned int uint;
|
||||
|
||||
class G
|
||||
{};
|
||||
|
||||
class H
|
||||
: public G
|
||||
{
|
||||
private:
|
||||
int width;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -90,8 +90,9 @@ void Edge::addComponentDataType(std::shared_ptr<TokenComponentDataType> 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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -66,7 +66,7 @@ void ASTBodyVisitor::VisitMemberExpr(clang::make_ptr<clang::MemberExpr>::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<clang::DeclRefExpr>::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<clang::VarDecl>(decl))
|
||||
{
|
||||
m_client->VisitVarDeclInDeclBody(m_functionDecl, clang::dyn_cast<clang::VarDecl>(decl));
|
||||
}
|
||||
}
|
||||
VisitStmt(stmt);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
void VisitCXXConstructExpr(clang::CXXConstructExpr* expr);
|
||||
void VisitMemberExpr(clang::make_ptr<clang::MemberExpr>::type expr);
|
||||
void VisitDeclRefExpr(clang::make_ptr<clang::DeclRefExpr>::type expr);
|
||||
void VisitDeclStmt(clang::DeclStmt* stmt);
|
||||
|
||||
private:
|
||||
ASTBodyVisitorClient* m_client;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<TestParserClient> 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<TestParserClient> 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<TestParserClient> 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<TestParserClient> 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<TestParserClient> 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<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
@@ -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<std::string> typedefs;
|
||||
std::vector<std::string> classes;
|
||||
std::vector<std::string> enums;
|
||||
@@ -1018,6 +1118,7 @@ private:
|
||||
std::vector<std::string> methods;
|
||||
std::vector<std::string> namespaces;
|
||||
std::vector<std::string> structs;
|
||||
|
||||
std::vector<std::string> inheritances;
|
||||
std::vector<std::string> calls;
|
||||
std::vector<std::string> 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<TestParserClient> parseCode(std::string code) const
|
||||
|
||||
Reference in New Issue
Block a user