From 51f7c3c2b291af423b53c9c73f3ad30239fcd970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Thu, 16 Feb 2017 21:19:20 +0100 Subject: [PATCH] Add libclang parsing outline --- src/libclang/libclang_parser.cpp | 58 ++++++++++++++++++++++++-- src/libclang/libclang_visitor.hpp | 52 ++++++++++++++++++++++++ src/libclang/raii_wrapper.hpp | 67 +++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 src/libclang/libclang_visitor.hpp diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index 0ef6ec3..820822c 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -5,7 +5,9 @@ #include #include +#include +#include "libclang_visitor.hpp" #include "raii_wrapper.hpp" #include "preprocessor.hpp" @@ -26,6 +28,7 @@ const std::vector& detail::libclang_compile_config_access::flags( libclang_compile_config::libclang_compile_config() : compile_config({}) { set_clang_binary("clang++"); + add_include_dir(LIBCLANG_SYSTEM_INCLUDE_DIR); } 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 get_arguments(const libclang_compile_config& config) + { + std::vector 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(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 libclang_parser::do_parse(const cpp_entity_index& idx, std::string path, const compile_config& c) const { DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{}, "config has mismatched type"); - auto& config = static_cast(c); - auto preprocessed = detail::preprocess(config, path.c_str()); + auto& config = static_cast(c); - 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) builder.add_child(std::move(e.entity)); + detail::visit_tu(tu, path.c_str(), [&](const CXCursor&) { + + }); + return builder.finish(idx); } diff --git a/src/libclang/libclang_visitor.hpp b/src/libclang/libclang_visitor.hpp new file mode 100644 index 0000000..bc11481 --- /dev/null +++ b/src/libclang/libclang_visitor.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2017 Jonathan Müller +// 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 + +#include "raii_wrapper.hpp" + +namespace cppast +{ + namespace detail + { + // visits direct children of an entity + template + void visit_children(CXCursor parent, Func f) + { + clang_visitChildren(parent, + [](CXCursor cur, CXCursor, CXClientData data) { + auto& actual_cb = *static_cast(data); + actual_cb(cur); + return CXChildVisit_Continue; + }, + &f); + } + + // visits a translation unit + // notes: only visits if directly defined in file, not included + template + 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 diff --git a/src/libclang/raii_wrapper.hpp b/src/libclang/raii_wrapper.hpp index 3f6277b..fd34c74 100644 --- a/src/libclang/raii_wrapper.hpp +++ b/src/libclang/raii_wrapper.hpp @@ -83,6 +83,73 @@ namespace cppast }; using cxtranslation_unit = raii_wrapper; + + 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