data: Added CxxParser, currently only detecting classes

This change adds CxxParser a class for parsing cxx files. It holds basic functionality to detect classes using the clang
libTooling classes. CxxParser is derived from a common Parser interface, which can later be used for other language
parsers. The Parser forwards detected elements to a ParserClient interface, which is implemented by the Storage class.
The detected classes only get logged so far.

review id = 6

* bd3c63a - (HEAD, origin/class, class) applied second review <Eberhard Graether> (4 minutes ago)
* 3db7d93 - added missing files <Eberhard Graether> (4 days ago)
* 6d09f4e - applied review <Eberhard Graether> (4 days ago)
* d9d3e64 - fixed CMake files <Eberhard Graether> (4 days ago)
* f22a771 - only one Storage class <Eberhard Graether> (4 days ago)
* 6ee9553 - added tests <Eberhard Graether> (4 days ago)
* 0a525e8 - fixed includes <Eberhard Graether> (4 days ago)
* ca3fbb8 - added StorageManager as ParserClient <Eberhard Graether> (4 days ago)
* fa185a5 - renamed ParseLocation to ParseObject <Eberhard Graether> (4 days ago)
* 8b89808 - pass location with ParseLocation object <Eberhard Graether> (4 days ago)
* 548ae3c - renamed clang AST classes <Eberhard Graether> (4 days ago)
* d3b2caf - cleaned includes <Eberhard Graether> (4 days ago)
* f7fdf33 - removed using namespace stmts <Eberhard Graether> (4 days ago)
* 5378ef6 - using ParserClient <Eberhard Graether> (4 days ago)
* b9ce2f6 - working with test file <Eberhard Graether> (4 days ago)
* 5585abc - added CxxParser and ParserClient <Eberhard Graether> (4 days ago)
This commit is contained in:
Eberhard Graether
2014-05-06 14:50:51 +02:00
parent 6b82ea6860
commit 82c88ebd97
35 changed files with 436 additions and 156 deletions
-4
View File
@@ -7,12 +7,8 @@
#include "includes.h"
#include "qt/QtElementFactory.h"
#include "data/parser/clang.h"
int main(int argv, char **args)
{
clang_main(argv, args);
QApplication qtApp(argv, args);
std::shared_ptr<GuiElementFactory> elementFactory = std::make_shared<QtElementFactory>();
+2
View File
@@ -29,4 +29,6 @@ Application::~Application()
void Application::loadProject()
{
m_project = Project::create(m_codeAccess, m_graphAccess);
m_project->parseCode();
}
+18 -8
View File
@@ -1,8 +1,16 @@
add_files(
CLANG_FILES
data/parser/clang.cpp
data/parser/clang.h
data/parser/cxx/ASTAction.cpp
data/parser/cxx/ASTAction.h
data/parser/cxx/ASTActionFactory.cpp
data/parser/cxx/ASTActionFactory.h
data/parser/cxx/ASTConsumer.cpp
data/parser/cxx/ASTConsumer.h
data/parser/cxx/ASTVisitor.cpp
data/parser/cxx/ASTVisitor.h
data/parser/cxx/CxxParser.cpp
data/parser/cxx/CxxParser.h
)
add_files(
@@ -32,6 +40,12 @@ add_files(
data/access/GraphAccess.cpp
data/access/GraphAccess.h
data/parser/ParseObject.h
data/parser/Parser.cpp
data/parser/Parser.h
data/parser/ParserClient.cpp
data/parser/ParserClient.h
data/Edge.cpp
data/Edge.h
data/Element.cpp
@@ -40,22 +54,18 @@ add_files(
data/ElementIndex.h
data/Graph.cpp
data/Graph.h
data/GraphStorage.cpp
data/GraphStorage.h
data/Node.cpp
data/Node.h
data/Parser.cpp
data/Parser.h
data/SearchIndex.cpp
data/SearchIndex.h
data/Storage.cpp
data/Storage.h
data/TextLocation.cpp
data/TextLocation.h
data/TextLocationFile.cpp
data/TextLocationFile.h
data/TextLocationLine.cpp
data/TextLocationLine.h
data/TextLocationStorage.cpp
data/TextLocationStorage.h
gui/GuiElement.cpp
gui/GuiElement.h
+20 -2
View File
@@ -1,12 +1,21 @@
#include "Project.h"
#include <vector>
#include <string>
#include "data/parser/cxx/CxxParser.h"
std::shared_ptr<Project> Project::create(
const std::shared_ptr<CodeAccess>& codeAccess,
const std::shared_ptr<GraphAccess>& graphAccess)
std::shared_ptr<CodeAccess> codeAccess,
std::shared_ptr<GraphAccess> graphAccess
)
{
std::shared_ptr<Project> ptr(new Project());
ptr->m_codeAccess = codeAccess;
ptr->m_graphAccess = graphAccess;
ptr->m_storage = std::make_shared<Storage>();
return ptr;
}
@@ -22,3 +31,12 @@ const ProjectSettings& Project::getProjectSettings() const
{
return m_settings;
}
void Project::parseCode()
{
std::vector<std::string> filePaths;
filePaths.push_back("data/test_code.cpp");
CxxParser parser(m_storage);
parser.parseFiles(filePaths);
}
+8 -8
View File
@@ -5,34 +5,34 @@
#include "data/access/CodeAccess.h"
#include "data/access/GraphAccess.h"
#include "data/GraphStorage.h"
#include "data/Parser.h"
#include "data/Storage.h"
#include "ProjectSettings.h"
class Project
{
public:
static std::shared_ptr<Project> create(
const std::shared_ptr<CodeAccess>& codeAccess,
const std::shared_ptr<GraphAccess>& graphAccess);
std::shared_ptr<CodeAccess> codeAccess,
std::shared_ptr<GraphAccess> graphAccess
);
~Project();
const ProjectSettings& getProjectSettings() const;
void parseCode();
private:
Project();
Project(const Project&);
Project operator=(const Project&);
ProjectSettings m_settings;
std::shared_ptr<Parser> m_parser;
std::shared_ptr<GraphStorage> m_graphStorage;
std::shared_ptr<Storage> m_storage;
std::shared_ptr<CodeAccess> m_codeAccess;
std::shared_ptr<GraphAccess> m_graphAccess;
};
#endif // PROJECT_H
-1
View File
@@ -5,5 +5,4 @@ class Element
{
};
#endif // ELEMENT_H
-9
View File
@@ -1,9 +0,0 @@
#include "data/GraphStorage.h"
GraphStorage::GraphStorage()
{
}
GraphStorage::~GraphStorage()
{
}
-17
View File
@@ -1,17 +0,0 @@
#ifndef GRAPH_STORAGE_H
#define GRAPH_STORAGE_H
#include "data/Graph.h"
class GraphStorage
{
public:
GraphStorage();
~GraphStorage();
private:
Graph m_graph;
};
#endif // GRAPH_STORAGE_H
-5
View File
@@ -1,5 +0,0 @@
#include "data/Parser.h"
Parser::~Parser()
{
}
-10
View File
@@ -1,10 +0,0 @@
#ifndef PARSER_H
#define PARSER_H
class Parser
{
virtual ~Parser();
};
#endif // PARSER_H
+21
View File
@@ -0,0 +1,21 @@
#include "data/Storage.h"
#include <sstream>
#include "utility/logging/logging.h"
Storage::Storage()
{
}
Storage::~Storage()
{
}
void Storage::addClass(const ParseObject& object)
{
std::stringstream info;
info << "class " << object.name
<< " <" << object.fileName << " " << object.lineNumber << ":" << object.columnNumber << ">";
LOG_INFO(info.str());
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef STORAGE_H
#define STORAGE_H
#include <memory>
#include <vector>
#include "data/Graph.h"
#include "data/parser/ParserClient.h"
#include "data/TextLocationFile.h"
class Storage: public ParserClient
{
public:
Storage();
~Storage();
virtual void addClass(const ParseObject& object);
private:
Graph m_graph;
std::vector<std::shared_ptr<TextLocationFile> > m_textLocationFiles;
};
#endif // STORAGE_H
-9
View File
@@ -1,9 +0,0 @@
#include "data/TextLocationStorage.h"
TextLocationStorage::TextLocationStorage()
{
}
TextLocationStorage::~TextLocationStorage()
{
}
-19
View File
@@ -1,19 +0,0 @@
#ifndef TEXT_LOCATION_STORAGE_H
#define TEXT_LOCATION_STORAGE_H
#include <vector>
#include "data/TextLocationFile.h"
class TextLocationStorage
{
public:
TextLocationStorage();
~TextLocationStorage();
private:
std::vector<std::shared_ptr<TextLocationFile> > m_textLocationFiles;
};
#endif // TEXT_LOCATION_STORAGE_H
+25
View File
@@ -0,0 +1,25 @@
#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
+10
View File
@@ -0,0 +1,10 @@
#include "data/parser/Parser.h"
Parser::Parser(std::shared_ptr<ParserClient> client)
: m_client(client)
{
}
Parser::~Parser()
{
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef PARSER_H
#define PARSER_H
#include <memory>
#include <string>
#include <vector>
#include "data/parser/ParserClient.h"
class Parser
{
public:
Parser(std::shared_ptr<ParserClient> client);
virtual ~Parser();
virtual void parseFiles(const std::vector<std::string>& filePaths) = 0;
protected:
std::shared_ptr<ParserClient> m_client;
};
#endif // PARSER_H
+9
View File
@@ -0,0 +1,9 @@
#include "data/parser/ParserClient.h"
ParserClient::ParserClient()
{
}
ParserClient::~ParserClient()
{
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef PARSER_CLIENT_H
#define PARSER_CLIENT_H
#include <string>
#include "data/parser/ParseObject.h"
class ParserClient
{
public:
ParserClient();
virtual ~ParserClient();
virtual void addClass(const ParseObject& object) = 0;
};
#endif // PARSER_CLIENT_H
-58
View File
@@ -1,58 +0,0 @@
#include "clang.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
using namespace clang;
class FindNamedClassVisitor
: public RecursiveASTVisitor<FindNamedClassVisitor> {
public:
explicit FindNamedClassVisitor(ASTContext *Context)
: Context(Context) {}
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
if (Declaration->getQualifiedNameAsString() == "n::m::C") {
FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
if (FullLocation.isValid())
llvm::outs() << "Found declaration at "
<< FullLocation.getSpellingLineNumber() << ":"
<< FullLocation.getSpellingColumnNumber() << "\n";
}
return true;
}
private:
ASTContext *Context;
};
class FindNamedClassConsumer : public clang::ASTConsumer {
public:
explicit FindNamedClassConsumer(ASTContext *Context)
: Visitor(Context) {}
virtual void HandleTranslationUnit(clang::ASTContext &Context) {
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
}
private:
FindNamedClassVisitor Visitor;
};
class FindNamedClassAction : public clang::ASTFrontendAction {
public:
virtual clang::ASTConsumer *CreateASTConsumer(
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
return new FindNamedClassConsumer(&Compiler.getASTContext());
}
};
int clang_main(int argc, char **argv) {
if (argc > 1) {
clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]);
}
return 0;
}
-6
View File
@@ -1,6 +0,0 @@
#ifndef CLANG_MAIN_H
#define CLANG_MAIN_H
int clang_main(int argc, char **argv);
#endif // CLANG_MAIN_H
+15
View File
@@ -0,0 +1,15 @@
#include "data/parser/cxx/ASTAction.h"
ASTAction::ASTAction(std::shared_ptr<ParserClient> client)
: m_client(client)
{
}
ASTAction::~ASTAction()
{
}
clang::ASTConsumer* ASTAction::CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile)
{
return new ASTConsumer(&compiler.getASTContext(), m_client);
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef AST_ACTION_H
#define AST_ACTION_H
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "data/parser/cxx/ASTConsumer.h"
class ASTAction : public clang::ASTFrontendAction
{
public:
explicit ASTAction(std::shared_ptr<ParserClient> client);
virtual ~ASTAction();
virtual clang::ASTConsumer* CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile);
private:
std::shared_ptr<ParserClient> m_client;
};
#endif // AST_ACTION_H
@@ -0,0 +1,15 @@
#include "data/parser/cxx/ASTActionFactory.h"
ASTActionFactory::ASTActionFactory(std::shared_ptr<ParserClient> client)
: m_client(client)
{
}
ASTActionFactory::~ASTActionFactory()
{
}
clang::FrontendAction* ASTActionFactory::create()
{
return new ASTAction(m_client);
}
@@ -0,0 +1,20 @@
#ifndef AST_ACTION_FACTORY
#define AST_ACTION_FACTORY
#include "clang/Tooling/Tooling.h"
#include "data/parser/cxx/ASTAction.h"
class ASTActionFactory : public clang::tooling::FrontendActionFactory
{
public:
explicit ASTActionFactory(std::shared_ptr<ParserClient> client);
virtual ~ASTActionFactory();
virtual clang::FrontendAction* create();
private:
std::shared_ptr<ParserClient> m_client;
};
#endif // AST_ACTION_FACTORY
+15
View File
@@ -0,0 +1,15 @@
#include "data/parser/cxx/ASTConsumer.h"
ASTConsumer::ASTConsumer(clang::ASTContext* context, std::shared_ptr<ParserClient> client)
: m_visitor(context, client)
{
}
ASTConsumer::~ASTConsumer()
{
}
void ASTConsumer::HandleTranslationUnit(clang::ASTContext& context)
{
m_visitor.TraverseDecl(context.getTranslationUnitDecl());
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef AST_CONSUMER_H
#define AST_CONSUMER_H
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "data/parser/cxx/AstVisitor.h"
class ASTConsumer : public clang::ASTConsumer
{
public:
explicit ASTConsumer(clang::ASTContext* context, std::shared_ptr<ParserClient> client);
virtual ~ASTConsumer();
virtual void HandleTranslationUnit(clang::ASTContext& context);
private:
ASTVisitor m_visitor;
};
#endif // AST_CONSUMER_H
+30
View File
@@ -0,0 +1,30 @@
#include "data/parser/cxx/ASTVisitor.h"
ASTVisitor::ASTVisitor(clang::ASTContext* context, std::shared_ptr<ParserClient> client)
: m_context(context)
, m_client(client)
{
}
ASTVisitor::~ASTVisitor()
{
}
bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl *declaration)
{
clang::FullSourceLoc location = m_context->getFullLoc(declaration->getLocStart());
if (location.isValid() && m_context->getSourceManager().isWrittenInMainFile(location))
{
ParseObject parseObject(
declaration->getQualifiedNameAsString(),
m_context->getSourceManager().getFilename(location),
location.getSpellingLineNumber(),
location.getSpellingColumnNumber()
);
m_client->addClass(parseObject);
}
return true;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef AST_VISITOR_H
#define AST_VISITOR_H
#include <memory>
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "data/parser/ParserClient.h"
class ASTVisitor: public clang::RecursiveASTVisitor<ASTVisitor>
{
public:
ASTVisitor(clang::ASTContext* context, std::shared_ptr<ParserClient> client);
virtual ~ASTVisitor();
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *declaration);
private:
clang::ASTContext* m_context;
std::shared_ptr<ParserClient> m_client;
};
#endif // AST_VISITOR_H
+35
View File
@@ -0,0 +1,35 @@
#include "data/parser/cxx/CxxParser.h"
#include "data/parser/cxx/ASTActionFactory.h"
#include "utility/logging/logging.h"
CxxParser::CxxParser(std::shared_ptr<ParserClient> client)
: Parser(client)
{
}
CxxParser::~CxxParser()
{
}
void CxxParser::parseFiles(const std::vector<std::string>& filePaths)
{
const char* argv[] = { "app", "--" };
int argc = 2;
std::shared_ptr<clang::tooling::FixedCompilationDatabase> compilationDatabase(
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)
);
if (!compilationDatabase)
{
LOG_ERROR("Failed to load compilation database");
return;
}
clang::tooling::ClangTool tool(*compilationDatabase, filePaths);
ASTActionFactory actionFactory(m_client);
tool.run(&actionFactory);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef CXX_PARSER_H
#define CXX_PARSER_H
#include "data/parser/Parser.h"
class CxxParser: public Parser
{
public:
CxxParser(std::shared_ptr<ParserClient> client);
~CxxParser();
virtual void parseFiles(const std::vector<std::string>& filePaths);
};
#endif // CXX_PARSER_H
+1
View File
@@ -2,6 +2,7 @@ add_files(
TEST_FILES
ConfigManagerTestSuite.h
CxxParserTestSuite.h
LogManagerTestSuite.h
Vector2TestSuite.h
)
+34
View File
@@ -0,0 +1,34 @@
#include "cxxtest/TestSuite.h"
#include "data/parser/cxx/CxxParser.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;
};
class CxxParserTestSuite: public CxxTest::TestSuite
{
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);
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");
}
};