Parse cpp_namespace
This commit is contained in:
parent
51567da741
commit
ce69b0157f
11 changed files with 160 additions and 16 deletions
|
|
@ -17,6 +17,8 @@ namespace cppast
|
|||
public cpp_entity_container<cpp_namespace, cpp_entity>
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// Builds a [cppast::cpp_namespace]().
|
||||
class builder
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,11 +8,16 @@
|
|||
|
||||
using namespace cppast;
|
||||
|
||||
cpp_entity_kind cpp_namespace::do_get_entity_kind() const noexcept
|
||||
cpp_entity_kind cpp_namespace::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::namespace_t;
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_namespace::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
||||
bool detail::cpp_namespace_ref_predicate::operator()(const cpp_entity& e)
|
||||
{
|
||||
return e.kind() == cpp_entity_kind::namespace_t;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ void detail::print_tokens(const detail::cxtranslation_unit& tu, const CXFile& fi
|
|||
const CXCursor& cur) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
detail::tokenizer tokenizer(tu, file, cur);
|
||||
detail::tokenizer tokenizer(tu.get(), file, cur);
|
||||
for (auto& token : tokenizer)
|
||||
std::printf("%s ", token.c_str());
|
||||
std::puts("\n");
|
||||
|
|
|
|||
48
src/libclang/namespace_parser.cpp
Normal file
48
src/libclang/namespace_parser.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// 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.
|
||||
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_namespace.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
namespace
|
||||
{
|
||||
cpp_namespace::builder make_builder(const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
// [inline] namespace [<attribute>] <identifier> {
|
||||
|
||||
auto is_inline = false;
|
||||
if (skip_if(stream, "inline"))
|
||||
is_inline = true;
|
||||
|
||||
skip(stream, "namespace");
|
||||
skip_attribute(stream);
|
||||
|
||||
// <identifier> {
|
||||
auto& name = stream.get().value();
|
||||
skip(stream, "{");
|
||||
|
||||
return cpp_namespace::builder(name.c_str(), is_inline);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_Namespace, detail::assert_handler{});
|
||||
|
||||
auto builder = make_builder(context, cur);
|
||||
detail::visit_children(cur, [&](const CXCursor& cur) {
|
||||
auto entity = parse_entity(context, cur);
|
||||
if (entity)
|
||||
builder.add_child(std::move(entity));
|
||||
});
|
||||
return builder.finish(*context.idx, get_entity_id(cur));
|
||||
}
|
||||
|
|
@ -4,13 +4,28 @@
|
|||
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
#include "parse_error.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
cpp_entity_id detail::get_entity_id(const CXCursor& cur)
|
||||
{
|
||||
cxstring usr(clang_getCursorUSR(cur));
|
||||
DEBUG_ASSERT(!usr.empty(), detail::parse_error_handler{}, cur, "cannot create id for entity");
|
||||
return cpp_entity_id(usr.c_str());
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& context,
|
||||
const CXCursor& cur) try
|
||||
{
|
||||
auto kind = clang_getCursorKind(cur);
|
||||
switch (kind)
|
||||
{
|
||||
case CXCursor_Namespace:
|
||||
return parse_cpp_namespace(context, cur);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
catch (parse_error& ex)
|
||||
|
|
|
|||
|
|
@ -9,11 +9,15 @@
|
|||
#include <cppast/parser.hpp>
|
||||
|
||||
#include "raii_wrapper.hpp"
|
||||
#include "tokenizer.hpp" // for convenience
|
||||
#include "parse_error.hpp" // for convenience
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
cpp_entity_id get_entity_id(const CXCursor& cur);
|
||||
|
||||
struct parse_context
|
||||
{
|
||||
CXTranslationUnit tu;
|
||||
|
|
@ -22,6 +26,9 @@ namespace cppast
|
|||
type_safe::object_ref<const cpp_entity_index> idx;
|
||||
};
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
|
|
|||
|
|
@ -129,6 +129,11 @@ namespace cppast
|
|||
return str_ ? str_.value().length : 0u;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return length() == 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
struct string
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
using namespace cppast;
|
||||
|
||||
detail::token::token(const detail::cxtranslation_unit& tu_unit, const CXToken& token)
|
||||
: value_(clang_getTokenSpelling(tu_unit.get(), token)), kind_(clang_getTokenKind(token))
|
||||
detail::token::token(const CXTranslationUnit& tu_unit, const CXToken& token)
|
||||
: value_(clang_getTokenSpelling(tu_unit, token)), kind_(clang_getTokenKind(token))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -157,12 +157,11 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
detail::tokenizer::tokenizer(const detail::cxtranslation_unit& tu, const CXFile& file,
|
||||
const CXCursor& cur)
|
||||
detail::tokenizer::tokenizer(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur)
|
||||
{
|
||||
auto extent = get_extent(tu.get(), file, cur);
|
||||
auto extent = get_extent(tu, file, cur);
|
||||
|
||||
simple_tokenizer tokenizer(tu.get(), extent, cur);
|
||||
simple_tokenizer tokenizer(tu, extent, cur);
|
||||
tokens_.reserve(tokenizer.size());
|
||||
for (auto i = 0u; i != tokenizer.size(); ++i)
|
||||
tokens_.emplace_back(tu, tokenizer[i]);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace cppast
|
|||
class token
|
||||
{
|
||||
public:
|
||||
explicit token(const cxtranslation_unit& tu_unit, const CXToken& token);
|
||||
explicit token(const CXTranslationUnit& tu_unit, const CXToken& token);
|
||||
|
||||
const cxstring& value() const noexcept
|
||||
{
|
||||
|
|
@ -63,7 +63,7 @@ namespace cppast
|
|||
class tokenizer
|
||||
{
|
||||
public:
|
||||
explicit tokenizer(const cxtranslation_unit& tu, const CXFile& file,
|
||||
explicit tokenizer(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur);
|
||||
|
||||
token_iterator begin() const noexcept
|
||||
|
|
|
|||
53
test/cpp_namespace.cpp
Normal file
53
test/cpp_namespace.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// 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.
|
||||
|
||||
#include <cppast/cpp_namespace.hpp>
|
||||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
TEST_CASE("cpp_namespace")
|
||||
{
|
||||
auto code = R"(
|
||||
namespace a {}
|
||||
|
||||
inline namespace b {}
|
||||
|
||||
namespace c
|
||||
{
|
||||
namespace d {}
|
||||
}
|
||||
)";
|
||||
|
||||
auto file = parse({}, "cpp_namespace.cpp", code);
|
||||
auto count = test_visit<cpp_namespace>(*file, [&](const cpp_namespace& ns) {
|
||||
auto no_children = count_children(ns);
|
||||
if (ns.name() == "a")
|
||||
{
|
||||
REQUIRE(!ns.is_inline());
|
||||
REQUIRE(no_children == 0u);
|
||||
}
|
||||
else if (ns.name() == "b")
|
||||
{
|
||||
REQUIRE(ns.is_inline());
|
||||
REQUIRE(no_children == 0u);
|
||||
}
|
||||
else if (ns.name() == "c")
|
||||
{
|
||||
REQUIRE(!ns.is_inline());
|
||||
REQUIRE(no_children == 1u);
|
||||
}
|
||||
else if (ns.name() == "d")
|
||||
{
|
||||
REQUIRE(ns.parent());
|
||||
REQUIRE(ns.parent().value().name() == "c");
|
||||
REQUIRE(!ns.is_inline());
|
||||
REQUIRE(no_children == 0u);
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
REQUIRE(count == 4u);
|
||||
}
|
||||
|
|
@ -13,14 +13,14 @@
|
|||
#include <cppast/libclang_parser.hpp>
|
||||
#include <cppast/visitor.hpp>
|
||||
|
||||
void write_file(const char* name, const char* code)
|
||||
inline void write_file(const char* name, const char* code)
|
||||
{
|
||||
std::ofstream file(name);
|
||||
file << code;
|
||||
}
|
||||
|
||||
std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& idx, const char* name,
|
||||
const char* code)
|
||||
inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& idx,
|
||||
const char* name, const char* code)
|
||||
{
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -38,7 +38,10 @@ template <typename T, typename Func>
|
|||
unsigned test_visit(const cppast::cpp_file& file, Func f)
|
||||
{
|
||||
auto count = 0u;
|
||||
cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info) {
|
||||
cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||
if (info == cppast::visitor_info::container_entity_exit)
|
||||
return true; // already handled
|
||||
|
||||
if (e.kind() == T::kind())
|
||||
{
|
||||
auto& obj = static_cast<const T&>(e);
|
||||
|
|
@ -52,4 +55,11 @@ unsigned test_visit(const cppast::cpp_file& file, Func f)
|
|||
return count;
|
||||
}
|
||||
|
||||
// number of direct children
|
||||
template <class Entity>
|
||||
unsigned count_children(const Entity& cont)
|
||||
{
|
||||
return std::distance(cont.begin(), cont.end());
|
||||
}
|
||||
|
||||
#endif // CPPAST_TEST_PARSER_HPP_INCLUDED
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue