diff --git a/include/cppast/code_generator.hpp b/include/cppast/code_generator.hpp index 39f24b7..b2925e5 100644 --- a/include/cppast/code_generator.hpp +++ b/include/cppast/code_generator.hpp @@ -500,12 +500,17 @@ namespace cppast /// \exclude class cpp_template_argument; + /// \exclude + class cpp_token_string; + /// \exclude namespace detail { void write_template_arguments( code_generator::output& output, type_safe::optional> arguments); + + void write_token_string(code_generator::output& output, const cpp_token_string& tokens); } // namespace detail } // namespace cppast diff --git a/include/cppast/cpp_entity.hpp b/include/cppast/cpp_entity.hpp index 6fbee19..73f2bc7 100644 --- a/include/cppast/cpp_entity.hpp +++ b/include/cppast/cpp_entity.hpp @@ -11,6 +11,7 @@ #include #include +#include namespace cppast { @@ -141,9 +142,7 @@ namespace cppast protected: /// \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: /// \returns The kind of the entity. @@ -182,27 +181,27 @@ namespace cppast /// \returns A newly built and registered unexposed entity. /// \notes It will be registered as a declaration. static std::unique_ptr 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. /// It will not be registered. - static std::unique_ptr build(std::string spelling); + static std::unique_ptr build(cpp_token_string spelling); /// \returns The spelling of that entity. - const std::string& spelling() const noexcept + const cpp_token_string& spelling() const noexcept { return spelling_; } 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_kind do_get_entity_kind() const noexcept override; - std::string spelling_; + cpp_token_string spelling_; }; /// \returns Whether or not the entity is templated. diff --git a/include/cppast/cpp_expression.hpp b/include/cppast/cpp_expression.hpp index 5ea2503..c9166d3 100644 --- a/include/cppast/cpp_expression.hpp +++ b/include/cppast/cpp_expression.hpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace cppast @@ -82,20 +83,20 @@ namespace cppast public: /// \returns A newly created unexposed expression. static std::unique_ptr build(std::unique_ptr type, - std::string str) + cpp_token_string str) { return std::unique_ptr( new cpp_unexposed_expression(std::move(type), std::move(str))); } /// \returns The expression as a string. - const std::string& expression() const noexcept + const cpp_token_string& expression() const noexcept { return str_; } private: - cpp_unexposed_expression(std::unique_ptr type, std::string str) + cpp_unexposed_expression(std::unique_ptr type, cpp_token_string str) : cpp_expression(std::move(type)), str_(std::move(str)) { } @@ -105,7 +106,7 @@ namespace cppast return cpp_expression_kind::unexposed_t; } - std::string str_; + cpp_token_string str_; }; /// A [cppast::cpp_expression]() that is a literal. diff --git a/include/cppast/cpp_template.hpp b/include/cppast/cpp_template.hpp index a92f58a..ce5a4f4 100644 --- a/include/cppast/cpp_template.hpp +++ b/include/cppast/cpp_template.hpp @@ -11,6 +11,7 @@ #include #include +#include #include namespace cppast @@ -179,7 +180,7 @@ namespace cppast } type_safe::variant, std::string> arguments_; - cpp_template_ref templ_; + cpp_template_ref templ_; }; /// 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`. /// \notes For function template specializations it can be empty, /// 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{}); + return arguments_.value(type_safe::variant_type{}); } /// \returns Whether or not the specialization is a full specialization. @@ -252,7 +253,7 @@ namespace cppast } /// \effects Adds unexposed arguments as string. - void add_unexposed_arguments(std::string arg) + void add_unexposed_arguments(cpp_token_string arg) { auto& specialization = static_cast(*this->template_entity); @@ -276,8 +277,8 @@ namespace cppast } private: - type_safe::variant, std::string> arguments_; - cpp_entity_id templ_; + type_safe::variant, cpp_token_string> arguments_; + cpp_entity_id templ_; }; } // namespace cppast diff --git a/include/cppast/cpp_token.hpp b/include/cppast/cpp_token.hpp new file mode 100644 index 0000000..1daf036 --- /dev/null +++ b/include/cppast/cpp_token.hpp @@ -0,0 +1,137 @@ +// Copyright (C) 2017 Jonathan Müller +// 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 +#include + +#include + +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 tokens_; + }; + + /// \effects Creates it from a sequence of tokens. + cpp_token_string(std::vector 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::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 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f2af0c..04e1714 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ set(header ../include/cppast/cpp_storage_class_specifiers.hpp ../include/cppast/cpp_template.hpp ../include/cppast/cpp_template_parameter.hpp + ../include/cppast/cpp_token.hpp ../include/cppast/cpp_type.hpp ../include/cppast/cpp_type_alias.hpp ../include/cppast/cpp_variable.hpp @@ -68,6 +69,7 @@ set(source cpp_preprocessor.cpp cpp_static_assert.cpp cpp_template_parameter.cpp + cpp_token.cpp cpp_type.cpp cpp_type_alias.cpp cpp_variable.cpp diff --git a/src/code_generator.cpp b/src/code_generator.cpp index eb88d96..39d44fb 100644 --- a/src/code_generator.cpp +++ b/src/code_generator.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -343,8 +344,11 @@ namespace if (spec.arguments_exposed()) detail::write_template_arguments(output, spec.arguments()); 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) @@ -537,7 +541,8 @@ namespace output << keyword("noexcept") << punctuation("(") << bracket_ws; // update check when expression gets exposed if (cond.kind() == cpp_expression_kind::unexposed_t - && static_cast(cond).expression() == "false") + && static_cast(cond).expression().front().spelling + == "false") output << keyword("false"); else if (output.options().is_set(code_generator::exclude_noexcept_condition)) output.excluded(base); @@ -1029,7 +1034,7 @@ namespace code_generator::output output(type_safe::ref(generator), type_safe::ref(entity), cur_access); if (output) - output << token_seq(entity.spelling()); + detail::write_token_string(output, entity.spelling()); return static_cast(output); } @@ -1147,3 +1152,63 @@ void detail::write_template_arguments( 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; + } +} diff --git a/src/cpp_entity.cpp b/src/cpp_entity.cpp index 4f7aa31..9b6d96f 100644 --- a/src/cpp_entity.cpp +++ b/src/cpp_entity.cpp @@ -45,7 +45,7 @@ cpp_entity_kind cpp_unexposed_entity::kind() noexcept std::unique_ptr cpp_unexposed_entity::build(const cpp_entity_index& index, cpp_entity_id id, std::string name, - std::string spelling) + cpp_token_string spelling) { std::unique_ptr result( new cpp_unexposed_entity(std::move(name), std::move(spelling))); @@ -53,7 +53,7 @@ std::unique_ptr cpp_unexposed_entity::build(const cpp_entity_index& return result; } -std::unique_ptr cpp_unexposed_entity::build(std::string spelling) +std::unique_ptr cpp_unexposed_entity::build(cpp_token_string spelling) { return std::unique_ptr(new cpp_unexposed_entity("", std::move(spelling))); } diff --git a/src/cpp_expression.cpp b/src/cpp_expression.cpp index f0142cd..a3585dd 100644 --- a/src/cpp_expression.cpp +++ b/src/cpp_expression.cpp @@ -75,7 +75,7 @@ namespace void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr) { - output << token_seq(expr.expression()); + detail::write_token_string(output, expr.expression()); } } diff --git a/src/cpp_token.cpp b/src/cpp_token.cpp new file mode 100644 index 0000000..3d68d0c --- /dev/null +++ b/src/cpp_token.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#include + +#include +#include +#include + +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()); +} diff --git a/src/libclang/class_parser.cpp b/src/libclang/class_parser.cpp index 97d68b0..ea661ad 100644 --- a/src/libclang/class_parser.cpp +++ b/src/libclang/class_parser.cpp @@ -81,7 +81,7 @@ namespace detail::skip(stream, "virtual"); 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)); builder.base_class(std::move(name), std::move(type), access, is_virtual); diff --git a/src/libclang/expression_parser.cpp b/src/libclang/expression_parser.cpp index 49e5293..9950675 100644 --- a/src/libclang/expression_parser.cpp +++ b/src/libclang/expression_parser.cpp @@ -19,7 +19,7 @@ std::unique_ptr detail::parse_expression(const detail::parse_con auto type = parse_type(context, cur, clang_getCursorType(cur)); 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 // this means default constructor, don't parse it at all @@ -30,7 +30,7 @@ std::unique_ptr detail::parse_expression(const detail::parse_con || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral || 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 return cpp_unexposed_expression::build(std::move(type), std::move(expr)); } @@ -42,8 +42,7 @@ std::unique_ptr detail::parse_raw_expression(const parse_context { if (stream.done()) return nullptr; - auto expr = to_string(stream, end); - if (!expr.empty() && expr.back() == ';') - expr.pop_back(); + + auto expr = to_string(stream, std::prev(end)->value() == ";" ? std::prev(end) : end); return cpp_unexposed_expression::build(std::move(type), std::move(expr)); } diff --git a/src/libclang/function_parser.cpp b/src/libclang/function_parser.cpp index c3b6163..f13974d 100644 --- a/src/libclang/function_parser.cpp +++ b/src/libclang/function_parser.cpp @@ -705,7 +705,7 @@ std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_ // read the type 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 detail::skip(stream, "("); diff --git a/src/libclang/template_parser.cpp b/src/libclang/template_parser.cpp index 1b4ca78..b16bcee 100644 --- a/src/libclang/template_parser.cpp +++ b/src/libclang/template_parser.cpp @@ -279,7 +279,7 @@ namespace b.add_unexposed_arguments(std::move(args)); } else - b.add_unexposed_arguments(""); + b.add_unexposed_arguments(cpp_token_string::builder().finish()); } } diff --git a/src/libclang/tokenizer.cpp b/src/libclang/tokenizer.cpp index 5e5642e..f6895c5 100644 --- a/src/libclang/tokenizer.cpp +++ b/src/libclang/tokenizer.cpp @@ -223,9 +223,15 @@ namespace || clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier || kind == CXCursor_TemplateTypeParameter #endif - ) + ) // need to shrink range by one 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); } @@ -405,29 +411,41 @@ bool detail::skip_attribute(detail::token_stream& stream) 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) { auto& token = stream.get(); - if (!result.empty() && is_identifier(result.back()) && is_identifier(token.value()[0u])) - result += ' '; - result += token.c_str(); + builder.add_token(cpp_token(get_kind(token.kind()), token.c_str())); } + if (stream.unmunch()) - { - DEBUG_ASSERT(!result.empty() && result.back() == '>', detail::assert_handler{}); - result.pop_back(); - DEBUG_ASSERT(!result.empty() && result.back() == '>', detail::assert_handler{}); - } - return result; + builder.unmunch(); + + return builder.finish(); } 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() == "<") { 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, ">>")) detail::skip(stream, ">"); scope += ">"; diff --git a/src/libclang/tokenizer.hpp b/src/libclang/tokenizer.hpp index dcf41cd..78ac31b 100644 --- a/src/libclang/tokenizer.hpp +++ b/src/libclang/tokenizer.hpp @@ -8,6 +8,8 @@ #include #include +#include + #include "raii_wrapper.hpp" namespace cppast @@ -190,8 +192,8 @@ namespace cppast // skips an attribute bool skip_attribute(token_stream& stream); - // converts a token range to a string, adding whitespace where necessary - std::string to_string(token_stream& stream, token_iterator end); + // converts a token range to a string + cpp_token_string to_string(token_stream& stream, token_iterator end); // appends token to scope, if it is still valid // else clears it diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index a96332d..9603992 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -246,8 +246,9 @@ namespace return size_expr.empty() ? nullptr : cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_ulonglong), - std::string(size_expr.rbegin(), - size_expr.rend())); + cpp_token_string::from_string( + std::string(size_expr.rbegin(), + size_expr.rend()))); } std::unique_ptr try_parse_array_type(const detail::parse_context& context, @@ -486,7 +487,8 @@ namespace spelling.pop_back(); return cpp_decltype_type::build( - cpp_unexposed_expression::build(cpp_unexposed_type::build(""), spelling)); + cpp_unexposed_expression::build(cpp_unexposed_type::build(""), + cpp_token_string::from_string(spelling))); }); } @@ -734,7 +736,7 @@ std::unique_ptr detail::parse_raw_type(const detail::parse_context&, detail::token_iterator 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 detail::parse_cpp_type_alias(const detail::parse_context& context, diff --git a/src/libclang/variable_parser.cpp b/src/libclang/variable_parser.cpp index 89e00d4..d4a65bf 100644 --- a/src/libclang/variable_parser.cpp +++ b/src/libclang/variable_parser.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "libclang_visitor.hpp" diff --git a/test/cpp_class_template.cpp b/test/cpp_class_template.cpp index 0fafa23..427f4a9 100644 --- a/test/cpp_class_template.cpp +++ b/test/cpp_class_template.cpp @@ -110,9 +110,8 @@ struct b<0, T> {}; } else if (templ.name() == "b") { - check_template_parameters(templ, - {{cpp_entity_kind::non_type_template_parameter_t, "I"}, - {cpp_entity_kind::template_type_parameter_t, "T"}}); + check_template_parameters(templ, {{cpp_entity_kind::non_type_template_parameter_t, "I"}, + {cpp_entity_kind::template_type_parameter_t, "T"}}); REQUIRE(c.class_kind() == cpp_class_kind::struct_t); REQUIRE(c.is_definition()); } @@ -223,45 +222,46 @@ struct b<0, T> {}; }); REQUIRE(count == 5u); - count = test_visit( - *file, [&](const cpp_class_template_specialization& templ) { - REQUIRE(!templ.arguments_exposed()); - REQUIRE(templ.scope_name()); + count = test_visit< + cpp_class_template_specialization>(*file, [&](const cpp_class_template_specialization& + templ) { + 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(), - cpp_template_ref(cpp_entity_id(""), "a"))); - 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"); - } + check_template_parameters(templ, {}); + REQUIRE(templ.unexposed_arguments().as_string() == "int"); } 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); } diff --git a/test/cpp_enum.cpp b/test/cpp_enum.cpp index 8b70cf0..3e6cf14 100644 --- a/test/cpp_enum.cpp +++ b/test/cpp_enum.cpp @@ -55,8 +55,8 @@ enum ns::c : int {}; )"; cpp_entity_index idx; - auto file = parse(idx, "cpp_enum.cpp", code); - auto count = test_visit(*file, [&](const cpp_enum& e) { + auto file = parse(idx, "cpp_enum.cpp", code); + auto count = test_visit(*file, [&](const cpp_enum& e) { if (e.name() == "a") { REQUIRE(e.is_definition()); @@ -80,7 +80,9 @@ enum ns::c : int {}; if (equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint))) { REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t); - REQUIRE(static_cast(expr).expression() + REQUIRE(static_cast(expr) + .expression() + .as_string() == "42"); } else @@ -96,8 +98,9 @@ enum ns::c : int {}; REQUIRE(val.value()); auto& expr = val.value().value(); REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t); - REQUIRE(static_cast(expr).expression() - == "a_a+2"); + REQUIRE( + static_cast(expr).expression().as_string() + == "a_a+2"); if (!equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int))) REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint))); } diff --git a/test/cpp_friend.cpp b/test/cpp_friend.cpp index 7f4fbc0..be400ae 100644 --- a/test/cpp_friend.cpp +++ b/test/cpp_friend.cpp @@ -232,7 +232,7 @@ int d() {} { REQUIRE(func.function().is_declaration()); REQUIRE(!func.arguments_exposed()); - REQUIRE(func.unexposed_arguments() == "ns::h"); + REQUIRE(func.unexposed_arguments().as_string() == "ns::h"); } else REQUIRE(false); diff --git a/test/cpp_function.cpp b/test/cpp_function.cpp index 8789951..1208093 100644 --- a/test/cpp_function.cpp +++ b/test/cpp_function.cpp @@ -65,8 +65,8 @@ void ns::l() }; cpp_entity_index idx; - auto file = parse(idx, "cpp_function.cpp", code); - auto count = test_visit(*file, [&](const cpp_function& func) { + auto file = parse(idx, "cpp_function.cpp", code); + auto count = test_visit(*file, [&](const cpp_function& func) { if (func.name() == "a" || func.name() == "b" || func.name() == "c") { REQUIRE(!func.noexcept_condition()); @@ -99,11 +99,12 @@ void ns::l() *cpp_pointer_type::build( cpp_builtin_type::build(cpp_float)))); REQUIRE(param.default_value()); - REQUIRE(equal_expressions(param.default_value().value(), - *cpp_unexposed_expression:: - build(cpp_pointer_type::build( - cpp_builtin_type::build(cpp_float)), - "nullptr"))); + REQUIRE( + equal_expressions(param.default_value().value(), + *cpp_unexposed_expression:: + build(cpp_pointer_type::build( + cpp_builtin_type::build(cpp_float)), + cpp_token_string::from_string("nullptr")))); } else REQUIRE(false); @@ -130,12 +131,11 @@ void ns::l() { if (param.name() == "a") { - REQUIRE( - equal_types(idx, param.type(), - *cpp_decltype_type::build( - cpp_unexposed_expression::build(cpp_builtin_type::build( - cpp_int), - "42")))); + REQUIRE(equal_types(idx, param.type(), + *cpp_decltype_type::build( + cpp_unexposed_expression:: + build(cpp_builtin_type::build(cpp_int), + cpp_token_string::from_string("42"))))); REQUIRE(!param.default_value()); } else @@ -163,12 +163,15 @@ void ns::l() *cpp_literal_expression::build(std::move(bool_t), "true"))); else if (func.name() == "e") REQUIRE(equal_expressions(func.noexcept_condition().value(), - *cpp_unexposed_expression::build(std::move(bool_t), - "false"))); + *cpp_unexposed_expression:: + build(std::move(bool_t), + cpp_token_string::from_string("false")))); else if (func.name() == "f") - REQUIRE(equal_expressions(func.noexcept_condition().value(), - *cpp_unexposed_expression::build(std::move(bool_t), - "noexcept(d())"))); + REQUIRE( + equal_expressions(func.noexcept_condition().value(), + *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" || func.name() == "j") @@ -246,8 +249,8 @@ void foo::a() {} )"; cpp_entity_index idx; - auto file = parse(idx, "static_cpp_function.cpp", code); - auto count = test_visit(*file, [&](const cpp_function& func) { + auto file = parse(idx, "static_cpp_function.cpp", code); + auto count = test_visit(*file, [&](const cpp_function& func) { REQUIRE(!func.is_variadic()); REQUIRE(func.signature() == "()"); REQUIRE(func.storage_class() == cpp_storage_class_static); diff --git a/test/cpp_function_template.cpp b/test/cpp_function_template.cpp index d44aa8b..a2e77e5 100644 --- a/test/cpp_function_template.cpp +++ b/test/cpp_function_template.cpp @@ -105,9 +105,8 @@ d::d(const int&); else if (tfunc.name() == "b") { check_parent(tfunc, "d", "d::b"); - check_template_parameters(tfunc, - {{cpp_entity_kind::non_type_template_parameter_t, "I"}, - {cpp_entity_kind::template_type_parameter_t, "T"}}); + check_template_parameters(tfunc, {{cpp_entity_kind::non_type_template_parameter_t, "I"}, + {cpp_entity_kind::template_type_parameter_t, "T"}}); REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); auto& func = static_cast(tfunc.function()); @@ -181,110 +180,109 @@ d::d(const int&); }); REQUIRE(count == 5u); - count = test_visit( - *file, [&](const cpp_function_template_specialization& tfunc) { - REQUIRE(tfunc.is_full_specialization()); - REQUIRE(!tfunc.arguments_exposed()); - REQUIRE(!tfunc.scope_name()); + count = test_visit< + cpp_function_template_specialization>(*file, [&](const cpp_function_template_specialization& + tfunc) { + REQUIRE(tfunc.is_full_specialization()); + REQUIRE(!tfunc.arguments_exposed()); + REQUIRE(!tfunc.scope_name()); - auto templ = tfunc.primary_template(); - if (tfunc.name() == "operator int") - REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), - "d::operator T")); - else - REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), - (tfunc.function().semantic_scope() + tfunc.name()).c_str())); + auto templ = tfunc.primary_template(); + if (tfunc.name() == "operator int") + REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), + "d::operator T")); + else + REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), + (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(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() == ""); - - REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); - auto& func = static_cast(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(), + ++count; + REQUIRE(equal_types(idx, param.type(), *cpp_reference_type:: build(cpp_cv_qualified_type::build(cpp_builtin_type::build( cpp_int), cpp_cv_const), 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(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"); - - REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); - auto& func = static_cast(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); + ++count; + REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int))); } - 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(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(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(tfunc.function()); + REQUIRE(func.semantic_scope() == "d::"); + + auto count = 0u; + for (auto& param : func.parameters()) { - REQUIRE(tfunc.unexposed_arguments() == ""); - - REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t); - auto& func = static_cast(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(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(tfunc.function()); - REQUIRE(func.semantic_scope() == "d::"); - - auto count = 0u; - for (auto& param : func.parameters()) - { - ++count; - REQUIRE( - equal_types(idx, param.type(), + ++count; + REQUIRE(equal_types(idx, param.type(), *cpp_reference_type:: build(cpp_cv_qualified_type::build(cpp_builtin_type::build( cpp_int), cpp_cv_const), cpp_ref_lvalue))); - } - REQUIRE(count == 1u); } - else - REQUIRE(false); - }); + REQUIRE(count == 1u); + } + else + REQUIRE(false); + }); REQUIRE(count == 5u); } diff --git a/test/cpp_member_function.cpp b/test/cpp_member_function.cpp index 1f84780..6165a94 100644 --- a/test/cpp_member_function.cpp +++ b/test/cpp_member_function.cpp @@ -201,8 +201,8 @@ struct foo )"; cpp_entity_index idx; - auto file = parse(idx, "cpp_conversion_op.cpp", code); - auto count = test_visit(*file, [&](const cpp_conversion_op& op) { + auto file = parse(idx, "cpp_conversion_op.cpp", code); + auto count = test_visit(*file, [&](const cpp_conversion_op& op) { REQUIRE(count_children(op.parameters()) == 0u); REQUIRE(!op.is_variadic()); REQUIRE(op.body_kind() == cpp_function_definition); @@ -301,8 +301,8 @@ foo::foo(int) {} } cpp_entity_index idx; - auto file = parse(idx, "cpp_constructor.cpp", code); - auto count = test_visit(*file, [&](const cpp_constructor& cont) { + auto file = parse(idx, "cpp_constructor.cpp", code); + auto count = test_visit(*file, [&](const cpp_constructor& cont) { REQUIRE(!cont.is_variadic()); REQUIRE(cont.name() == "foo"); @@ -402,10 +402,12 @@ d::~d() {} REQUIRE(!dtor.is_virtual()); REQUIRE(dtor.body_kind() == cpp_function_definition); REQUIRE(dtor.noexcept_condition()); - REQUIRE(equal_expressions(dtor.noexcept_condition().value(), - *cpp_unexposed_expression::build(cpp_builtin_type::build( - cpp_bool), - "false"))); + REQUIRE( + equal_expressions(dtor.noexcept_condition().value(), + *cpp_unexposed_expression::build(cpp_builtin_type::build( + cpp_bool), + cpp_token_string::from_string( + "false")))); } else if (dtor.name() == "~c") { diff --git a/test/cpp_member_variable.cpp b/test/cpp_member_variable.cpp index 6b694b5..52db1d5 100644 --- a/test/cpp_member_variable.cpp +++ b/test/cpp_member_variable.cpp @@ -38,7 +38,8 @@ struct foo REQUIRE(equal_types(idx, var.type(), *type)); // 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(equal_expressions(var.default_value().value(), *def)); diff --git a/test/cpp_static_assert.cpp b/test/cpp_static_assert.cpp index ebd6b80..ceed7b4 100644 --- a/test/cpp_static_assert.cpp +++ b/test/cpp_static_assert.cpp @@ -34,12 +34,17 @@ struct foo REQUIRE(equal_expressions(assert.expression(), *cpp_literal_expression::build(std::move(bool_t), "true"))); else if (assert.message() == "a") - REQUIRE(equal_expressions(assert.expression(), - *cpp_unexposed_expression::build(std::move(bool_t), - "true||false"))); + REQUIRE( + equal_expressions(assert.expression(), + *cpp_unexposed_expression::build(std::move(bool_t), + cpp_token_string::from_string( + "true||false")))); else if (assert.message() == "b") - REQUIRE(equal_expressions(assert.expression(), - *cpp_unexposed_expression::build(std::move(bool_t), "!B"))); + REQUIRE( + equal_expressions(assert.expression(), + *cpp_unexposed_expression::build(std::move(bool_t), + cpp_token_string::from_string( + "!B")))); else REQUIRE(false); }); diff --git a/test/cpp_template_parameter.cpp b/test/cpp_template_parameter.cpp index faccfee..74d5f26 100644 --- a/test/cpp_template_parameter.cpp +++ b/test/cpp_template_parameter.cpp @@ -34,83 +34,72 @@ using e = void; )"; cpp_entity_index idx; - auto file = parse(idx, "cpp_template_type_parameter.cpp", code); - auto count = - test_visit(*file, - [&](const cpp_alias_template& alias) { - REQUIRE(equal_types(idx, - alias.type_alias().underlying_type(), - *cpp_builtin_type::build(cpp_void))); + auto file = parse(idx, "cpp_template_type_parameter.cpp", code); + auto count = test_visit< + cpp_alias_template>(*file, + [&](const cpp_alias_template& alias) { + REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), + *cpp_builtin_type::build(cpp_void))); - for (auto& p : alias.parameters()) - { - REQUIRE( - p.kind() - == cpp_entity_kind::template_type_parameter_t); + for (auto& p : alias.parameters()) + { + REQUIRE(p.kind() == cpp_entity_kind::template_type_parameter_t); - auto& param = - static_cast( - p); - if (param.name() == "A") - { - REQUIRE(alias.name() == "a"); - REQUIRE( - param.keyword() - == cpp_template_keyword::keyword_typename); - REQUIRE(!param.is_variadic()); - REQUIRE(!param.default_type()); - } - else if (param.name() == "B") - { - REQUIRE(alias.name() == "b"); - REQUIRE(param.keyword() - == cpp_template_keyword::keyword_class); - REQUIRE(param.is_variadic()); - REQUIRE(!param.default_type()); - } - else if (param.name() == "") - { - REQUIRE(alias.name() == "c"); - REQUIRE( - param.keyword() - == cpp_template_keyword::keyword_typename); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_type().has_value()); - REQUIRE(equal_types(idx, - param.default_type().value(), - *cpp_unexposed_type::build( - "const int*"))); - } - else if (param.name() == "D") - { - REQUIRE(alias.name() == "d"); - REQUIRE(param.keyword() - == cpp_template_keyword::keyword_class); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_type().has_value()); - REQUIRE(equal_types(idx, - param.default_type().value(), - *cpp_unexposed_type::build( - "decltype(1+3)"))); - } - else if (param.name() == "E") - { - REQUIRE(alias.name() == "e"); - REQUIRE( - param.keyword() - == cpp_template_keyword::keyword_typename); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_type().has_value()); - REQUIRE(equal_types(idx, - param.default_type().value(), - *cpp_unexposed_type::build( - "a"))); - } - else - REQUIRE(false); - } - }, - false); // can't check synopsis with comments + auto& param = + static_cast(p); + if (param.name() == "A") + { + REQUIRE(alias.name() == "a"); + REQUIRE(param.keyword() + == cpp_template_keyword::keyword_typename); + REQUIRE(!param.is_variadic()); + REQUIRE(!param.default_type()); + } + else if (param.name() == "B") + { + REQUIRE(alias.name() == "b"); + REQUIRE(param.keyword() + == cpp_template_keyword::keyword_class); + REQUIRE(param.is_variadic()); + REQUIRE(!param.default_type()); + } + else if (param.name() == "") + { + REQUIRE(alias.name() == "c"); + REQUIRE(param.keyword() + == cpp_template_keyword::keyword_typename); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_type().has_value()); + REQUIRE( + equal_types(idx, param.default_type().value(), + *cpp_unexposed_type::build("const int*"))); + } + else if (param.name() == "D") + { + REQUIRE(alias.name() == "d"); + REQUIRE(param.keyword() + == cpp_template_keyword::keyword_class); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_type().has_value()); + REQUIRE(equal_types(idx, param.default_type().value(), + *cpp_unexposed_type::build( + "decltype(1+3)"))); + } + else if (param.name() == "E") + { + REQUIRE(alias.name() == "e"); + REQUIRE(param.keyword() + == cpp_template_keyword::keyword_typename); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_type().has_value()); + REQUIRE(equal_types(idx, param.default_type().value(), + *cpp_unexposed_type::build("a"))); + } + else + REQUIRE(false); + } + }, + false); // can't check synopsis with comments REQUIRE(count == 5u); } @@ -132,61 +121,71 @@ using d = void; cpp_entity_index idx; auto file = parse(idx, "cpp_non_type_template_parameter.cpp", code); - auto count = test_visit( - *file, - [&](const cpp_alias_template& alias) { - REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), - *cpp_builtin_type::build(cpp_void))); + auto count = test_visit< + cpp_alias_template>(*file, + [&](const cpp_alias_template& alias) { + REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), + *cpp_builtin_type::build(cpp_void))); - for (auto& p : alias.parameters()) - { - REQUIRE(p.kind() == cpp_entity_kind::non_type_template_parameter_t); + for (auto& p : alias.parameters()) + { + REQUIRE(p.kind() + == cpp_entity_kind::non_type_template_parameter_t); - auto& param = static_cast(p); - if (param.name() == "A") - { - REQUIRE(alias.name() == "a"); - REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int))); - REQUIRE(!param.is_variadic()); - REQUIRE(!param.default_value()); - } - else if (param.name() == "") - { - REQUIRE(alias.name() == "b"); - REQUIRE(equal_types(idx, param.type(), *cpp_pointer_type::build( - cpp_builtin_type::build(cpp_char)))); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_value()); - REQUIRE( - equal_expressions(param.default_value().value(), - *cpp_unexposed_expression::build(cpp_builtin_type::build( - cpp_nullptr), - "nullptr"))); - } - else if (param.name() == "C") - { - REQUIRE(alias.name() == "c"); - 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"); + auto& param = + static_cast(p); + if (param.name() == "A") + { + REQUIRE(alias.name() == "a"); + REQUIRE(equal_types(idx, param.type(), + *cpp_builtin_type::build(cpp_int))); + REQUIRE(!param.is_variadic()); + REQUIRE(!param.default_value()); + } + else if (param.name() == "") + { + REQUIRE(alias.name() == "b"); + REQUIRE( + equal_types(idx, param.type(), + *cpp_pointer_type::build( + cpp_builtin_type::build(cpp_char)))); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_value()); + REQUIRE(equal_expressions(param.default_value().value(), + *cpp_unexposed_expression:: + build(cpp_builtin_type::build( + cpp_nullptr), + cpp_token_string:: + from_string( + "nullptr")))); + } + else if (param.name() == "C") + { + REQUIRE(alias.name() == "c"); + 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)); - builder.is_variadic(); - REQUIRE( - equal_types(idx, param.type(), *cpp_pointer_type::build(builder.finish()))); + cpp_function_type::builder builder( + cpp_builtin_type::build(cpp_void)); + builder.is_variadic(); + REQUIRE(equal_types(idx, param.type(), + *cpp_pointer_type::build( + builder.finish()))); - REQUIRE(!param.is_variadic()); - REQUIRE(!param.default_value()); - } - else - REQUIRE(false); - } - }, - false); // can't check synopsis with comments + REQUIRE(!param.is_variadic()); + REQUIRE(!param.default_value()); + } + else + REQUIRE(false); + } + }, + false); // can't check synopsis with comments REQUIRE(count == 4u); } @@ -215,109 +214,122 @@ using d = void; cpp_entity_index idx; auto file = parse(idx, "cpp_template_template_parameter.cpp", code); - auto count = test_visit( - *file, - [&](const cpp_alias_template& alias) { - REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), - *cpp_builtin_type::build(cpp_void))); - if (alias.name() == "def") - return; + auto count = test_visit< + cpp_alias_template>(*file, + [&](const cpp_alias_template& alias) { + REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), + *cpp_builtin_type::build(cpp_void))); + if (alias.name() == "def") + return; - for (auto& p : alias.parameters()) - { - REQUIRE(p.kind() == cpp_entity_kind::template_template_parameter_t); + for (auto& p : alias.parameters()) + { + REQUIRE(p.kind() + == cpp_entity_kind::template_template_parameter_t); - auto& param = static_cast(p); - REQUIRE(param.keyword() == cpp_template_keyword::keyword_class); - if (param.name() == "A") - { - REQUIRE(alias.name() == "a"); - REQUIRE(!param.is_variadic()); - REQUIRE(!param.default_template()); + auto& param = + static_cast(p); + REQUIRE(param.keyword() == cpp_template_keyword::keyword_class); + if (param.name() == "A") + { + REQUIRE(alias.name() == "a"); + REQUIRE(!param.is_variadic()); + REQUIRE(!param.default_template()); - auto no = 0u; - for (auto& p_param : param.parameters()) - { - ++no; - REQUIRE(p_param.name() == "T"); - REQUIRE(p_param.kind() == cpp_entity_kind::template_type_parameter_t); - } - REQUIRE(no == 1u); - } - else if (param.name() == "B") - { - REQUIRE(alias.name() == "b"); - REQUIRE(param.is_variadic()); - REQUIRE(!param.default_template()); + auto no = 0u; + for (auto& p_param : param.parameters()) + { + ++no; + REQUIRE(p_param.name() == "T"); + REQUIRE(p_param.kind() + == cpp_entity_kind::template_type_parameter_t); + } + REQUIRE(no == 1u); + } + else if (param.name() == "B") + { + REQUIRE(alias.name() == "b"); + REQUIRE(param.is_variadic()); + REQUIRE(!param.default_template()); - auto cur = param.parameters().begin(); - REQUIRE(cur != param.parameters().end()); - REQUIRE(cur->name().empty()); - REQUIRE(cur->kind() == cpp_entity_kind::non_type_template_parameter_t); + auto cur = param.parameters().begin(); + REQUIRE(cur != param.parameters().end()); + REQUIRE(cur->name().empty()); + REQUIRE(cur->kind() + == cpp_entity_kind::non_type_template_parameter_t); - ++cur; - REQUIRE(cur != param.parameters().end()); - REQUIRE(cur->name().empty()); - REQUIRE(cur->kind() == cpp_entity_kind::template_type_parameter_t); + ++cur; + REQUIRE(cur != param.parameters().end()); + REQUIRE(cur->name().empty()); + REQUIRE(cur->kind() + == cpp_entity_kind::template_type_parameter_t); - ++cur; - REQUIRE(cur == param.parameters().end()); - } - else if (param.name() == "C") - { - REQUIRE(alias.name() == "c"); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_template()); + ++cur; + REQUIRE(cur == param.parameters().end()); + } + else if (param.name() == "C") + { + REQUIRE(alias.name() == "c"); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_template()); - auto def = param.default_template().value(); - REQUIRE(def.name() == "ns::def"); - auto entities = def.get(idx); - REQUIRE(entities.size() == 1u); - REQUIRE(entities[0]->name() == "def"); + auto def = param.default_template().value(); + REQUIRE(def.name() == "ns::def"); + auto entities = def.get(idx); + REQUIRE(entities.size() == 1u); + REQUIRE(entities[0]->name() == "def"); - auto no = 0u; - for (auto& p_param : param.parameters()) - { - ++no; - REQUIRE(p_param.name() == ""); - REQUIRE(p_param.kind() == cpp_entity_kind::non_type_template_parameter_t); - } - REQUIRE(no == 1u); - } - else if (param.name() == "D") - { - REQUIRE(alias.name() == "d"); - REQUIRE(!param.is_variadic()); - REQUIRE(param.default_template()); + auto no = 0u; + for (auto& p_param : param.parameters()) + { + ++no; + REQUIRE(p_param.name() == ""); + REQUIRE( + p_param.kind() + == cpp_entity_kind::non_type_template_parameter_t); + } + REQUIRE(no == 1u); + } + else if (param.name() == "D") + { + REQUIRE(alias.name() == "d"); + REQUIRE(!param.is_variadic()); + REQUIRE(param.default_template()); - auto def = param.default_template().value(); - REQUIRE(def.name() == "a"); - auto entities = def.get(idx); - REQUIRE(entities.size() == 1u); - REQUIRE(entities[0]->name() == "a"); + auto def = param.default_template().value(); + REQUIRE(def.name() == "a"); + auto entities = def.get(idx); + REQUIRE(entities.size() == 1u); + REQUIRE(entities[0]->name() == "a"); - auto no = 0u; - for (auto& p_param : param.parameters()) - { - ++no; - REQUIRE(p_param.name() == ""); - REQUIRE(p_param.kind() == cpp_entity_kind::template_template_parameter_t); - for (auto& p_p_param : - static_cast(p_param) - .parameters()) - { - ++no; - REQUIRE(p_p_param.name() == ""); - REQUIRE(p_p_param.kind() == cpp_entity_kind::template_type_parameter_t); - REQUIRE(p_p_param.is_variadic()); - } - } - REQUIRE(no == 2u); - } - else - REQUIRE(false); - } - }, - false); // can't check synopsis with comments + auto no = 0u; + for (auto& p_param : param.parameters()) + { + ++no; + REQUIRE(p_param.name() == ""); + REQUIRE( + p_param.kind() + == cpp_entity_kind::template_template_parameter_t); + for (auto& p_p_param : + static_cast< + const cpp_template_template_parameter&>( + p_param) + .parameters()) + { + ++no; + REQUIRE(p_p_param.name() == ""); + REQUIRE( + p_p_param.kind() + == cpp_entity_kind::template_type_parameter_t); + REQUIRE(p_p_param.is_variadic()); + } + } + REQUIRE(no == 2u); + } + else + REQUIRE(false); + } + }, + false); // can't check synopsis with comments REQUIRE(count == 5u); } diff --git a/test/cpp_type_alias.cpp b/test/cpp_type_alias.cpp index 13d9b1b..2454efd 100644 --- a/test/cpp_type_alias.cpp +++ b/test/cpp_type_alias.cpp @@ -333,12 +333,13 @@ typedef decltype(0) w; if (literal) return cpp_literal_expression::build(std::move(type), std::move(size)); 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; - auto file = parse(idx, "cpp_type_alias.cpp", code); - auto count = test_visit(*file, [&](const cpp_type_alias& alias) { + auto file = parse(idx, "cpp_type_alias.cpp", code); + auto count = test_visit(*file, [&](const cpp_type_alias& alias) { if (alias.name() == "a") { auto type = cpp_builtin_type::build(cpp_int); @@ -505,7 +506,8 @@ typedef decltype(0) w; else if (alias.name() == "w") { 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)); } else diff --git a/test/cpp_variable.cpp b/test/cpp_variable.cpp index ae68acc..83c6bd4 100644 --- a/test/cpp_variable.cpp +++ b/test/cpp_variable.cpp @@ -62,7 +62,7 @@ int r[] = {0}; )"; 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 default_value, int storage_class, bool is_constexpr, bool is_declaration) { if (is_declaration) @@ -101,13 +101,15 @@ int r[] = {0}; // unexposed due to implicit cast, I think type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "42")), + cpp_token_string::from_string( + "42"))), cpp_storage_class_none, false, false); else if (var.name() == "c") check_variable(var, *cpp_builtin_type::build(cpp_float), type_safe::ref( *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); else if (var.name() == "d") 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, cpp_storage_class_static | cpp_storage_class_thread_local, false, false); else if (var.name() == "h") - check_variable(var, *cpp_cv_qualified_type::build(cpp_builtin_type::build(cpp_int), - cpp_cv_const), + check_variable(var, + *cpp_cv_qualified_type::build(cpp_builtin_type::build(cpp_int), + cpp_cv_const), type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "12")), + cpp_token_string::from_string( + "12"))), cpp_storage_class_none, true, false); else if (var.name() == "i") { @@ -134,15 +138,17 @@ int r[] = {0}; } else if (var.name() == "j") { - check_variable(var, *cpp_cv_qualified_type::build(cpp_user_defined_type::build( - cpp_type_ref(cpp_entity_id(""), - "bar")), - cpp_cv_const), + check_variable(var, + *cpp_cv_qualified_type::build(cpp_user_defined_type::build( + cpp_type_ref(cpp_entity_id(""), + "bar")), + cpp_cv_const), type_safe::ref( *cpp_unexposed_expression::build(cpp_user_defined_type::build( cpp_type_ref(cpp_entity_id(""), "bar")), - "bar()")), + cpp_token_string::from_string( + "bar()"))), cpp_storage_class_none, false, false); return false; } @@ -163,35 +169,40 @@ int r[] = {0}; check_variable(var, *cpp_auto_type::build(), type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "128")), + cpp_token_string::from_string( + "128"))), cpp_storage_class_none, false, false); else if (var.name() == "n") - check_variable(var, *cpp_reference_type:: - build(cpp_cv_qualified_type::build(cpp_auto_type::build(), - cpp_cv_const), - cpp_ref_lvalue), + check_variable(var, + *cpp_reference_type:: + build(cpp_cv_qualified_type::build(cpp_auto_type::build(), + cpp_cv_const), + cpp_ref_lvalue), type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "m")), + cpp_token_string::from_string( + "m"))), cpp_storage_class_none, false, false); else if (var.name() == "o") check_variable(var, *cpp_decltype_type::build( cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "0")), + cpp_token_string::from_string("0"))), nullptr, cpp_storage_class_none, false, false); else if (var.name() == "p") - check_variable(var, *cpp_reference_type:: - build(cpp_cv_qualified_type:: - build(cpp_decltype_type::build( - cpp_unexposed_expression:: - build(cpp_builtin_type::build(cpp_int), - "o")), - cpp_cv_const), - cpp_ref_lvalue), + check_variable(var, + *cpp_reference_type:: + build(cpp_cv_qualified_type:: + build(cpp_decltype_type::build( + cpp_unexposed_expression:: + build(cpp_builtin_type::build(cpp_int), + cpp_token_string::from_string("o"))), + cpp_cv_const), + cpp_ref_lvalue), type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - "o")), + cpp_token_string::from_string( + "o"))), cpp_storage_class_none, false, false); else if (var.name() == "q") check_variable(var, @@ -208,7 +219,8 @@ int r[] = {0}; "1")), type_safe::ref( *cpp_unexposed_expression::build(cpp_unexposed_type::build(""), - "{0}")), + cpp_token_string::from_string( + "{0}"))), cpp_storage_class_none, false, false); else REQUIRE(false); diff --git a/test/test_parser.hpp b/test/test_parser.hpp index 609588a..a36d356 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -49,9 +49,7 @@ inline std::unique_ptr parse(const cppast::cpp_entity_index& i class test_generator : public cppast::code_generator { 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 { @@ -205,8 +203,10 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed, switch (parsed.kind()) { case cpp_expression_kind::unexposed_t: - return static_cast(parsed).expression() - == static_cast(synthesized).expression(); + return static_cast(parsed).expression().as_string() + == static_cast(synthesized) + .expression() + .as_string(); case cpp_expression_kind::literal_t: return static_cast(parsed).value() @@ -217,10 +217,10 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed, } template -bool equal_ref(const cppast::cpp_entity_index& idx, +bool equal_ref(const cppast::cpp_entity_index& idx, const cppast::basic_cpp_entity_ref& parsed, const cppast::basic_cpp_entity_ref& synthesized, - const char* full_name_override = nullptr) + const char* full_name_override = nullptr) { if (parsed.name() != synthesized.name()) return false;