diff --git a/test/quick-lint-js/diagnostic-assertion.cpp b/test/quick-lint-js/diagnostic-assertion.cpp index 0290157f91..42526002a3 100644 --- a/test/quick-lint-js/diagnostic-assertion.cpp +++ b/test/quick-lint-js/diagnostic-assertion.cpp @@ -151,6 +151,7 @@ Diagnostic_Assertion::parse(const Char8* specification) { Diagnostic_Assertion_Lexer lexer(specification); Diagnostic_Assertion out_assertion; + out_assertion.needs_adjustment = true; // Names of diagnostic member variables. // @@ -388,6 +389,10 @@ Diagnostic_Assertion Diagnostic_Assertion::parse_or_exit( Diagnostic_Assertion Diagnostic_Assertion::adjusted_for_escaped_characters( String8_View code) const { + if (!this->needs_adjustment) { + return *this; + } + static auto has_utf8_continuation = [](Char8 c) -> bool { return (static_cast(c) & 0x80) != 0; }; @@ -426,6 +431,7 @@ Diagnostic_Assertion Diagnostic_Assertion::adjusted_for_escaped_characters( }; Diagnostic_Assertion result = *this; + result.needs_adjustment = false; for (Member& member : result.members) { if (member.type != Diagnostic_Arg_Type::source_code_span) { continue; @@ -443,6 +449,16 @@ Diagnostic_Assertion Diagnostic_Assertion::adjusted_for_escaped_characters( return result; } +Diagnostic_Assertion Diagnostic_Assertion::make_raw( + Diag_Type type, std::initializer_list members) { + Diagnostic_Assertion assertion; + assertion.type = type; + for (const Member& m : members) { + assertion.members.push_back(m); + } + return assertion; +} + Diagnostic_Assertion operator""_diag( const Char8* specification, [[maybe_unused]] std::size_t specification_length) { diff --git a/test/quick-lint-js/diagnostic-assertion.h b/test/quick-lint-js/diagnostic-assertion.h index 062fda56f7..d66b19536e 100644 --- a/test/quick-lint-js/diagnostic-assertion.h +++ b/test/quick-lint-js/diagnostic-assertion.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -105,8 +107,14 @@ struct Diagnostic_Assertion { Diag_Type type = Diag_Type(); Fixed_Vector members; + // Whether adjusted_for_escaped_characters should be called to compensate for + // control characters. + bool needs_adjustment = false; + // If the specification is malformed, return a list of messages to report to // the user. + // + // Postcondition: return.needs_adjustment static Result> parse( const Char8* specification); @@ -129,10 +137,44 @@ struct Diagnostic_Assertion { // from the offsets in the _diag string so that assert_diagnostics will work // correctly. // + // If this->needs_adjustment is false, returns an unmodified copy of *this. + // + // Postcondition: !return.needs_adjustment + // // TODO(strager): Support Unicode escape sequences (\u2063 for example). Diagnostic_Assertion adjusted_for_escaped_characters(String8_View code) const; + + // Manually create a Diagnostic_Assertion without the short-hand syntax. + // + // See DIAGNOSTIC_ASSERTION_SPAN. + // + // Postcondition: !return.needs_adjustment + static Diagnostic_Assertion make_raw(Diag_Type, + std::initializer_list); }; +// Create a Diagnostic_Assertion which matches 'type_'. It asserts that +// 'type_::member_' is a Source_Code_Span beginning at 'begin_offset_' and +// ending at 'begin_offset_ + span_string_.size()'. +#define DIAGNOSTIC_ASSERTION_SPAN(type_, member_, begin_offset_, span_string_) \ + (::quick_lint_js::Diagnostic_Assertion::make_raw( \ + Diag_Type::type_, \ + { \ + ::quick_lint_js::Diagnostic_Assertion::Member{ \ + .name = QLJS_CPP_QUOTE_U8_SV(member_), \ + .offset = offsetof(type_, member_), \ + .type = Diagnostic_Arg_Type::source_code_span, \ + .span_begin_offset = \ + ::quick_lint_js::narrow_cast( \ + (begin_offset_)), \ + .span_end_offset = \ + ::quick_lint_js::narrow_cast( \ + (begin_offset_)) + \ + ::quick_lint_js::narrow_cast( \ + (span_string_).size()), \ + }, \ + })) + // See [_diag-syntax]. // // Exits the program at run-time if the specification is malformed. diff --git a/test/test-lex.cpp b/test/test-lex.cpp index a3c880189e..8dc52a0355 100644 --- a/test/test-lex.cpp +++ b/test/test-lex.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -2145,17 +2146,17 @@ TEST_F(Test_Lex, ascii_control_characters_are_disallowed) { for (String8_View control_character : control_characters_except_whitespace) { Padded_String input(String8(control_character) + u8"hello"); SCOPED_TRACE(input); - Diag_Collector v; + Diag_List_Diag_Reporter diags(&this->memory_); - Lexer l(&input, &v); + Lexer l(&input, &diags); EXPECT_EQ(l.peek().type, Token_Type::identifier) << "control character should be skipped"; - EXPECT_THAT( - v.errors, - ElementsAreArray({ - DIAG_TYPE_OFFSETS(&input, Diag_Unexpected_Control_Character, // - character, 0, control_character), - })); + assert_diagnostics( + &input, diags.diags(), + { + DIAGNOSTIC_ASSERTION_SPAN(Diag_Unexpected_Control_Character, // + character, 0, control_character), + }); } }