data: parsing and saving inheritance
This change parses inheritance in CxxParser and saves them as EDGE_INHERITANCE in the Storage's graph. Tests for correct inheritance recognition were added to CxxParserTestSuite. fortune cookie message = If you continually give, you will continually have.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config>
|
||||
<SourcePath>data/src</SourcePath>
|
||||
</config>
|
||||
</config>
|
||||
|
||||
@@ -2,3 +2,6 @@ int main();
|
||||
void foo();
|
||||
int sum(int a, int b);
|
||||
int diff(int a, int b);
|
||||
|
||||
class A {};
|
||||
class B : public A {};
|
||||
|
||||
@@ -162,6 +162,20 @@ void Storage::onEnumFieldParsed(const ParseLocation& location, const std::string
|
||||
addTokenLocation(node, location);
|
||||
}
|
||||
|
||||
void Storage::onInheritanceParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access)
|
||||
{
|
||||
log("inheritance", fullName + " : " + baseName, location);
|
||||
|
||||
Node* node = m_graph.createNodeHierarchy(fullName);
|
||||
Node* baseNode = m_graph.createNodeHierarchy(baseName);
|
||||
|
||||
Edge* edge = m_graph.createEdge(Edge::EDGE_INHERITANCE, node, baseNode);
|
||||
edge->setAccess(convertAccessType(access));
|
||||
|
||||
addTokenLocation(edge, location);
|
||||
}
|
||||
|
||||
void Storage::logGraph() const
|
||||
{
|
||||
std::stringstream str;
|
||||
@@ -210,7 +224,13 @@ TokenLocationCollection Storage::getTokenLocationsForTokenId(Id id) const
|
||||
{
|
||||
TokenLocationCollection ret;
|
||||
|
||||
std::vector<Id> locationIds = m_graph.getTokenById(id)->getLocationIds();
|
||||
Token* token = m_graph.getTokenById(id);
|
||||
if (!token)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<Id> locationIds = token->getLocationIds();
|
||||
for (Id locationId: locationIds)
|
||||
{
|
||||
TokenLocation* location = m_locationCollection.findTokenLocationById(locationId);
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access);
|
||||
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName);
|
||||
|
||||
virtual void onInheritanceParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access);
|
||||
|
||||
void logGraph() const;
|
||||
void logLocations() const;
|
||||
|
||||
|
||||
@@ -93,6 +93,8 @@ std::string Edge::getTypeString() const
|
||||
return "has return type";
|
||||
case EDGE_PARAMETER_OF:
|
||||
return "has parameter of type";
|
||||
case EDGE_INHERITANCE:
|
||||
return "is derived from";
|
||||
default:
|
||||
LOG_ERROR("TypeString not implemented for edge type.");
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
|
||||
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access) = 0;
|
||||
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName) = 0;
|
||||
|
||||
virtual void onInheritanceParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access) = 0;
|
||||
};
|
||||
|
||||
#endif // PARSER_CLIENT_H
|
||||
|
||||
@@ -18,7 +18,7 @@ bool ASTVisitor::VisitTypedefDecl(const clang::TypedefDecl* declaration)
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onTypedefParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
declaration->getUnderlyingType().getAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
@@ -35,15 +35,28 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration)
|
||||
if (declaration->isClass())
|
||||
{
|
||||
m_client->onClassParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
|
||||
if (declaration->hasDefinition() && declaration->getNumBases())
|
||||
{
|
||||
for (const auto& it : declaration->bases())
|
||||
{
|
||||
m_client->onInheritanceParsed(
|
||||
getParseLocation(it.getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
getTypeName(it.getType()),
|
||||
convertAccessType(it.getAccessSpecifier())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (declaration->isStruct())
|
||||
{
|
||||
m_client->onStructParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
@@ -67,12 +80,15 @@ bool ASTVisitor::VisitVarDecl(clang::VarDecl* declaration)
|
||||
|
||||
if (access == clang::AS_none)
|
||||
{
|
||||
m_client->onGlobalVariableParsed(getParseLocation(declaration), getParseVariable(declaration));
|
||||
m_client->onGlobalVariableParsed(
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
getParseVariable(declaration)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_client->onFieldParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
getParseVariable(declaration),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
@@ -87,7 +103,7 @@ bool ASTVisitor::VisitFieldDecl(clang::FieldDecl* declaration)
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onFieldParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
getParseVariable(declaration),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
@@ -107,7 +123,7 @@ bool ASTVisitor::VisitFunctionDecl(clang::FunctionDecl* declaration)
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onFunctionParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
getTypeName(declaration->getReturnType()),
|
||||
getParameters(declaration)
|
||||
@@ -132,7 +148,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
|
||||
}
|
||||
|
||||
m_client->onMethodParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
getTypeName(declaration->getReturnType()),
|
||||
getParameters(declaration),
|
||||
@@ -150,7 +166,10 @@ bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration)
|
||||
{
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onNamespaceParsed(getParseLocation(declaration), declaration->getQualifiedNameAsString());
|
||||
m_client->onNamespaceParsed(
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -161,7 +180,7 @@ bool ASTVisitor::VisitEnumDecl(clang::EnumDecl* declaration)
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onEnumParsed(
|
||||
getParseLocation(declaration),
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
@@ -174,7 +193,10 @@ bool ASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* declaration)
|
||||
{
|
||||
if (hasValidLocation(declaration))
|
||||
{
|
||||
m_client->onEnumFieldParsed(getParseLocation(declaration), declaration->getQualifiedNameAsString());
|
||||
m_client->onEnumFieldParsed(
|
||||
getParseLocation(declaration->getSourceRange()),
|
||||
declaration->getQualifiedNameAsString()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -186,9 +208,8 @@ bool ASTVisitor::hasValidLocation(const clang::Decl* declaration) const
|
||||
return location.isValid() && m_context->getSourceManager().isWrittenInMainFile(location);
|
||||
}
|
||||
|
||||
ParseLocation ASTVisitor::getParseLocation(const clang::Decl* declaration) const
|
||||
ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange) const
|
||||
{
|
||||
const clang::SourceRange& sourceRange = declaration->getSourceRange();
|
||||
const clang::SourceManager& sourceManager = m_context->getSourceManager();
|
||||
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(sourceRange.getBegin());
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
// }
|
||||
|
||||
virtual bool VisitTypedefDecl(const clang::TypedefDecl* declaration); // typedefs
|
||||
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* declaration); // classes and structs
|
||||
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* declaration); // structs, classes and inheritance
|
||||
virtual bool VisitVarDecl(clang::VarDecl* declaration); // global variables and static fields
|
||||
virtual bool VisitFieldDecl(clang::FieldDecl* declaration); // fields
|
||||
virtual bool VisitFunctionDecl(clang::FunctionDecl* declaration); // functions
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
private:
|
||||
bool hasValidLocation(const clang::Decl* declaration) const;
|
||||
ParseLocation getParseLocation(const clang::Decl* declaration) const;
|
||||
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
|
||||
ParseVariable getParseVariable(clang::ValueDecl* declaration) const;
|
||||
std::vector<ParseVariable> getParameters(clang::FunctionDecl* declaration) const;
|
||||
std::string getTypeName(const clang::QualType& type) const;
|
||||
|
||||
@@ -477,6 +477,67 @@ public:
|
||||
TS_ASSERT_EQUALS(client->typedefs[0], "test::TestStruct -> globalTestStruct <5:1 5:26>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_public_inheritance()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
std::string text =
|
||||
"class A {};\n"
|
||||
"class B : public A {};\n";
|
||||
|
||||
parser.parseFile(TextAccess::createFromString(text));
|
||||
|
||||
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "B : public A <2:11 2:18>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_protected_inheritance()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
std::string text =
|
||||
"class A {};\n"
|
||||
"class B : protected A {};\n";
|
||||
|
||||
parser.parseFile(TextAccess::createFromString(text));
|
||||
|
||||
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "B : protected A <2:11 2:21>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_private_inheritance()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
std::string text =
|
||||
"class A {};\n"
|
||||
"class B : private A {};\n";
|
||||
|
||||
parser.parseFile(TextAccess::createFromString(text));
|
||||
|
||||
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "B : private A <2:11 2:19>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_multiple_inheritance()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
std::string text =
|
||||
"class A {};\n"
|
||||
"class B {};\n"
|
||||
"class C\n"
|
||||
" : public A\n"
|
||||
" , private B\n"
|
||||
"{};\n";
|
||||
|
||||
parser.parseFile(TextAccess::createFromString(text));
|
||||
|
||||
TS_ASSERT_EQUALS(client->inheritances.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "C : public A <4:4 4:11>");
|
||||
TS_ASSERT_EQUALS(client->inheritances[1], "C : private B <5:4 5:12>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_parses_multiple_files()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
@@ -569,6 +630,13 @@ private:
|
||||
enumFields.push_back(addLocationSuffix(fullName, location));
|
||||
}
|
||||
|
||||
virtual void onInheritanceParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access)
|
||||
{
|
||||
std::string str = fullName + " : " + addAccessPrefix(baseName, access);
|
||||
inheritances.push_back(addLocationSuffix(str, location));
|
||||
}
|
||||
|
||||
std::vector<std::string> typedefs;
|
||||
std::vector<std::string> classes;
|
||||
std::vector<std::string> enums;
|
||||
@@ -579,6 +647,7 @@ private:
|
||||
std::vector<std::string> methods;
|
||||
std::vector<std::string> namespaces;
|
||||
std::vector<std::string> structs;
|
||||
std::vector<std::string> inheritances;
|
||||
|
||||
private:
|
||||
std::string addAccessPrefix(const std::string& str, AccessType access)
|
||||
|
||||
Reference in New Issue
Block a user