From 1ee2154f909805b51c5682eba4bdae49ccc4ab57 Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Fri, 22 Dec 2023 14:21:15 -0500 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 e73889963b..162d527cc5 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -1373,6 +1373,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 625c141b2d..56c9db01c2 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -3543,6 +3543,20 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, + // Diag_Newline_Not_Allowed_After_In_Out_Const_Modifiers + { + .code = 440, + .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 bafd3cb522..6c69bb9621 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -247,6 +247,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) \ @@ -461,7 +462,7 @@ namespace quick_lint_js { /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 447; +inline constexpr int Diag_Type_Count = 448; 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 74be585b8e..4a49a892fb 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -1820,6 +1820,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("E0440", 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 fa5f9988de..fb7fea694d 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1694,6 +1694,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 6beba831fe..6749867cf1 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -461,6 +461,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}, // @@ -2316,6 +2317,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 7eae8922e6..fef79c3461 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 = 590; -constexpr std::size_t translation_table_string_table_size = 81673; +constexpr std::uint16_t translation_table_mapping_table_size = 591; +constexpr std::size_t translation_table_string_table_size = 81738; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -475,6 +475,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 a2c7e64f3d..7b89a28694 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[589] = { +inline const Translated_String test_translation_table[590] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -4967,6 +4967,17 @@ inline const Translated_String test_translation_table[589] = { 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 78f164e9fe..12a3565806 100644 --- a/test/test-parse-typescript-generic.cpp +++ b/test/test-parse-typescript-generic.cpp @@ -1385,6 +1385,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); + } +} } }