Parse cpp_type_alias and simple cpp_type's
This commit is contained in:
parent
a38641ecb1
commit
b183513166
13 changed files with 533 additions and 13 deletions
|
|
@ -14,7 +14,18 @@ namespace cppast
|
||||||
/// \exclude
|
/// \exclude
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
void check_entity_cast(const cpp_entity& e, cpp_entity_kind expected_kind);
|
void check_entity_cast_impl(const cpp_entity& e, cpp_entity_kind expected_kind);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void check_entity_cast(const cpp_entity& e)
|
||||||
|
{
|
||||||
|
check_entity_cast_impl(e, T::kind());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void check_entity_cast<cpp_entity>(const cpp_entity&)
|
||||||
|
{
|
||||||
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// A basic reference to some kind of [cppast::cpp_entity]().
|
/// A basic reference to some kind of [cppast::cpp_entity]().
|
||||||
|
|
@ -46,7 +57,7 @@ namespace cppast
|
||||||
auto entity = idx.lookup(target_);
|
auto entity = idx.lookup(target_);
|
||||||
if (!entity)
|
if (!entity)
|
||||||
return type_safe::nullopt;
|
return type_safe::nullopt;
|
||||||
detail::check_entity_cast(entity.value(), T::kind());
|
detail::check_entity_cast<T>(entity.value());
|
||||||
return static_cast<const T&>(entity.value());
|
return static_cast<const T&>(entity.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ namespace cppast
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \returns A newly created unexposed type.
|
/// \returns A newly created unexposed type.
|
||||||
std::unique_ptr<cpp_unexposed_type> build(std::string name)
|
static std::unique_ptr<cpp_unexposed_type> build(std::string name)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<cpp_unexposed_type>(new cpp_unexposed_type(std::move(name)));
|
return std::unique_ptr<cpp_unexposed_type>(new cpp_unexposed_type(std::move(name)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace cppast
|
||||||
class cpp_type_alias final : public cpp_entity
|
class cpp_type_alias final : public cpp_entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static cpp_entity_kind kind() noexcept;
|
||||||
|
|
||||||
/// \returns A newly created and registered type alias.
|
/// \returns A newly created and registered type alias.
|
||||||
static std::unique_ptr<cpp_type_alias> build(const cpp_entity_index& idx, cpp_entity_id id,
|
static std::unique_ptr<cpp_type_alias> build(const cpp_entity_index& idx, cpp_entity_id id,
|
||||||
std::string name,
|
std::string name,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
void detail::check_entity_cast(const cpp_entity& e, cpp_entity_kind expected_kind)
|
void detail::check_entity_cast_impl(const cpp_entity& e, cpp_entity_kind expected_kind)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(e.kind() == expected_kind, detail::precondition_error_handler{},
|
DEBUG_ASSERT(e.kind() == expected_kind, detail::precondition_error_handler{},
|
||||||
"mismatched entity kind");
|
"mismatched entity kind");
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
|
cpp_entity_kind cpp_type_alias::kind() noexcept
|
||||||
|
{
|
||||||
|
return cpp_entity_kind::type_alias_t;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<cpp_type_alias> cpp_type_alias::build(const cpp_entity_index& idx, cpp_entity_id id,
|
std::unique_ptr<cpp_type_alias> cpp_type_alias::build(const cpp_entity_index& idx, cpp_entity_id id,
|
||||||
std::string name,
|
std::string name,
|
||||||
std::unique_ptr<cpp_type> type)
|
std::unique_ptr<cpp_type> type)
|
||||||
|
|
@ -25,5 +30,5 @@ std::unique_ptr<cpp_type_alias> cpp_type_alias::build(std::string
|
||||||
|
|
||||||
cpp_entity_kind cpp_type_alias::do_get_entity_kind() const noexcept
|
cpp_entity_kind cpp_type_alias::do_get_entity_kind() const noexcept
|
||||||
{
|
{
|
||||||
return cpp_entity_kind::type_alias_t;
|
return kind();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ detail::cxstring detail::get_cursor_kind_spelling(const CXCursor& cur) noexcept
|
||||||
return cxstring(clang_getCursorKindSpelling(clang_getCursorKind(cur)));
|
return cxstring(clang_getCursorKindSpelling(clang_getCursorKind(cur)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::cxstring detail::get_type_kind_spelling(const CXType& type) noexcept
|
||||||
|
{
|
||||||
|
return cxstring(clang_getTypeKindSpelling(type.kind));
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace cppast
|
||||||
|
|
||||||
cxstring get_cursor_kind_spelling(const CXCursor& cur) noexcept;
|
cxstring get_cursor_kind_spelling(const CXCursor& cur) noexcept;
|
||||||
|
|
||||||
|
cxstring get_type_kind_spelling(const CXType& type) noexcept;
|
||||||
|
|
||||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||||
|
|
||||||
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,6 @@
|
||||||
|
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
cpp_language_linkage::builder make_ll_builder(const detail::parse_context& context,
|
|
||||||
const CXCursor& cur)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<cpp_entity> detail::try_parse_cpp_language_linkage(const parse_context& context,
|
std::unique_ptr<cpp_entity> detail::try_parse_cpp_language_linkage(const parse_context& context,
|
||||||
const CXCursor& cur)
|
const CXCursor& cur)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,11 @@ namespace cppast
|
||||||
return source_location::make(get_display_name(cur).c_str());
|
return source_location::make(get_display_name(cur).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline source_location make_location(const CXType& type)
|
||||||
|
{
|
||||||
|
return source_location::make(cxstring(clang_getTypeSpelling(type)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// thrown on a parsing error
|
// thrown on a parsing error
|
||||||
// not meant to escape to the user
|
// not meant to escape to the user
|
||||||
class parse_error : public std::logic_error
|
class parse_error : public std::logic_error
|
||||||
|
|
@ -37,6 +42,11 @@ namespace cppast
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_error(const CXType& type, std::string message)
|
||||||
|
: parse_error(make_location(type), std::move(message))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
diagnostic get_diagnostic() const
|
diagnostic get_diagnostic() const
|
||||||
{
|
{
|
||||||
return diagnostic{what(), location_, severity::error};
|
return diagnostic{what(), location_, severity::error};
|
||||||
|
|
@ -55,6 +65,12 @@ namespace cppast
|
||||||
{
|
{
|
||||||
throw parse_error(cur, std::move(message));
|
throw parse_error(cur, std::move(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle(const debug_assert::source_location&, const char*,
|
||||||
|
const CXType& type, std::string message)
|
||||||
|
{
|
||||||
|
throw parse_error(type, std::move(message));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
||||||
case CXCursor_UsingDeclaration:
|
case CXCursor_UsingDeclaration:
|
||||||
return parse_cpp_using_declaration(context, cur);
|
return parse_cpp_using_declaration(context, cur);
|
||||||
|
|
||||||
|
case CXCursor_TypeAliasDecl:
|
||||||
|
return parse_cpp_type_alias(context, cur);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
namespace cppast
|
namespace cppast
|
||||||
{
|
{
|
||||||
|
class cpp_type;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
cpp_entity_id get_entity_id(const CXCursor& cur);
|
cpp_entity_id get_entity_id(const CXCursor& cur);
|
||||||
|
|
@ -26,6 +28,8 @@ namespace cppast
|
||||||
type_safe::object_ref<const cpp_entity_index> idx;
|
type_safe::object_ref<const cpp_entity_index> idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_type> parse_type(const parse_context& context, const CXType& type);
|
||||||
|
|
||||||
// parse_entity() dispatches on the cursor type
|
// parse_entity() dispatches on the cursor type
|
||||||
// it calls one of the other parse functions defined elsewhere
|
// it calls one of the other parse functions defined elsewhere
|
||||||
// try_parse_XXX are not exposed entities
|
// try_parse_XXX are not exposed entities
|
||||||
|
|
@ -43,6 +47,9 @@ namespace cppast
|
||||||
std::unique_ptr<cpp_entity> parse_cpp_using_declaration(const parse_context& context,
|
std::unique_ptr<cpp_entity> parse_cpp_using_declaration(const parse_context& context,
|
||||||
const CXCursor& cur);
|
const CXCursor& cur);
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_entity> parse_cpp_type_alias(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
|
||||||
|
|
|
||||||
309
src/libclang/type_parser.cpp
Normal file
309
src/libclang/type_parser.cpp
Normal file
|
|
@ -0,0 +1,309 @@
|
||||||
|
// 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_array_type.hpp>
|
||||||
|
#include <cppast/cpp_function_type.hpp>
|
||||||
|
#include <cppast/cpp_type.hpp>
|
||||||
|
#include <cppast/cpp_type_alias.hpp>
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void remove_trailing_ws(std::string& str)
|
||||||
|
{
|
||||||
|
while (!str.empty() && std::isspace(str.back()))
|
||||||
|
str.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_leading_ws(std::string& str)
|
||||||
|
{
|
||||||
|
while (!str.empty() && std::isspace(str.front()))
|
||||||
|
str.erase(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove_suffix(std::string& str, const char* suffix)
|
||||||
|
{
|
||||||
|
auto length = std::strlen(suffix);
|
||||||
|
if (str.length() >= length && str.compare(str.length() - length, length, suffix) == 0)
|
||||||
|
{
|
||||||
|
str.erase(str.length() - length);
|
||||||
|
remove_trailing_ws(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove_prefix(std::string& str, const char* prefix)
|
||||||
|
{
|
||||||
|
auto length = std::strlen(prefix);
|
||||||
|
if (str.length() >= length && str.compare(0u, length, prefix) == 0)
|
||||||
|
{
|
||||||
|
str.erase(0u, length);
|
||||||
|
remove_leading_ws(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_type_spelling(const CXType& type)
|
||||||
|
{
|
||||||
|
return detail::cxstring(clang_getTypeSpelling(type)).c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// const/volatile at the end (because people do that apparently!)
|
||||||
|
cpp_cv suffix_cv(std::string& spelling)
|
||||||
|
{
|
||||||
|
auto cv = cpp_cv_none;
|
||||||
|
if (remove_suffix(spelling, "const"))
|
||||||
|
{
|
||||||
|
if (remove_suffix(spelling, "volatile"))
|
||||||
|
cv = cpp_cv_const_volatile;
|
||||||
|
else
|
||||||
|
cv = cpp_cv_const;
|
||||||
|
}
|
||||||
|
else if (remove_suffix(spelling, "volatile"))
|
||||||
|
{
|
||||||
|
if (remove_suffix(spelling, "const"))
|
||||||
|
cv = cpp_cv_const_volatile;
|
||||||
|
else
|
||||||
|
cv = cpp_cv_volatile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const/volatile at the beginning
|
||||||
|
// (weird that the better version is less performant, isn't it?)
|
||||||
|
cpp_cv prefix_cv(std::string& spelling)
|
||||||
|
{
|
||||||
|
auto cv = cpp_cv_none;
|
||||||
|
if (remove_prefix(spelling, "const"))
|
||||||
|
{
|
||||||
|
if (remove_prefix(spelling, "volatile"))
|
||||||
|
cv = cpp_cv_const_volatile;
|
||||||
|
else
|
||||||
|
cv = cpp_cv_const;
|
||||||
|
}
|
||||||
|
else if (remove_prefix(spelling, "volatile"))
|
||||||
|
{
|
||||||
|
if (remove_prefix(spelling, "const"))
|
||||||
|
cv = cpp_cv_const_volatile;
|
||||||
|
else
|
||||||
|
cv = cpp_cv_volatile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_cv merge_cv(cpp_cv a, cpp_cv b)
|
||||||
|
{
|
||||||
|
switch (a)
|
||||||
|
{
|
||||||
|
case cpp_cv_none:
|
||||||
|
return b;
|
||||||
|
|
||||||
|
case cpp_cv_const:
|
||||||
|
switch (b)
|
||||||
|
{
|
||||||
|
case cpp_cv_none:
|
||||||
|
return cpp_cv_const;
|
||||||
|
case cpp_cv_const:
|
||||||
|
return cpp_cv_const;
|
||||||
|
case cpp_cv_volatile:
|
||||||
|
return cpp_cv_const_volatile;
|
||||||
|
case cpp_cv_const_volatile:
|
||||||
|
return cpp_cv_const_volatile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cpp_cv_volatile:
|
||||||
|
switch (b)
|
||||||
|
{
|
||||||
|
case cpp_cv_none:
|
||||||
|
return cpp_cv_volatile;
|
||||||
|
case cpp_cv_const:
|
||||||
|
return cpp_cv_const_volatile;
|
||||||
|
case cpp_cv_volatile:
|
||||||
|
return cpp_cv_volatile;
|
||||||
|
case cpp_cv_const_volatile:
|
||||||
|
return cpp_cv_const_volatile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cpp_cv_const_volatile:
|
||||||
|
return cpp_cv_const_volatile;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
|
return cpp_cv_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_type> make_cv_qualified(std::unique_ptr<cpp_type> entity, cpp_cv cv)
|
||||||
|
{
|
||||||
|
if (cv == cpp_cv_none)
|
||||||
|
return std::move(entity);
|
||||||
|
return cpp_cv_qualified_type::build(std::move(entity), cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Builder>
|
||||||
|
std::unique_ptr<cpp_type> make_leave_type(const CXType& type, Builder b)
|
||||||
|
{
|
||||||
|
auto spelling = get_type_spelling(type);
|
||||||
|
|
||||||
|
// check for cv qualifiers on the leave type
|
||||||
|
auto prefix = prefix_cv(spelling);
|
||||||
|
auto suffix = suffix_cv(spelling);
|
||||||
|
auto cv = merge_cv(prefix, suffix);
|
||||||
|
|
||||||
|
auto entity = b(std::move(spelling));
|
||||||
|
return make_cv_qualified(std::move(entity), cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_reference get_reference_kind(const CXType& type)
|
||||||
|
{
|
||||||
|
if (type.kind == CXType_LValueReference)
|
||||||
|
return cpp_ref_lvalue;
|
||||||
|
else if (type.kind == CXType_RValueReference)
|
||||||
|
return cpp_ref_rvalue;
|
||||||
|
return cpp_ref_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_type> parse_type_impl(const detail::parse_context& context,
|
||||||
|
const CXType& type)
|
||||||
|
{
|
||||||
|
switch (type.kind)
|
||||||
|
{
|
||||||
|
// stuff I can't parse
|
||||||
|
// or have no idea what it is and wait for bug report
|
||||||
|
case CXType_Invalid:
|
||||||
|
case CXType_Overload:
|
||||||
|
case CXType_ObjCId:
|
||||||
|
case CXType_ObjCClass:
|
||||||
|
case CXType_ObjCSel:
|
||||||
|
case CXType_Complex:
|
||||||
|
case CXType_BlockPointer:
|
||||||
|
case CXType_Vector:
|
||||||
|
case CXType_ObjCInterface:
|
||||||
|
case CXType_ObjCObjectPointer:
|
||||||
|
{
|
||||||
|
auto msg = detail::format("unexpected type of kind '",
|
||||||
|
detail::get_type_kind_spelling(type).c_str(), "'");
|
||||||
|
auto location = source_location::make(get_type_spelling(type).c_str());
|
||||||
|
context.logger->log("libclang parser", diagnostic{msg, location, severity::warning});
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
|
case CXType_Unexposed:
|
||||||
|
return cpp_unexposed_type::build(get_type_spelling(type).c_str());
|
||||||
|
|
||||||
|
case CXType_Void:
|
||||||
|
case CXType_Bool:
|
||||||
|
case CXType_Char_U:
|
||||||
|
case CXType_UChar:
|
||||||
|
case CXType_Char16:
|
||||||
|
case CXType_Char32:
|
||||||
|
case CXType_UShort:
|
||||||
|
case CXType_UInt:
|
||||||
|
case CXType_ULong:
|
||||||
|
case CXType_ULongLong:
|
||||||
|
case CXType_UInt128:
|
||||||
|
case CXType_Char_S:
|
||||||
|
case CXType_SChar:
|
||||||
|
case CXType_WChar:
|
||||||
|
case CXType_Short:
|
||||||
|
case CXType_Int:
|
||||||
|
case CXType_Long:
|
||||||
|
case CXType_LongLong:
|
||||||
|
case CXType_Int128:
|
||||||
|
case CXType_Float:
|
||||||
|
case CXType_Double:
|
||||||
|
case CXType_LongDouble:
|
||||||
|
case CXType_NullPtr:
|
||||||
|
case CXType_Float128:
|
||||||
|
return make_leave_type(type, [](std::string&& spelling) {
|
||||||
|
return cpp_builtin_type::build(std::move(spelling));
|
||||||
|
});
|
||||||
|
|
||||||
|
case CXType_Record:
|
||||||
|
case CXType_Enum:
|
||||||
|
case CXType_Typedef:
|
||||||
|
case CXType_Elaborated:
|
||||||
|
return make_leave_type(type, [&](std::string&& spelling) {
|
||||||
|
auto decl = clang_getTypeDeclaration(type);
|
||||||
|
return cpp_user_defined_type::build(
|
||||||
|
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));
|
||||||
|
});
|
||||||
|
|
||||||
|
case CXType_Pointer:
|
||||||
|
{
|
||||||
|
auto pointee = parse_type_impl(context, clang_getPointeeType(type));
|
||||||
|
auto pointer = cpp_pointer_type::build(std::move(pointee));
|
||||||
|
|
||||||
|
auto spelling = get_type_spelling(type);
|
||||||
|
auto cv = suffix_cv(spelling);
|
||||||
|
return make_cv_qualified(std::move(pointer), cv);
|
||||||
|
}
|
||||||
|
case CXType_LValueReference:
|
||||||
|
case CXType_RValueReference:
|
||||||
|
{
|
||||||
|
auto referee = parse_type_impl(context, clang_getPointeeType(type));
|
||||||
|
return cpp_reference_type::build(std::move(referee), get_reference_kind(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
case CXType_IncompleteArray:
|
||||||
|
case CXType_VariableArray:
|
||||||
|
case CXType_DependentSizedArray:
|
||||||
|
case CXType_ConstantArray:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CXType_Dependent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CXType_FunctionNoProto:
|
||||||
|
break;
|
||||||
|
case CXType_FunctionProto:
|
||||||
|
break;
|
||||||
|
case CXType_MemberPointer:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CXType_Auto:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_type> detail::parse_type(const detail::parse_context& context,
|
||||||
|
const CXType& type)
|
||||||
|
{
|
||||||
|
auto result = parse_type_impl(context, type);
|
||||||
|
DEBUG_ASSERT(result && is_valid(*result), detail::parse_error_handler{}, type,
|
||||||
|
"invalid type parsed");
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<cpp_entity> detail::parse_cpp_type_alias(const detail::parse_context& context,
|
||||||
|
const CXCursor& cur)
|
||||||
|
{
|
||||||
|
DEBUG_ASSERT(cur.kind == CXCursor_TypeAliasDecl, detail::assert_handler{});
|
||||||
|
|
||||||
|
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||||
|
detail::token_stream stream(tokenizer, cur);
|
||||||
|
|
||||||
|
// using <identifier> = ...
|
||||||
|
detail::skip(stream, "using");
|
||||||
|
auto& name = stream.get().value();
|
||||||
|
detail::skip(stream, "=");
|
||||||
|
|
||||||
|
auto type = parse_type(context, clang_getTypedefDeclUnderlyingType(cur));
|
||||||
|
return cpp_type_alias::build(*context.idx, get_entity_id(cur), name.c_str(), std::move(type));
|
||||||
|
}
|
||||||
168
test/cpp_type_alias.cpp
Normal file
168
test/cpp_type_alias.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
// 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_type_alias.hpp>
|
||||||
|
|
||||||
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
|
bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_type& synthesized)
|
||||||
|
{
|
||||||
|
if (parsed.kind() != synthesized.kind())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (parsed.kind())
|
||||||
|
{
|
||||||
|
case cpp_type_kind::builtin:
|
||||||
|
return static_cast<const cpp_builtin_type&>(parsed).name()
|
||||||
|
== static_cast<const cpp_builtin_type&>(synthesized).name();
|
||||||
|
|
||||||
|
case cpp_type_kind::user_defined:
|
||||||
|
{
|
||||||
|
auto user_parsed = static_cast<const cpp_user_defined_type&>(parsed).entity();
|
||||||
|
auto user_synthesized = static_cast<const cpp_user_defined_type&>(synthesized).entity();
|
||||||
|
if (user_parsed.name() != user_synthesized.name())
|
||||||
|
return false;
|
||||||
|
// check that the referring also works
|
||||||
|
auto entity = user_parsed.get(idx);
|
||||||
|
return entity.has_value() && entity.value().name() == user_parsed.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
case cpp_type_kind::cv_qualified:
|
||||||
|
{
|
||||||
|
auto& cv_a = static_cast<const cpp_cv_qualified_type&>(parsed);
|
||||||
|
auto& cv_b = static_cast<const cpp_cv_qualified_type&>(synthesized);
|
||||||
|
return cv_a.cv_qualifier() == cv_b.cv_qualifier()
|
||||||
|
&& equal_types(idx, cv_a.type(), cv_b.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
case cpp_type_kind::pointer:
|
||||||
|
return equal_types(idx, static_cast<const cpp_pointer_type&>(parsed).pointee(),
|
||||||
|
static_cast<const cpp_pointer_type&>(synthesized).pointee());
|
||||||
|
case cpp_type_kind::reference:
|
||||||
|
{
|
||||||
|
auto& ref_a = static_cast<const cpp_reference_type&>(parsed);
|
||||||
|
auto& ref_b = static_cast<const cpp_reference_type&>(synthesized);
|
||||||
|
return ref_a.reference_kind() == ref_b.reference_kind()
|
||||||
|
&& equal_types(idx, ref_a.referee(), ref_b.referee());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
case cpp_type_kind::array:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::function:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::member_function:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::member_object:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::template_parameter:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::template_instantiation:
|
||||||
|
break;
|
||||||
|
case cpp_type_kind::dependent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cpp_type_kind::unexposed:
|
||||||
|
return static_cast<const cpp_unexposed_type&>(parsed).name()
|
||||||
|
== static_cast<const cpp_unexposed_type&>(synthesized).name();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// also tests the type parsing code
|
||||||
|
// other test cases don't need that anymore
|
||||||
|
TEST_CASE("cpp_type_alias")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
// basic
|
||||||
|
using a = int;
|
||||||
|
using b = const long double volatile;
|
||||||
|
|
||||||
|
// pointers
|
||||||
|
using c = int*;
|
||||||
|
using d = const unsigned int*;
|
||||||
|
using e = unsigned const * volatile;
|
||||||
|
|
||||||
|
// references
|
||||||
|
using f = int&;
|
||||||
|
using g = const int&&;
|
||||||
|
|
||||||
|
// user-defined types
|
||||||
|
using h = c;
|
||||||
|
using i = const d;
|
||||||
|
using j = e*;
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto add_cv = [](std::unique_ptr<cpp_type> type, cpp_cv cv) {
|
||||||
|
return cpp_cv_qualified_type::build(std::move(type), cv);
|
||||||
|
};
|
||||||
|
|
||||||
|
cpp_entity_index idx;
|
||||||
|
auto file = parse(idx, "cpp_type_alias.cpp", code);
|
||||||
|
auto count = test_visit<cpp_type_alias>(*file, [&](const cpp_type_alias& alias) {
|
||||||
|
if (alias.name() == "a")
|
||||||
|
{
|
||||||
|
auto type = cpp_builtin_type::build("int");
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "b")
|
||||||
|
{
|
||||||
|
auto type = add_cv(cpp_builtin_type::build("long double"), cpp_cv_const_volatile);
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "c")
|
||||||
|
{
|
||||||
|
auto type = cpp_pointer_type::build(cpp_builtin_type::build("int"));
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "d")
|
||||||
|
{
|
||||||
|
auto type = cpp_pointer_type::build(
|
||||||
|
add_cv(cpp_builtin_type::build("unsigned int"), cpp_cv_const));
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "e")
|
||||||
|
{
|
||||||
|
auto type = add_cv(cpp_pointer_type::build(
|
||||||
|
add_cv(cpp_builtin_type::build("unsigned int"), cpp_cv_const)),
|
||||||
|
cpp_cv_volatile);
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "f")
|
||||||
|
{
|
||||||
|
auto type = cpp_reference_type::build(cpp_builtin_type::build("int"), cpp_ref_lvalue);
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "g")
|
||||||
|
{
|
||||||
|
auto type =
|
||||||
|
cpp_reference_type::build(add_cv(cpp_builtin_type::build("int"), cpp_cv_const),
|
||||||
|
cpp_ref_rvalue);
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "h")
|
||||||
|
{
|
||||||
|
auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "c"));
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "i")
|
||||||
|
{
|
||||||
|
auto type = add_cv(cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "d")),
|
||||||
|
cpp_cv_const);
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else if (alias.name() == "j")
|
||||||
|
{
|
||||||
|
auto type = cpp_pointer_type::build(
|
||||||
|
cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "e")));
|
||||||
|
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
REQUIRE(false);
|
||||||
|
});
|
||||||
|
REQUIRE(count == 10u);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue