Steal comment of nested namespace

This commit is contained in:
Jonathan Müller 2017-12-22 10:54:37 +01:00
commit 755f251da9
10 changed files with 52 additions and 35 deletions

View file

@ -23,9 +23,9 @@ namespace cppast
class builder class builder
{ {
public: public:
/// \effects Sets the namespace name and whether it is inline. /// \effects Sets the namespace name and whether it is inline and nested.
explicit builder(std::string name, bool is_inline) explicit builder(std::string name, bool is_inline, bool is_nested)
: namespace_(new cpp_namespace(std::move(name), is_inline)) : namespace_(new cpp_namespace(std::move(name), is_inline, is_nested))
{ {
} }
@ -60,6 +60,12 @@ namespace cppast
return inline_; return inline_;
} }
/// \returns Whether or not the namespace is part of a C++17 nested namespace.
bool is_nested() const noexcept
{
return nested_;
}
/// \returns Whether or not the namespace is anonymous. /// \returns Whether or not the namespace is anonymous.
bool is_anonymous() const noexcept bool is_anonymous() const noexcept
{ {
@ -67,8 +73,8 @@ namespace cppast
} }
private: private:
cpp_namespace(std::string name, bool is_inline) cpp_namespace(std::string name, bool is_inline, bool is_nested)
: cpp_entity(std::move(name)), inline_(is_inline) : cpp_entity(std::move(name)), inline_(is_inline), nested_(is_nested)
{ {
} }
@ -80,6 +86,7 @@ namespace cppast
} }
bool inline_; bool inline_;
bool nested_;
}; };
/// \exclude /// \exclude
@ -184,9 +191,7 @@ namespace cppast
} }
private: private:
cpp_using_declaration(cpp_entity_ref target) : cpp_entity(""), target_(std::move(target)) cpp_using_declaration(cpp_entity_ref target) : cpp_entity(""), target_(std::move(target)) {}
{
}
cpp_entity_kind do_get_entity_kind() const noexcept override; cpp_entity_kind do_get_entity_kind() const noexcept override;

View file

@ -167,7 +167,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
== CXCursor_UnexposedAttr) // I have no idea what this is, but happens on Windows == CXCursor_UnexposedAttr) // I have no idea what this is, but happens on Windows
// other children due to templates and stuff // other children due to templates and stuff
return; return;
else if (auto entity = parse_entity(context, child)) else if (auto entity = parse_entity(context, &builder.get(), child))
builder.add_child(std::move(entity)); builder.add_child(std::move(entity));
}); });
} }

View file

@ -54,7 +54,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_friend(const detail::parse_context
// for some reason libclang gives a type ref here // for some reason libclang gives a type ref here
// we actually need a class decl cursor, so parse the referenced one // we actually need a class decl cursor, so parse the referenced one
// this might be a definition, so give friend information to the parser // this might be a definition, so give friend information to the parser
entity = parse_entity(context, referenced, cur); entity = parse_entity(context, nullptr, referenced, cur);
comment = type_safe::copy(entity->comment()).value_or(""); comment = type_safe::copy(entity->comment()).value_or("");
} }
} }
@ -74,7 +74,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_friend(const detail::parse_context
} }
else if (clang_isDeclaration(kind)) else if (clang_isDeclaration(kind))
{ {
entity = parse_entity(context, child, cur); entity = parse_entity(context, nullptr, child, cur);
if (entity) if (entity)
{ {
// steal comment // steal comment

View file

@ -30,7 +30,7 @@ std::unique_ptr<cpp_entity> detail::try_parse_cpp_language_linkage(const parse_c
auto builder = cpp_language_linkage::builder(name.c_str()); auto builder = cpp_language_linkage::builder(name.c_str());
context.comments.match(builder.get(), cur); context.comments.match(builder.get(), cur);
detail::visit_children(cur, [&](const CXCursor& child) { detail::visit_children(cur, [&](const CXCursor& child) {
auto entity = parse_entity(context, child); auto entity = parse_entity(context, &builder.get(), child);
if (entity) if (entity)
builder.add_child(std::move(entity)); builder.add_child(std::move(entity));
}); });

View file

@ -504,7 +504,7 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
macro_iter != preprocessed.macros.end() && macro_iter->line <= line; ++macro_iter) macro_iter != preprocessed.macros.end() && macro_iter->line <= line; ++macro_iter)
builder.add_child(std::move(macro_iter->macro)); builder.add_child(std::move(macro_iter->macro));
auto entity = detail::parse_entity(context, cur); auto entity = detail::parse_entity(context, &builder.get(), cur);
if (entity) if (entity)
builder.add_child(std::move(entity)); builder.add_child(std::move(entity));
} }

View file

@ -27,15 +27,19 @@ namespace
// C++17 nested namespace declarations get one cursor per nested name. // C++17 nested namespace declarations get one cursor per nested name.
// The first cursor starts with the `namespace` keyword, and the // The first cursor starts with the `namespace` keyword, and the
// following start with the `::` separator. Either way, it is skipped. // following start with the `::` separator. Either way, it is skipped.
auto is_nested = false;
if (!detail::skip_if(stream, "namespace")) if (!detail::skip_if(stream, "namespace"))
skip(stream, "::"); {
is_nested = true;
skip(stream, "::");
}
auto attributes = parse_attributes(stream); auto attributes = parse_attributes(stream);
// <identifier> { // <identifier> {
// or when anonymous: { // or when anonymous: {
if (detail::skip_if(stream, "{")) if (detail::skip_if(stream, "{"))
return cpp_namespace::builder("", is_inline); return cpp_namespace::builder("", is_inline, false);
auto& name = stream.get().value(); auto& name = stream.get().value();
@ -45,23 +49,32 @@ namespace
// If the next token is not `::`, there are no more nested namespace // If the next token is not `::`, there are no more nested namespace
// names, and we expect to see an opening brace. // names, and we expect to see an opening brace.
if (!detail::skip_if(stream, "::")) if (!detail::skip_if(stream, "::"))
skip(stream, "{"); skip(stream, "{");
auto result = cpp_namespace::builder(name.c_str(), is_inline); auto result = cpp_namespace::builder(name.c_str(), is_inline, is_nested);
result.get().add_attribute(attributes); result.get().add_attribute(attributes);
return result; return result;
} }
} }
std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_context& context, std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_context& context,
const CXCursor& cur) cpp_entity& parent, const CXCursor& cur)
{ {
DEBUG_ASSERT(cur.kind == CXCursor_Namespace, detail::assert_handler{}); DEBUG_ASSERT(cur.kind == CXCursor_Namespace, detail::assert_handler{});
auto builder = make_ns_builder(context, cur); auto builder = make_ns_builder(context, cur);
context.comments.match(builder.get(), cur); if (builder.get().is_nested())
{
// steal comment from parent
DEBUG_ASSERT(parent.kind() == cpp_namespace::kind(), detail::assert_handler{});
builder.get().set_comment(type_safe::copy(parent.comment()));
parent.set_comment(type_safe::nullopt);
}
else
context.comments.match(builder.get(), cur);
detail::visit_children(cur, [&](const CXCursor& cur) { detail::visit_children(cur, [&](const CXCursor& cur) {
auto entity = parse_entity(context, cur); auto entity = parse_entity(context, &builder.get(), cur);
if (entity) if (entity)
builder.add_child(std::move(entity)); builder.add_child(std::move(entity));
}); });

View file

@ -112,8 +112,8 @@ namespace
} }
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, cpp_entity* parent, const CXCursor& cur,
const CXCursor& parent_cur) try const CXCursor& parent_cur) try
{ {
if (context.logger->is_verbose()) if (context.logger->is_verbose())
{ {
@ -138,7 +138,8 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
break; break;
case CXCursor_Namespace: case CXCursor_Namespace:
return parse_cpp_namespace(context, cur); DEBUG_ASSERT(parent, detail::assert_handler{});
return parse_cpp_namespace(context, *parent, cur);
case CXCursor_NamespaceAlias: case CXCursor_NamespaceAlias:
return parse_cpp_namespace_alias(context, cur); return parse_cpp_namespace_alias(context, cur);
case CXCursor_UsingDirective: case CXCursor_UsingDirective:

View file

@ -112,7 +112,7 @@ namespace cppast
const parse_context& context, const CXCursor& cur); const parse_context& context, const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context, std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context,
const CXCursor& cur); cpp_entity& parent, const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_namespace_alias(const parse_context& context, std::unique_ptr<cpp_entity> parse_cpp_namespace_alias(const parse_context& context,
const CXCursor& cur); const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_using_directive(const parse_context& context, std::unique_ptr<cpp_entity> parse_cpp_using_directive(const parse_context& context,
@ -162,9 +162,10 @@ namespace cppast
std::unique_ptr<cpp_entity> parse_cpp_static_assert(const parse_context& context, std::unique_ptr<cpp_entity> parse_cpp_static_assert(const parse_context& context,
const CXCursor& cur); const CXCursor& cur);
// parent: used for nested namespace, doesn't matter otherwise
// parent_cur: used when parsing templates or friends // parent_cur: used when parsing templates or friends
std::unique_ptr<cpp_entity> parse_entity( std::unique_ptr<cpp_entity> parse_entity(
const parse_context& context, const CXCursor& cur, const parse_context& context, cpp_entity* parent, const CXCursor& cur,
const CXCursor& parent_cur = clang_getNullCursor()); const CXCursor& parent_cur = clang_getNullCursor());
} }
} // namespace cppast::detail } // namespace cppast::detail

View file

@ -35,7 +35,7 @@ namespace
DEBUG_ASSERT(!clang_Cursor_isNull(result), detail::parse_error_handler{}, cur, DEBUG_ASSERT(!clang_Cursor_isNull(result), detail::parse_error_handler{}, cur,
"missing child of template"); "missing child of template");
auto entity = detail::parse_entity(context, result, cur); auto entity = detail::parse_entity(context, nullptr, result, cur);
if (!entity) if (!entity)
return type_safe::nullopt; return type_safe::nullopt;
DEBUG_ASSERT(p(entity->kind()), detail::parse_error_handler{}, cur, DEBUG_ASSERT(p(entity->kind()), detail::parse_error_handler{}, cur,

View file

@ -34,15 +34,9 @@ namespace c
/// } /// }
namespace {} namespace {}
/// namespace e{
/// namespace f{
/// }
/// }
namespace e::f {}
/// \entity e::f
/// namespace f{ /// namespace f{
/// } /// }
namespace e::f {}
)"; )";
auto file = parse({}, "cpp_namespace.cpp", code); auto file = parse({}, "cpp_namespace.cpp", code);
@ -84,6 +78,7 @@ namespace e::f {}
REQUIRE(!ns.is_anonymous()); REQUIRE(!ns.is_anonymous());
REQUIRE(!ns.is_inline()); REQUIRE(!ns.is_inline());
REQUIRE(no_children == 1u); REQUIRE(no_children == 1u);
return false; // don't have a comment
} }
else if (ns.name() == "f") else if (ns.name() == "f")
{ {
@ -94,8 +89,10 @@ namespace e::f {}
} }
else else
REQUIRE(false); REQUIRE(false);
return true;
}); });
REQUIRE(count == 5u); REQUIRE(count == 7u);
} }
TEST_CASE("cpp_namespace_alias") TEST_CASE("cpp_namespace_alias")
@ -126,7 +123,7 @@ namespace f = outer::c;
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto check_alias = [&](const cpp_namespace_alias& alias, const char* target_name, auto check_alias = [&](const cpp_namespace_alias& alias, const char* target_name,
const char* target_full_name, unsigned no) { const char* target_full_name, unsigned no) {
auto& target = alias.target(); auto& target = alias.target();
REQUIRE(target.name() == target_name); REQUIRE(target.name() == target_name);