Parse cpp_using_directive/declaration
Both of them now also don't have a name() anymore as it was inconsistent with get_full_name().
This commit is contained in:
parent
45e9e5305b
commit
087b9583ff
7 changed files with 176 additions and 22 deletions
|
|
@ -117,65 +117,69 @@ namespace cppast
|
|||
/// A [cppast::cpp_entity]() modelling a using directive.
|
||||
///
|
||||
/// A using directive is `using namespace std`, for example.
|
||||
/// \notes It does not have a name.
|
||||
class cpp_using_directive final : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly created using directive.
|
||||
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
||||
/// as nothing can refer to it.
|
||||
static std::unique_ptr<cpp_using_directive> build(const cpp_namespace_ref& target)
|
||||
static std::unique_ptr<cpp_using_directive> build(cpp_namespace_ref target)
|
||||
{
|
||||
return std::unique_ptr<cpp_using_directive>(new cpp_using_directive(target));
|
||||
return std::unique_ptr<cpp_using_directive>(new cpp_using_directive(std::move(target)));
|
||||
}
|
||||
|
||||
/// \returns The [cppast::cpp_namespace_ref]() that is being used.
|
||||
/// \notes The name of the reference is the same as the name of this entity.
|
||||
cpp_namespace_ref target() const
|
||||
const cpp_namespace_ref& target() const
|
||||
{
|
||||
return {target_, name()};
|
||||
return target_;
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_using_directive(const cpp_namespace_ref& target)
|
||||
: cpp_entity(target.name()), target_(target.id())
|
||||
cpp_using_directive(cpp_namespace_ref target) : cpp_entity(""), target_(std::move(target))
|
||||
{
|
||||
}
|
||||
|
||||
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
||||
|
||||
cpp_entity_id target_;
|
||||
cpp_namespace_ref target_;
|
||||
};
|
||||
|
||||
/// A [cppast::cpp_entity]() modelling a using declaration.
|
||||
///
|
||||
/// A using declaration is `using std::vector`, for example.
|
||||
/// \notes It does not have a name.
|
||||
class cpp_using_declaration final : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly created using declaration.
|
||||
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
||||
/// as nothing can refer to it.
|
||||
static std::unique_ptr<cpp_using_declaration> build(const cpp_entity_ref& target)
|
||||
static std::unique_ptr<cpp_using_declaration> build(cpp_entity_ref target)
|
||||
{
|
||||
return std::unique_ptr<cpp_using_declaration>(new cpp_using_declaration(target));
|
||||
return std::unique_ptr<cpp_using_declaration>(
|
||||
new cpp_using_declaration(std::move(target)));
|
||||
}
|
||||
|
||||
/// \returns The [cppast::cpp_entity_ref]() that is being used.
|
||||
/// \notes The name of the reference is the same as the name of this entity.
|
||||
cpp_entity_ref target() const
|
||||
const cpp_entity_ref& target() const noexcept
|
||||
{
|
||||
return {target_, name()};
|
||||
return target_;
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_using_declaration(const cpp_entity_ref& target)
|
||||
: cpp_entity(target.name()), target_(target.id())
|
||||
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_id target_;
|
||||
cpp_entity_ref target_;
|
||||
};
|
||||
} // namespace cppast
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ using namespace cppast;
|
|||
|
||||
std::string cppast::full_name(const cpp_entity& e)
|
||||
{
|
||||
if (e.name().empty())
|
||||
return "";
|
||||
|
||||
std::string scopes;
|
||||
|
||||
for (auto cur = e.parent(); cur; cur = cur.value().parent())
|
||||
|
|
|
|||
|
|
@ -43,12 +43,22 @@ cpp_entity_kind cpp_namespace_alias::do_get_entity_kind() const noexcept
|
|||
return kind();
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_using_directive::do_get_entity_kind() const noexcept
|
||||
cpp_entity_kind cpp_using_directive::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::using_directive_t;
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_using_declaration::do_get_entity_kind() const noexcept
|
||||
cpp_entity_kind cpp_using_directive::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_using_declaration::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::using_declaration_t;
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_using_declaration::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_namespace.hpp>
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_cont
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_entity_id ns_alias_target_id(const CXCursor& cur)
|
||||
cpp_entity_id parse_ns_target_cursor(const CXCursor& cur)
|
||||
{
|
||||
cpp_entity_id result("");
|
||||
detail::visit_children(cur,
|
||||
|
|
@ -61,10 +62,11 @@ namespace
|
|||
result = detail::get_entity_id(referenced);
|
||||
else if (kind == CXCursor_NamespaceAlias)
|
||||
// get target of namespace alias instead
|
||||
result = ns_alias_target_id(referenced);
|
||||
result = parse_ns_target_cursor(referenced);
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected child of namespace alias");
|
||||
"unexpected target for namespace "
|
||||
"alias/using directive");
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
|
|
@ -89,7 +91,77 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_namespace_alias(const detail::pars
|
|||
while (!detail::skip_if(stream, ";"))
|
||||
target_name += stream.get().c_str();
|
||||
|
||||
auto target = cpp_namespace_ref(ns_alias_target_id(cur), std::move(target_name));
|
||||
auto target = cpp_namespace_ref(parse_ns_target_cursor(cur), std::move(target_name));
|
||||
return cpp_namespace_alias::build(*context.idx, get_entity_id(cur), std::move(name),
|
||||
std::move(target));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_using_directive(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_UsingDirective, detail::assert_handler{});
|
||||
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
// using namespace <nested identifier>;
|
||||
detail::skip(stream, "using");
|
||||
detail::skip(stream, "namespace");
|
||||
|
||||
// <nested identifier>;
|
||||
std::string target_name;
|
||||
while (!detail::skip_if(stream, ";"))
|
||||
target_name += stream.get().c_str();
|
||||
|
||||
auto target = cpp_namespace_ref(parse_ns_target_cursor(cur), std::move(target_name));
|
||||
return cpp_using_directive::build(target);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
cpp_entity_id parse_entity_target_cursor(const CXCursor& cur)
|
||||
{
|
||||
cpp_entity_id result("");
|
||||
detail::visit_children(cur,
|
||||
[&](const CXCursor& child) {
|
||||
switch (clang_getCursorKind(child))
|
||||
{
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_TemplateRef:
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_OverloadedDeclRef:
|
||||
case CXCursor_VariableRef:
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected target for using declaration");
|
||||
}
|
||||
|
||||
auto referenced = clang_getCursorReferenced(child);
|
||||
result = detail::get_entity_id(referenced);
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_using_declaration(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_UsingDeclaration, detail::assert_handler{});
|
||||
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
// using <nested identifier>;
|
||||
detail::skip(stream, "using");
|
||||
|
||||
// <nested identifier>;
|
||||
std::string target_name;
|
||||
while (!detail::skip_if(stream, ";"))
|
||||
target_name += stream.get().c_str();
|
||||
|
||||
auto target = cpp_entity_ref(parse_entity_target_cursor(cur), std::move(target_name));
|
||||
return cpp_using_declaration::build(std::move(target));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
|||
return parse_cpp_namespace(context, cur);
|
||||
case CXCursor_NamespaceAlias:
|
||||
return parse_cpp_namespace_alias(context, cur);
|
||||
case CXCursor_UsingDirective:
|
||||
return parse_cpp_using_directive(context, cur);
|
||||
case CXCursor_UsingDeclaration:
|
||||
return parse_cpp_using_declaration(context, cur);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -28,9 +28,12 @@ namespace cppast
|
|||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace_alias(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_directive(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_declaration(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,3 +108,61 @@ namespace f = outer::c;
|
|||
});
|
||||
REQUIRE(count == 6u);
|
||||
}
|
||||
|
||||
TEST_CASE("cpp_using_directive")
|
||||
{
|
||||
auto code = R"(
|
||||
namespace ns1 {}
|
||||
namespace ns2 {}
|
||||
|
||||
using namespace ns1;
|
||||
using namespace ns2;
|
||||
|
||||
namespace outer
|
||||
{
|
||||
namespace ns {}
|
||||
|
||||
using namespace ns;
|
||||
using namespace ::ns1;
|
||||
}
|
||||
|
||||
using namespace outer::ns;
|
||||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto check_directive = [&](const cpp_using_directive& directive, const char* target_full_name) {
|
||||
auto target = directive.target();
|
||||
|
||||
auto entity = target.get(idx);
|
||||
REQUIRE(entity);
|
||||
REQUIRE(full_name(entity.value()) == target_full_name);
|
||||
};
|
||||
|
||||
auto file = parse(idx, "cpp_using_directive.cpp", code);
|
||||
auto count = test_visit<cpp_using_directive>(*file, [&](const cpp_using_directive& directive) {
|
||||
if (directive.target().name() == "ns1")
|
||||
check_directive(directive, "ns1");
|
||||
else if (directive.target().name() == "ns2")
|
||||
check_directive(directive, "ns2");
|
||||
else if (directive.target().name() == "ns")
|
||||
{
|
||||
check_parent(directive, "outer", "");
|
||||
check_directive(directive, "outer::ns");
|
||||
}
|
||||
else if (directive.target().name() == "::ns1")
|
||||
{
|
||||
check_parent(directive, "outer", "");
|
||||
check_directive(directive, "ns1");
|
||||
}
|
||||
else if (directive.target().name() == "outer::ns")
|
||||
check_directive(directive, "outer::ns");
|
||||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
REQUIRE(count == 5u);
|
||||
}
|
||||
|
||||
TEST_CASE("cpp_using_declaration")
|
||||
{
|
||||
// TODO: write test when actual entities can be parsed
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue