Parse cpp_namespace

This commit is contained in:
Jonathan Müller 2017-02-21 22:36:38 +01:00
commit ce69b0157f
11 changed files with 160 additions and 16 deletions

View file

@ -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
{

View file

@ -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;

View file

@ -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");

View 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));
}

View file

@ -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)

View file

@ -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

View file

@ -129,6 +129,11 @@ namespace cppast
return str_ ? str_.value().length : 0u;
}
bool empty() const noexcept
{
return length() == 0u;
}
private:
struct string
{

View file

@ -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]);

View file

@ -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
View 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);
}

View file

@ -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