Skip to content

Commit

Permalink
fix: new diag for async/generator on getter/setter
Browse files Browse the repository at this point in the history
  • Loading branch information
koopiehoop committed Sep 23, 2023
1 parent af321e1 commit 8462f95
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 6 deletions.
36 changes: 36 additions & 0 deletions docs/errors/E0713.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# E0713: '*' keyword is not allowed on getters or setters

Use of the '*' character, defining generator functions, is not allowed on getters or setters.
Getters and setters are synchronous operations and do not support the generator functionality.

```javascript
class C {
constructor() {
this._value = 0;
}

get *value() {
return this._value;
}
set *value(newValue) {
this._value = newValue;
}
}
```

To fix this error define with a getter or setter, using regular function syntax.

```javascript
class C {
constructor() {
this._value = 0;
}

get value() {
return this._value;
}
set value(newValue) {
this._value = newValue;
}
}
```
64 changes: 64 additions & 0 deletions docs/errors/E0714.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# E0714: 'async' keyword is not allowed on getters or setters

Use of 'async' keyword, defining asynchronous functions, is not allowed on getters or setters.
Getters and setters are synchronous operations and do not support the asynchronous functionality.


```javascript
class C {
constructor() {
this._value = 0;
}

async get value() {
return this._value;
}

async set value(newValue) {
this._value = newValue;
}
}
```

To fix this error simply remove 'async' keyword from getters and setters,
so they can function properly as synchronous operations


```javascript
class C {
constructor() {
this._value = 0;
}

get value() {
return this._value;
}

set value(newValue) {
this._value = newValue;
}
}
```

However, if you require asynchronous behavior within getters or setters,
you can achieve this by implementing separate asynchronous methods


```javascript
class C {
constructor() {
this._value = 0;
}

async getValueAsync() {
// Perform asynchronous operations here
return await asyncFuctnion();
}

async setValueAsync(newValue) {
// Perform asynchronous operations here
await asyncFuctnion();
this._value = newValue;
}
}
```
8 changes: 8 additions & 0 deletions po/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1929,6 +1929,14 @@ msgstr ""
msgid "missing expression in placeholder within template literal"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "'*' keyword is not allowed on getters or setters"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "'async' keyword is not allowed on getters or setters"
msgstr ""

#: test/test-diagnostic-formatter.cpp
#: test/test-vim-qflist-json-diag-reporter.cpp
msgid "something happened"
Expand Down
36 changes: 36 additions & 0 deletions src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5961,6 +5961,42 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = {
},
},
},

// Diag_Class_Generator_On_Getter_Or_Setter
{
.code = 713,
.severity = Diagnostic_Severity::error,
.message_formats = {
QLJS_TRANSLATABLE("'*' keyword is not allowed on getters or setters"),
QLJS_TRANSLATABLE("'{0}' here"),
},
.message_args = {
{
Diagnostic_Message_Arg_Info(offsetof(Diag_Class_Generator_On_Getter_Or_Setter, generator_keyword), Diagnostic_Arg_Type::source_code_span),
},
{
Diagnostic_Message_Arg_Info(offsetof(Diag_Class_Generator_On_Getter_Or_Setter, getter_setter_keyword), Diagnostic_Arg_Type::source_code_span),
},
},
},

// Diag_Class_Async_On_Getter_Or_Setter
{
.code = 714,
.severity = Diagnostic_Severity::error,
.message_formats = {
QLJS_TRANSLATABLE("'async' keyword is not allowed on getters or setters"),
QLJS_TRANSLATABLE("'{0}' here"),
},
.message_args = {
{
Diagnostic_Message_Arg_Info(offsetof(Diag_Class_Async_On_Getter_Or_Setter, async_keyword), Diagnostic_Arg_Type::source_code_span),
},
{
Diagnostic_Message_Arg_Info(offsetof(Diag_Class_Async_On_Getter_Or_Setter, getter_setter_keyword), Diagnostic_Arg_Type::source_code_span),
},
},
},
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/quick-lint-js/diag/diagnostic-metadata-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,12 @@ namespace quick_lint_js {
QLJS_DIAG_TYPE_NAME(Diag_Variable_Assigned_To_Self_Is_Noop) \
QLJS_DIAG_TYPE_NAME(Diag_Xor_Used_As_Exponentiation) \
QLJS_DIAG_TYPE_NAME(Diag_Expected_Expression_In_Template_Literal) \
QLJS_DIAG_TYPE_NAME(Diag_Class_Generator_On_Getter_Or_Setter) \
QLJS_DIAG_TYPE_NAME(Diag_Class_Async_On_Getter_Or_Setter) \
/* END */
// clang-format on

inline constexpr int Diag_Type_Count = 401;
inline constexpr int Diag_Type_Count = 403;

extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count];
}
Expand Down
20 changes: 20 additions & 0 deletions src/quick-lint-js/diag/diagnostic-types-2.h
Original file line number Diff line number Diff line change
Expand Up @@ -3065,6 +3065,26 @@ struct Diag_Expected_Expression_In_Template_Literal {
ARG(placeholder))]] //
Source_Code_Span placeholder;
};

struct Diag_Class_Generator_On_Getter_Or_Setter {
[[qljs::diag("E0713", Diagnostic_Severity::error)]] //
[[qljs::message("'*' keyword is not allowed on getters or setters",
ARG(generator_keyword))]] //
[[qljs::message("'{0}' here", ARG(getter_setter_keyword))]] //
Source_Code_Span method_start;
Source_Code_Span generator_keyword;
Source_Code_Span getter_setter_keyword;
};

struct Diag_Class_Async_On_Getter_Or_Setter {
[[qljs::diag("E0714", Diagnostic_Severity::error)]] //
[[qljs::message("'async' keyword is not allowed on getters or setters",
ARG(async_keyword))]] //
[[qljs::message("'{0}' here", ARG(getter_setter_keyword))]] //
Source_Code_Span method_start;
Source_Code_Span async_keyword;
Source_Code_Span getter_setter_keyword;
};
}

QLJS_WARNING_POP
Expand Down
43 changes: 43 additions & 0 deletions src/quick-lint-js/fe/parse-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,8 @@ void Parser::parse_and_visit_class_or_interface_member(

void check_modifiers_for_method() {
error_if_accessor_method();
error_if_generator_method();
error_if_async_method();
error_if_readonly_method();
error_if_async_or_generator_without_method_body();
error_if_invalid_access_specifier();
Expand Down Expand Up @@ -1131,6 +1133,47 @@ void Parser::parse_and_visit_class_or_interface_member(
}
}

void error_if_generator_method() {
if (const Modifier *star_modifier = find_modifier(Token_Type::star)) {
Source_Code_Span method_start = p->peek().span();
if (const Modifier *get_modifier = find_modifier(Token_Type::kw_get)) {
p->diag_reporter_->report(Diag_Class_Generator_On_Getter_Or_Setter{
.method_start = method_start,
.generator_keyword = star_modifier->span,
.getter_setter_keyword = get_modifier->span,
});
} else if (const Modifier *set_modifier =
find_modifier(Token_Type::kw_set)) {
p->diag_reporter_->report(Diag_Class_Generator_On_Getter_Or_Setter{
.method_start = method_start,
.generator_keyword = star_modifier->span,
.getter_setter_keyword = set_modifier->span,
});
}
}
}

void error_if_async_method() {
if (const Modifier *async_modifier =
find_modifier(Token_Type::kw_async)) {
Source_Code_Span method_start = p->peek().span();
if (const Modifier *get_modifier = find_modifier(Token_Type::kw_get)) {
p->diag_reporter_->report(Diag_Class_Async_On_Getter_Or_Setter{
.method_start = method_start,
.async_keyword = async_modifier->span,
.getter_setter_keyword = get_modifier->span,
});
} else if (const Modifier *set_modifier =
find_modifier(Token_Type::kw_set)) {
p->diag_reporter_->report(Diag_Class_Async_On_Getter_Or_Setter{
.method_start = method_start,
.async_keyword = async_modifier->span,
.getter_setter_keyword = set_modifier->span,
});
}
}
}

void error_if_readonly_method() {
if (const Modifier *readonly_modifier =
find_modifier(Token_Type::kw_readonly)) {
Expand Down
8 changes: 6 additions & 2 deletions src/quick-lint-js/i18n/translation-table-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const Translation_Table translation_data = {
{74, 87, 79, 56, 0, 59}, //
{71, 80, 60, 58, 0, 52}, //
{0, 0, 0, 0, 0, 28}, //
{31, 56, 0, 32, 0, 63}, //
{0, 0, 0, 0, 0, 63}, //
{31, 56, 0, 32, 0, 49}, //
{0, 0, 0, 0, 0, 67}, //
{0, 0, 0, 70, 0, 26}, //
{79, 25, 30, 63, 49593, 66}, //
Expand All @@ -40,7 +41,8 @@ const Translation_Table translation_data = {
{0, 0, 0, 100, 0, 89}, //
{0, 0, 0, 0, 0, 24}, //
{50, 77, 41, 27, 0, 60}, //
{70, 31, 69, 53, 0, 60}, //
{0, 0, 0, 0, 0, 60}, //
{70, 31, 69, 53, 0, 53}, //
{93, 15, 80, 68, 26, 69}, //
{0, 0, 0, 0, 0, 43}, //
{0, 0, 0, 0, 0, 44}, //
Expand Down Expand Up @@ -1773,6 +1775,7 @@ const Translation_Table translation_data = {
u8"\"globals\" descriptor must be a boolean or an object\0"
u8"\"globals\" must be an object\0"
u8"'!' here treated as the TypeScript non-null assertion operator\0"
u8"'*' keyword is not allowed on getters or setters\0"
u8"'**' operator cannot be used after unary '{1}' without parentheses\0"
u8"',' should be ';' instead\0"
u8"'.' is not allowed after generic arguments; write [\"{1}\"] instead\0"
Expand All @@ -1795,6 +1798,7 @@ const Translation_Table translation_data = {
u8"'as const' located here\0"
u8"'async export' is not allowed; write 'export async' instead\0"
u8"'async static' is not allowed; write 'static async' instead\0"
u8"'async' keyword is not allowed on getters or setters\0"
u8"'await' cannot be followed by an arrow function; use 'async' instead\0"
u8"'await' is only allowed in async functions\0"
u8"'declare class' cannot contain static block\0"
Expand Down
6 changes: 4 additions & 2 deletions src/quick-lint-js/i18n/translation-table-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 484;
constexpr std::size_t translation_table_string_table_size = 78112;
constexpr std::uint16_t translation_table_mapping_table_size = 486;
constexpr std::size_t translation_table_string_table_size = 78214;
constexpr std::size_t translation_table_locale_table_size = 35;

QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
Expand All @@ -33,6 +33,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
"\"globals\" descriptor must be a boolean or an object"sv,
"\"globals\" must be an object"sv,
"'!' here treated as the TypeScript non-null assertion operator"sv,
"'*' keyword is not allowed on getters or setters"sv,
"'**' operator cannot be used after unary '{1}' without parentheses"sv,
"',' should be ';' instead"sv,
"'.' is not allowed after generic arguments; write [\"{1}\"] instead"sv,
Expand All @@ -55,6 +56,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
"'as const' located here"sv,
"'async export' is not allowed; write 'export async' instead"sv,
"'async static' is not allowed; write 'static async' instead"sv,
"'async' keyword is not allowed on getters or setters"sv,
"'await' cannot be followed by an arrow function; use 'async' instead"sv,
"'await' is only allowed in async functions"sv,
"'declare class' cannot contain static block"sv,
Expand Down
24 changes: 23 additions & 1 deletion src/quick-lint-js/i18n/translation-table-test-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct Translated_String {
};

// clang-format off
inline const Translated_String test_translation_table[483] = {
inline const Translated_String test_translation_table[485] = {
{
"\"global-groups\" entries must be strings"_translatable,
u8"\"global-groups\" entries must be strings",
Expand Down Expand Up @@ -105,6 +105,17 @@ inline const Translated_String test_translation_table[483] = {
u8"'!' here treated as the TypeScript non-null assertion operator",
},
},
{
"'*' keyword is not allowed on getters or setters"_translatable,
u8"'*' keyword is not allowed on getters or setters",
{
u8"'*' keyword is not allowed on getters or setters",
u8"'*' keyword is not allowed on getters or setters",
u8"'*' keyword is not allowed on getters or setters",
u8"'*' keyword is not allowed on getters or setters",
u8"'*' keyword is not allowed on getters or setters",
},
},
{
"'**' operator cannot be used after unary '{1}' without parentheses"_translatable,
u8"'**' operator cannot be used after unary '{1}' without parentheses",
Expand Down Expand Up @@ -347,6 +358,17 @@ inline const Translated_String test_translation_table[483] = {
u8"'async static' is not allowed; write 'static async' instead",
},
},
{
"'async' keyword is not allowed on getters or setters"_translatable,
u8"'async' keyword is not allowed on getters or setters",
{
u8"'async' keyword is not allowed on getters or setters",
u8"'async' keyword is not allowed on getters or setters",
u8"'async' keyword is not allowed on getters or setters",
u8"'async' keyword is not allowed on getters or setters",
u8"'async' keyword is not allowed on getters or setters",
},
},
{
"'await' cannot be followed by an arrow function; use 'async' instead"_translatable,
u8"'await' cannot be followed by an arrow function; use 'async' instead",
Expand Down
Loading

0 comments on commit 8462f95

Please sign in to comment.