From 94e210833d439c27dda2cfd61880baddfd42358c Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Sun, 17 Dec 2023 14:39:35 -0600 Subject: [PATCH] feat(typescript): disallow newline after modifiers in generic parameter Report error for newline(s) after 'in'/'out'/'const' modifier in generic parameter. --- po/messages.pot | 4 +++ .../diag/diagnostic-metadata-generated.cpp | 14 ++++++++++ .../diag/diagnostic-metadata-generated.h | 3 ++- src/quick-lint-js/diag/diagnostic-types-2.h | 8 ++++++ src/quick-lint-js/fe/parse-statement.cpp | 5 ++++ .../i18n/translation-table-generated.cpp | 2 ++ .../i18n/translation-table-generated.h | 5 ++-- .../i18n/translation-table-test-generated.h | 13 ++++++++- test/test-parse-typescript-generic.cpp | 27 +++++++++++++++++++ 9 files changed, 77 insertions(+), 4 deletions(-) diff --git a/po/messages.pot b/po/messages.pot index d9a06e7168..036b34f001 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -1221,6 +1221,10 @@ msgstr "" msgid "newline is not allowed before '<'" msgstr "" +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "newline is not allowed after '{0}' modifier in generic parameter" +msgstr "" + #: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp msgid "number literal contains consecutive underscores" msgstr "" diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp index dd3a85e1cf..eb9e612ce6 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -3509,6 +3509,20 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, + // Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers + { + .code = 433, + .severity = Diagnostic_Severity::error, + .message_formats = { + QLJS_TRANSLATABLE("newline is not allowed after '{0}' modifier in generic parameter"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers, modifier), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, + // Diag_Number_Literal_Contains_Consecutive_Underscores { .code = 28, diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.h b/src/quick-lint-js/diag/diagnostic-metadata-generated.h index d0f43bbb52..a6f705151b 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -245,6 +245,7 @@ namespace quick_lint_js { QLJS_DIAG_TYPE_NAME(Diag_Newline_Not_Allowed_After_Type_Keyword) \ QLJS_DIAG_TYPE_NAME(Diag_Newline_Not_Allowed_Before_Assignment_Assertion_Operator) \ QLJS_DIAG_TYPE_NAME(Diag_Newline_Not_Allowed_Before_Generic_Arguments_In_Type) \ + QLJS_DIAG_TYPE_NAME(Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers) \ QLJS_DIAG_TYPE_NAME(Diag_Number_Literal_Contains_Consecutive_Underscores) \ QLJS_DIAG_TYPE_NAME(Diag_Number_Literal_Contains_Trailing_Underscores) \ QLJS_DIAG_TYPE_NAME(Diag_Octal_Literal_May_Not_Have_Exponent) \ @@ -454,7 +455,7 @@ namespace quick_lint_js { /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 440; +inline constexpr int Diag_Type_Count = 441; extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count]; } diff --git a/src/quick-lint-js/diag/diagnostic-types-2.h b/src/quick-lint-js/diag/diagnostic-types-2.h index cfde629f55..5a4d8ef33b 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -1801,6 +1801,14 @@ struct Diag_Newline_Not_Allowed_Before_Generic_Arguments_In_Type { Source_Code_Span less; }; +struct Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers { + [[qljs::diag("E0433", Diagnostic_Severity::error)]] // + [[qljs::message( + "newline is not allowed after '{0}' modifier in generic parameter", + ARG(modifier))]] // + Source_Code_Span modifier; +}; + struct Diag_Number_Literal_Contains_Consecutive_Underscores { [[qljs::diag("E0028", Diagnostic_Severity::error)]] // [[qljs::message("number literal contains consecutive underscores", diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 06a3120336..3738bc692c 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1683,6 +1683,11 @@ void Parser::parse_and_visit_typescript_generic_parameters( .token_type = this->peek().type, }); this->skip(); + if (this->lexer_.peek().has_leading_newline) { + this->diag_reporter_->report( + Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers{ + .modifier = modifiers.back().identifier.span()}); + } break; default: diff --git a/src/quick-lint-js/i18n/translation-table-generated.cpp b/src/quick-lint-js/i18n/translation-table-generated.cpp index 348eeda535..c14c492c31 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -425,6 +425,7 @@ const Translation_Table translation_data = { {0, 0, 0, 52, 0, 41}, // {0, 0, 0, 0, 0, 36}, // {0, 0, 0, 0, 0, 35}, // + {0, 0, 0, 0, 0, 65}, // {0, 0, 0, 47, 0, 34}, // {52, 31, 25, 61, 21, 54}, // {0, 0, 0, 0, 0, 73}, // @@ -2240,6 +2241,7 @@ const Translation_Table translation_data = { u8"newline is not allowed after 'interface'\0" u8"newline is not allowed after 'type'\0" u8"newline is not allowed after '{0}'\0" + u8"newline is not allowed after '{0}' modifier in generic parameter\0" u8"newline is not allowed before '<'\0" u8"newline is not allowed between 'async' and 'function'\0" u8"newline is not allowed between 'async' and arrow function parameter list\0" diff --git a/src/quick-lint-js/i18n/translation-table-generated.h b/src/quick-lint-js/i18n/translation-table-generated.h index ca6eebafc3..9de67ae19f 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.h +++ b/src/quick-lint-js/i18n/translation-table-generated.h @@ -18,8 +18,8 @@ namespace quick_lint_js { using namespace std::literals::string_view_literals; constexpr std::uint32_t translation_table_locale_count = 5; -constexpr std::uint16_t translation_table_mapping_table_size = 545; -constexpr std::size_t translation_table_string_table_size = 80903; +constexpr std::uint16_t translation_table_mapping_table_size = 546; +constexpr std::size_t translation_table_string_table_size = 80968; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -439,6 +439,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "newline is not allowed after 'interface'"sv, "newline is not allowed after 'type'"sv, "newline is not allowed after '{0}'"sv, + "newline is not allowed after '{0}' modifier in generic parameter"sv, "newline is not allowed before '<'"sv, "newline is not allowed between 'async' and 'function'"sv, "newline is not allowed between 'async' and arrow function parameter list"sv, diff --git a/src/quick-lint-js/i18n/translation-table-test-generated.h b/src/quick-lint-js/i18n/translation-table-test-generated.h index 5c6b0342b9..547de1898c 100644 --- a/src/quick-lint-js/i18n/translation-table-test-generated.h +++ b/src/quick-lint-js/i18n/translation-table-test-generated.h @@ -27,7 +27,7 @@ struct Translated_String { }; // clang-format off -inline const Translated_String test_translation_table[544] = { +inline const Translated_String test_translation_table[545] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -4571,6 +4571,17 @@ inline const Translated_String test_translation_table[544] = { u8"newline is not allowed after '{0}'", }, }, + { + "newline is not allowed after '{0}' modifier in generic parameter"_translatable, + u8"newline is not allowed after '{0}' modifier in generic parameter", + { + u8"newline is not allowed after '{0}' modifier in generic parameter", + u8"newline is not allowed after '{0}' modifier in generic parameter", + u8"newline is not allowed after '{0}' modifier in generic parameter", + u8"newline is not allowed after '{0}' modifier in generic parameter", + u8"newline is not allowed after '{0}' modifier in generic parameter", + }, + }, { "newline is not allowed before '<'"_translatable, u8"newline is not allowed before '<'", diff --git a/test/test-parse-typescript-generic.cpp b/test/test-parse-typescript-generic.cpp index 6afce67e1a..fe589859c9 100644 --- a/test/test-parse-typescript-generic.cpp +++ b/test/test-parse-typescript-generic.cpp @@ -1333,6 +1333,33 @@ TEST_F(Test_Parse_TypeScript_Generic, typescript_options); } } + +TEST_F(Test_Parse_TypeScript_Generic, + newline_is_not_allowed_after_in_out_const_modifiers) { + { + test_parse_and_visit_module( + u8"class C {}"_sv, // + u8" ^^ Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers.modifier"_diag, // + typescript_options); + test_parse_and_visit_module( + u8"class C {}"_sv, // + u8" ^^^ Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers.modifier"_diag, // + typescript_options); + test_parse_and_visit_module( + u8"class C {}"_sv, // + u8" ^^^^^ Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers.modifier"_diag, // + typescript_options); + } + + { + test_parse_and_visit_module(u8"class C {}"_sv, no_diags, + typescript_options); + test_parse_and_visit_module(u8"class C {}"_sv, no_diags, + typescript_options); + test_parse_and_visit_module(u8"class C {}"_sv, no_diags, + typescript_options); + } +} } }