Parse cpp_class
This commit is contained in:
parent
895ac5d0c9
commit
e0b76a07d0
9 changed files with 425 additions and 50 deletions
|
|
@ -37,6 +37,8 @@ namespace cppast
|
||||||
class cpp_access_specifier final : public cpp_entity
|
class cpp_access_specifier final : public cpp_entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static cpp_entity_kind kind() noexcept;
|
||||||
|
|
||||||
/// \returns A newly created access specifier.
|
/// \returns A newly created access specifier.
|
||||||
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
||||||
/// as nothing can refer to it.
|
/// as nothing can refer to it.
|
||||||
|
|
@ -66,6 +68,8 @@ namespace cppast
|
||||||
class cpp_base_class final : public cpp_entity
|
class cpp_base_class final : public cpp_entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static cpp_entity_kind kind() noexcept;
|
||||||
|
|
||||||
/// \returns A newly created base class specifier.
|
/// \returns A newly created base class specifier.
|
||||||
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
/// \notes It is not meant to be registered at the [cppast::cpp_entity_index](),
|
||||||
/// as nothing can refer to the specifier itself.
|
/// as nothing can refer to the specifier itself.
|
||||||
|
|
@ -111,16 +115,24 @@ namespace cppast
|
||||||
class cpp_class final : public cpp_entity, public cpp_entity_container<cpp_class, cpp_entity>
|
class cpp_class final : public cpp_entity, public cpp_entity_container<cpp_class, cpp_entity>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static cpp_entity_kind kind() noexcept;
|
||||||
|
|
||||||
/// Builds a [cppast::cpp_class]().
|
/// Builds a [cppast::cpp_class]().
|
||||||
class builder
|
class builder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \effects Sets the name and kind and whether it is `final`.
|
/// \effects Sets the name and kind and whether it is `final`.
|
||||||
explicit builder(std::string name, cpp_class_kind kind, bool is_final)
|
explicit builder(std::string name, cpp_class_kind kind, bool is_final = false)
|
||||||
: class_(new cpp_class(std::move(name), kind, is_final))
|
: class_(new cpp_class(std::move(name), kind, is_final))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Marks the class as final.
|
||||||
|
void is_final() noexcept
|
||||||
|
{
|
||||||
|
class_->final_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Builds a [cppast::cpp_base_class]() and adds it.
|
/// \effects Builds a [cppast::cpp_base_class]() and adds it.
|
||||||
void base_class(const cpp_type_ref& base, cpp_access_specifier_kind access,
|
void base_class(const cpp_type_ref& base, cpp_access_specifier_kind access,
|
||||||
bool is_virtual)
|
bool is_virtual)
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,32 @@ const char* cppast::to_string(cpp_access_specifier_kind access) noexcept
|
||||||
return "should not get here either";
|
return "should not get here either";
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp_entity_kind cpp_access_specifier::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_access_specifier::kind() noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::access_specifier_t;
|
return cpp_entity_kind::access_specifier_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp_entity_kind cpp_base_class::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_access_specifier::do_get_entity_kind() const noexcept
|
||||||
|
{
|
||||||
|
return kind();
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_entity_kind cpp_base_class::kind() noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::base_class_t;
|
return cpp_entity_kind::base_class_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp_entity_kind cpp_class::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_base_class::do_get_entity_kind() const noexcept
|
||||||
|
{
|
||||||
|
return kind();
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_entity_kind cpp_class::kind() noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::class_t;
|
return cpp_entity_kind::class_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpp_entity_kind cpp_class::do_get_entity_kind() const noexcept
|
||||||
|
{
|
||||||
|
return kind();
|
||||||
|
}
|
||||||
|
|
|
||||||
109
src/libclang/class_parser.cpp
Normal file
109
src/libclang/class_parser.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
// 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_class.hpp>
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
#include "libclang_visitor.hpp"
|
||||||
|
#include "parse_functions.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
cpp_class_kind parse_class_kind(const CXCursor& cur)
|
||||||
|
{
|
||||||
|
switch (clang_getCursorKind(cur))
|
||||||
|
{
|
||||||
|
case CXCursor_ClassDecl:
|
||||||
|
return cpp_class_kind::class_t;
|
||||||
|
case CXCursor_StructDecl:
|
||||||
|
return cpp_class_kind::struct_t;
|
||||||
|
case CXCursor_UnionDecl:
|
||||||
|
return cpp_class_kind::union_t;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
|
return cpp_class_kind::class_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_class::builder make_class_builder(const CXCursor& cur)
|
||||||
|
{
|
||||||
|
auto kind = parse_class_kind(cur);
|
||||||
|
auto name = detail::cxstring(clang_getCursorSpelling(cur));
|
||||||
|
return cpp_class::builder(name.c_str(), kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_access_specifier_kind convert_access(const CXCursor& cur)
|
||||||
|
{
|
||||||
|
switch (clang_getCXXAccessSpecifier(cur))
|
||||||
|
{
|
||||||
|
case CX_CXXInvalidAccessSpecifier:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CX_CXXPublic:
|
||||||
|
return cpp_public;
|
||||||
|
case CX_CXXProtected:
|
||||||
|
return cpp_protected;
|
||||||
|
case CX_CXXPrivate:
|
||||||
|
return cpp_private;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
|
return cpp_public;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_access_specifier(cpp_class::builder& builder, const CXCursor& cur)
|
||||||
|
{
|
||||||
|
DEBUG_ASSERT(cur.kind == CXCursor_CXXAccessSpecifier, detail::assert_handler{});
|
||||||
|
builder.access_specifier(convert_access(cur));
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
|
||||||
|
const CXCursor& cur)
|
||||||
|
{
|
||||||
|
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
|
||||||
|
auto access = convert_access(cur);
|
||||||
|
auto is_virtual = clang_isVirtualBase(cur) != 0u;
|
||||||
|
|
||||||
|
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||||
|
detail::token_stream stream(tokenizer, cur);
|
||||||
|
|
||||||
|
// [<attribute>] [virtual] [<access>] <name>
|
||||||
|
// can't use spelling to get the name
|
||||||
|
detail::skip_attribute(stream);
|
||||||
|
if (is_virtual)
|
||||||
|
detail::skip(stream, "virtual");
|
||||||
|
detail::skip_if(stream, to_string(access));
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
while (!stream.done())
|
||||||
|
name += stream.get().c_str();
|
||||||
|
|
||||||
|
auto type =
|
||||||
|
cpp_type_ref(detail::get_entity_id(clang_getCursorReferenced(cur)), std::move(name));
|
||||||
|
builder.base_class(type, access, is_virtual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context& context,
|
||||||
|
const CXCursor& cur)
|
||||||
|
{
|
||||||
|
if (!clang_isCursorDefinition(cur))
|
||||||
|
return nullptr;
|
||||||
|
auto builder = make_class_builder(cur);
|
||||||
|
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||||
|
auto kind = clang_getCursorKind(child);
|
||||||
|
if (kind == CXCursor_CXXAccessSpecifier)
|
||||||
|
add_access_specifier(builder, child);
|
||||||
|
else if (kind == CXCursor_CXXBaseSpecifier)
|
||||||
|
add_base_class(builder, context, child);
|
||||||
|
else if (kind == CXCursor_CXXFinalAttr)
|
||||||
|
builder.is_final();
|
||||||
|
else if (auto entity = parse_entity(context, child))
|
||||||
|
builder.add_child(std::move(entity));
|
||||||
|
});
|
||||||
|
return builder.finish(*context.idx, get_entity_id(cur));
|
||||||
|
}
|
||||||
|
|
@ -37,9 +37,12 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
||||||
case CXCursor_TypeAliasDecl:
|
case CXCursor_TypeAliasDecl:
|
||||||
case CXCursor_TypedefDecl:
|
case CXCursor_TypedefDecl:
|
||||||
return parse_cpp_type_alias(context, cur);
|
return parse_cpp_type_alias(context, cur);
|
||||||
|
|
||||||
case CXCursor_EnumDecl:
|
case CXCursor_EnumDecl:
|
||||||
return parse_cpp_enum(context, cur);
|
return parse_cpp_enum(context, cur);
|
||||||
|
case CXCursor_ClassDecl:
|
||||||
|
case CXCursor_StructDecl:
|
||||||
|
case CXCursor_UnionDecl:
|
||||||
|
return parse_cpp_class(context, cur);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,10 @@ namespace cppast
|
||||||
|
|
||||||
std::unique_ptr<cpp_entity> parse_cpp_type_alias(const parse_context& context,
|
std::unique_ptr<cpp_entity> parse_cpp_type_alias(const parse_context& context,
|
||||||
const CXCursor& cur);
|
const CXCursor& cur);
|
||||||
|
|
||||||
std::unique_ptr<cpp_entity> parse_cpp_enum(const parse_context& context,
|
std::unique_ptr<cpp_entity> parse_cpp_enum(const parse_context& context,
|
||||||
const CXCursor& cur);
|
const CXCursor& cur);
|
||||||
|
std::unique_ptr<cpp_entity> parse_cpp_class(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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,11 @@ namespace cppast
|
||||||
return str_ ? str_.value().c_str : "";
|
return str_ ? str_.value().c_str : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string std_str() const noexcept
|
||||||
|
{
|
||||||
|
return c_str();
|
||||||
|
}
|
||||||
|
|
||||||
char operator[](std::size_t i) const noexcept
|
char operator[](std::size_t i) const noexcept
|
||||||
{
|
{
|
||||||
return c_str()[i];
|
return c_str()[i];
|
||||||
|
|
|
||||||
|
|
@ -142,17 +142,8 @@ namespace
|
||||||
end = prev;
|
end = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (clang_getCursorKind(cur) == CXCursor_TypeAliasDecl
|
else if (clang_isExpression(clang_getCursorKind(cur))
|
||||||
&& !token_after_is(tu, file, cur, end, ";"))
|
|| clang_getCursorKind(cur) == CXCursor_CXXBaseSpecifier)
|
||||||
{
|
|
||||||
// type alias tokens don't include everything
|
|
||||||
do
|
|
||||||
{
|
|
||||||
end = get_next_location(tu, file, end);
|
|
||||||
} while (!token_after_is(tu, file, cur, end, ";"));
|
|
||||||
end = get_next_location(tu, file, end);
|
|
||||||
}
|
|
||||||
else if (clang_isExpression(clang_getCursorKind(cur)))
|
|
||||||
// need to shrink range by one
|
// need to shrink range by one
|
||||||
end = get_next_location(tu, file, end, -1);
|
end = get_next_location(tu, file, end, -1);
|
||||||
|
|
||||||
|
|
@ -236,35 +227,46 @@ void detail::skip_brackets(detail::token_stream& stream)
|
||||||
stream.set_cur(std::next(closing));
|
stream.set_cur(std::next(closing));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool skip_attribute_impl(detail::token_stream& stream)
|
||||||
|
{
|
||||||
|
if (skip_if(stream, "[") && stream.peek() == "[")
|
||||||
|
{
|
||||||
|
// C++11 attribute
|
||||||
|
// [[<attribute>]]
|
||||||
|
// ^
|
||||||
|
skip_brackets(stream);
|
||||||
|
// [[<attribute>]]
|
||||||
|
// ^
|
||||||
|
skip(stream, "]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (skip_if(stream, "__attribute__"))
|
||||||
|
{
|
||||||
|
// GCC/clang attributes
|
||||||
|
// __attribute__(<attribute>)
|
||||||
|
// ^
|
||||||
|
skip_brackets(stream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (skip_if(stream, "__declspec"))
|
||||||
|
{
|
||||||
|
// MSVC declspec
|
||||||
|
// __declspec(<attribute>)
|
||||||
|
// ^
|
||||||
|
skip_brackets(stream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool detail::skip_attribute(detail::token_stream& stream)
|
bool detail::skip_attribute(detail::token_stream& stream)
|
||||||
{
|
{
|
||||||
if (skip_if(stream, "[") && stream.peek() == "[")
|
auto any = false;
|
||||||
{
|
while (skip_attribute_impl(stream))
|
||||||
// C++11 attribute
|
any = true;
|
||||||
// [[<attribute>]]
|
return any;
|
||||||
// ^
|
|
||||||
skip_brackets(stream);
|
|
||||||
// [[<attribute>]]
|
|
||||||
// ^
|
|
||||||
skip(stream, "]");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (skip_if(stream, "__attribute__"))
|
|
||||||
{
|
|
||||||
// GCC/clang attributes
|
|
||||||
// __attribute__(<attribute>)
|
|
||||||
// ^
|
|
||||||
skip_brackets(stream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (skip_if(stream, "__declspec"))
|
|
||||||
{
|
|
||||||
// MSVC declspec
|
|
||||||
// __declspec(<attribute>)
|
|
||||||
// ^
|
|
||||||
skip_brackets(stream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
230
test/cpp_class.cpp
Normal file
230
test/cpp_class.cpp
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
// 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_class.hpp>
|
||||||
|
|
||||||
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
|
TEST_CASE("cpp_class")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
// basic
|
||||||
|
struct a {};
|
||||||
|
class b final {};
|
||||||
|
union c {};
|
||||||
|
|
||||||
|
struct ignore_me;
|
||||||
|
|
||||||
|
// members
|
||||||
|
struct d
|
||||||
|
{
|
||||||
|
enum m1 {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum m2 {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
private:
|
||||||
|
enum m3 {};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum m4 {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// bases
|
||||||
|
class e
|
||||||
|
: a, private d {};
|
||||||
|
|
||||||
|
namespace ns
|
||||||
|
{
|
||||||
|
struct base {};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct f
|
||||||
|
: public ns::base, virtual protected e
|
||||||
|
{};
|
||||||
|
|
||||||
|
using namespace ns;
|
||||||
|
|
||||||
|
struct g
|
||||||
|
: base {};
|
||||||
|
)";
|
||||||
|
|
||||||
|
cpp_entity_index idx;
|
||||||
|
auto file = parse(idx, "cpp_class.cpp", code);
|
||||||
|
auto count = test_visit<cpp_class>(*file, [&](const cpp_class& c) {
|
||||||
|
if (c.name() == "a" || c.name() == "base")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.bases().begin() == c.bases().end());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
}
|
||||||
|
else if (c.name() == "b")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::class_t);
|
||||||
|
REQUIRE(c.is_final());
|
||||||
|
REQUIRE(c.bases().begin() == c.bases().end());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
}
|
||||||
|
else if (c.name() == "c")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::union_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.bases().begin() == c.bases().end());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
}
|
||||||
|
else if (c.name() == "d")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.bases().begin() == c.bases().end());
|
||||||
|
|
||||||
|
auto no_children = 0u;
|
||||||
|
for (auto& child : c)
|
||||||
|
{
|
||||||
|
switch (no_children++)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
REQUIRE(child.name() == "m1");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
REQUIRE(child.name() == "public");
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::access_specifier_t);
|
||||||
|
REQUIRE(static_cast<const cpp_access_specifier&>(child).access_specifier()
|
||||||
|
== cpp_public);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
REQUIRE(child.name() == "m2");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
REQUIRE(child.name() == "private");
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::access_specifier_t);
|
||||||
|
REQUIRE(static_cast<const cpp_access_specifier&>(child).access_specifier()
|
||||||
|
== cpp_private);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
REQUIRE(child.name() == "private");
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::access_specifier_t);
|
||||||
|
REQUIRE(static_cast<const cpp_access_specifier&>(child).access_specifier()
|
||||||
|
== cpp_private);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
REQUIRE(child.name() == "m3");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
REQUIRE(child.name() == "protected");
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::access_specifier_t);
|
||||||
|
REQUIRE(static_cast<const cpp_access_specifier&>(child).access_specifier()
|
||||||
|
== cpp_protected);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
REQUIRE(child.name() == "m4");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
REQUIRE(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
REQUIRE(no_children == 8u);
|
||||||
|
}
|
||||||
|
else if (c.name() == "e")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::class_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
|
||||||
|
auto no_bases = 0u;
|
||||||
|
for (auto& base : c.bases())
|
||||||
|
{
|
||||||
|
++no_bases;
|
||||||
|
if (base.name() == "a")
|
||||||
|
{
|
||||||
|
REQUIRE(base.access_specifier() == cpp_private);
|
||||||
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
|
auto entity = base.entity().get(idx);
|
||||||
|
REQUIRE(entity);
|
||||||
|
REQUIRE(entity.value().name() == "a");
|
||||||
|
}
|
||||||
|
else if (base.name() == "d")
|
||||||
|
{
|
||||||
|
REQUIRE(base.access_specifier() == cpp_private);
|
||||||
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
|
auto entity = base.entity().get(idx);
|
||||||
|
REQUIRE(entity);
|
||||||
|
REQUIRE(entity.value().name() == "d");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
REQUIRE(no_bases == 2u);
|
||||||
|
}
|
||||||
|
else if (c.name() == "f")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
|
||||||
|
auto no_bases = 0u;
|
||||||
|
for (auto& base : c.bases())
|
||||||
|
{
|
||||||
|
++no_bases;
|
||||||
|
if (base.name() == "ns::base")
|
||||||
|
{
|
||||||
|
REQUIRE(base.access_specifier() == cpp_public);
|
||||||
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
|
auto entity = base.entity().get(idx);
|
||||||
|
REQUIRE(entity);
|
||||||
|
REQUIRE(entity.value().name() == "base");
|
||||||
|
REQUIRE(full_name(entity.value()) == "ns::base");
|
||||||
|
}
|
||||||
|
else if (base.name() == "e")
|
||||||
|
{
|
||||||
|
REQUIRE(base.access_specifier() == cpp_protected);
|
||||||
|
REQUIRE(base.is_virtual());
|
||||||
|
|
||||||
|
auto entity = base.entity().get(idx);
|
||||||
|
REQUIRE(entity);
|
||||||
|
REQUIRE(entity.value().name() == "e");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
REQUIRE(no_bases == 2u);
|
||||||
|
}
|
||||||
|
else if (c.name() == "g")
|
||||||
|
{
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
REQUIRE(c.begin() == c.end());
|
||||||
|
|
||||||
|
auto no_bases = 0u;
|
||||||
|
for (auto& base : c.bases())
|
||||||
|
{
|
||||||
|
++no_bases;
|
||||||
|
if (base.name() == "base")
|
||||||
|
{
|
||||||
|
REQUIRE(base.access_specifier() == cpp_public);
|
||||||
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
|
auto entity = base.entity().get(idx);
|
||||||
|
REQUIRE(entity);
|
||||||
|
REQUIRE(entity.value().name() == "base");
|
||||||
|
REQUIRE(full_name(entity.value()) == "ns::base");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
REQUIRE(no_bases == 1u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
});
|
||||||
|
REQUIRE(count == 8u);
|
||||||
|
}
|
||||||
|
|
@ -28,10 +28,8 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
||||||
auto user_synthesized = static_cast<const cpp_user_defined_type&>(synthesized).entity();
|
auto user_synthesized = static_cast<const cpp_user_defined_type&>(synthesized).entity();
|
||||||
if (user_parsed.name() != user_synthesized.name())
|
if (user_parsed.name() != user_synthesized.name())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
auto entity = user_parsed.get(idx);
|
||||||
// TODO: check that the referring also works (need parsing of structs)
|
return entity.has_value() && entity.value().name() == user_parsed.name();
|
||||||
// auto entity = user_parsed.get(idx);
|
|
||||||
// return entity.has_value() && entity.value().name() == user_parsed.name();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case cpp_type_kind::cv_qualified:
|
case cpp_type_kind::cv_qualified:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue