Skip to content

Commit

Permalink
refactor(test): allow Diagnostic_Assertion to work with manual offsets
Browse files Browse the repository at this point in the history
Some tests cannot use the u8"^^^ Diag_Foo"_diag syntax and instead
need to work with manual offsets. Make this possible with
diagnostic_assertions. This will help us remove Diag_Collector.

#1154
  • Loading branch information
strager committed Jan 7, 2024
1 parent 90d63c4 commit ca9ce31
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 8 deletions.
16 changes: 16 additions & 0 deletions test/quick-lint-js/diagnostic-assertion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down Expand Up @@ -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<std::uint8_t>(c) & 0x80) != 0;
};
Expand Down Expand Up @@ -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;
Expand All @@ -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<Member> 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) {
Expand Down
42 changes: 42 additions & 0 deletions test/quick-lint-js/diagnostic-assertion.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <quick-lint-js/diag/diagnostic-types.h>
#include <quick-lint-js/port/char8.h>
#include <quick-lint-js/port/span.h>
#include <quick-lint-js/util/cast.h>
#include <quick-lint-js/util/cpp.h>
#include <string>
#include <vector>

Expand Down Expand Up @@ -105,8 +107,14 @@ struct Diagnostic_Assertion {
Diag_Type type = Diag_Type();
Fixed_Vector<Member, 3> 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<Diagnostic_Assertion, std::vector<std::string>> parse(
const Char8* specification);

Expand All @@ -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<Member>);
};

// 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<Padded_String_Size>( \
(begin_offset_)), \
.span_end_offset = \
::quick_lint_js::narrow_cast<Padded_String_Size>( \
(begin_offset_)) + \
::quick_lint_js::narrow_cast<Padded_String_Size>( \
(span_string_).size()), \
}, \
}))

// See [_diag-syntax].
//
// Exits the program at run-time if the specification is malformed.
Expand Down
17 changes: 9 additions & 8 deletions test/test-lex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <quick-lint-js/container/padded-string.h>
#include <quick-lint-js/diag-collector.h>
#include <quick-lint-js/diag-matcher.h>
#include <quick-lint-js/diagnostic-assertion.h>
#include <quick-lint-js/fe/lex.h>
#include <quick-lint-js/fe/source-code-span.h>
#include <quick-lint-js/fe/token.h>
Expand Down Expand Up @@ -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),
});
}
}

Expand Down

0 comments on commit ca9ce31

Please sign in to comment.