Add libclang parsing outline
This commit is contained in:
parent
2e1dce2ffd
commit
51f7c3c2b2
3 changed files with 173 additions and 4 deletions
|
|
@ -5,7 +5,9 @@
|
||||||
#include <cppast/libclang_parser.hpp>
|
#include <cppast/libclang_parser.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libclang_visitor.hpp"
|
||||||
#include "raii_wrapper.hpp"
|
#include "raii_wrapper.hpp"
|
||||||
#include "preprocessor.hpp"
|
#include "preprocessor.hpp"
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ const std::vector<std::string>& detail::libclang_compile_config_access::flags(
|
||||||
libclang_compile_config::libclang_compile_config() : compile_config({})
|
libclang_compile_config::libclang_compile_config() : compile_config({})
|
||||||
{
|
{
|
||||||
set_clang_binary("clang++");
|
set_clang_binary("clang++");
|
||||||
|
add_include_dir(LIBCLANG_SYSTEM_INCLUDE_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void libclang_compile_config::do_set_flags(cpp_standard standard,
|
void libclang_compile_config::do_set_flags(cpp_standard standard,
|
||||||
|
|
@ -92,7 +95,7 @@ struct libclang_parser::impl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
libclang_parser::libclang_parser()
|
libclang_parser::libclang_parser() : pimpl_(new impl)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,18 +103,65 @@ libclang_parser::~libclang_parser() noexcept
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::vector<const char*> get_arguments(const libclang_compile_config& config)
|
||||||
|
{
|
||||||
|
std::vector<const char*> args = {"-x", "c++"}; // force C++
|
||||||
|
for (auto& flag : detail::libclang_compile_config_access::flags(config))
|
||||||
|
args.push_back(flag.c_str());
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::cxtranslation_unit get_cxunit(const detail::cxindex& idx,
|
||||||
|
const libclang_compile_config& config, const char* path,
|
||||||
|
const std::string& source)
|
||||||
|
{
|
||||||
|
CXUnsavedFile file;
|
||||||
|
file.Filename = path;
|
||||||
|
file.Contents = source.c_str();
|
||||||
|
file.Length = source.length();
|
||||||
|
|
||||||
|
auto args = get_arguments(config);
|
||||||
|
|
||||||
|
CXTranslationUnit tu;
|
||||||
|
auto error =
|
||||||
|
clang_parseTranslationUnit2(idx.get(), path, // index and path
|
||||||
|
args.data(),
|
||||||
|
static_cast<int>(args.size()), // arguments (ptr + size)
|
||||||
|
&file, 1, // unsaved files (ptr + size)
|
||||||
|
CXTranslationUnit_Incomplete
|
||||||
|
| CXTranslationUnit_KeepGoing, // flags
|
||||||
|
&tu);
|
||||||
|
if (error != CXError_Success)
|
||||||
|
DEBUG_UNREACHABLE(detail::assert_handler{}, "libclang error"); // TODO
|
||||||
|
|
||||||
|
return tu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx, std::string path,
|
std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx, std::string path,
|
||||||
const compile_config& c) const
|
const compile_config& c) const
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{},
|
DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{},
|
||||||
"config has mismatched type");
|
"config has mismatched type");
|
||||||
auto& config = static_cast<const libclang_compile_config&>(c);
|
auto& config = static_cast<const libclang_compile_config&>(c);
|
||||||
auto preprocessed = detail::preprocess(config, path.c_str());
|
|
||||||
|
|
||||||
cpp_file::builder builder(std::move(path));
|
// preprocess + parse
|
||||||
|
auto preprocessed = detail::preprocess(config, path.c_str());
|
||||||
|
auto tu = get_cxunit(pimpl_->index, config, path.c_str(), preprocessed.source);
|
||||||
|
|
||||||
|
// convert entity hierachies
|
||||||
|
cpp_file::builder builder(path);
|
||||||
|
|
||||||
|
// add all preprocessor entities up-front
|
||||||
|
// TODO: add them in the correct place
|
||||||
for (auto& e : preprocessed.entities)
|
for (auto& e : preprocessed.entities)
|
||||||
builder.add_child(std::move(e.entity));
|
builder.add_child(std::move(e.entity));
|
||||||
|
|
||||||
|
detail::visit_tu(tu, path.c_str(), [&](const CXCursor&) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
return builder.finish(idx);
|
return builder.finish(idx);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
src/libclang/libclang_visitor.hpp
Normal file
52
src/libclang/libclang_visitor.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||||
|
// This file is subject to the license terms in the LICENSE file
|
||||||
|
// found in the top-level directory of this distribution.
|
||||||
|
|
||||||
|
#ifndef CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED
|
||||||
|
#define CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
#include "raii_wrapper.hpp"
|
||||||
|
|
||||||
|
namespace cppast
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// visits direct children of an entity
|
||||||
|
template <typename Func>
|
||||||
|
void visit_children(CXCursor parent, Func f)
|
||||||
|
{
|
||||||
|
clang_visitChildren(parent,
|
||||||
|
[](CXCursor cur, CXCursor, CXClientData data) {
|
||||||
|
auto& actual_cb = *static_cast<Func*>(data);
|
||||||
|
actual_cb(cur);
|
||||||
|
return CXChildVisit_Continue;
|
||||||
|
},
|
||||||
|
&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// visits a translation unit
|
||||||
|
// notes: only visits if directly defined in file, not included
|
||||||
|
template <typename Func>
|
||||||
|
void visit_tu(const cxtranslation_unit& tu, const char* path, Func f)
|
||||||
|
{
|
||||||
|
auto in_tu = [&](const CXCursor& cur) {
|
||||||
|
auto location = clang_getCursorLocation(cur);
|
||||||
|
|
||||||
|
CXString cx_file_name;
|
||||||
|
clang_getPresumedLocation(location, &cx_file_name, nullptr, nullptr);
|
||||||
|
cxstring file_name(cx_file_name);
|
||||||
|
|
||||||
|
return file_name == path;
|
||||||
|
};
|
||||||
|
|
||||||
|
visit_children(clang_getTranslationUnitCursor(tu.get()), [&](const CXCursor& cur) {
|
||||||
|
if (in_tu(cur))
|
||||||
|
f(cur);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace cppast::detail
|
||||||
|
|
||||||
|
#endif // CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED
|
||||||
|
|
@ -83,6 +83,73 @@ namespace cppast
|
||||||
};
|
};
|
||||||
|
|
||||||
using cxtranslation_unit = raii_wrapper<CXTranslationUnit, cxtranslation_unit_deleter>;
|
using cxtranslation_unit = raii_wrapper<CXTranslationUnit, cxtranslation_unit_deleter>;
|
||||||
|
|
||||||
|
class cxstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cxstring(CXString str) noexcept
|
||||||
|
: str_(str), c_str_(clang_getCString(str)), length_(std::strlen(c_str_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cxstring(const cxstring&) = delete;
|
||||||
|
cxstring& operator=(const cxstring&) = delete;
|
||||||
|
|
||||||
|
~cxstring() noexcept
|
||||||
|
{
|
||||||
|
clang_disposeString(str_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* c_str() const noexcept
|
||||||
|
{
|
||||||
|
return c_str_;
|
||||||
|
}
|
||||||
|
|
||||||
|
char operator[](std::size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return c_str()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t length() const noexcept
|
||||||
|
{
|
||||||
|
return length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CXString str_;
|
||||||
|
const char* c_str_;
|
||||||
|
std::size_t length_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const cxstring& a, const cxstring& b) noexcept
|
||||||
|
{
|
||||||
|
return std::strcmp(a.c_str(), b.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const cxstring& a, const char* str) noexcept
|
||||||
|
{
|
||||||
|
return std::strcmp(a.c_str(), str) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const char* str, const cxstring& b) noexcept
|
||||||
|
{
|
||||||
|
return std::strcmp(str, b.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const cxstring& a, const cxstring& b) noexcept
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const cxstring& a, const char* str) noexcept
|
||||||
|
{
|
||||||
|
return !(a == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const char* str, const cxstring& b) noexcept
|
||||||
|
{
|
||||||
|
return !(str == b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace cppast::detail
|
} // namespace cppast::detail
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue