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 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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
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_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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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
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/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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue