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 cpp_entity_container<cpp_namespace, cpp_entity>
{ {
public: public:
static cpp_entity_kind kind() noexcept;
/// Builds a [cppast::cpp_namespace](). /// Builds a [cppast::cpp_namespace]().
class builder class builder
{ {

View file

@ -8,11 +8,16 @@
using namespace cppast; 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; 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) bool detail::cpp_namespace_ref_predicate::operator()(const cpp_entity& e)
{ {
return e.kind() == cpp_entity_kind::namespace_t; 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 const CXCursor& cur) noexcept
{ {
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
detail::tokenizer tokenizer(tu, file, cur); detail::tokenizer tokenizer(tu.get(), file, cur);
for (auto& token : tokenizer) for (auto& token : tokenizer)
std::printf("%s ", token.c_str()); std::printf("%s ", token.c_str());
std::puts("\n"); 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_functions.hpp"
#include "parse_error.hpp"
using namespace cppast; 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, std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& context,
const CXCursor& cur) try const CXCursor& cur) try
{ {
auto kind = clang_getCursorKind(cur);
switch (kind)
{
case CXCursor_Namespace:
return parse_cpp_namespace(context, cur);
default:
break;
}
return nullptr; return nullptr;
} }
catch (parse_error& ex) catch (parse_error& ex)

View file

@ -9,11 +9,15 @@
#include <cppast/parser.hpp> #include <cppast/parser.hpp>
#include "raii_wrapper.hpp" #include "raii_wrapper.hpp"
#include "tokenizer.hpp" // for convenience
#include "parse_error.hpp" // for convenience
namespace cppast namespace cppast
{ {
namespace detail namespace detail
{ {
cpp_entity_id get_entity_id(const CXCursor& cur);
struct parse_context struct parse_context
{ {
CXTranslationUnit tu; CXTranslationUnit tu;
@ -22,6 +26,9 @@ namespace cppast
type_safe::object_ref<const cpp_entity_index> idx; 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); std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
} }
} // namespace cppast::detail } // namespace cppast::detail

View file

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

View file

@ -9,8 +9,8 @@
using namespace cppast; using namespace cppast;
detail::token::token(const detail::cxtranslation_unit& tu_unit, const CXToken& token) detail::token::token(const CXTranslationUnit& tu_unit, const CXToken& token)
: value_(clang_getTokenSpelling(tu_unit.get(), token)), kind_(clang_getTokenKind(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, detail::tokenizer::tokenizer(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur)
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()); tokens_.reserve(tokenizer.size());
for (auto i = 0u; i != tokenizer.size(); ++i) for (auto i = 0u; i != tokenizer.size(); ++i)
tokens_.emplace_back(tu, tokenizer[i]); tokens_.emplace_back(tu, tokenizer[i]);

View file

@ -16,7 +16,7 @@ namespace cppast
class token class token
{ {
public: 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 const cxstring& value() const noexcept
{ {
@ -63,7 +63,7 @@ namespace cppast
class tokenizer class tokenizer
{ {
public: public:
explicit tokenizer(const cxtranslation_unit& tu, const CXFile& file, explicit tokenizer(const CXTranslationUnit& tu, const CXFile& file,
const CXCursor& cur); const CXCursor& cur);
token_iterator begin() const noexcept 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/libclang_parser.hpp>
#include <cppast/visitor.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); std::ofstream file(name);
file << code; file << code;
} }
std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& idx, const char* name, inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& idx,
const char* code) const char* name, const char* code)
{ {
using namespace cppast; using namespace cppast;
@ -38,7 +38,10 @@ template <typename T, typename Func>
unsigned test_visit(const cppast::cpp_file& file, Func f) unsigned test_visit(const cppast::cpp_file& file, Func f)
{ {
auto count = 0u; 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()) if (e.kind() == T::kind())
{ {
auto& obj = static_cast<const T&>(e); auto& obj = static_cast<const T&>(e);
@ -52,4 +55,11 @@ unsigned test_visit(const cppast::cpp_file& file, Func f)
return count; 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 #endif // CPPAST_TEST_PARSER_HPP_INCLUDED