data: parsing and saving method overrides

This change parses method overrides and saves them in the Storage with type EDGE_OVERRIDE.
This commit is contained in:
Eberhard Graether
2015-02-10 12:18:40 +01:00
parent 53eab0a517
commit 51c6675464
14 changed files with 195 additions and 52 deletions
+27 -22
View File
@@ -1,4 +1,26 @@
ConfigManager.cpp ERROR: value path/to/nowhere is not present in config.
Token.cpp ERROR: Location Id was not referenced by this Token.
Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class
Edge.cpp ERROR: Nodes are not plain copies.
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
Storage.cpp INFO: method: A::getCount <input.cc 8:13 8:20>
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 10:10 10:14>
Storage.cpp INFO: method: A::process <input.cc 14:15 14:21>
Storage.cpp INFO: field: A::count <input.cc 17:13 17:17>
Storage.cpp INFO: class: B <input.cc 20:7 20:7>
Storage.cpp INFO: inheritance: B : A <input.cc 21:4 21:11>
Storage.cpp INFO: method: B::process <input.cc 24:15 24:21>
Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0>
Storage.cpp INFO: type usage: B::process -> int <input.cc 26:3 26:5>
Storage.cpp INFO: function: main <input.cc 30:5 30:8>
Storage.cpp INFO: type usage: main -> B <input.cc 32:2 32:2>
Storage.cpp INFO: call: main -> B::B <input.cc 32:4 32:4>
Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
@@ -11,6 +33,7 @@ Storage.cpp INFO: field: A::count <input.cc 21:13 21:17>
Storage.cpp INFO: class: B <input.cc 24:7 24:7>
Storage.cpp INFO: inheritance: B : A <input.cc 25:4 25:11>
Storage.cpp INFO: method: B::process <input.cc 28:15 28:21>
Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0>
Storage.cpp INFO: type usage: B::process -> int <input.cc 30:3 30:5>
Storage.cpp INFO: function: main <input.cc 34:5 34:8>
Storage.cpp INFO: type usage: main -> B <input.cc 36:2 36:2>
@@ -31,27 +54,6 @@ SearchMatch.cpp INFO:
237 A::A
^^^^
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
Storage.cpp INFO: method: A::getCount <input.cc 8:13 8:20>
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 10:10 10:14>
Storage.cpp INFO: method: A::process <input.cc 14:15 14:21>
Storage.cpp INFO: field: A::count <input.cc 17:13 17:17>
Storage.cpp INFO: class: B <input.cc 20:7 20:7>
Storage.cpp INFO: inheritance: B : A <input.cc 21:4 21:11>
Storage.cpp INFO: method: B::process <input.cc 24:15 24:21>
Storage.cpp INFO: type usage: B::process -> int <input.cc 26:3 26:5>
Storage.cpp INFO: function: main <input.cc 30:5 30:8>
Storage.cpp INFO: type usage: main -> B <input.cc 32:2 32:2>
Storage.cpp INFO: call: main -> B::B <input.cc 32:4 32:4>
Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
Token.cpp ERROR: Location Id was not referenced by this Token.
Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class
Edge.cpp ERROR: Nodes are not plain copies.
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined
Settings.cpp WARNING: File for Settings not found.
ConfigManager.cpp ERROR: value Bool is not present in config.
ConfigManager.cpp ERROR: value Int is not present in config.
@@ -67,7 +69,6 @@ ConfigManager.cpp ERROR: value Int is not present in config.
ConfigManager.cpp ERROR: value Float is not present in config.
ConfigManager.cpp ERROR: value String is not present in config.
ConfigManager.cpp ERROR: value NewBool is not present in config.
Graph.cpp ERROR: Can't remove member edge, without removing the child node.
Storage.cpp INFO: typedef: type -> int <file.cpp 1:1 1:1>
Storage.cpp INFO: class: Class <file.cpp 1:1 1:1>
Storage.cpp INFO: struct: Struct <file.cpp 1:1 1:1>
@@ -95,6 +96,9 @@ Storage.cpp INFO: inheritance: ClassB : ClassA <file.cpp 1:5 1:5>
Storage.cpp INFO: struct: StructA <file.cpp 1:0 1:0>
Storage.cpp INFO: struct: StructB <file.cpp 1:0 1:0>
Storage.cpp INFO: inheritance: StructB : StructA <file.cpp 1:5 1:5>
Storage.cpp INFO: method: A::isMethod <file.cpp 1:9 1:9>
Storage.cpp INFO: method: B::isMethod <file.cpp 1:7 1:7>
Storage.cpp INFO: override: A::isMethod -> B::isMethod < 0:0 0:0>
Storage.cpp INFO: function: isTrue <file.cpp 1:0 1:0>
Storage.cpp INFO: function: func <file.cpp 1:0 1:0>
Storage.cpp INFO: call: isTrue -> func <file.cpp 1:9 1:9>
@@ -120,6 +124,7 @@ Storage.cpp INFO: call: main -> isTrue <file.cpp 1:0 1:0>
Storage.cpp INFO: function: isTrue <file.h 1:0 1:0>
Storage.cpp INFO: function: main <file.cpp 1:0 1:0>
Storage.cpp INFO: call: main -> isTrue <file.cpp 1:0 1:0>
Graph.cpp ERROR: Can't remove member edge, without removing the child node.
TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2
TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8
TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8
@@ -446,6 +446,7 @@ void QtGraphEdge::updateLine()
color = QColor("#62B29D");
break;
case Edge::EDGE_INHERITANCE:
case Edge::EDGE_OVERRIDE:
color = QColor("#CC5E89");
break;
case Edge::EDGE_AGGREGATION:
+12
View File
@@ -357,6 +357,18 @@ Id Storage::onInheritanceParsed(
return edge->getId();
}
Id Storage::onMethodOverrideParsed(const ParseFunction& base, const ParseFunction& overrider)
{
log("override", base.getFullName() + " -> " + overrider.getFullName(), ParseLocation());
Node* baseNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, base);
Node* overriderNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, overrider);
Edge* edge = m_graph.createEdge(Edge::EDGE_OVERRIDE, baseNode, overriderNode);
return edge->getId();
}
Id Storage::onCallParsed(const ParseLocation& location, const ParseFunction& caller, const ParseFunction& callee)
{
log("call", caller.getFullName() + " -> " + callee.getFullName(), location);
+1
View File
@@ -63,6 +63,7 @@ public:
virtual Id onInheritanceParsed(
const ParseLocation& location, const std::vector<std::string>& nameHierarchy,
const std::vector<std::string>& baseNameHierarchy, AccessType access);
virtual Id onMethodOverrideParsed(const ParseFunction& base, const ParseFunction& overrider);
virtual Id onCallParsed(
const ParseLocation& location, const ParseFunction& caller, const ParseFunction& callee);
virtual Id onCallParsed(
+10
View File
@@ -125,6 +125,8 @@ std::string Edge::getTypeString(EdgeType type) const
return "type_usage";
case EDGE_INHERITANCE:
return "inheritance";
case EDGE_OVERRIDE:
return "override";
case EDGE_CALL:
return "call";
case EDGE_USAGE:
@@ -215,6 +217,14 @@ bool Edge::checkType() const
}
return true;
case EDGE_OVERRIDE:
if (!m_from->isType(Node::NODE_UNDEFINED_FUNCTION | Node::NODE_METHOD) ||
!m_to->isType(Node::NODE_UNDEFINED_FUNCTION | Node::NODE_METHOD))
{
break;
}
return true;
case EDGE_CALL:
if (!m_from->isType(variableMask | functionMask) || !m_to->isType(functionMask))
{
+7 -6
View File
@@ -25,13 +25,14 @@ public:
EDGE_USAGE = 0x20,
EDGE_CALL = 0x40,
EDGE_INHERITANCE = 0x80,
EDGE_TYPEDEF_OF = 0x100,
EDGE_TEMPLATE_PARAMETER_OF = 0x200,
EDGE_TEMPLATE_ARGUMENT_OF = 0x400,
EDGE_TEMPLATE_DEFAULT_ARGUMENT_OF = 0x800,
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x1000,
EDGE_OVERRIDE = 0x100,
EDGE_TYPEDEF_OF = 0x200,
EDGE_TEMPLATE_PARAMETER_OF = 0x400,
EDGE_TEMPLATE_ARGUMENT_OF = 0x800,
EDGE_TEMPLATE_DEFAULT_ARGUMENT_OF = 0x1000,
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000,
EDGE_AGGREGATION = 0x2000
EDGE_AGGREGATION = 0x4000
};
Edge(EdgeType type, Node* from, Node* to);
+1
View File
@@ -82,6 +82,7 @@ public:
virtual Id onInheritanceParsed(
const ParseLocation& location, const std::vector<std::string>& nameHierarchy,
const std::vector<std::string>& baseNameHierarchy, AccessType access) = 0;
virtual Id onMethodOverrideParsed(const ParseFunction& base, const ParseFunction& overrider) = 0;
virtual Id onCallParsed(
const ParseLocation& location, const ParseFunction& caller, const ParseFunction& callee) = 0;
virtual Id onCallParsed(
+16 -8
View File
@@ -180,14 +180,22 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
abstraction = ParserClient::ABSTRACTION_VIRTUAL;
}
ParseFunction parseFunction = getParseFunction(declaration);
m_client->onMethodParsed(
getParseLocationForNamedDecl(declaration),
getParseFunction(declaration),
parseFunction,
convertAccessType(declaration->getAccess()),
abstraction,
getParseLocationOfFunctionBody(declaration)
);
for (clang::CXXMethodDecl::method_iterator it = declaration->begin_overridden_methods();
it != declaration->end_overridden_methods(); it++)
{
m_client->onMethodOverrideParsed(getParseFunction(*it), parseFunction);
}
if (declaration->hasBody() && declaration->getBody() != NULL && declaration->isThisDeclarationADefinition())
{
ASTBodyVisitor bodyVisitor(this, declaration);
@@ -725,7 +733,7 @@ ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::TypeLoc typeLoc, const clang
return ParseTypeUsage(parseLocation, dataType);
}
ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const
ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(const clang::FunctionDecl* declaration) const
{
clang::TypeLoc typeLoc;
@@ -742,13 +750,13 @@ ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* de
return getParseTypeUsage(typeLoc, declaration->getReturnType());
}
std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* declaration) const
std::vector<ParseTypeUsage> ASTVisitor::getParameters(const clang::FunctionDecl* declaration) const
{
std::vector<ParseTypeUsage> parameters;
for (unsigned i = 0; i < declaration->getNumParams(); i++)
{
clang::ParmVarDecl* paramDecl = declaration->getParamDecl(i);
const clang::ParmVarDecl* paramDecl = declaration->getParamDecl(i);
if (paramDecl->getTypeSourceInfo())
{
parameters.push_back(getParseTypeUsage(paramDecl->getTypeSourceInfo()->getTypeLoc(), paramDecl->getType()));
@@ -758,13 +766,13 @@ std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* decla
return parameters;
}
ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) const
ParseVariable ASTVisitor::getParseVariable(const clang::DeclaratorDecl* declaration) const
{
bool isStatic = false;
std::vector<std::string> hameHierarchy = utility::getDeclNameHierarchy(declaration);
if (clang::isa<clang::VarDecl>(declaration))
{
clang::VarDecl* varDecl = clang::dyn_cast<clang::VarDecl>(declaration);
const clang::VarDecl* varDecl = clang::dyn_cast<const clang::VarDecl>(declaration);
isStatic = varDecl->isStaticDataMember() || varDecl->getStorageClass() == clang::SC_Static;
}
else if (clang::isa<clang::FieldDecl>(declaration))
@@ -779,14 +787,14 @@ ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) c
);
}
ParseFunction ASTVisitor::getParseFunction(clang::FunctionDecl* declaration) const
ParseFunction ASTVisitor::getParseFunction(const clang::FunctionDecl* declaration) const
{
bool isStatic = false;
bool isConst = false;
if (clang::isa<clang::CXXMethodDecl>(declaration))
{
clang::CXXMethodDecl* methodDecl = clang::dyn_cast<clang::CXXMethodDecl>(declaration);
const clang::CXXMethodDecl* methodDecl = clang::dyn_cast<const clang::CXXMethodDecl>(declaration);
isStatic = methodDecl->isStatic();
isConst = methodDecl->isConst();
}
+4 -4
View File
@@ -68,11 +68,11 @@ private:
ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const;
ParseTypeUsage getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const;
ParseTypeUsage getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const;
std::vector<ParseTypeUsage> getParameters(clang::FunctionDecl* declaration) const;
ParseTypeUsage getParseTypeUsageOfReturnType(const clang::FunctionDecl* declaration) const;
std::vector<ParseTypeUsage> getParameters(const clang::FunctionDecl* declaration) const;
ParseVariable getParseVariable(clang::DeclaratorDecl* declaration) const;
ParseFunction getParseFunction(clang::FunctionDecl* declaration) const;
ParseVariable getParseVariable(const clang::DeclaratorDecl* declaration) const;
ParseFunction getParseFunction(const clang::FunctionDecl* declaration) const;
clang::ASTContext* m_context;
ParserClient* m_client;
+6 -6
View File
@@ -105,7 +105,7 @@ namespace utility
return DataType(typeNameHerarchy, qualifierList, modifierStack);
}
std::vector<std::string> getDeclNameHierarchy(clang::Decl* declaration)
std::vector<std::string> getDeclNameHierarchy(const clang::Decl* declaration)
{
std::vector<std::string> contextNameHierarchy;
if (declaration)
@@ -114,7 +114,7 @@ namespace utility
if (clang::isa<clang::NamedDecl>(declaration))
{
declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declaration));
declName = getDeclName(clang::dyn_cast<const clang::NamedDecl>(declaration));
}
else
{
@@ -133,11 +133,11 @@ namespace utility
return contextNameHierarchy;
}
std::vector<std::string> getContextNameHierarchy(clang::DeclContext* declContext)
std::vector<std::string> getContextNameHierarchy(const clang::DeclContext* declContext)
{
std::vector<std::string> contextNameHierarchy;
clang::DeclContext* parentContext = declContext->getParent();
const clang::DeclContext* parentContext = declContext->getParent();
if (parentContext)
{
contextNameHierarchy = getContextNameHierarchy(parentContext);
@@ -145,7 +145,7 @@ namespace utility
if (clang::isa<clang::NamedDecl>(declContext))
{
std::string declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declContext));
std::string declName = getDeclName(clang::dyn_cast<const clang::NamedDecl>(declContext));
if (declName != "")
{
contextNameHierarchy.push_back(declName);
@@ -154,7 +154,7 @@ namespace utility
return contextNameHierarchy;
}
std::string getDeclName(clang::NamedDecl* declaration)
std::string getDeclName(const clang::NamedDecl* declaration)
{
std::string declName = declaration->getNameAsString();
+3 -3
View File
@@ -15,9 +15,9 @@ namespace utility
{
DataType qualTypeToDataType(clang::QualType qualType);
std::vector<std::string> getDeclNameHierarchy(clang::Decl* declaration);
std::vector<std::string> getContextNameHierarchy(clang::DeclContext* declaration);
std::string getDeclName(clang::NamedDecl* declaration);
std::vector<std::string> getDeclNameHierarchy(const clang::Decl* declaration);
std::vector<std::string> getContextNameHierarchy(const clang::DeclContext* declaration);
std::string getDeclName(const clang::NamedDecl* declaration);
std::vector<std::string> getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration);
DataType templateArgumentToDataType(const clang::TemplateArgument& argument);
}
+85
View File
@@ -599,6 +599,84 @@ public:
TS_ASSERT_EQUALS(client->inheritances[1], "C : private B <5:4 5:12>");
}
void test_cxx_parser_finds_method_override_when_virtual()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class A {\n"
" virtual void foo();\n"
"};\n"
"class B : public A {\n"
" void foo();\n"
"};"
);
TS_ASSERT_EQUALS(client->overrides.size(), 1);
TS_ASSERT_EQUALS(client->overrides[0], "void A::foo() -> void B::foo()");
}
void test_cxx_parser_finds_no_method_override_when_not_virtual()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class A {\n"
" void foo();\n"
"};\n"
"class B : public A {\n"
" void foo();\n"
"};"
);
TS_ASSERT_EQUALS(client->overrides.size(), 0);
}
void test_cxx_parser_finds_all_method_overrides()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class A {\n"
" virtual void foo();\n"
"};\n"
"class B : public A {\n"
" void foo();\n"
"};\n"
"class C : public B {\n"
" void foo();\n"
"};"
);
TS_ASSERT_EQUALS(client->overrides.size(), 2);
TS_ASSERT_EQUALS(client->overrides[0], "void A::foo() -> void B::foo()");
TS_ASSERT_EQUALS(client->overrides[1], "void B::foo() -> void C::foo()");
}
void test_cxx_parser_finds_no_method_overrides_on_different_signatures()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class A {\n"
" virtual void foo(int a);\n"
"};\n"
"class B : public A {\n"
" int foo(int a, int b);\n"
"};\n"
);
TS_ASSERT_EQUALS(client->overrides.size(), 0);
}
void test_cxx_parser_finds_method_overrides_on_different_return_types()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class A {\n"
" virtual void foo();\n"
"};\n"
"class B : public A {\n"
" int foo();\n"
"};\n"
);
TS_ASSERT_EQUALS(client->overrides.size(), 1);
TS_ASSERT_EQUALS(client->overrides[0], "void A::foo() -> int B::foo()");
TS_ASSERT_EQUALS(client->errors.size(), 1);
}
void test_cxx_parser_finds_call_in_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1678,6 +1756,12 @@ private:
return 0;
}
virtual Id onMethodOverrideParsed(const ParseFunction& base, const ParseFunction& overrider)
{
overrides.push_back(functionStr(base) + " -> " + functionStr(overrider));
return 0;
}
virtual Id onCallParsed(
const ParseLocation& location, const ParseFunction& caller, const ParseFunction& callee)
{
@@ -1812,6 +1896,7 @@ private:
std::vector<std::string> structs;
std::vector<std::string> inheritances;
std::vector<std::string> overrides;
std::vector<std::string> calls;
std::vector<std::string> usages; // for variables
std::vector<std::string> typeUses; // for types
+3 -3
View File
@@ -100,10 +100,10 @@ public:
"7 nodes: "
"class:A field:A::count undefined_type:int undefined_type:void class:B function:main "
"undefined_function:B::B\n"
"13 edges: "
"14 edges: "
"child:A->A::count aggregation:A->int aggregation:A->void type_use:A::count->int inheritance:B->A "
"aggregation:B->void aggregation:B->int return_type:main->int type_usage:main->B child:B->B::B "
"call:main->B::B aggregation:main->B aggregation:main->A\n"
"aggregation:B->void aggregation:A->B aggregation:B->int return_type:main->int type_usage:main->B "
"child:B->B::B call:main->B::B aggregation:main->B aggregation:main->A\n"
);
}
+19
View File
@@ -407,6 +407,25 @@ public:
TS_ASSERT(isValidLocation(locations[0], 5));
}
void test_storage_saves_method_override()
{
TestStorage storage;
ParseFunction a(typeUsage("void"), utility::splitToVector("A::isMethod", "::"), parameters("bool"));
ParseFunction b(typeUsage("void"), utility::splitToVector("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));
Id id = storage.onMethodOverrideParsed(a, b);
Edge* edge = storage.getEdgeWithId(id);
TS_ASSERT(edge);
TS_ASSERT_EQUALS(edge->getType(), Edge::EDGE_OVERRIDE);
TS_ASSERT_EQUALS(edge->getFrom()->getFullName(), "A::isMethod");
TS_ASSERT_EQUALS(edge->getTo()->getFullName(), "B::isMethod");
}
void test_storage_saves_call()
{
TestStorage storage;