data: Extended CxxParser to detect elements
Detects most elements in the code, currently classes, structs, global variables, fields, functions, methods, namespaces and enums. The structs ParseLocation and ParseVariable are helper objects to transmit information to the ParserClient. Currently the parsed information only gets logged in the Storage. review id = 15 fortune cookie message = In dreams and in life, nothing is impossible.
This commit is contained in:
+51
-2
@@ -1,12 +1,61 @@
|
||||
#include "test_header.h"
|
||||
|
||||
char* name;
|
||||
H g;
|
||||
|
||||
int ceil(float a)
|
||||
{
|
||||
return static_cast<int>(a) + 1;
|
||||
}
|
||||
|
||||
namespace X
|
||||
{
|
||||
class A;
|
||||
struct A;
|
||||
|
||||
enum E
|
||||
{
|
||||
P,
|
||||
Q
|
||||
};
|
||||
}
|
||||
|
||||
class B
|
||||
{
|
||||
public:
|
||||
class C;
|
||||
class C
|
||||
{
|
||||
static const int amount;
|
||||
};
|
||||
|
||||
B();
|
||||
|
||||
virtual ~B()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void process() = 0;
|
||||
|
||||
private:
|
||||
int getCount() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
const int count;
|
||||
H h;
|
||||
};
|
||||
|
||||
B::B()
|
||||
: count(0)
|
||||
{
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
int sum(int a, int b)
|
||||
{
|
||||
int c = a + b;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
class H;
|
||||
class H
|
||||
{
|
||||
private:
|
||||
int width;
|
||||
};
|
||||
|
||||
@@ -42,11 +42,14 @@ add_files(
|
||||
data/access/GraphAccess.cpp
|
||||
data/access/GraphAccess.h
|
||||
|
||||
data/parser/ParseObject.h
|
||||
data/parser/ParseLocation.cpp
|
||||
data/parser/ParseLocation.h
|
||||
data/parser/Parser.cpp
|
||||
data/parser/Parser.h
|
||||
data/parser/ParserClient.cpp
|
||||
data/parser/ParserClient.h
|
||||
data/parser/ParseVariable.cpp
|
||||
data/parser/ParseVariable.h
|
||||
|
||||
data/Edge.cpp
|
||||
data/Edge.h
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/parser/ParseVariable.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
Storage::Storage()
|
||||
@@ -12,10 +14,61 @@ Storage::~Storage()
|
||||
{
|
||||
}
|
||||
|
||||
void Storage::addClass(const ParseObject& object)
|
||||
void Storage::onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
log("class", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
log("struct", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable)
|
||||
{
|
||||
log("global", variable.fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access)
|
||||
{
|
||||
log("field", variable.fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onFunctionParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters
|
||||
)
|
||||
{
|
||||
log("function", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onMethodParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters, AccessType access, AbstractionType abstraction,
|
||||
bool isConst, bool isStatic
|
||||
)
|
||||
{
|
||||
log("method", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onNamespaceParsed(const ParseLocation& location, const std::string& fullName)
|
||||
{
|
||||
log("namespace", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
log("enum", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::onEnumFieldParsed(const ParseLocation& location, const std::string& fullName)
|
||||
{
|
||||
log("enum field", fullName, location);
|
||||
}
|
||||
|
||||
void Storage::log(std::string type, std::string str, const ParseLocation& location) const
|
||||
{
|
||||
std::stringstream info;
|
||||
info << "class " << object.name
|
||||
<< " <" << object.fileName << " " << object.lineNumber << ":" << object.columnNumber << ">";
|
||||
info << type << ": " << str << " <" << location.file << " " << location.line << ":" << location.column << ">";
|
||||
LOG_INFO(info.str());
|
||||
}
|
||||
|
||||
+21
-2
@@ -12,11 +12,30 @@ class Storage: public ParserClient
|
||||
{
|
||||
public:
|
||||
Storage();
|
||||
~Storage();
|
||||
virtual ~Storage();
|
||||
|
||||
virtual void addClass(const ParseObject& object);
|
||||
virtual void onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access);
|
||||
virtual void onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access);
|
||||
|
||||
virtual void onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable);
|
||||
virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access);
|
||||
|
||||
virtual void onFunctionParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters);
|
||||
virtual void onMethodParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters, AccessType access, AbstractionType abstraction,
|
||||
bool isConst, bool isStatic);
|
||||
|
||||
virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName);
|
||||
|
||||
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access);
|
||||
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName);
|
||||
|
||||
private:
|
||||
void log(std::string type, std::string str, const ParseLocation& location) const;
|
||||
|
||||
Graph m_graph;
|
||||
|
||||
std::vector<std::shared_ptr<TextLocationFile> > m_textLocationFiles;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "data/parser/ParseLocation.h"
|
||||
|
||||
ParseLocation::ParseLocation(const std::string& file, unsigned int line, unsigned int column)
|
||||
: file(file)
|
||||
, line(line)
|
||||
, column(column)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef PARSE_LOCATION_H
|
||||
#define PARSE_LOCATION_H
|
||||
|
||||
#include <string>
|
||||
|
||||
struct ParseLocation
|
||||
{
|
||||
ParseLocation(const std::string& file, unsigned int line, unsigned int column);
|
||||
|
||||
const std::string file;
|
||||
const unsigned int line;
|
||||
const unsigned int column;
|
||||
};
|
||||
|
||||
#endif // PARSE_LOCATION_H
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef PARSE_OBJECT_H
|
||||
#define PARSE_OBJECT_H
|
||||
|
||||
struct ParseObject
|
||||
{
|
||||
ParseObject(
|
||||
const std::string& name,
|
||||
const std::string& fileName,
|
||||
unsigned int lineNumber,
|
||||
unsigned int columnNumber
|
||||
)
|
||||
: name(name)
|
||||
, fileName(fileName)
|
||||
, lineNumber(lineNumber)
|
||||
, columnNumber(columnNumber)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string name;
|
||||
const std::string fileName;
|
||||
const unsigned int lineNumber;
|
||||
const unsigned int columnNumber;
|
||||
};
|
||||
|
||||
#endif // PARSE_OBJECT_H
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "data/parser/ParseVariable.h"
|
||||
|
||||
ParseVariable::ParseVariable(const std::string& typeName, const std::string& fullName, bool isConst, bool isStatic)
|
||||
: typeName(typeName)
|
||||
, fullName(fullName)
|
||||
, isConst(isConst)
|
||||
, isStatic(isStatic)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef PARSE_VARIABLE_H
|
||||
#define PARSE_VARIABLE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
struct ParseVariable
|
||||
{
|
||||
ParseVariable(const std::string& typeName, const std::string& fullName, bool isConst, bool isStatic);
|
||||
|
||||
const std::string typeName;
|
||||
const std::string fullName;
|
||||
const bool isConst;
|
||||
const bool isStatic;
|
||||
};
|
||||
|
||||
#endif // PARSE_VARIABLE_H
|
||||
@@ -2,16 +2,47 @@
|
||||
#define PARSER_CLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "data/parser/ParseObject.h"
|
||||
struct ParseLocation;
|
||||
struct ParseVariable;
|
||||
|
||||
class ParserClient
|
||||
{
|
||||
public:
|
||||
enum AccessType {
|
||||
ACCESS_PUBLIC,
|
||||
ACCESS_PROTECTED,
|
||||
ACCESS_PRIVATE,
|
||||
ACCESS_NONE
|
||||
};
|
||||
|
||||
enum AbstractionType {
|
||||
ABSTRACTION_VIRTUAL,
|
||||
ABSTRACTION_PURE_VIRTUAL,
|
||||
ABSTRACTION_NONE
|
||||
};
|
||||
|
||||
ParserClient();
|
||||
virtual ~ParserClient();
|
||||
|
||||
virtual void addClass(const ParseObject& object) = 0;
|
||||
virtual void onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access) = 0;
|
||||
virtual void onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access) = 0;
|
||||
|
||||
virtual void onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable) = 0;
|
||||
virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access) = 0;
|
||||
|
||||
virtual void onFunctionParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters) = 0;
|
||||
virtual void onMethodParsed(const ParseLocation& location, const std::string& fullName,
|
||||
const std::string& returnTypeName, const std::vector<ParseVariable>& parameters, AccessType access,
|
||||
AbstractionType abstraction, bool isConst, bool isStatic) = 0;
|
||||
|
||||
virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName) = 0;
|
||||
|
||||
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access) = 0;
|
||||
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName) = 0;
|
||||
};
|
||||
|
||||
#endif // PARSER_CLIENT_H
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "data/parser/cxx/ASTVisitor.h"
|
||||
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/parser/ParseVariable.h"
|
||||
|
||||
ASTVisitor::ASTVisitor(clang::ASTContext* context, std::shared_ptr<ParserClient> client)
|
||||
: m_context(context)
|
||||
, m_client(client)
|
||||
@@ -10,21 +13,250 @@ ASTVisitor::~ASTVisitor()
|
||||
{
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl *declaration)
|
||||
bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration)
|
||||
{
|
||||
clang::FullSourceLoc location = m_context->getFullLoc(declaration->getLocStart());
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (location.isValid() && m_context->getSourceManager().isWrittenInMainFile(location))
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
ParseObject parseObject(
|
||||
declaration->getQualifiedNameAsString(),
|
||||
m_context->getSourceManager().getFilename(location),
|
||||
location.getSpellingLineNumber(),
|
||||
location.getSpellingColumnNumber()
|
||||
);
|
||||
|
||||
m_client->addClass(parseObject);
|
||||
if (declaration->isClass())
|
||||
{
|
||||
m_client->onClassParsed(
|
||||
getParseLocation(location),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
}
|
||||
else if (declaration->isStruct())
|
||||
{
|
||||
m_client->onStructParsed(
|
||||
getParseLocation(location),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitVarDecl(clang::VarDecl* declaration)
|
||||
{
|
||||
// Abort on local variables and parameters.
|
||||
if (declaration->isFunctionOrMethodVarDecl() || clang::isa<clang::ParmVarDecl>(declaration))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
clang::AccessSpecifier access = declaration->getAccess();
|
||||
|
||||
if (access == clang::AS_none)
|
||||
{
|
||||
m_client->onGlobalVariableParsed(getParseLocation(location), getParseVariable(declaration));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_client->onFieldParsed(
|
||||
getParseLocation(location),
|
||||
getParseVariable(declaration),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitFieldDecl(clang::FieldDecl* declaration)
|
||||
{
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
m_client->onFieldParsed(
|
||||
getParseLocation(location),
|
||||
getParseVariable(declaration),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitFunctionDecl(clang::FunctionDecl* declaration)
|
||||
{
|
||||
// Abort for CXXMethodDecls to avoid duplicate call.
|
||||
if (clang::isa<clang::CXXMethodDecl>(declaration))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
m_client->onFunctionParsed(
|
||||
getParseLocation(location),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
getTypeName(declaration->getReturnType()),
|
||||
getParameters(declaration)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
|
||||
{
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE;
|
||||
if (declaration->isPure())
|
||||
{
|
||||
abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL;
|
||||
}
|
||||
else if (declaration->isVirtual())
|
||||
{
|
||||
abstraction = ParserClient::ABSTRACTION_VIRTUAL;
|
||||
}
|
||||
|
||||
m_client->onMethodParsed(
|
||||
getParseLocation(location),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
getTypeName(declaration->getReturnType()),
|
||||
getParameters(declaration),
|
||||
convertAccessType(declaration->getAccess()),
|
||||
abstraction,
|
||||
declaration->isConst(),
|
||||
declaration->isStatic()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration)
|
||||
{
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
m_client->onNamespaceParsed(getParseLocation(location), declaration->getQualifiedNameAsString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitEnumDecl(clang::EnumDecl* declaration)
|
||||
{
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
m_client->onEnumParsed(
|
||||
getParseLocation(location),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
convertAccessType(declaration->getAccess())
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* declaration)
|
||||
{
|
||||
const clang::SourceLocation& location = declaration->getLocStart();
|
||||
|
||||
if (isValidLocation(location))
|
||||
{
|
||||
m_client->onEnumFieldParsed(getParseLocation(location), declaration->getQualifiedNameAsString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTVisitor::isValidLocation(const clang::SourceLocation& location) const
|
||||
{
|
||||
return location.isValid() && m_context->getSourceManager().isWrittenInMainFile(location);
|
||||
}
|
||||
|
||||
ParseLocation ASTVisitor::getParseLocation(const clang::SourceLocation& location) const
|
||||
{
|
||||
clang::FullSourceLoc fullLocation = m_context->getFullLoc(location);
|
||||
return ParseLocation(
|
||||
m_context->getSourceManager().getFilename(location),
|
||||
fullLocation.getSpellingLineNumber(),
|
||||
fullLocation.getSpellingColumnNumber()
|
||||
);
|
||||
}
|
||||
|
||||
ParseVariable ASTVisitor::getParseVariable(clang::ValueDecl* declaration) const
|
||||
{
|
||||
clang::QualType type = declaration->getType();
|
||||
|
||||
bool isStatic = false;
|
||||
if (clang::isa<clang::VarDecl>(declaration))
|
||||
{
|
||||
isStatic = static_cast<clang::VarDecl*>(declaration)->isStaticDataMember();
|
||||
}
|
||||
|
||||
return ParseVariable(
|
||||
getTypeName(type),
|
||||
declaration->getQualifiedNameAsString(),
|
||||
type.isConstQualified(),
|
||||
isStatic
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<ParseVariable> ASTVisitor::getParameters(clang::FunctionDecl* declaration) const
|
||||
{
|
||||
std::vector<ParseVariable> parameters;
|
||||
|
||||
for (unsigned i = 0; i < declaration->getNumParams(); i++)
|
||||
{
|
||||
parameters.push_back(getParseVariable(declaration->getParamDecl(i)));
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
std::string ASTVisitor::getTypeName(const clang::QualType& type) const
|
||||
{
|
||||
std::string typeName = type.getUnqualifiedType().getAsString();
|
||||
|
||||
// Remove keywords from type.
|
||||
std::string keyword;
|
||||
size_t pos = typeName.find_first_of(' ');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
keyword = typeName.substr(0, pos);
|
||||
}
|
||||
|
||||
if (keyword == "class" || keyword == "struct" || keyword == "enum")
|
||||
{
|
||||
typeName = typeName.substr(pos + 1);
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
ParserClient::AccessType ASTVisitor::convertAccessType(clang::AccessSpecifier access) const
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case clang::AS_public:
|
||||
return ParserClient::ACCESS_PUBLIC;
|
||||
case clang::AS_protected:
|
||||
return ParserClient::ACCESS_PROTECTED;
|
||||
case clang::AS_private:
|
||||
return ParserClient::ACCESS_PRIVATE;
|
||||
case clang::AS_none:
|
||||
return ParserClient::ACCESS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,31 @@ public:
|
||||
ASTVisitor(clang::ASTContext* context, std::shared_ptr<ParserClient> client);
|
||||
virtual ~ASTVisitor();
|
||||
|
||||
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *declaration);
|
||||
// Left for debugging purposes. Uncomment to see a colored ast-dump of the parsed file.
|
||||
// virtual bool VisitDecl(clang::Decl* declaration)
|
||||
// {
|
||||
// // declaration->print(llvm::outs());
|
||||
// declaration->dump();
|
||||
// return false;
|
||||
// }
|
||||
|
||||
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* declaration); // classes and structs
|
||||
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
|
||||
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl* declaration); // methods
|
||||
virtual bool VisitNamespaceDecl(clang::NamespaceDecl* declaration); // namespaces
|
||||
virtual bool VisitEnumDecl(clang::EnumDecl* declaration); // enums
|
||||
virtual bool VisitEnumConstantDecl(clang::EnumConstantDecl* declaration); // enum fields
|
||||
|
||||
private:
|
||||
bool isValidLocation(const clang::SourceLocation& location) const;
|
||||
ParseLocation getParseLocation(const clang::SourceLocation& location) const;
|
||||
ParseVariable getParseVariable(clang::ValueDecl* declaration) const;
|
||||
std::vector<ParseVariable> getParameters(clang::FunctionDecl* declaration) const;
|
||||
std::string getTypeName(const clang::QualType& type) const;
|
||||
ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const;
|
||||
|
||||
clang::ASTContext* m_context;
|
||||
std::shared_ptr<ParserClient> m_client;
|
||||
};
|
||||
|
||||
@@ -14,8 +14,10 @@ CxxParser::~CxxParser()
|
||||
|
||||
void CxxParser::parseFiles(const std::vector<std::string>& filePaths)
|
||||
{
|
||||
const char* argv[] = { "app", "--" };
|
||||
int argc = 2;
|
||||
// Fake commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool.
|
||||
// The option '-x c++' treats subsequent input files as C++.
|
||||
const char* argv[] = { "app", "--", "-x", "c++" };
|
||||
int argc = 4;
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> compilationDatabase(
|
||||
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)
|
||||
|
||||
+250
-18
@@ -1,18 +1,9 @@
|
||||
#include "cxxtest/TestSuite.h"
|
||||
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/parser/ParserClient.h"
|
||||
|
||||
class TestParserClient: public ParserClient
|
||||
{
|
||||
public:
|
||||
virtual void addClass(const ParseObject& object)
|
||||
{
|
||||
classes.push_back(object.name);
|
||||
}
|
||||
|
||||
std::vector<std::string> classes;
|
||||
};
|
||||
#include "data/parser/ParseVariable.h"
|
||||
|
||||
class CxxParserTestSuite: public CxxTest::TestSuite
|
||||
{
|
||||
@@ -20,15 +11,256 @@ public:
|
||||
void test_cxx_parser_finds_classes()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
|
||||
std::vector<std::string> filePaths;
|
||||
filePaths.push_back("data/test_code.cpp");
|
||||
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->classes[0], "X::A");
|
||||
TS_ASSERT_EQUALS(client->classes[1], "B");
|
||||
TS_ASSERT_EQUALS(client->classes[2], "B::C");
|
||||
TS_ASSERT_EQUALS(client->classes.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->classes[0], "B");
|
||||
TS_ASSERT_EQUALS(client->classes[1], "public B::C");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_structs()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->structs[0], "X::A");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_globals()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->globals.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->globals[0], "char * name");
|
||||
TS_ASSERT_EQUALS(client->globals[1], "H g");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_fields()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->fields.size(), 3);
|
||||
TS_ASSERT_EQUALS(client->fields[0], "private static const int B::C::amount");
|
||||
TS_ASSERT_EQUALS(client->fields[1], "private const int B::count");
|
||||
TS_ASSERT_EQUALS(client->fields[2], "private H B::h");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_functions()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->functions.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->functions[0], "int ceil(float a)");
|
||||
TS_ASSERT_EQUALS(client->functions[1], "int (anonymous namespace)::sum(int a, int b)");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_methods()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->methods.size(), 5);
|
||||
TS_ASSERT_EQUALS(client->methods[0], "public void B::B()");
|
||||
TS_ASSERT_EQUALS(client->methods[1], "public virtual void B::~B()");
|
||||
TS_ASSERT_EQUALS(client->methods[2], "protected pure virtual void B::process()");
|
||||
TS_ASSERT_EQUALS(client->methods[3], "private int B::getCount() const");
|
||||
TS_ASSERT_EQUALS(client->methods[4], "public void B::B()");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_namespaces()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->namespaces.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->namespaces[0], "X");
|
||||
TS_ASSERT_EQUALS(client->namespaces[1], "(anonymous)");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_enums()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->enums.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->enums[0], "X::E");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_enum_fields()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
||||
CxxParser parser(client);
|
||||
|
||||
std::vector<std::string> filePaths(1, "data/test_code.cpp");
|
||||
parser.parseFiles(filePaths);
|
||||
|
||||
TS_ASSERT_EQUALS(client->enumFields.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->enumFields[0], "X::E::P");
|
||||
TS_ASSERT_EQUALS(client->enumFields[1], "X::E::Q");
|
||||
}
|
||||
|
||||
private:
|
||||
class TestParserClient: public ParserClient
|
||||
{
|
||||
public:
|
||||
virtual void onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
classes.push_back(addAccessPrefix(fullName, access));
|
||||
}
|
||||
|
||||
virtual void onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
structs.push_back(addAccessPrefix(fullName, access));
|
||||
}
|
||||
|
||||
virtual void onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable)
|
||||
{
|
||||
globals.push_back(variableStr(variable));
|
||||
}
|
||||
|
||||
virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access)
|
||||
{
|
||||
fields.push_back(addAccessPrefix(variableStr(variable), access));
|
||||
}
|
||||
|
||||
virtual void onFunctionParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters
|
||||
)
|
||||
{
|
||||
functions.push_back(returnTypeName + " " + fullName + parameterStr(parameters));
|
||||
}
|
||||
|
||||
virtual void onMethodParsed(
|
||||
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
||||
const std::vector<ParseVariable>& parameters, AccessType access, AbstractionType abstraction,
|
||||
bool isConst, bool isStatic
|
||||
)
|
||||
{
|
||||
std::string str = returnTypeName + " " + fullName + parameterStr(parameters);
|
||||
str = addStaticPrefix(addAbstractionPrefix(str, abstraction), isStatic);
|
||||
str = addConstPrefix(addAccessPrefix(str, access), isConst, false);
|
||||
methods.push_back(str);
|
||||
}
|
||||
|
||||
virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName)
|
||||
{
|
||||
namespaces.push_back(fullName);
|
||||
}
|
||||
|
||||
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
||||
{
|
||||
enums.push_back(addAccessPrefix(fullName, access));
|
||||
}
|
||||
|
||||
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName)
|
||||
{
|
||||
enumFields.push_back(fullName);
|
||||
}
|
||||
|
||||
std::vector<std::string> classes;
|
||||
std::vector<std::string> enums;
|
||||
std::vector<std::string> enumFields;
|
||||
std::vector<std::string> functions;
|
||||
std::vector<std::string> fields;
|
||||
std::vector<std::string> globals;
|
||||
std::vector<std::string> methods;
|
||||
std::vector<std::string> namespaces;
|
||||
std::vector<std::string> structs;
|
||||
|
||||
private:
|
||||
std::string addAccessPrefix(const std::string& str, AccessType access)
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case ACCESS_PUBLIC:
|
||||
return "public " + str;
|
||||
case ACCESS_PROTECTED:
|
||||
return "protected " + str;
|
||||
case ACCESS_PRIVATE:
|
||||
return "private " + str;
|
||||
case ACCESS_NONE:
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction)
|
||||
{
|
||||
switch (abstraction)
|
||||
{
|
||||
case ABSTRACTION_VIRTUAL:
|
||||
return "virtual " + str;
|
||||
case ABSTRACTION_PURE_VIRTUAL:
|
||||
return "pure virtual " + str;
|
||||
case ABSTRACTION_NONE:
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
std::string addStaticPrefix(const std::string& str, bool isStatic)
|
||||
{
|
||||
if (isStatic)
|
||||
{
|
||||
return "static " + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string addConstPrefix(const std::string& str, bool isConst, bool atFront)
|
||||
{
|
||||
if (isConst)
|
||||
{
|
||||
return atFront ? "const " + str : str + " const";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string variableStr(const ParseVariable& variable)
|
||||
{
|
||||
std::string str = variable.typeName + " " + variable.fullName;
|
||||
return addStaticPrefix(addConstPrefix(str, variable.isConst, true), variable.isStatic);
|
||||
}
|
||||
|
||||
std::string parameterStr(const std::vector<ParseVariable> parameters)
|
||||
{
|
||||
std::string str = "(";
|
||||
for (size_t i = 0; i < parameters.size(); i++)
|
||||
{
|
||||
str += variableStr(parameters[i]);
|
||||
if (i < parameters.size() - 1)
|
||||
{
|
||||
str += ", ";
|
||||
}
|
||||
}
|
||||
return str + ")";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user