Parse cpp_class_template
This commit is contained in:
parent
bf7c85a9dd
commit
22fd582756
12 changed files with 289 additions and 56 deletions
|
|
@ -74,17 +74,19 @@ namespace cppast
|
||||||
/// \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.
|
||||||
static std::unique_ptr<cpp_base_class> build(const cpp_type_ref& base,
|
static std::unique_ptr<cpp_base_class> build(std::string name,
|
||||||
|
std::unique_ptr<cpp_type> base,
|
||||||
cpp_access_specifier_kind access,
|
cpp_access_specifier_kind access,
|
||||||
bool is_virtual)
|
bool is_virtual)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<cpp_base_class>(new cpp_base_class(base, access, is_virtual));
|
return std::unique_ptr<cpp_base_class>(
|
||||||
|
new cpp_base_class(std::move(name), std::move(base), access, is_virtual));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns An entity reference to the base class.
|
/// \returns The type of the base class.
|
||||||
cpp_type_ref entity() const
|
const cpp_type& type() const
|
||||||
{
|
{
|
||||||
return cpp_type_ref(base_id_, name());
|
return *type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns The access specifier of the base class.
|
/// \returns The access specifier of the base class.
|
||||||
|
|
@ -100,15 +102,15 @@ namespace cppast
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cpp_base_class(const cpp_type_ref& base, cpp_access_specifier_kind access, bool is_virtual)
|
cpp_base_class(std::string name, std::unique_ptr<cpp_type> base,
|
||||||
: cpp_entity(base.name()), base_id_(base.id()[0u]), access_(access), virtual_(is_virtual)
|
cpp_access_specifier_kind access, bool is_virtual)
|
||||||
|
: cpp_entity(std::move(name)), type_(std::move(base)), access_(access), virtual_(is_virtual)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(!base.is_overloaded(), detail::precondition_error_handler{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
||||||
|
|
||||||
cpp_entity_id base_id_;
|
std::unique_ptr<cpp_type> type_;
|
||||||
cpp_access_specifier_kind access_;
|
cpp_access_specifier_kind access_;
|
||||||
bool virtual_;
|
bool virtual_;
|
||||||
};
|
};
|
||||||
|
|
@ -142,10 +144,11 @@ namespace cppast
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \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(std::string name, std::unique_ptr<cpp_type> type,
|
||||||
bool is_virtual)
|
cpp_access_specifier_kind access, bool is_virtual)
|
||||||
{
|
{
|
||||||
add_base_class(cpp_base_class::build(base, access, is_virtual));
|
add_base_class(
|
||||||
|
cpp_base_class::build(std::move(name), std::move(type), access, is_virtual));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects Adds a new base class.
|
/// \effects Adds a new base class.
|
||||||
|
|
@ -179,10 +182,17 @@ namespace cppast
|
||||||
|
|
||||||
/// \effects Marks the class as forward declaration.
|
/// \effects Marks the class as forward declaration.
|
||||||
/// \returns The finished class.
|
/// \returns The finished class.
|
||||||
/// \notes It will not be registered, as it is not the main definition.
|
|
||||||
std::unique_ptr<cpp_class> finish_declaration(const cpp_entity_index& idx,
|
std::unique_ptr<cpp_class> finish_declaration(const cpp_entity_index& idx,
|
||||||
cpp_entity_id definition_id);
|
cpp_entity_id definition_id);
|
||||||
|
|
||||||
|
/// \effects Returns the finished class without registering it.
|
||||||
|
/// \notes This is intended for templated classes only.
|
||||||
|
std::unique_ptr<cpp_class> finish();
|
||||||
|
|
||||||
|
/// \effects Returns the finish class without registering it and marks it as forward declaration.
|
||||||
|
/// \notes This is intended for templated classes only.
|
||||||
|
std::unique_ptr<cpp_class> finish_declaration(cpp_entity_id definition_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<cpp_class> class_;
|
std::unique_ptr<cpp_class> class_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ namespace cppast
|
||||||
class cpp_class_template final : public cpp_template
|
class cpp_class_template final : public cpp_template
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static cpp_entity_kind kind() noexcept;
|
||||||
|
|
||||||
/// Builder for [cppast::cpp_class_template]().
|
/// Builder for [cppast::cpp_class_template]().
|
||||||
class builder : public basic_builder<cpp_class_template, cpp_class>
|
class builder : public basic_builder<cpp_class_template, cpp_class>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,14 @@ namespace cppast
|
||||||
|
|
||||||
/// \effects Registers the template.
|
/// \effects Registers the template.
|
||||||
/// \returns The finished template.
|
/// \returns The finished template.
|
||||||
std::unique_ptr<T> finish(const cpp_entity_index& idx, cpp_entity_id id)
|
std::unique_ptr<T> finish(const cpp_entity_index& idx, cpp_entity_id id,
|
||||||
|
bool is_definition)
|
||||||
{
|
{
|
||||||
|
if (is_definition)
|
||||||
idx.register_definition(std::move(id), type_safe::cref(*template_entity));
|
idx.register_definition(std::move(id), type_safe::cref(*template_entity));
|
||||||
|
else
|
||||||
|
idx.register_forward_declaration(std::move(id),
|
||||||
|
type_safe::cref(*template_entity));
|
||||||
return std::move(template_entity);
|
return std::move(template_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,17 @@ std::unique_ptr<cpp_class> cpp_class::builder::finish_declaration(const cpp_enti
|
||||||
return std::move(class_);
|
return std::move(class_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_class> cpp_class::builder::finish()
|
||||||
|
{
|
||||||
|
return std::move(class_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_class> cpp_class::builder::finish_declaration(cpp_entity_id definition_id)
|
||||||
|
{
|
||||||
|
class_->set_definition(definition_id);
|
||||||
|
return std::move(class_);
|
||||||
|
}
|
||||||
|
|
||||||
const char* cppast::to_string(cpp_class_kind kind) noexcept
|
const char* cppast::to_string(cpp_class_kind kind) noexcept
|
||||||
{
|
{
|
||||||
switch (kind)
|
switch (kind)
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,16 @@
|
||||||
|
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
cpp_entity_kind cpp_class_template::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_class_template::kind() noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::class_template_t;
|
return cpp_entity_kind::class_template_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpp_entity_kind cpp_class_template::do_get_entity_kind() const noexcept
|
||||||
|
{
|
||||||
|
return kind();
|
||||||
|
}
|
||||||
|
|
||||||
cpp_entity_kind cpp_class_template_specialization::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_class_template_specialization::do_get_entity_kind() const noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::class_template_specialization_t;
|
return cpp_entity_kind::class_template_specialization_t;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@ namespace
|
||||||
{
|
{
|
||||||
cpp_class_kind parse_class_kind(const CXCursor& cur)
|
cpp_class_kind parse_class_kind(const CXCursor& cur)
|
||||||
{
|
{
|
||||||
switch (clang_getCursorKind(cur))
|
auto kind = clang_getTemplateCursorKind(cur);
|
||||||
|
if (kind == CXCursor_NoDeclFound)
|
||||||
|
kind = clang_getCursorKind(cur);
|
||||||
|
switch (kind)
|
||||||
{
|
{
|
||||||
case CXCursor_ClassDecl:
|
case CXCursor_ClassDecl:
|
||||||
return cpp_class_kind::class_t;
|
return cpp_class_kind::class_t;
|
||||||
|
|
@ -62,7 +65,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
|
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
|
||||||
const CXCursor& cur)
|
const CXCursor& cur, const CXCursor& class_cur)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
|
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
|
||||||
auto access = convert_access(cur);
|
auto access = convert_access(cur);
|
||||||
|
|
@ -82,9 +85,8 @@ namespace
|
||||||
while (!stream.done())
|
while (!stream.done())
|
||||||
name += stream.get().c_str();
|
name += stream.get().c_str();
|
||||||
|
|
||||||
auto type =
|
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
|
||||||
cpp_type_ref(detail::get_entity_id(clang_getCursorReferenced(cur)), std::move(name));
|
builder.base_class(std::move(name), std::move(type), access, is_virtual);
|
||||||
builder.base_class(type, access, is_virtual);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,14 +100,19 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
||||||
if (kind == CXCursor_CXXAccessSpecifier)
|
if (kind == CXCursor_CXXAccessSpecifier)
|
||||||
add_access_specifier(builder, child);
|
add_access_specifier(builder, child);
|
||||||
else if (kind == CXCursor_CXXBaseSpecifier)
|
else if (kind == CXCursor_CXXBaseSpecifier)
|
||||||
add_base_class(builder, context, child);
|
add_base_class(builder, context, child, cur);
|
||||||
else if (kind == CXCursor_CXXFinalAttr)
|
else if (kind == CXCursor_CXXFinalAttr)
|
||||||
builder.is_final();
|
builder.is_final();
|
||||||
|
else if (kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||||
|
|| kind == CXCursor_TemplateTemplateParameter)
|
||||||
|
return;
|
||||||
else if (auto entity = parse_entity(context, child))
|
else if (auto entity = parse_entity(context, child))
|
||||||
builder.add_child(std::move(entity));
|
builder.add_child(std::move(entity));
|
||||||
});
|
});
|
||||||
|
auto is_templated = clang_getTemplateCursorKind(cur) != CXCursor_NoDeclFound;
|
||||||
if (clang_isCursorDefinition(cur))
|
if (clang_isCursorDefinition(cur))
|
||||||
return builder.finish(*context.idx, get_entity_id(cur));
|
return is_templated ? builder.finish() : builder.finish(*context.idx, get_entity_id(cur));
|
||||||
else
|
else
|
||||||
return builder.finish_declaration(*context.idx, get_entity_id(cur));
|
return is_templated ? builder.finish_declaration(detail::get_entity_id(cur)) :
|
||||||
|
builder.finish_declaration(*context.idx, get_entity_id(cur));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,8 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
||||||
return parse_cpp_alias_template(context, cur);
|
return parse_cpp_alias_template(context, cur);
|
||||||
case CXCursor_FunctionTemplate:
|
case CXCursor_FunctionTemplate:
|
||||||
return parse_cpp_function_template(context, cur);
|
return parse_cpp_function_template(context, cur);
|
||||||
|
case CXCursor_ClassTemplate:
|
||||||
|
return parse_cpp_class_template(context, cur);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,8 @@ namespace cppast
|
||||||
const CXCursor& cur);
|
const CXCursor& cur);
|
||||||
std::unique_ptr<cpp_entity> parse_cpp_function_template(const parse_context& context,
|
std::unique_ptr<cpp_entity> parse_cpp_function_template(const parse_context& context,
|
||||||
const CXCursor& cur);
|
const CXCursor& cur);
|
||||||
|
std::unique_ptr<cpp_entity> parse_cpp_class_template(const parse_context& context,
|
||||||
|
const CXCursor& cur);
|
||||||
|
|
||||||
// as_template: true, iff currently parsing a template
|
// as_template: true, iff currently parsing a template
|
||||||
std::unique_ptr<cpp_entity> parse_entity(
|
std::unique_ptr<cpp_entity> parse_entity(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// found in the top-level directory of this distribution.
|
// found in the top-level directory of this distribution.
|
||||||
|
|
||||||
#include <cppast/cpp_alias_template.hpp>
|
#include <cppast/cpp_alias_template.hpp>
|
||||||
|
#include <cppast/cpp_class_template.hpp>
|
||||||
#include <cppast/cpp_function_template.hpp>
|
#include <cppast/cpp_function_template.hpp>
|
||||||
|
|
||||||
#include <cppast/cpp_entity_kind.hpp>
|
#include <cppast/cpp_entity_kind.hpp>
|
||||||
|
|
@ -217,7 +218,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_alias_template(const detail::parse
|
||||||
return nullptr;
|
return nullptr;
|
||||||
context.comments.match(builder.value().get(), cur);
|
context.comments.match(builder.value().get(), cur);
|
||||||
parse_parameters(builder.value(), context, cur);
|
parse_parameters(builder.value(), context, cur);
|
||||||
return builder.value().finish(*context.idx, detail::get_entity_id(cur));
|
return builder.value().finish(*context.idx, detail::get_entity_id(cur), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<cpp_entity> detail::parse_cpp_function_template(
|
std::unique_ptr<cpp_entity> detail::parse_cpp_function_template(
|
||||||
|
|
@ -259,13 +260,14 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_function_template(
|
||||||
std::unique_ptr<cpp_function_base>(static_cast<cpp_function_base*>(func.release())));
|
std::unique_ptr<cpp_function_base>(static_cast<cpp_function_base*>(func.release())));
|
||||||
builder.get().set_comment(std::move(comment));
|
builder.get().set_comment(std::move(comment));
|
||||||
parse_parameters(builder, context, cur);
|
parse_parameters(builder, context, cur);
|
||||||
return builder.finish(*context.idx, detail::get_entity_id(cur));
|
return builder.finish(*context.idx, detail::get_entity_id(cur),
|
||||||
|
builder.get().function().is_definition());
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template <class Builder>
|
template <class Builder>
|
||||||
void add_arguments(Builder& b, const detail::parse_context& context, const CXCursor& cur)
|
void parse_arguments(Builder& b, const detail::parse_context& context, const CXCursor& cur)
|
||||||
{
|
{
|
||||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||||
detail::token_stream stream(tokenizer, cur);
|
detail::token_stream stream(tokenizer, cur);
|
||||||
|
|
@ -320,10 +322,36 @@ std::unique_ptr<cpp_entity> detail::try_parse_cpp_function_template_specializati
|
||||||
if (!func)
|
if (!func)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// steal comment
|
||||||
|
auto comment = type_safe::copy(func->comment());
|
||||||
|
func->set_comment(type_safe::nullopt);
|
||||||
|
|
||||||
cpp_function_template_specialization::builder
|
cpp_function_template_specialization::builder
|
||||||
builder(std::unique_ptr<cpp_function_base>(static_cast<cpp_function_base*>(func.release())),
|
builder(std::unique_ptr<cpp_function_base>(static_cast<cpp_function_base*>(func.release())),
|
||||||
cpp_template_ref(detail::get_entity_id(templ), ""));
|
cpp_template_ref(detail::get_entity_id(templ), ""));
|
||||||
|
builder.get().set_comment(std::move(comment));
|
||||||
add_arguments(builder, context, cur);
|
parse_arguments(builder, context, cur);
|
||||||
return builder.finish(*context.idx, detail::get_entity_id(cur));
|
return builder.finish(*context.idx, detail::get_entity_id(cur),
|
||||||
|
builder.get().function().is_definition());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_entity> detail::parse_cpp_class_template(const detail::parse_context& context,
|
||||||
|
const CXCursor& cur)
|
||||||
|
{
|
||||||
|
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ClassTemplate, detail::assert_handler{});
|
||||||
|
|
||||||
|
auto c = detail::parse_cpp_class(context, cur);
|
||||||
|
if (!c)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// steal comment
|
||||||
|
auto comment = type_safe::copy(c->comment());
|
||||||
|
c->set_comment(type_safe::nullopt);
|
||||||
|
|
||||||
|
cpp_class_template::builder builder(
|
||||||
|
std::unique_ptr<cpp_class>(static_cast<cpp_class*>(c.release())));
|
||||||
|
builder.get().set_comment(std::move(comment));
|
||||||
|
parse_parameters(builder, context, cur);
|
||||||
|
return builder.finish(*context.idx, detail::get_entity_id(cur),
|
||||||
|
builder.get().class_().is_definition());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -451,6 +451,7 @@ namespace
|
||||||
case CXType_Vector:
|
case CXType_Vector:
|
||||||
case CXType_ObjCInterface:
|
case CXType_ObjCInterface:
|
||||||
case CXType_ObjCObjectPointer:
|
case CXType_ObjCObjectPointer:
|
||||||
|
case CXType_Dependent:
|
||||||
{
|
{
|
||||||
auto msg = detail::format("unexpected type of kind '",
|
auto msg = detail::format("unexpected type of kind '",
|
||||||
detail::get_type_kind_spelling(type).c_str(), "'");
|
detail::get_type_kind_spelling(type).c_str(), "'");
|
||||||
|
|
@ -543,10 +544,6 @@ namespace
|
||||||
case CXType_MemberPointer:
|
case CXType_MemberPointer:
|
||||||
return cpp_pointer_type::build(parse_member_pointee_type(context, cur, type));
|
return cpp_pointer_type::build(parse_member_pointee_type(context, cur, type));
|
||||||
|
|
||||||
// TODO: everything template related
|
|
||||||
case CXType_Dependent:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: auto/decltype
|
// TODO: auto/decltype
|
||||||
case CXType_Auto:
|
case CXType_Auto:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -179,20 +179,18 @@ struct g
|
||||||
REQUIRE(base.access_specifier() == cpp_private);
|
REQUIRE(base.access_specifier() == cpp_private);
|
||||||
REQUIRE(!base.is_virtual());
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
REQUIRE(!base.entity().is_overloaded());
|
REQUIRE(
|
||||||
auto entities = base.entity().get(idx);
|
equal_types(idx, base.type(), *cpp_user_defined_type::build(
|
||||||
REQUIRE(entities.size() == 1u);
|
cpp_type_ref(cpp_entity_id(""), "a"))));
|
||||||
REQUIRE(entities[0u]->name() == "a");
|
|
||||||
}
|
}
|
||||||
else if (base.name() == "d")
|
else if (base.name() == "d")
|
||||||
{
|
{
|
||||||
REQUIRE(base.access_specifier() == cpp_private);
|
REQUIRE(base.access_specifier() == cpp_private);
|
||||||
REQUIRE(!base.is_virtual());
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
REQUIRE(!base.entity().is_overloaded());
|
REQUIRE(
|
||||||
auto entities = base.entity().get(idx);
|
equal_types(idx, base.type(), *cpp_user_defined_type::build(
|
||||||
REQUIRE(entities.size() == 1u);
|
cpp_type_ref(cpp_entity_id(""), "d"))));
|
||||||
REQUIRE(entities[0u]->name() == "d");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
|
|
@ -216,21 +214,18 @@ struct g
|
||||||
REQUIRE(base.access_specifier() == cpp_public);
|
REQUIRE(base.access_specifier() == cpp_public);
|
||||||
REQUIRE(!base.is_virtual());
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
REQUIRE(!base.entity().is_overloaded());
|
REQUIRE(equal_types(idx, base.type(),
|
||||||
auto entities = base.entity().get(idx);
|
*cpp_user_defined_type::build(
|
||||||
REQUIRE(entities.size() == 1u);
|
cpp_type_ref(cpp_entity_id(""), "ns::base"))));
|
||||||
REQUIRE(entities[0u]->name() == "base");
|
|
||||||
REQUIRE(full_name(*entities[0u]) == "ns::base");
|
|
||||||
}
|
}
|
||||||
else if (base.name() == "e")
|
else if (base.name() == "e")
|
||||||
{
|
{
|
||||||
REQUIRE(base.access_specifier() == cpp_protected);
|
REQUIRE(base.access_specifier() == cpp_protected);
|
||||||
REQUIRE(base.is_virtual());
|
REQUIRE(base.is_virtual());
|
||||||
|
|
||||||
REQUIRE(!base.entity().is_overloaded());
|
REQUIRE(
|
||||||
auto entities = base.entity().get(idx);
|
equal_types(idx, base.type(), *cpp_user_defined_type::build(
|
||||||
REQUIRE(entities.size() == 1u);
|
cpp_type_ref(cpp_entity_id(""), "e"))));
|
||||||
REQUIRE(entities[0u]->name() == "e");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
|
|
@ -254,11 +249,9 @@ struct g
|
||||||
REQUIRE(base.access_specifier() == cpp_public);
|
REQUIRE(base.access_specifier() == cpp_public);
|
||||||
REQUIRE(!base.is_virtual());
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
REQUIRE(!base.entity().is_overloaded());
|
REQUIRE(equal_types(idx, base.type(),
|
||||||
auto entities = base.entity().get(idx);
|
*cpp_user_defined_type::build(
|
||||||
REQUIRE(entities.size() == 1u);
|
cpp_type_ref(cpp_entity_id(""), "ns::base"))));
|
||||||
REQUIRE(entities[0u]->name() == "base");
|
|
||||||
REQUIRE(full_name(*entities[0u]) == "ns::base");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
|
|
|
||||||
171
test/cpp_class_template.cpp
Normal file
171
test/cpp_class_template.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
// 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_template.hpp>
|
||||||
|
|
||||||
|
#include <cppast/cpp_function_template.hpp>
|
||||||
|
#include <cppast/cpp_member_function.hpp>
|
||||||
|
#include <cppast/cpp_member_variable.hpp>
|
||||||
|
|
||||||
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
|
TEST_CASE("cpp_class_template")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
// check everything not related to members first
|
||||||
|
template <typename T>
|
||||||
|
class a {};
|
||||||
|
|
||||||
|
template <int I, typename T>
|
||||||
|
struct b {};
|
||||||
|
|
||||||
|
template <template <typename> class T>
|
||||||
|
union c;
|
||||||
|
|
||||||
|
// bases
|
||||||
|
template <typename T>
|
||||||
|
struct d : T, a<T>, T::type, a<T>::type {};
|
||||||
|
|
||||||
|
// members
|
||||||
|
template <typename T>
|
||||||
|
struct e
|
||||||
|
{
|
||||||
|
T var_a;
|
||||||
|
a<T> var_b;
|
||||||
|
typename T::type var_c;
|
||||||
|
typename a<T>::type var_d;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
T func(U);
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
cpp_entity_index idx;
|
||||||
|
auto file = parse(idx, "cpp_class_template.cpp", code);
|
||||||
|
auto count = test_visit<cpp_class_template>(*file, [&](const cpp_class_template& templ) {
|
||||||
|
auto& c = templ.class_();
|
||||||
|
REQUIRE(!c.is_final());
|
||||||
|
|
||||||
|
if (templ.name() == "a")
|
||||||
|
{
|
||||||
|
check_template_parameters(templ, {{cpp_entity_kind::template_type_parameter_t, "T"}});
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::class_t);
|
||||||
|
REQUIRE(c.is_definition());
|
||||||
|
}
|
||||||
|
else if (templ.name() == "b")
|
||||||
|
{
|
||||||
|
check_template_parameters(templ, {{cpp_entity_kind::non_type_template_parameter_t, "I"},
|
||||||
|
{cpp_entity_kind::template_type_parameter_t, "T"}});
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(c.is_definition());
|
||||||
|
}
|
||||||
|
else if (templ.name() == "c")
|
||||||
|
{
|
||||||
|
check_template_parameters(templ,
|
||||||
|
{{cpp_entity_kind::template_template_parameter_t, "T"}});
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::union_t);
|
||||||
|
REQUIRE(c.is_declaration());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
check_template_parameters(templ, {{cpp_entity_kind::template_type_parameter_t, "T"}});
|
||||||
|
REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
|
||||||
|
REQUIRE(c.is_definition());
|
||||||
|
|
||||||
|
if (templ.name() == "d")
|
||||||
|
{
|
||||||
|
auto no = 0u;
|
||||||
|
for (auto& base : c.bases())
|
||||||
|
{
|
||||||
|
++no;
|
||||||
|
|
||||||
|
REQUIRE(base.access_specifier() == cpp_public);
|
||||||
|
REQUIRE(!base.is_virtual());
|
||||||
|
|
||||||
|
if (base.name() == "T")
|
||||||
|
REQUIRE(equal_types(idx, base.type(),
|
||||||
|
*cpp_template_parameter_type::build(
|
||||||
|
cpp_template_type_parameter_ref(cpp_entity_id(""),
|
||||||
|
"T"))));
|
||||||
|
else if (base.name() == "a<T>")
|
||||||
|
{
|
||||||
|
cpp_template_instantiation_type::builder builder(
|
||||||
|
cpp_template_ref(cpp_entity_id(""), "a"));
|
||||||
|
builder.add_unexposed_arguments("T");
|
||||||
|
REQUIRE(equal_types(idx, base.type(), *builder.finish()));
|
||||||
|
}
|
||||||
|
else if (base.name() == "T::type")
|
||||||
|
REQUIRE(
|
||||||
|
equal_types(idx, base.type(), *cpp_unexposed_type::build("T::type")));
|
||||||
|
else if (base.name() == "a<T>::type")
|
||||||
|
REQUIRE(equal_types(idx, base.type(),
|
||||||
|
*cpp_unexposed_type::build("a<T>::type")));
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
REQUIRE(no == 4u);
|
||||||
|
}
|
||||||
|
else if (templ.name() == "e")
|
||||||
|
{
|
||||||
|
auto no = 0u;
|
||||||
|
for (auto& child : c)
|
||||||
|
{
|
||||||
|
++no;
|
||||||
|
|
||||||
|
if (child.name().length() == 5u && child.name().substr(0, 3u) == "var")
|
||||||
|
{
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::member_variable_t);
|
||||||
|
auto& var = static_cast<const cpp_member_variable&>(child);
|
||||||
|
if (child.name() == "var_a")
|
||||||
|
REQUIRE(
|
||||||
|
equal_types(idx, var.type(),
|
||||||
|
*cpp_template_parameter_type::build(
|
||||||
|
cpp_template_type_parameter_ref(cpp_entity_id(""),
|
||||||
|
"T"))));
|
||||||
|
else if (child.name() == "var_b")
|
||||||
|
{
|
||||||
|
cpp_template_instantiation_type::builder builder(
|
||||||
|
cpp_template_ref(cpp_entity_id(""), "a"));
|
||||||
|
builder.add_unexposed_arguments("T");
|
||||||
|
REQUIRE(equal_types(idx, var.type(), *builder.finish()));
|
||||||
|
}
|
||||||
|
else if (child.name() == "var_c")
|
||||||
|
REQUIRE(equal_types(idx, var.type(),
|
||||||
|
*cpp_unexposed_type::build("typename T::type")));
|
||||||
|
else if (child.name() == "var_d")
|
||||||
|
REQUIRE(equal_types(idx, var.type(),
|
||||||
|
*cpp_unexposed_type::build("typename a<T>::type")));
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
else if (child.name() == "func")
|
||||||
|
{
|
||||||
|
REQUIRE(child.kind() == cpp_entity_kind::function_template_t);
|
||||||
|
auto& templ = static_cast<const cpp_function_template&>(child);
|
||||||
|
|
||||||
|
REQUIRE(templ.function().kind() == cpp_entity_kind::member_function_t);
|
||||||
|
auto& mfunc = static_cast<const cpp_member_function&>(templ.function());
|
||||||
|
|
||||||
|
REQUIRE(equal_types(idx, mfunc.return_type(),
|
||||||
|
*cpp_template_parameter_type::build(
|
||||||
|
cpp_template_type_parameter_ref(cpp_entity_id(""),
|
||||||
|
"T"))));
|
||||||
|
for (auto& param : mfunc)
|
||||||
|
REQUIRE(
|
||||||
|
equal_types(idx, param.type(),
|
||||||
|
*cpp_template_parameter_type::build(
|
||||||
|
cpp_template_type_parameter_ref(cpp_entity_id(""),
|
||||||
|
"U"))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
REQUIRE(no == 5u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
REQUIRE(count == 5u);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue