Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document type for the Clang parser #84

Merged
merged 3 commits into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions clang/include/bindgen_ast_consumer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class FunctionMatchHandler;

class BindgenASTConsumer : public clang::ASTConsumer {
public:
BindgenASTConsumer(std::vector<Macro> &macros, clang::CompilerInstance &compiler);
BindgenASTConsumer(Document &doc, clang::CompilerInstance &compiler);

~BindgenASTConsumer() override;

Expand All @@ -17,14 +17,12 @@ class BindgenASTConsumer : public clang::ASTConsumer {

void evaluateMacros(clang::ASTContext &ctx);
void serializeAndOutput();
void serializeEnumerations(JsonStream &stream);
void serializeClasses(JsonStream &stream);

clang::CompilerInstance &m_compiler;
std::vector<RecordMatchHandler *> m_classHandlers;
std::vector<EnumMatchHandler *> m_enumHandlers;
FunctionMatchHandler *m_functionHandler;
std::vector<Macro> &m_macros;
std::vector<std::unique_ptr<RecordMatchHandler>> m_classHandlers;
std::vector<std::unique_ptr<EnumMatchHandler>> m_enumHandlers;
std::unique_ptr<FunctionMatchHandler> m_functionHandler;
Document &m_document;
clang::ast_matchers::MatchFinder::MatchFinderOptions m_matchFinderOpts;
clang::ast_matchers::MatchFinder m_matchFinder;
};
Expand Down
2 changes: 1 addition & 1 deletion clang/include/bindgen_frontend_action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class BindgenFrontendAction : public clang::ASTFrontendAction {
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef file) override;

private:
std::vector<Macro> m_macros;
Document m_document;
};

#endif // BINDGEN_FRONTEND_ACTION_HPPd
5 changes: 2 additions & 3 deletions clang/include/enum_match_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

class EnumMatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
EnumMatchHandler(const std::string &name);

Enum enumeration() const;
EnumMatchHandler(Document &doc, const std::string &name);

virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override;

Expand All @@ -19,6 +17,7 @@ class EnumMatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback
void handleQFlagsType(const clang::ClassTemplateSpecializationDecl *tmpl);

private:
Document &m_document;
Enum m_enum;
};

Expand Down
7 changes: 2 additions & 5 deletions clang/include/function_match_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,16 @@ namespace clang {

class FunctionMatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
FunctionMatchHandler();
FunctionMatchHandler(Document &doc);
static bool isActive();

const std::vector<Method> &functions() const
{ return this->m_functions; };

virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override;
bool isFunctionInteresting(const std::string &name) const;
void runOnFunction(const clang::FunctionDecl *func);

private:
Document &m_document;
Regex m_regex;
std::vector<Method> m_functions;
};

#endif // FUNCTION_MATCH_HANDLER_HPP
23 changes: 20 additions & 3 deletions clang/include/helper.hpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
#ifndef HELPER_HPP
#define HELPER_HPP

#include <memory>

/* Pointer guard, which copies the instance on each copy.
* Useful to mark optional data.
*/
template< typename T >
struct CopyPtr {
T *ptr;
T *ptr = nullptr;

CopyPtr() : ptr(nullptr) { }
CopyPtr() = default;
CopyPtr(T *ptr) : ptr(ptr) { }
CopyPtr(const T &t) : ptr(new T(t)) { }
CopyPtr(const CopyPtr<T> &other) {
this->ptr = nullptr;
if (other.ptr) {
this->ptr = new T(*other.ptr);
}
}
CopyPtr(CopyPtr<T> &&other) : ptr(other.ptr) {
other.ptr = nullptr;
}

const T *operator=(const T *other) {
delete this->ptr;
Expand All @@ -40,6 +44,12 @@ struct CopyPtr {
return this->ptr != nullptr;
}

CopyPtr<T> &operator=(const CopyPtr<T> &other) {
delete this->ptr;
this->ptr = new T(*other.ptr);
return *this;
}

CopyPtr<T> &operator=(CopyPtr<T> &&other) {
delete this->ptr;
this->ptr = other.ptr;
Expand All @@ -58,4 +68,11 @@ struct CopyPtr {
const T &operator*() const { return *this->ptr; }
};

// compatibility for C++11
template< typename T, typename... Args >
std::unique_ptr<T> make_unique(Args&&... args)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future I don't think we'll want to support C++11 compilers. When I started this I think I had C++14-ish in mind, I think it's safe nowadays to move on to C++17. This will also enable us to use std::variant and std::optional in certain places.

{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

#endif // HELPER_HPP
16 changes: 16 additions & 0 deletions clang/include/json_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "helper.hpp"
#include <ostream>
#include <vector>
#include <map>

/* Simple stream writer for JSON data. */
class JsonStream {
Expand Down Expand Up @@ -50,6 +51,21 @@ class JsonStream {
return *this;
}

template< typename K, typename V >
JsonStream &operator<<(const std::map<K, V> &hash) {
bool first = true;
*this << ObjectBegin;

for (const auto &kv : hash) {
if (!first) *this << Comma;
*this << kv;
first = false;
}

*this << ObjectEnd;
return *this;
}

template< typename U, typename V >
JsonStream &operator<<(const std::pair<U, V> &pair) {
return *this << pair.first << Separator << pair.second;
Expand Down
6 changes: 3 additions & 3 deletions clang/include/preprocessor_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class PreprocessorHandler : public clang::PPCallbacks {
public:
PreprocessorHandler(std::vector<Macro> &macros, clang::Preprocessor &preprocessor);
PreprocessorHandler(Document &doc, clang::Preprocessor &preprocessor);

void MacroDefined(const clang::Token &token, const clang::MacroDirective *md) override;

Expand All @@ -15,8 +15,8 @@ class PreprocessorHandler : public clang::PPCallbacks {
bool initializeMacro(Macro &m, const clang::Token &token, const clang::MacroDirective *md);

clang::Preprocessor &m_preprocessor;
std::vector<Macro> &m_macros;
Regex m_regex;
Document &m_document;
Regex m_regex;
};

#endif // PREPROCESSOR_HANDLER_HPP
6 changes: 3 additions & 3 deletions clang/include/record_match_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

class RecordMatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
RecordMatchHandler(const std::string &name);

Class klass() const;
RecordMatchHandler(Document &doc, const std::string &name);

virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override;

Expand All @@ -20,7 +18,9 @@ class RecordMatchHandler : public clang::ast_matchers::MatchFinder::MatchCallbac
std::string getSourceFromRange(clang::SourceRange range, clang::SourceManager &sourceMgr);

BaseClass handleBaseClass(const clang::CXXBaseSpecifier &base);

private:
Document &m_document;
Class m_class;
};

Expand Down
9 changes: 9 additions & 0 deletions clang/include/structures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,13 @@ struct Macro {

JsonStream &operator<<(JsonStream &s, const Macro &value);

struct Document {
std::map<std::string, Enum> enums;
std::map<std::string, Class> classes;
std::vector<Method> functions;
std::vector<Macro> macros;
};

JsonStream &operator<<(JsonStream &s, const Document &value);

#endif // STRUCTURES_HPP
85 changes: 17 additions & 68 deletions clang/src/bindgen_ast_consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,45 @@
static llvm::cl::list<std::string> ClassList("c", llvm::cl::desc("Classes to inspect"), llvm::cl::value_desc("class"));
static llvm::cl::list<std::string> EnumList("e", llvm::cl::desc("Enums to inspect"), llvm::cl::value_desc("enum"));

BindgenASTConsumer::BindgenASTConsumer(std::vector<Macro> &macros, clang::CompilerInstance &compiler)
: m_compiler(compiler), m_functionHandler(nullptr), m_macros(macros), m_matchFinder(m_matchFinderOpts)
BindgenASTConsumer::BindgenASTConsumer(Document &doc, clang::CompilerInstance &compiler)
: m_compiler(compiler), m_functionHandler(nullptr), m_document(doc), m_matchFinder(m_matchFinderOpts)
{
using namespace clang::ast_matchers;

for (const std::string &className : ClassList) {
DeclarationMatcher classMatcher = cxxRecordDecl(isDefinition(), hasName(className)).bind("recordDecl");

RecordMatchHandler *handler = new RecordMatchHandler(className);
this->m_matchFinder.addMatcher(classMatcher, handler);
this->m_classHandlers.push_back(handler);
auto handler = make_unique<RecordMatchHandler>(m_document, className);
this->m_matchFinder.addMatcher(classMatcher, handler.get());
this->m_classHandlers.push_back(std::move(handler));
}

if (FunctionMatchHandler::isActive()) {
DeclarationMatcher funcMatcher = functionDecl(unless(hasParent(cxxRecordDecl()))).bind("functionDecl");
FunctionMatchHandler *handler = new FunctionMatchHandler();
this->m_matchFinder.addMatcher(funcMatcher, handler);
this->m_functionHandler = handler;
auto handler = make_unique<FunctionMatchHandler>(m_document);
this->m_matchFinder.addMatcher(funcMatcher, handler.get());
this->m_functionHandler = std::move(handler);
}

for (const std::string &enumName : EnumList) {
DeclarationMatcher enumMatcher = enumDecl(hasName(enumName)).bind("enumDecl");
DeclarationMatcher typedefMatcher = typedefNameDecl(hasName(enumName)).bind("typedefNameDecl");

EnumMatchHandler *handler = new EnumMatchHandler(enumName);
this->m_matchFinder.addMatcher(enumMatcher, handler);
this->m_matchFinder.addMatcher(typedefMatcher, handler);
this->m_enumHandlers.push_back(handler);
auto handler = make_unique<EnumMatchHandler>(m_document, enumName);
this->m_matchFinder.addMatcher(enumMatcher, handler.get());
this->m_matchFinder.addMatcher(typedefMatcher, handler.get());
this->m_enumHandlers.push_back(std::move(handler));
}
}

BindgenASTConsumer::~BindgenASTConsumer() {
for (RecordMatchHandler *handler : this->m_classHandlers) {
delete handler;
}
}

void BindgenASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
this->m_matchFinder.matchAST(ctx);
// FIXME: clang segfaults in 6 or newer when calling ParseAST in destructor
this->evaluateMacros(ctx);
this->serializeAndOutput();
this->serializeAndOutput();
}

static std::string buildMacroEvaluationFile(const std::vector<Macro> &macros) {
Expand All @@ -70,8 +67,8 @@ static std::string buildMacroEvaluationFile(const std::vector<Macro> &macros) {

void BindgenASTConsumer::evaluateMacros(clang::ASTContext &ctx) {
clang::SourceManager &sourceMgr = this->m_compiler.getSourceManager();
MacroAstConsumer *consumer = new MacroAstConsumer(this->m_macros);
std::string evalFile = buildMacroEvaluationFile(this->m_macros);
MacroAstConsumer *consumer = new MacroAstConsumer(this->m_document.macros);
std::string evalFile = buildMacroEvaluationFile(this->m_document.macros);

clang::FileID macroFile = sourceMgr.createFileID(llvm::MemoryBuffer::getMemBuffer(evalFile));
sourceMgr.setMainFileID(macroFile);
Expand All @@ -82,57 +79,9 @@ void BindgenASTConsumer::evaluateMacros(clang::ASTContext &ctx) {

void BindgenASTConsumer::serializeAndOutput() {
JsonStream stream(std::cout);

stream << JsonStream::ObjectBegin; // {
stream << "enums" << JsonStream::Separator; // "enums":
serializeEnumerations(stream); // { ... }
stream << JsonStream::Comma; // ,
stream << "classes" << JsonStream::Separator; // "classes":
serializeClasses(stream); // { ... }
stream << JsonStream::Comma; // ,

if (this->m_functionHandler) { // "functions": [ ... ],
stream
<< "functions" << JsonStream::Separator
<< this->m_functionHandler->functions()
<< JsonStream::Comma;
}

stream << "macros" << JsonStream::Separator << this->m_macros; // "macros": [ ... ]
stream << JsonStream::ObjectEnd; // }
stream << this->m_document;
std::cout << std::endl;

// FIXME: Currently the process crashes during clang's Parser destructor. This is a workaround.
exit(0);
}

void BindgenASTConsumer::serializeEnumerations(JsonStream &stream) {
stream << JsonStream::ObjectBegin;

bool first = true;
for (EnumMatchHandler *handler : this->m_enumHandlers) {
Enum enumeration = handler->enumeration();

if (!first) stream << JsonStream::Comma;
stream << std::make_pair(enumeration.name, enumeration);

first = false;
}

stream << JsonStream::ObjectEnd;
}

void BindgenASTConsumer::serializeClasses(JsonStream &stream) {
stream << JsonStream::ObjectBegin;

bool first = true;
for (RecordMatchHandler *handler : this->m_classHandlers) {
Class klass = handler->klass();

if (!first) stream << JsonStream::Comma;
stream << std::make_pair(klass.name, klass);

first = false;
}

stream << JsonStream::ObjectEnd;
}
12 changes: 2 additions & 10 deletions clang/src/bindgen_frontend_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,10 @@ bool BindgenFrontendAction::BeginSourceFileAction(clang::CompilerInstance &ci)
#endif
{
clang::Preprocessor &preprocessor = ci.getPreprocessor();
#if __clang_major__ >= 10
preprocessor.addPPCallbacks(std::make_unique<PreprocessorHandler>(this->m_macros, preprocessor));
#else
preprocessor.addPPCallbacks(llvm::make_unique<PreprocessorHandler>(this->m_macros, preprocessor));
#endif
preprocessor.addPPCallbacks(make_unique<PreprocessorHandler>(this->m_document, preprocessor));
return true;
}

std::unique_ptr<clang::ASTConsumer> BindgenFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef file) {
#if __clang_major__ >= 10
return std::make_unique<BindgenASTConsumer>(this->m_macros, ci);
#else
return llvm::make_unique<BindgenASTConsumer>(this->m_macros, ci);
#endif
return make_unique<BindgenASTConsumer>(this->m_document, ci);
}
10 changes: 5 additions & 5 deletions clang/src/enum_match_handler.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#include "common.hpp"
#include "enum_match_handler.hpp"

EnumMatchHandler::EnumMatchHandler(const std::string &name) {
EnumMatchHandler::EnumMatchHandler(Document &doc, const std::string &name)
: m_document(doc)
{
this->m_enum.name = name;
}

Enum EnumMatchHandler::enumeration() const {
return this->m_enum;
}

void EnumMatchHandler::run(const clang::ast_matchers::MatchFinder::MatchResult &Result) {
const clang::EnumDecl *enumeration = Result.Nodes.getNodeAs<clang::EnumDecl>("enumDecl");
const clang::TypedefNameDecl *typeDecl = Result.Nodes.getNodeAs<clang::TypedefNameDecl>("typedefNameDecl");
Expand All @@ -25,6 +23,8 @@ void EnumMatchHandler::runOnEnum(const clang::EnumDecl *enumeration) {
int64_t value = field->getInitVal().getExtValue();
this->m_enum.values.push_back(std::make_pair(name, value));
}

this->m_document.enums[this->m_enum.name] = this->m_enum;
}

void EnumMatchHandler::runOnTypedef(const clang::TypedefNameDecl *typeDecl) {
Expand Down
Loading