Improve handling of unexposed entities

This commit is contained in:
Jonathan Müller 2017-10-11 14:34:30 +02:00
commit 69ca035b5a
30 changed files with 796 additions and 483 deletions

View file

@ -500,12 +500,17 @@ namespace cppast
/// \exclude /// \exclude
class cpp_template_argument; class cpp_template_argument;
/// \exclude
class cpp_token_string;
/// \exclude /// \exclude
namespace detail namespace detail
{ {
void write_template_arguments( void write_template_arguments(
code_generator::output& output, code_generator::output& output,
type_safe::optional<type_safe::array_ref<const cpp_template_argument>> arguments); type_safe::optional<type_safe::array_ref<const cpp_template_argument>> arguments);
void write_token_string(code_generator::output& output, const cpp_token_string& tokens);
} // namespace detail } // namespace detail
} // namespace cppast } // namespace cppast

View file

@ -11,6 +11,7 @@
#include <type_safe/optional_ref.hpp> #include <type_safe/optional_ref.hpp>
#include <cppast/detail/intrusive_list.hpp> #include <cppast/detail/intrusive_list.hpp>
#include <cppast/cpp_token.hpp>
namespace cppast namespace cppast
{ {
@ -141,9 +142,7 @@ namespace cppast
protected: protected:
/// \effects Creates it giving it the the name. /// \effects Creates it giving it the the name.
cpp_entity(std::string name) : name_(std::move(name)), user_data_(nullptr) cpp_entity(std::string name) : name_(std::move(name)), user_data_(nullptr) {}
{
}
private: private:
/// \returns The kind of the entity. /// \returns The kind of the entity.
@ -182,27 +181,27 @@ namespace cppast
/// \returns A newly built and registered unexposed entity. /// \returns A newly built and registered unexposed entity.
/// \notes It will be registered as a declaration. /// \notes It will be registered as a declaration.
static std::unique_ptr<cpp_entity> build(const cpp_entity_index& index, cpp_entity_id id, static std::unique_ptr<cpp_entity> build(const cpp_entity_index& index, cpp_entity_id id,
std::string name, std::string spelling); std::string name, cpp_token_string spelling);
/// \returns A newly built unnamed unexposed entity. /// \returns A newly built unnamed unexposed entity.
/// It will not be registered. /// It will not be registered.
static std::unique_ptr<cpp_entity> build(std::string spelling); static std::unique_ptr<cpp_entity> build(cpp_token_string spelling);
/// \returns The spelling of that entity. /// \returns The spelling of that entity.
const std::string& spelling() const noexcept const cpp_token_string& spelling() const noexcept
{ {
return spelling_; return spelling_;
} }
private: private:
cpp_unexposed_entity(std::string name, std::string spelling) cpp_unexposed_entity(std::string name, cpp_token_string spelling)
: cpp_entity(std::move(name)), spelling_(std::move(spelling)) : cpp_entity(std::move(name)), spelling_(std::move(spelling))
{ {
} }
cpp_entity_kind do_get_entity_kind() const noexcept override; cpp_entity_kind do_get_entity_kind() const noexcept override;
std::string spelling_; cpp_token_string spelling_;
}; };
/// \returns Whether or not the entity is templated. /// \returns Whether or not the entity is templated.

View file

@ -8,6 +8,7 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <cppast/cpp_token.hpp>
#include <cppast/cpp_type.hpp> #include <cppast/cpp_type.hpp>
namespace cppast namespace cppast
@ -82,20 +83,20 @@ namespace cppast
public: public:
/// \returns A newly created unexposed expression. /// \returns A newly created unexposed expression.
static std::unique_ptr<cpp_unexposed_expression> build(std::unique_ptr<cpp_type> type, static std::unique_ptr<cpp_unexposed_expression> build(std::unique_ptr<cpp_type> type,
std::string str) cpp_token_string str)
{ {
return std::unique_ptr<cpp_unexposed_expression>( return std::unique_ptr<cpp_unexposed_expression>(
new cpp_unexposed_expression(std::move(type), std::move(str))); new cpp_unexposed_expression(std::move(type), std::move(str)));
} }
/// \returns The expression as a string. /// \returns The expression as a string.
const std::string& expression() const noexcept const cpp_token_string& expression() const noexcept
{ {
return str_; return str_;
} }
private: private:
cpp_unexposed_expression(std::unique_ptr<cpp_type> type, std::string str) cpp_unexposed_expression(std::unique_ptr<cpp_type> type, cpp_token_string str)
: cpp_expression(std::move(type)), str_(std::move(str)) : cpp_expression(std::move(type)), str_(std::move(str))
{ {
} }
@ -105,7 +106,7 @@ namespace cppast
return cpp_expression_kind::unexposed_t; return cpp_expression_kind::unexposed_t;
} }
std::string str_; cpp_token_string str_;
}; };
/// A [cppast::cpp_expression]() that is a literal. /// A [cppast::cpp_expression]() that is a literal.

View file

@ -11,6 +11,7 @@
#include <cppast/cpp_entity.hpp> #include <cppast/cpp_entity.hpp>
#include <cppast/cpp_entity_container.hpp> #include <cppast/cpp_entity_container.hpp>
#include <cppast/cpp_token.hpp>
#include <cppast/cpp_template_parameter.hpp> #include <cppast/cpp_template_parameter.hpp>
namespace cppast namespace cppast
@ -179,7 +180,7 @@ namespace cppast
} }
type_safe::variant<std::vector<cpp_template_argument>, std::string> arguments_; type_safe::variant<std::vector<cpp_template_argument>, std::string> arguments_;
cpp_template_ref templ_; cpp_template_ref templ_;
}; };
/// Base class for all entities modelling a C++ template specialization. /// Base class for all entities modelling a C++ template specialization.
@ -214,9 +215,9 @@ namespace cppast
/// \requires The arguments are not exposed, i.e. `arguments_exposed()` returns `false`. /// \requires The arguments are not exposed, i.e. `arguments_exposed()` returns `false`.
/// \notes For function template specializations it can be empty, /// \notes For function template specializations it can be empty,
/// meaning that the arguments are not explictly given but deduced from the signature. /// meaning that the arguments are not explictly given but deduced from the signature.
const std::string& unexposed_arguments() const noexcept const cpp_token_string& unexposed_arguments() const noexcept
{ {
return arguments_.value(type_safe::variant_type<std::string>{}); return arguments_.value(type_safe::variant_type<cpp_token_string>{});
} }
/// \returns Whether or not the specialization is a full specialization. /// \returns Whether or not the specialization is a full specialization.
@ -252,7 +253,7 @@ namespace cppast
} }
/// \effects Adds unexposed arguments as string. /// \effects Adds unexposed arguments as string.
void add_unexposed_arguments(std::string arg) void add_unexposed_arguments(cpp_token_string arg)
{ {
auto& specialization = auto& specialization =
static_cast<cpp_template_specialization&>(*this->template_entity); static_cast<cpp_template_specialization&>(*this->template_entity);
@ -276,8 +277,8 @@ namespace cppast
} }
private: private:
type_safe::variant<std::vector<cpp_template_argument>, std::string> arguments_; type_safe::variant<std::vector<cpp_template_argument>, cpp_token_string> arguments_;
cpp_entity_id templ_; cpp_entity_id templ_;
}; };
} // namespace cppast } // namespace cppast

View file

@ -0,0 +1,137 @@
// 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.
#ifndef CPPAST_CPP_TOKEN_HPP_INCLUDED
#define CPPAST_CPP_TOKEN_HPP_INCLUDED
#include <string>
#include <vector>
#include <type_safe/reference.hpp>
namespace cppast
{
/// The kinds of C++ tokens.
enum class cpp_token_kind
{
identifier, //< Any identifier.
keyword, //< Any keyword.
literal, //< Any literal.
punctuation, //< Any other punctuation.
unknown, //< An unknown token.
};
/// A C++ token.
struct cpp_token
{
std::string spelling;
cpp_token_kind kind;
cpp_token(cpp_token_kind kind, std::string spelling)
: spelling(std::move(spelling)), kind(kind)
{
}
friend bool operator==(const cpp_token& lhs, const cpp_token& rhs) noexcept
{
return lhs.spelling == rhs.spelling;
}
friend bool operator!=(const cpp_token& lhs, const cpp_token& rhs) noexcept
{
return !(rhs == lhs);
}
};
/// A combination of multiple C++ tokens.
class cpp_token_string
{
public:
/// Builds a token string.
class builder
{
public:
builder() = default;
/// \effects Adds a token.
void add_token(cpp_token tok)
{
tokens_.push_back(std::move(tok));
}
/// \effects Converts a trailing `>>` to `>` token.
void unmunch();
/// \returns The finished string.
cpp_token_string finish()
{
return cpp_token_string(std::move(tokens_));
}
private:
std::vector<cpp_token> tokens_;
};
/// \effects Creates it from a sequence of tokens.
cpp_token_string(std::vector<cpp_token> tokens) : tokens_(std::move(tokens)) {}
/// \effects Creates from a string.
/// \notes This does not do tokenization, it will only store a single, unknown token!
static cpp_token_string from_string(std::string str)
{
return cpp_token_string({cpp_token(cpp_token_kind::unknown, std::move(str))});
}
/// \exclude target
using iterator = std::vector<cpp_token>::const_iterator;
/// \returns An iterator to the first token.
iterator begin() const noexcept
{
return tokens_.begin();
}
/// \returns An iterator one past the last token.
iterator end() const noexcept
{
return tokens_.end();
}
/// \returns Whether or not the string is empty.
bool empty() const noexcept
{
return tokens_.empty();
}
/// \returns A reference to the first token.
const cpp_token& front() const noexcept
{
return tokens_.front();
}
/// \returns A reference to the last token.
const cpp_token& back() const noexcept
{
return tokens_.back();
}
/// \returns The string representation of the tokens, without any whitespace.
std::string as_string() const;
private:
std::vector<cpp_token> tokens_;
friend bool operator==(const cpp_token_string& lhs, const cpp_token_string& rhs);
};
bool operator==(const cpp_token_string& lhs, const cpp_token_string& rhs);
inline bool operator!=(const cpp_token_string& lhs, const cpp_token_string& rhs)
{
return !(lhs == rhs);
}
} // namespace cppast
#endif // CPPAST_CPP_TOKEN_HPP_INCLUDED

View file

@ -36,6 +36,7 @@ set(header
../include/cppast/cpp_storage_class_specifiers.hpp ../include/cppast/cpp_storage_class_specifiers.hpp
../include/cppast/cpp_template.hpp ../include/cppast/cpp_template.hpp
../include/cppast/cpp_template_parameter.hpp ../include/cppast/cpp_template_parameter.hpp
../include/cppast/cpp_token.hpp
../include/cppast/cpp_type.hpp ../include/cppast/cpp_type.hpp
../include/cppast/cpp_type_alias.hpp ../include/cppast/cpp_type_alias.hpp
../include/cppast/cpp_variable.hpp ../include/cppast/cpp_variable.hpp
@ -68,6 +69,7 @@ set(source
cpp_preprocessor.cpp cpp_preprocessor.cpp
cpp_static_assert.cpp cpp_static_assert.cpp
cpp_template_parameter.cpp cpp_template_parameter.cpp
cpp_token.cpp
cpp_type.cpp cpp_type.cpp
cpp_type_alias.cpp cpp_type_alias.cpp
cpp_variable.cpp cpp_variable.cpp

View file

@ -20,6 +20,7 @@
#include <cppast/cpp_preprocessor.hpp> #include <cppast/cpp_preprocessor.hpp>
#include <cppast/cpp_static_assert.hpp> #include <cppast/cpp_static_assert.hpp>
#include <cppast/cpp_template_parameter.hpp> #include <cppast/cpp_template_parameter.hpp>
#include <cppast/cpp_token.hpp>
#include <cppast/cpp_type_alias.hpp> #include <cppast/cpp_type_alias.hpp>
#include <cppast/cpp_variable.hpp> #include <cppast/cpp_variable.hpp>
#include <cppast/cpp_variable_template.hpp> #include <cppast/cpp_variable_template.hpp>
@ -343,8 +344,11 @@ namespace
if (spec.arguments_exposed()) if (spec.arguments_exposed())
detail::write_template_arguments(output, spec.arguments()); detail::write_template_arguments(output, spec.arguments());
else if (!spec.unexposed_arguments().empty()) else if (!spec.unexposed_arguments().empty())
output << punctuation("<") << bracket_ws << token_seq(spec.unexposed_arguments()) {
<< bracket_ws << punctuation(">"); output << punctuation("<") << bracket_ws;
detail::write_token_string(output, spec.unexposed_arguments());
output << bracket_ws << punctuation(">");
}
} }
void write_bases(code_generator& generator, code_generator::output& output, const cpp_class& c) void write_bases(code_generator& generator, code_generator::output& output, const cpp_class& c)
@ -537,7 +541,8 @@ namespace
output << keyword("noexcept") << punctuation("(") << bracket_ws; output << keyword("noexcept") << punctuation("(") << bracket_ws;
// update check when expression gets exposed // update check when expression gets exposed
if (cond.kind() == cpp_expression_kind::unexposed_t if (cond.kind() == cpp_expression_kind::unexposed_t
&& static_cast<const cpp_unexposed_expression&>(cond).expression() == "false") && static_cast<const cpp_unexposed_expression&>(cond).expression().front().spelling
== "false")
output << keyword("false"); output << keyword("false");
else if (output.options().is_set(code_generator::exclude_noexcept_condition)) else if (output.options().is_set(code_generator::exclude_noexcept_condition))
output.excluded(base); output.excluded(base);
@ -1029,7 +1034,7 @@ namespace
code_generator::output output(type_safe::ref(generator), type_safe::ref(entity), code_generator::output output(type_safe::ref(generator), type_safe::ref(entity),
cur_access); cur_access);
if (output) if (output)
output << token_seq(entity.spelling()); detail::write_token_string(output, entity.spelling());
return static_cast<bool>(output); return static_cast<bool>(output);
} }
@ -1147,3 +1152,63 @@ void detail::write_template_arguments(
output << bracket_ws << punctuation(">"); output << bracket_ws << punctuation(">");
} }
} }
void detail::write_token_string(code_generator::output& output, const cpp_token_string& tokens)
{
auto last_kind = cpp_token_kind::unknown;
for (auto& token : tokens)
{
switch (token.kind)
{
case cpp_token_kind::identifier:
if (last_kind == cpp_token_kind::identifier || last_kind == cpp_token_kind::keyword)
output << whitespace;
output << keyword(token.spelling);
break;
case cpp_token_kind::keyword:
if (last_kind == cpp_token_kind::identifier || last_kind == cpp_token_kind::keyword)
output << whitespace;
output << identifier(token.spelling);
if (token.spelling == "template")
output << operator_ws;
break;
case cpp_token_kind::literal:
// determine kind of literal
if (token.spelling.front() == '\"')
output << string_literal(token.spelling);
else if (token.spelling.find('.') != std::string::npos)
output << float_literal(token.spelling);
else
output << int_literal(token.spelling);
break;
case cpp_token_kind::punctuation:
if (token.spelling == ",")
output << comma;
// print brackets
// don't treat <> special as they might be operators...
else if (token.spelling == "(" || token.spelling == "[" || token.spelling == "{")
output << punctuation(token.spelling) << bracket_ws;
else if (token.spelling == ")" || token.spelling == "]" || token.spelling == "}")
output << bracket_ws << punctuation(token.spelling);
// operators that are always binary operators in all contexts
else if (token.spelling.back() == '=' // all assignment operators
|| token.spelling == "/" || token.spelling == "%" || token.spelling == "=="
|| token.spelling == "!=" || token.spelling == "<" || token.spelling == ">"
|| token.spelling == "<=" || token.spelling == ">=" || token.spelling == "&&"
|| token.spelling == "||" || token.spelling == "|" || token.spelling == "^"
|| token.spelling == "?")
output << operator_ws << punctuation(token.spelling) << operator_ws;
else
output << punctuation(token.spelling);
break;
case cpp_token_kind::unknown:
output << token_seq(token.spelling);
}
last_kind = token.kind;
}
}

View file

@ -45,7 +45,7 @@ cpp_entity_kind cpp_unexposed_entity::kind() noexcept
std::unique_ptr<cpp_entity> cpp_unexposed_entity::build(const cpp_entity_index& index, std::unique_ptr<cpp_entity> cpp_unexposed_entity::build(const cpp_entity_index& index,
cpp_entity_id id, std::string name, cpp_entity_id id, std::string name,
std::string spelling) cpp_token_string spelling)
{ {
std::unique_ptr<cpp_entity> result( std::unique_ptr<cpp_entity> result(
new cpp_unexposed_entity(std::move(name), std::move(spelling))); new cpp_unexposed_entity(std::move(name), std::move(spelling)));
@ -53,7 +53,7 @@ std::unique_ptr<cpp_entity> cpp_unexposed_entity::build(const cpp_entity_index&
return result; return result;
} }
std::unique_ptr<cpp_entity> cpp_unexposed_entity::build(std::string spelling) std::unique_ptr<cpp_entity> cpp_unexposed_entity::build(cpp_token_string spelling)
{ {
return std::unique_ptr<cpp_entity>(new cpp_unexposed_entity("", std::move(spelling))); return std::unique_ptr<cpp_entity>(new cpp_unexposed_entity("", std::move(spelling)));
} }

View file

@ -75,7 +75,7 @@ namespace
void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr) void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr)
{ {
output << token_seq(expr.expression()); detail::write_token_string(output, expr.expression());
} }
} }

45
src/cpp_token.cpp Normal file
View file

@ -0,0 +1,45 @@
// 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_token.hpp>
#include <algorithm>
#include <cctype>
#include <cppast/detail/assert.hpp>
using namespace cppast;
void cpp_token_string::builder::unmunch()
{
DEBUG_ASSERT(!tokens_.empty() && tokens_.back().spelling == ">>", detail::assert_handler{});
tokens_.back().spelling = ">";
}
namespace
{
bool is_identifier(char c)
{
return std::isalnum(c) || c == '_';
}
}
std::string cpp_token_string::as_string() const
{
std::string result;
for (auto& token : tokens_)
{
DEBUG_ASSERT(!token.spelling.empty(), detail::assert_handler{});
if (!result.empty() && is_identifier(result.back()) && is_identifier(token.spelling[0u]))
result += ' ';
result += token.spelling;
}
return result;
}
bool cppast::operator==(const cpp_token_string& lhs, const cpp_token_string& rhs)
{
if (lhs.tokens_.size() != rhs.tokens_.size())
return false;
return std::equal(lhs.tokens_.begin(), lhs.tokens_.end(), rhs.tokens_.begin());
}

View file

@ -81,7 +81,7 @@ namespace
detail::skip(stream, "virtual"); detail::skip(stream, "virtual");
detail::skip_if(stream, to_string(access)); detail::skip_if(stream, to_string(access));
auto name = detail::to_string(stream, stream.end()); auto name = detail::to_string(stream, stream.end()).as_string();
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur)); auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
builder.base_class(std::move(name), std::move(type), access, is_virtual); builder.base_class(std::move(name), std::move(type), access, is_virtual);

View file

@ -19,7 +19,7 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
auto type = parse_type(context, cur, clang_getCursorType(cur)); auto type = parse_type(context, cur, clang_getCursorType(cur));
auto expr = to_string(stream, stream.end()); auto expr = to_string(stream, stream.end());
if (kind == CXCursor_CallExpr && (expr.empty() || expr.back() != ')')) if (kind == CXCursor_CallExpr && (expr.empty() || expr.back().spelling != ")"))
{ {
// we have a call expression that doesn't end in a closing parentheses // we have a call expression that doesn't end in a closing parentheses
// this means default constructor, don't parse it at all // this means default constructor, don't parse it at all
@ -30,7 +30,7 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
|| kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral
|| kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral
|| kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr) || kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr)
return cpp_literal_expression::build(std::move(type), std::move(expr)); return cpp_literal_expression::build(std::move(type), expr.as_string());
else else
return cpp_unexposed_expression::build(std::move(type), std::move(expr)); return cpp_unexposed_expression::build(std::move(type), std::move(expr));
} }
@ -42,8 +42,7 @@ std::unique_ptr<cpp_expression> detail::parse_raw_expression(const parse_context
{ {
if (stream.done()) if (stream.done())
return nullptr; return nullptr;
auto expr = to_string(stream, end);
if (!expr.empty() && expr.back() == ';') auto expr = to_string(stream, std::prev(end)->value() == ";" ? std::prev(end) : end);
expr.pop_back();
return cpp_unexposed_expression::build(std::move(type), std::move(expr)); return cpp_unexposed_expression::build(std::move(type), std::move(expr));
} }

View file

@ -705,7 +705,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
// read the type // read the type
stream.set_cur(type_start); stream.set_cur(type_start);
auto type_spelling = detail::to_string(stream, type_end); auto type_spelling = detail::to_string(stream, type_end).as_string();
// parse arguments again // parse arguments again
detail::skip(stream, "("); detail::skip(stream, "(");

View file

@ -279,7 +279,7 @@ namespace
b.add_unexposed_arguments(std::move(args)); b.add_unexposed_arguments(std::move(args));
} }
else else
b.add_unexposed_arguments(""); b.add_unexposed_arguments(cpp_token_string::builder().finish());
} }
} }

View file

@ -223,9 +223,15 @@ namespace
|| clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier || clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier
|| kind == CXCursor_TemplateTypeParameter || kind == CXCursor_TemplateTypeParameter
#endif #endif
) )
// 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);
else if (kind == CXCursor_UnexposedDecl)
{
// include semicolon, if necessary
if (token_after_is(tu, file, cur, end, ";"))
end = get_next_location(tu, file, end);
}
return clang_getRange(begin, end); return clang_getRange(begin, end);
} }
@ -405,29 +411,41 @@ bool detail::skip_attribute(detail::token_stream& stream)
namespace namespace
{ {
bool is_identifier(char c) cpp_token_kind get_kind(CXTokenKind kind)
{ {
return std::isalnum(c) || c == '_'; switch (kind)
{
case CXToken_Punctuation:
return cpp_token_kind::punctuation;
case CXToken_Keyword:
return cpp_token_kind::keyword;
case CXToken_Identifier:
return cpp_token_kind::identifier;
case CXToken_Literal:
return cpp_token_kind::literal;
case CXToken_Comment:
break;
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return cpp_token_kind ::literal;
} }
} }
std::string detail::to_string(token_stream& stream, token_iterator end) cpp_token_string detail::to_string(token_stream& stream, token_iterator end)
{ {
std::string result; cpp_token_string::builder builder;
while (stream.cur() != end) while (stream.cur() != end)
{ {
auto& token = stream.get(); auto& token = stream.get();
if (!result.empty() && is_identifier(result.back()) && is_identifier(token.value()[0u])) builder.add_token(cpp_token(get_kind(token.kind()), token.c_str()));
result += ' ';
result += token.c_str();
} }
if (stream.unmunch()) if (stream.unmunch())
{ builder.unmunch();
DEBUG_ASSERT(!result.empty() && result.back() == '>', detail::assert_handler{});
result.pop_back(); return builder.finish();
DEBUG_ASSERT(!result.empty() && result.back() == '>', detail::assert_handler{});
}
return result;
} }
bool detail::append_scope(detail::token_stream& stream, std::string& scope) bool detail::append_scope(detail::token_stream& stream, std::string& scope)
@ -449,7 +467,7 @@ bool detail::append_scope(detail::token_stream& stream, std::string& scope)
else if (stream.peek() == "<") else if (stream.peek() == "<")
{ {
auto iter = detail::find_closing_bracket(stream); auto iter = detail::find_closing_bracket(stream);
scope += detail::to_string(stream, iter); scope += detail::to_string(stream, iter).as_string();
if (!detail::skip_if(stream, ">>")) if (!detail::skip_if(stream, ">>"))
detail::skip(stream, ">"); detail::skip(stream, ">");
scope += ">"; scope += ">";

View file

@ -8,6 +8,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <cppast/cpp_token.hpp>
#include "raii_wrapper.hpp" #include "raii_wrapper.hpp"
namespace cppast namespace cppast
@ -190,8 +192,8 @@ namespace cppast
// skips an attribute // skips an attribute
bool skip_attribute(token_stream& stream); bool skip_attribute(token_stream& stream);
// converts a token range to a string, adding whitespace where necessary // converts a token range to a string
std::string to_string(token_stream& stream, token_iterator end); cpp_token_string to_string(token_stream& stream, token_iterator end);
// appends token to scope, if it is still valid // appends token to scope, if it is still valid
// else clears it // else clears it

View file

@ -246,8 +246,9 @@ namespace
return size_expr.empty() ? return size_expr.empty() ?
nullptr : nullptr :
cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_ulonglong), cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_ulonglong),
std::string(size_expr.rbegin(), cpp_token_string::from_string(
size_expr.rend())); std::string(size_expr.rbegin(),
size_expr.rend())));
} }
std::unique_ptr<cpp_type> try_parse_array_type(const detail::parse_context& context, std::unique_ptr<cpp_type> try_parse_array_type(const detail::parse_context& context,
@ -486,7 +487,8 @@ namespace
spelling.pop_back(); spelling.pop_back();
return cpp_decltype_type::build( return cpp_decltype_type::build(
cpp_unexposed_expression::build(cpp_unexposed_type::build("<decltype>"), spelling)); cpp_unexposed_expression::build(cpp_unexposed_type::build("<decltype>"),
cpp_token_string::from_string(spelling)));
}); });
} }
@ -734,7 +736,7 @@ std::unique_ptr<cpp_type> detail::parse_raw_type(const detail::parse_context&,
detail::token_iterator end) detail::token_iterator end)
{ {
auto result = detail::to_string(stream, end); auto result = detail::to_string(stream, end);
return cpp_unexposed_type::build(std::move(result)); return cpp_unexposed_type::build(result.as_string());
} }
std::unique_ptr<cpp_entity> detail::parse_cpp_type_alias(const detail::parse_context& context, std::unique_ptr<cpp_entity> detail::parse_cpp_type_alias(const detail::parse_context& context,

View file

@ -6,7 +6,6 @@
#include <cppast/cpp_member_variable.hpp> #include <cppast/cpp_member_variable.hpp>
#include <cppast/cpp_variable.hpp> #include <cppast/cpp_variable.hpp>
#include <clang-c/Index.h>
#include "libclang_visitor.hpp" #include "libclang_visitor.hpp"

View file

@ -110,9 +110,8 @@ struct b<0, T> {};
} }
else if (templ.name() == "b") else if (templ.name() == "b")
{ {
check_template_parameters(templ, check_template_parameters(templ, {{cpp_entity_kind::non_type_template_parameter_t, "I"},
{{cpp_entity_kind::non_type_template_parameter_t, "I"}, {cpp_entity_kind::template_type_parameter_t, "T"}});
{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(c.class_kind() == cpp_class_kind::struct_t); REQUIRE(c.class_kind() == cpp_class_kind::struct_t);
REQUIRE(c.is_definition()); REQUIRE(c.is_definition());
} }
@ -223,45 +222,46 @@ struct b<0, T> {};
}); });
REQUIRE(count == 5u); REQUIRE(count == 5u);
count = test_visit<cpp_class_template_specialization>( count = test_visit<
*file, [&](const cpp_class_template_specialization& templ) { cpp_class_template_specialization>(*file, [&](const cpp_class_template_specialization&
REQUIRE(!templ.arguments_exposed()); templ) {
REQUIRE(templ.scope_name()); REQUIRE(!templ.arguments_exposed());
REQUIRE(templ.scope_name());
if (templ.name() == "a") if (templ.name() == "a")
{
REQUIRE(
equal_ref(idx, templ.primary_template(), cpp_template_ref(cpp_entity_id(""), "a")));
if (templ.is_full_specialization())
{ {
REQUIRE(equal_ref(idx, templ.primary_template(), check_template_parameters(templ, {});
cpp_template_ref(cpp_entity_id(""), "a"))); REQUIRE(templ.unexposed_arguments().as_string() == "int");
if (templ.is_full_specialization())
{
check_template_parameters(templ, {});
REQUIRE(templ.unexposed_arguments() == "int");
}
else
{
check_template_parameters(templ,
{{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(templ.unexposed_arguments() == "T*");
}
}
else if (templ.name() == "b")
{
REQUIRE(equal_ref(idx, templ.primary_template(),
cpp_template_ref(cpp_entity_id(""), "b")));
if (templ.is_full_specialization())
{
check_template_parameters(templ, {});
REQUIRE(templ.unexposed_arguments() == "0,int");
}
else
{
check_template_parameters(templ,
{{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(templ.unexposed_arguments() == "0,T");
}
} }
else else
REQUIRE(false); {
}); check_template_parameters(templ,
{{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(templ.unexposed_arguments().as_string() == "T*");
}
}
else if (templ.name() == "b")
{
REQUIRE(
equal_ref(idx, templ.primary_template(), cpp_template_ref(cpp_entity_id(""), "b")));
if (templ.is_full_specialization())
{
check_template_parameters(templ, {});
REQUIRE(templ.unexposed_arguments().as_string() == "0,int");
}
else
{
check_template_parameters(templ,
{{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(templ.unexposed_arguments().as_string() == "0,T");
}
}
else
REQUIRE(false);
});
REQUIRE(count == 4u); REQUIRE(count == 4u);
} }

View file

@ -55,8 +55,8 @@ enum ns::c : int {};
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_enum.cpp", code); auto file = parse(idx, "cpp_enum.cpp", code);
auto count = test_visit<cpp_enum>(*file, [&](const cpp_enum& e) { auto count = test_visit<cpp_enum>(*file, [&](const cpp_enum& e) {
if (e.name() == "a") if (e.name() == "a")
{ {
REQUIRE(e.is_definition()); REQUIRE(e.is_definition());
@ -80,7 +80,9 @@ enum ns::c : int {};
if (equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint))) if (equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)))
{ {
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t); REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression() REQUIRE(static_cast<const cpp_unexposed_expression&>(expr)
.expression()
.as_string()
== "42"); == "42");
} }
else else
@ -96,8 +98,9 @@ enum ns::c : int {};
REQUIRE(val.value()); REQUIRE(val.value());
auto& expr = val.value().value(); auto& expr = val.value().value();
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t); REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression() REQUIRE(
== "a_a+2"); static_cast<const cpp_unexposed_expression&>(expr).expression().as_string()
== "a_a+2");
if (!equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int))) if (!equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int)))
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint))); REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
} }

View file

@ -232,7 +232,7 @@ int d() {}
{ {
REQUIRE(func.function().is_declaration()); REQUIRE(func.function().is_declaration());
REQUIRE(!func.arguments_exposed()); REQUIRE(!func.arguments_exposed());
REQUIRE(func.unexposed_arguments() == "ns::h"); REQUIRE(func.unexposed_arguments().as_string() == "ns::h");
} }
else else
REQUIRE(false); REQUIRE(false);

View file

@ -65,8 +65,8 @@ void ns::l()
}; };
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_function.cpp", code); auto file = parse(idx, "cpp_function.cpp", code);
auto count = test_visit<cpp_function>(*file, [&](const cpp_function& func) { auto count = test_visit<cpp_function>(*file, [&](const cpp_function& func) {
if (func.name() == "a" || func.name() == "b" || func.name() == "c") if (func.name() == "a" || func.name() == "b" || func.name() == "c")
{ {
REQUIRE(!func.noexcept_condition()); REQUIRE(!func.noexcept_condition());
@ -99,11 +99,12 @@ void ns::l()
*cpp_pointer_type::build( *cpp_pointer_type::build(
cpp_builtin_type::build(cpp_float)))); cpp_builtin_type::build(cpp_float))));
REQUIRE(param.default_value()); REQUIRE(param.default_value());
REQUIRE(equal_expressions(param.default_value().value(), REQUIRE(
*cpp_unexposed_expression:: equal_expressions(param.default_value().value(),
build(cpp_pointer_type::build( *cpp_unexposed_expression::
cpp_builtin_type::build(cpp_float)), build(cpp_pointer_type::build(
"nullptr"))); cpp_builtin_type::build(cpp_float)),
cpp_token_string::from_string("nullptr"))));
} }
else else
REQUIRE(false); REQUIRE(false);
@ -130,12 +131,11 @@ void ns::l()
{ {
if (param.name() == "a") if (param.name() == "a")
{ {
REQUIRE( REQUIRE(equal_types(idx, param.type(),
equal_types(idx, param.type(), *cpp_decltype_type::build(
*cpp_decltype_type::build( cpp_unexposed_expression::
cpp_unexposed_expression::build(cpp_builtin_type::build( build(cpp_builtin_type::build(cpp_int),
cpp_int), cpp_token_string::from_string("42")))));
"42"))));
REQUIRE(!param.default_value()); REQUIRE(!param.default_value());
} }
else else
@ -163,12 +163,15 @@ void ns::l()
*cpp_literal_expression::build(std::move(bool_t), "true"))); *cpp_literal_expression::build(std::move(bool_t), "true")));
else if (func.name() == "e") else if (func.name() == "e")
REQUIRE(equal_expressions(func.noexcept_condition().value(), REQUIRE(equal_expressions(func.noexcept_condition().value(),
*cpp_unexposed_expression::build(std::move(bool_t), *cpp_unexposed_expression::
"false"))); build(std::move(bool_t),
cpp_token_string::from_string("false"))));
else if (func.name() == "f") else if (func.name() == "f")
REQUIRE(equal_expressions(func.noexcept_condition().value(), REQUIRE(
*cpp_unexposed_expression::build(std::move(bool_t), equal_expressions(func.noexcept_condition().value(),
"noexcept(d())"))); *cpp_unexposed_expression::
build(std::move(bool_t),
cpp_token_string::from_string("noexcept(d())"))));
} }
else if (func.name() == "g" || func.name() == "h" || func.name() == "i" else if (func.name() == "g" || func.name() == "h" || func.name() == "i"
|| func.name() == "j") || func.name() == "j")
@ -246,8 +249,8 @@ void foo::a() {}
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "static_cpp_function.cpp", code); auto file = parse(idx, "static_cpp_function.cpp", code);
auto count = test_visit<cpp_function>(*file, [&](const cpp_function& func) { auto count = test_visit<cpp_function>(*file, [&](const cpp_function& func) {
REQUIRE(!func.is_variadic()); REQUIRE(!func.is_variadic());
REQUIRE(func.signature() == "()"); REQUIRE(func.signature() == "()");
REQUIRE(func.storage_class() == cpp_storage_class_static); REQUIRE(func.storage_class() == cpp_storage_class_static);

View file

@ -105,9 +105,8 @@ d::d(const int&);
else if (tfunc.name() == "b") else if (tfunc.name() == "b")
{ {
check_parent(tfunc, "d", "d::b"); check_parent(tfunc, "d", "d::b");
check_template_parameters(tfunc, check_template_parameters(tfunc, {{cpp_entity_kind::non_type_template_parameter_t, "I"},
{{cpp_entity_kind::non_type_template_parameter_t, "I"}, {cpp_entity_kind::template_type_parameter_t, "T"}});
{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function()); auto& func = static_cast<const cpp_function&>(tfunc.function());
@ -181,110 +180,109 @@ d::d(const int&);
}); });
REQUIRE(count == 5u); REQUIRE(count == 5u);
count = test_visit<cpp_function_template_specialization>( count = test_visit<
*file, [&](const cpp_function_template_specialization& tfunc) { cpp_function_template_specialization>(*file, [&](const cpp_function_template_specialization&
REQUIRE(tfunc.is_full_specialization()); tfunc) {
REQUIRE(!tfunc.arguments_exposed()); REQUIRE(tfunc.is_full_specialization());
REQUIRE(!tfunc.scope_name()); REQUIRE(!tfunc.arguments_exposed());
REQUIRE(!tfunc.scope_name());
auto templ = tfunc.primary_template(); auto templ = tfunc.primary_template();
if (tfunc.name() == "operator int") if (tfunc.name() == "operator int")
REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()),
"d::operator T")); "d::operator T"));
else else
REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()),
(tfunc.function().semantic_scope() + tfunc.name()).c_str())); (tfunc.function().semantic_scope() + tfunc.name()).c_str()));
if (tfunc.name() == "a") if (tfunc.name() == "a")
{
REQUIRE(tfunc.unexposed_arguments().empty());
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "");
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
auto count = 0u;
for (auto& param : func.parameters())
{ {
REQUIRE(tfunc.unexposed_arguments() == ""); ++count;
REQUIRE(equal_types(idx, param.type(),
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "");
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
auto count = 0u;
for (auto& param : func.parameters())
{
++count;
REQUIRE(
equal_types(idx, param.type(),
*cpp_reference_type:: *cpp_reference_type::
build(cpp_cv_qualified_type::build(cpp_builtin_type::build( build(cpp_cv_qualified_type::build(cpp_builtin_type::build(
cpp_int), cpp_int),
cpp_cv_const), cpp_cv_const),
cpp_ref_lvalue))); cpp_ref_lvalue)));
}
REQUIRE(count == 1u);
} }
else if (tfunc.name() == "b") REQUIRE(count == 1u);
}
else if (tfunc.name() == "b")
{
REQUIRE(tfunc.unexposed_arguments().as_string() == "0,int");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "type"));
builder.add_unexposed_arguments("0");
REQUIRE(equal_types(idx, func.return_type(), *builder.finish()));
auto count = 0u;
for (auto& param : func.parameters())
{ {
REQUIRE(tfunc.unexposed_arguments() == "0,int"); ++count;
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "type"));
builder.add_unexposed_arguments("0");
REQUIRE(equal_types(idx, func.return_type(), *builder.finish()));
auto count = 0u;
for (auto& param : func.parameters())
{
++count;
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
}
REQUIRE(count == 1u);
} }
else if (tfunc.name() == "c") REQUIRE(count == 1u);
}
else if (tfunc.name() == "c")
{
REQUIRE(tfunc.unexposed_arguments().empty());
REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t);
auto& func = static_cast<const cpp_member_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
REQUIRE(func.cv_qualifier() == cpp_cv_none);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
}
else if (tfunc.name() == "operator int")
{
REQUIRE(tfunc.unexposed_arguments().empty());
REQUIRE(tfunc.function().kind() == cpp_entity_kind::conversion_op_t);
auto& func = static_cast<const cpp_conversion_op&>(tfunc.function());
REQUIRE(func.cv_qualifier() == cpp_cv_const);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
}
else if (tfunc.name() == "d")
{
REQUIRE(tfunc.unexposed_arguments().empty());
REQUIRE(tfunc.function().kind() == cpp_entity_kind::constructor_t);
auto& func = static_cast<const cpp_constructor&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
auto count = 0u;
for (auto& param : func.parameters())
{ {
REQUIRE(tfunc.unexposed_arguments() == ""); ++count;
REQUIRE(equal_types(idx, param.type(),
REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t);
auto& func = static_cast<const cpp_member_function&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
REQUIRE(func.cv_qualifier() == cpp_cv_none);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
}
else if (tfunc.name() == "operator int")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::conversion_op_t);
auto& func = static_cast<const cpp_conversion_op&>(tfunc.function());
REQUIRE(func.cv_qualifier() == cpp_cv_const);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int)));
}
else if (tfunc.name() == "d")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::constructor_t);
auto& func = static_cast<const cpp_constructor&>(tfunc.function());
REQUIRE(func.semantic_scope() == "d::");
auto count = 0u;
for (auto& param : func.parameters())
{
++count;
REQUIRE(
equal_types(idx, param.type(),
*cpp_reference_type:: *cpp_reference_type::
build(cpp_cv_qualified_type::build(cpp_builtin_type::build( build(cpp_cv_qualified_type::build(cpp_builtin_type::build(
cpp_int), cpp_int),
cpp_cv_const), cpp_cv_const),
cpp_ref_lvalue))); cpp_ref_lvalue)));
}
REQUIRE(count == 1u);
} }
else REQUIRE(count == 1u);
REQUIRE(false); }
}); else
REQUIRE(false);
});
REQUIRE(count == 5u); REQUIRE(count == 5u);
} }

View file

@ -201,8 +201,8 @@ struct foo
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_conversion_op.cpp", code); auto file = parse(idx, "cpp_conversion_op.cpp", code);
auto count = test_visit<cpp_conversion_op>(*file, [&](const cpp_conversion_op& op) { auto count = test_visit<cpp_conversion_op>(*file, [&](const cpp_conversion_op& op) {
REQUIRE(count_children(op.parameters()) == 0u); REQUIRE(count_children(op.parameters()) == 0u);
REQUIRE(!op.is_variadic()); REQUIRE(!op.is_variadic());
REQUIRE(op.body_kind() == cpp_function_definition); REQUIRE(op.body_kind() == cpp_function_definition);
@ -301,8 +301,8 @@ foo<T>::foo(int) {}
} }
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_constructor.cpp", code); auto file = parse(idx, "cpp_constructor.cpp", code);
auto count = test_visit<cpp_constructor>(*file, [&](const cpp_constructor& cont) { auto count = test_visit<cpp_constructor>(*file, [&](const cpp_constructor& cont) {
REQUIRE(!cont.is_variadic()); REQUIRE(!cont.is_variadic());
REQUIRE(cont.name() == "foo"); REQUIRE(cont.name() == "foo");
@ -402,10 +402,12 @@ d::~d() {}
REQUIRE(!dtor.is_virtual()); REQUIRE(!dtor.is_virtual());
REQUIRE(dtor.body_kind() == cpp_function_definition); REQUIRE(dtor.body_kind() == cpp_function_definition);
REQUIRE(dtor.noexcept_condition()); REQUIRE(dtor.noexcept_condition());
REQUIRE(equal_expressions(dtor.noexcept_condition().value(), REQUIRE(
*cpp_unexposed_expression::build(cpp_builtin_type::build( equal_expressions(dtor.noexcept_condition().value(),
cpp_bool), *cpp_unexposed_expression::build(cpp_builtin_type::build(
"false"))); cpp_bool),
cpp_token_string::from_string(
"false"))));
} }
else if (dtor.name() == "~c") else if (dtor.name() == "~c")
{ {

View file

@ -38,7 +38,8 @@ struct foo
REQUIRE(equal_types(idx, var.type(), *type)); REQUIRE(equal_types(idx, var.type(), *type));
// all initializers are unexposed // all initializers are unexposed
auto def = cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_float), "3.14f"); auto def = cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_float),
cpp_token_string::from_string("3.14f"));
REQUIRE(var.default_value()); REQUIRE(var.default_value());
REQUIRE(equal_expressions(var.default_value().value(), *def)); REQUIRE(equal_expressions(var.default_value().value(), *def));

View file

@ -34,12 +34,17 @@ struct foo
REQUIRE(equal_expressions(assert.expression(), REQUIRE(equal_expressions(assert.expression(),
*cpp_literal_expression::build(std::move(bool_t), "true"))); *cpp_literal_expression::build(std::move(bool_t), "true")));
else if (assert.message() == "a") else if (assert.message() == "a")
REQUIRE(equal_expressions(assert.expression(), REQUIRE(
*cpp_unexposed_expression::build(std::move(bool_t), equal_expressions(assert.expression(),
"true||false"))); *cpp_unexposed_expression::build(std::move(bool_t),
cpp_token_string::from_string(
"true||false"))));
else if (assert.message() == "b") else if (assert.message() == "b")
REQUIRE(equal_expressions(assert.expression(), REQUIRE(
*cpp_unexposed_expression::build(std::move(bool_t), "!B"))); equal_expressions(assert.expression(),
*cpp_unexposed_expression::build(std::move(bool_t),
cpp_token_string::from_string(
"!B"))));
else else
REQUIRE(false); REQUIRE(false);
}); });

View file

@ -34,83 +34,72 @@ using e = void;
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_template_type_parameter.cpp", code); auto file = parse(idx, "cpp_template_type_parameter.cpp", code);
auto count = auto count = test_visit<
test_visit<cpp_alias_template>(*file, cpp_alias_template>(*file,
[&](const cpp_alias_template& alias) { [&](const cpp_alias_template& alias) {
REQUIRE(equal_types(idx, REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
alias.type_alias().underlying_type(), *cpp_builtin_type::build(cpp_void)));
*cpp_builtin_type::build(cpp_void)));
for (auto& p : alias.parameters()) for (auto& p : alias.parameters())
{ {
REQUIRE( REQUIRE(p.kind() == cpp_entity_kind::template_type_parameter_t);
p.kind()
== cpp_entity_kind::template_type_parameter_t);
auto& param = auto& param =
static_cast<const cpp_template_type_parameter&>( static_cast<const cpp_template_type_parameter&>(p);
p); if (param.name() == "A")
if (param.name() == "A") {
{ REQUIRE(alias.name() == "a");
REQUIRE(alias.name() == "a"); REQUIRE(param.keyword()
REQUIRE( == cpp_template_keyword::keyword_typename);
param.keyword() REQUIRE(!param.is_variadic());
== cpp_template_keyword::keyword_typename); REQUIRE(!param.default_type());
REQUIRE(!param.is_variadic()); }
REQUIRE(!param.default_type()); else if (param.name() == "B")
} {
else if (param.name() == "B") REQUIRE(alias.name() == "b");
{ REQUIRE(param.keyword()
REQUIRE(alias.name() == "b"); == cpp_template_keyword::keyword_class);
REQUIRE(param.keyword() REQUIRE(param.is_variadic());
== cpp_template_keyword::keyword_class); REQUIRE(!param.default_type());
REQUIRE(param.is_variadic()); }
REQUIRE(!param.default_type()); else if (param.name() == "")
} {
else if (param.name() == "") REQUIRE(alias.name() == "c");
{ REQUIRE(param.keyword()
REQUIRE(alias.name() == "c"); == cpp_template_keyword::keyword_typename);
REQUIRE( REQUIRE(!param.is_variadic());
param.keyword() REQUIRE(param.default_type().has_value());
== cpp_template_keyword::keyword_typename); REQUIRE(
REQUIRE(!param.is_variadic()); equal_types(idx, param.default_type().value(),
REQUIRE(param.default_type().has_value()); *cpp_unexposed_type::build("const int*")));
REQUIRE(equal_types(idx, }
param.default_type().value(), else if (param.name() == "D")
*cpp_unexposed_type::build( {
"const int*"))); REQUIRE(alias.name() == "d");
} REQUIRE(param.keyword()
else if (param.name() == "D") == cpp_template_keyword::keyword_class);
{ REQUIRE(!param.is_variadic());
REQUIRE(alias.name() == "d"); REQUIRE(param.default_type().has_value());
REQUIRE(param.keyword() REQUIRE(equal_types(idx, param.default_type().value(),
== cpp_template_keyword::keyword_class); *cpp_unexposed_type::build(
REQUIRE(!param.is_variadic()); "decltype(1+3)")));
REQUIRE(param.default_type().has_value()); }
REQUIRE(equal_types(idx, else if (param.name() == "E")
param.default_type().value(), {
*cpp_unexposed_type::build( REQUIRE(alias.name() == "e");
"decltype(1+3)"))); REQUIRE(param.keyword()
} == cpp_template_keyword::keyword_typename);
else if (param.name() == "E") REQUIRE(!param.is_variadic());
{ REQUIRE(param.default_type().has_value());
REQUIRE(alias.name() == "e"); REQUIRE(equal_types(idx, param.default_type().value(),
REQUIRE( *cpp_unexposed_type::build("a<void>")));
param.keyword() }
== cpp_template_keyword::keyword_typename); else
REQUIRE(!param.is_variadic()); REQUIRE(false);
REQUIRE(param.default_type().has_value()); }
REQUIRE(equal_types(idx, },
param.default_type().value(), false); // can't check synopsis with comments
*cpp_unexposed_type::build(
"a<void>")));
}
else
REQUIRE(false);
}
},
false); // can't check synopsis with comments
REQUIRE(count == 5u); REQUIRE(count == 5u);
} }
@ -132,61 +121,71 @@ using d = void;
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_non_type_template_parameter.cpp", code); auto file = parse(idx, "cpp_non_type_template_parameter.cpp", code);
auto count = test_visit<cpp_alias_template>( auto count = test_visit<
*file, cpp_alias_template>(*file,
[&](const cpp_alias_template& alias) { [&](const cpp_alias_template& alias) {
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
*cpp_builtin_type::build(cpp_void))); *cpp_builtin_type::build(cpp_void)));
for (auto& p : alias.parameters()) for (auto& p : alias.parameters())
{ {
REQUIRE(p.kind() == cpp_entity_kind::non_type_template_parameter_t); REQUIRE(p.kind()
== cpp_entity_kind::non_type_template_parameter_t);
auto& param = static_cast<const cpp_non_type_template_parameter&>(p); auto& param =
if (param.name() == "A") static_cast<const cpp_non_type_template_parameter&>(p);
{ if (param.name() == "A")
REQUIRE(alias.name() == "a"); {
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int))); REQUIRE(alias.name() == "a");
REQUIRE(!param.is_variadic()); REQUIRE(equal_types(idx, param.type(),
REQUIRE(!param.default_value()); *cpp_builtin_type::build(cpp_int)));
} REQUIRE(!param.is_variadic());
else if (param.name() == "") REQUIRE(!param.default_value());
{ }
REQUIRE(alias.name() == "b"); else if (param.name() == "")
REQUIRE(equal_types(idx, param.type(), *cpp_pointer_type::build( {
cpp_builtin_type::build(cpp_char)))); REQUIRE(alias.name() == "b");
REQUIRE(!param.is_variadic()); REQUIRE(
REQUIRE(param.default_value()); equal_types(idx, param.type(),
REQUIRE( *cpp_pointer_type::build(
equal_expressions(param.default_value().value(), cpp_builtin_type::build(cpp_char))));
*cpp_unexposed_expression::build(cpp_builtin_type::build( REQUIRE(!param.is_variadic());
cpp_nullptr), REQUIRE(param.default_value());
"nullptr"))); REQUIRE(equal_expressions(param.default_value().value(),
} *cpp_unexposed_expression::
else if (param.name() == "C") build(cpp_builtin_type::build(
{ cpp_nullptr),
REQUIRE(alias.name() == "c"); cpp_token_string::
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int))); from_string(
REQUIRE(param.is_variadic()); "nullptr"))));
REQUIRE(!param.default_value()); }
} else if (param.name() == "C")
else if (param.name() == "D") {
{ REQUIRE(alias.name() == "c");
REQUIRE(alias.name() == "d"); REQUIRE(equal_types(idx, param.type(),
*cpp_builtin_type::build(cpp_int)));
REQUIRE(param.is_variadic());
REQUIRE(!param.default_value());
}
else if (param.name() == "D")
{
REQUIRE(alias.name() == "d");
cpp_function_type::builder builder(cpp_builtin_type::build(cpp_void)); cpp_function_type::builder builder(
builder.is_variadic(); cpp_builtin_type::build(cpp_void));
REQUIRE( builder.is_variadic();
equal_types(idx, param.type(), *cpp_pointer_type::build(builder.finish()))); REQUIRE(equal_types(idx, param.type(),
*cpp_pointer_type::build(
builder.finish())));
REQUIRE(!param.is_variadic()); REQUIRE(!param.is_variadic());
REQUIRE(!param.default_value()); REQUIRE(!param.default_value());
} }
else else
REQUIRE(false); REQUIRE(false);
} }
}, },
false); // can't check synopsis with comments false); // can't check synopsis with comments
REQUIRE(count == 4u); REQUIRE(count == 4u);
} }
@ -215,109 +214,122 @@ using d = void;
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_template_template_parameter.cpp", code); auto file = parse(idx, "cpp_template_template_parameter.cpp", code);
auto count = test_visit<cpp_alias_template>( auto count = test_visit<
*file, cpp_alias_template>(*file,
[&](const cpp_alias_template& alias) { [&](const cpp_alias_template& alias) {
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
*cpp_builtin_type::build(cpp_void))); *cpp_builtin_type::build(cpp_void)));
if (alias.name() == "def") if (alias.name() == "def")
return; return;
for (auto& p : alias.parameters()) for (auto& p : alias.parameters())
{ {
REQUIRE(p.kind() == cpp_entity_kind::template_template_parameter_t); REQUIRE(p.kind()
== cpp_entity_kind::template_template_parameter_t);
auto& param = static_cast<const cpp_template_template_parameter&>(p); auto& param =
REQUIRE(param.keyword() == cpp_template_keyword::keyword_class); static_cast<const cpp_template_template_parameter&>(p);
if (param.name() == "A") REQUIRE(param.keyword() == cpp_template_keyword::keyword_class);
{ if (param.name() == "A")
REQUIRE(alias.name() == "a"); {
REQUIRE(!param.is_variadic()); REQUIRE(alias.name() == "a");
REQUIRE(!param.default_template()); REQUIRE(!param.is_variadic());
REQUIRE(!param.default_template());
auto no = 0u; auto no = 0u;
for (auto& p_param : param.parameters()) for (auto& p_param : param.parameters())
{ {
++no; ++no;
REQUIRE(p_param.name() == "T"); REQUIRE(p_param.name() == "T");
REQUIRE(p_param.kind() == cpp_entity_kind::template_type_parameter_t); REQUIRE(p_param.kind()
} == cpp_entity_kind::template_type_parameter_t);
REQUIRE(no == 1u); }
} REQUIRE(no == 1u);
else if (param.name() == "B") }
{ else if (param.name() == "B")
REQUIRE(alias.name() == "b"); {
REQUIRE(param.is_variadic()); REQUIRE(alias.name() == "b");
REQUIRE(!param.default_template()); REQUIRE(param.is_variadic());
REQUIRE(!param.default_template());
auto cur = param.parameters().begin(); auto cur = param.parameters().begin();
REQUIRE(cur != param.parameters().end()); REQUIRE(cur != param.parameters().end());
REQUIRE(cur->name().empty()); REQUIRE(cur->name().empty());
REQUIRE(cur->kind() == cpp_entity_kind::non_type_template_parameter_t); REQUIRE(cur->kind()
== cpp_entity_kind::non_type_template_parameter_t);
++cur; ++cur;
REQUIRE(cur != param.parameters().end()); REQUIRE(cur != param.parameters().end());
REQUIRE(cur->name().empty()); REQUIRE(cur->name().empty());
REQUIRE(cur->kind() == cpp_entity_kind::template_type_parameter_t); REQUIRE(cur->kind()
== cpp_entity_kind::template_type_parameter_t);
++cur; ++cur;
REQUIRE(cur == param.parameters().end()); REQUIRE(cur == param.parameters().end());
} }
else if (param.name() == "C") else if (param.name() == "C")
{ {
REQUIRE(alias.name() == "c"); REQUIRE(alias.name() == "c");
REQUIRE(!param.is_variadic()); REQUIRE(!param.is_variadic());
REQUIRE(param.default_template()); REQUIRE(param.default_template());
auto def = param.default_template().value(); auto def = param.default_template().value();
REQUIRE(def.name() == "ns::def"); REQUIRE(def.name() == "ns::def");
auto entities = def.get(idx); auto entities = def.get(idx);
REQUIRE(entities.size() == 1u); REQUIRE(entities.size() == 1u);
REQUIRE(entities[0]->name() == "def"); REQUIRE(entities[0]->name() == "def");
auto no = 0u; auto no = 0u;
for (auto& p_param : param.parameters()) for (auto& p_param : param.parameters())
{ {
++no; ++no;
REQUIRE(p_param.name() == ""); REQUIRE(p_param.name() == "");
REQUIRE(p_param.kind() == cpp_entity_kind::non_type_template_parameter_t); REQUIRE(
} p_param.kind()
REQUIRE(no == 1u); == cpp_entity_kind::non_type_template_parameter_t);
} }
else if (param.name() == "D") REQUIRE(no == 1u);
{ }
REQUIRE(alias.name() == "d"); else if (param.name() == "D")
REQUIRE(!param.is_variadic()); {
REQUIRE(param.default_template()); REQUIRE(alias.name() == "d");
REQUIRE(!param.is_variadic());
REQUIRE(param.default_template());
auto def = param.default_template().value(); auto def = param.default_template().value();
REQUIRE(def.name() == "a"); REQUIRE(def.name() == "a");
auto entities = def.get(idx); auto entities = def.get(idx);
REQUIRE(entities.size() == 1u); REQUIRE(entities.size() == 1u);
REQUIRE(entities[0]->name() == "a"); REQUIRE(entities[0]->name() == "a");
auto no = 0u; auto no = 0u;
for (auto& p_param : param.parameters()) for (auto& p_param : param.parameters())
{ {
++no; ++no;
REQUIRE(p_param.name() == ""); REQUIRE(p_param.name() == "");
REQUIRE(p_param.kind() == cpp_entity_kind::template_template_parameter_t); REQUIRE(
for (auto& p_p_param : p_param.kind()
static_cast<const cpp_template_template_parameter&>(p_param) == cpp_entity_kind::template_template_parameter_t);
.parameters()) for (auto& p_p_param :
{ static_cast<
++no; const cpp_template_template_parameter&>(
REQUIRE(p_p_param.name() == ""); p_param)
REQUIRE(p_p_param.kind() == cpp_entity_kind::template_type_parameter_t); .parameters())
REQUIRE(p_p_param.is_variadic()); {
} ++no;
} REQUIRE(p_p_param.name() == "");
REQUIRE(no == 2u); REQUIRE(
} p_p_param.kind()
else == cpp_entity_kind::template_type_parameter_t);
REQUIRE(false); REQUIRE(p_p_param.is_variadic());
} }
}, }
false); // can't check synopsis with comments REQUIRE(no == 2u);
}
else
REQUIRE(false);
}
},
false); // can't check synopsis with comments
REQUIRE(count == 5u); REQUIRE(count == 5u);
} }

View file

@ -333,12 +333,13 @@ typedef decltype(0) w;
if (literal) if (literal)
return cpp_literal_expression::build(std::move(type), std::move(size)); return cpp_literal_expression::build(std::move(type), std::move(size));
else else
return cpp_unexposed_expression::build(std::move(type), std::move(size)); return cpp_unexposed_expression::build(std::move(type),
cpp_token_string::from_string(std::move(size)));
}; };
cpp_entity_index idx; cpp_entity_index idx;
auto file = parse(idx, "cpp_type_alias.cpp", code); auto file = parse(idx, "cpp_type_alias.cpp", code);
auto count = test_visit<cpp_type_alias>(*file, [&](const cpp_type_alias& alias) { auto count = test_visit<cpp_type_alias>(*file, [&](const cpp_type_alias& alias) {
if (alias.name() == "a") if (alias.name() == "a")
{ {
auto type = cpp_builtin_type::build(cpp_int); auto type = cpp_builtin_type::build(cpp_int);
@ -505,7 +506,8 @@ typedef decltype(0) w;
else if (alias.name() == "w") else if (alias.name() == "w")
{ {
auto type = cpp_decltype_type::build( auto type = cpp_decltype_type::build(
cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), "0")); cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
cpp_token_string::from_string("0")));
REQUIRE(equal_types(idx, alias.underlying_type(), *type)); REQUIRE(equal_types(idx, alias.underlying_type(), *type));
} }
else else

View file

@ -62,7 +62,7 @@ int r[] = {0};
)"; )";
cpp_entity_index idx; cpp_entity_index idx;
auto check_variable = [&](const cpp_variable& var, const cpp_type& type, auto check_variable = [&](const cpp_variable& var, const cpp_type& type,
type_safe::optional_ref<const cpp_expression> default_value, type_safe::optional_ref<const cpp_expression> default_value,
int storage_class, bool is_constexpr, bool is_declaration) { int storage_class, bool is_constexpr, bool is_declaration) {
if (is_declaration) if (is_declaration)
@ -101,13 +101,15 @@ int r[] = {0};
// unexposed due to implicit cast, I think // unexposed due to implicit cast, I think
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"42")), cpp_token_string::from_string(
"42"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else if (var.name() == "c") else if (var.name() == "c")
check_variable(var, *cpp_builtin_type::build(cpp_float), check_variable(var, *cpp_builtin_type::build(cpp_float),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_float), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_float),
"3.f+0.14f")), cpp_token_string::from_string(
"3.f+0.14f"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else if (var.name() == "d") else if (var.name() == "d")
check_variable(var, *int_type, nullptr, cpp_storage_class_extern, false, true); check_variable(var, *int_type, nullptr, cpp_storage_class_extern, false, true);
@ -119,11 +121,13 @@ int r[] = {0};
check_variable(var, *int_type, nullptr, check_variable(var, *int_type, nullptr,
cpp_storage_class_static | cpp_storage_class_thread_local, false, false); cpp_storage_class_static | cpp_storage_class_thread_local, false, false);
else if (var.name() == "h") else if (var.name() == "h")
check_variable(var, *cpp_cv_qualified_type::build(cpp_builtin_type::build(cpp_int), check_variable(var,
cpp_cv_const), *cpp_cv_qualified_type::build(cpp_builtin_type::build(cpp_int),
cpp_cv_const),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"12")), cpp_token_string::from_string(
"12"))),
cpp_storage_class_none, true, false); cpp_storage_class_none, true, false);
else if (var.name() == "i") else if (var.name() == "i")
{ {
@ -134,15 +138,17 @@ int r[] = {0};
} }
else if (var.name() == "j") else if (var.name() == "j")
{ {
check_variable(var, *cpp_cv_qualified_type::build(cpp_user_defined_type::build( check_variable(var,
cpp_type_ref(cpp_entity_id(""), *cpp_cv_qualified_type::build(cpp_user_defined_type::build(
"bar")), cpp_type_ref(cpp_entity_id(""),
cpp_cv_const), "bar")),
cpp_cv_const),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_user_defined_type::build( *cpp_unexposed_expression::build(cpp_user_defined_type::build(
cpp_type_ref(cpp_entity_id(""), cpp_type_ref(cpp_entity_id(""),
"bar")), "bar")),
"bar()")), cpp_token_string::from_string(
"bar()"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
return false; return false;
} }
@ -163,35 +169,40 @@ int r[] = {0};
check_variable(var, *cpp_auto_type::build(), check_variable(var, *cpp_auto_type::build(),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"128")), cpp_token_string::from_string(
"128"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else if (var.name() == "n") else if (var.name() == "n")
check_variable(var, *cpp_reference_type:: check_variable(var,
build(cpp_cv_qualified_type::build(cpp_auto_type::build(), *cpp_reference_type::
cpp_cv_const), build(cpp_cv_qualified_type::build(cpp_auto_type::build(),
cpp_ref_lvalue), cpp_cv_const),
cpp_ref_lvalue),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"m")), cpp_token_string::from_string(
"m"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else if (var.name() == "o") else if (var.name() == "o")
check_variable(var, check_variable(var,
*cpp_decltype_type::build( *cpp_decltype_type::build(
cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"0")), cpp_token_string::from_string("0"))),
nullptr, cpp_storage_class_none, false, false); nullptr, cpp_storage_class_none, false, false);
else if (var.name() == "p") else if (var.name() == "p")
check_variable(var, *cpp_reference_type:: check_variable(var,
build(cpp_cv_qualified_type:: *cpp_reference_type::
build(cpp_decltype_type::build( build(cpp_cv_qualified_type::
cpp_unexposed_expression:: build(cpp_decltype_type::build(
build(cpp_builtin_type::build(cpp_int), cpp_unexposed_expression::
"o")), build(cpp_builtin_type::build(cpp_int),
cpp_cv_const), cpp_token_string::from_string("o"))),
cpp_ref_lvalue), cpp_cv_const),
cpp_ref_lvalue),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int),
"o")), cpp_token_string::from_string(
"o"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else if (var.name() == "q") else if (var.name() == "q")
check_variable(var, check_variable(var,
@ -208,7 +219,8 @@ int r[] = {0};
"1")), "1")),
type_safe::ref( type_safe::ref(
*cpp_unexposed_expression::build(cpp_unexposed_type::build(""), *cpp_unexposed_expression::build(cpp_unexposed_type::build(""),
"{0}")), cpp_token_string::from_string(
"{0}"))),
cpp_storage_class_none, false, false); cpp_storage_class_none, false, false);
else else
REQUIRE(false); REQUIRE(false);

View file

@ -49,9 +49,7 @@ inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& i
class test_generator : public cppast::code_generator class test_generator : public cppast::code_generator
{ {
public: public:
test_generator(generation_options options) : options_(std::move(options)) test_generator(generation_options options) : options_(std::move(options)) {}
{
}
const std::string& str() const noexcept const std::string& str() const noexcept
{ {
@ -205,8 +203,10 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed,
switch (parsed.kind()) switch (parsed.kind())
{ {
case cpp_expression_kind::unexposed_t: case cpp_expression_kind::unexposed_t:
return static_cast<const cpp_unexposed_expression&>(parsed).expression() return static_cast<const cpp_unexposed_expression&>(parsed).expression().as_string()
== static_cast<const cpp_unexposed_expression&>(synthesized).expression(); == static_cast<const cpp_unexposed_expression&>(synthesized)
.expression()
.as_string();
case cpp_expression_kind::literal_t: case cpp_expression_kind::literal_t:
return static_cast<const cpp_literal_expression&>(parsed).value() return static_cast<const cpp_literal_expression&>(parsed).value()
@ -217,10 +217,10 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed,
} }
template <typename T, class Predicate> template <typename T, class Predicate>
bool equal_ref(const cppast::cpp_entity_index& idx, bool equal_ref(const cppast::cpp_entity_index& idx,
const cppast::basic_cpp_entity_ref<T, Predicate>& parsed, const cppast::basic_cpp_entity_ref<T, Predicate>& parsed,
const cppast::basic_cpp_entity_ref<T, Predicate>& synthesized, const cppast::basic_cpp_entity_ref<T, Predicate>& synthesized,
const char* full_name_override = nullptr) const char* full_name_override = nullptr)
{ {
if (parsed.name() != synthesized.name()) if (parsed.name() != synthesized.name())
return false; return false;