Skip to content

Commit

Permalink
fix(typescript): don't treat 'case await a: b;' as arrow function
Browse files Browse the repository at this point in the history
quick-lint-js's error detection for 'async a: b => c' is too
optimistic. Disable it when the keyword prior is 'await' instead of
'async', fixing false positives for valid code such as the following:

    async function f() {
      switch (x) {
      case await y:
        z;
        break;
      }
    }
  • Loading branch information
strager committed Nov 4, 2023
1 parent 7b78dca commit 64ee83d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Semantic Versioning.

* TypeScript support (still experimental):
* `export as namespace` statements are now parsed.
* `case await x:` no longer treats `:` as if it was a type annotation colon in
an arrow function parameter list.

## 2.18.0 (2023-11-03)

Expand Down
3 changes: 2 additions & 1 deletion src/quick-lint-js/fe/parse-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,8 @@ Expression* Parser::parse_async_expression_only(
}

std::optional<Source_Code_Span> type_colon_span;
if (this->peek().type == Token_Type::colon && this->options_.typescript) {
if (is_async && this->peek().type == Token_Type::colon &&
this->options_.typescript) {
// async param: Type => {} // Invalid.
type_colon_span = this->peek().span();
Buffering_Visitor type_visits(&this->type_expression_memory_);
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ quick_lint_js_add_executable(
test-parse-typescript-module.cpp
test-parse-typescript-namespace.cpp
test-parse-typescript-object.cpp
test-parse-typescript-statement.cpp
test-parse-typescript-this-parameters.cpp
test-parse-typescript-type-alias.cpp
test-parse-typescript-type.cpp
Expand Down
64 changes: 64 additions & 0 deletions test/test-parse-typescript-statement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (C) 2020 Matthew "strager" Glazar
// See end of file for extended copyright information.

#include <algorithm>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <iterator>
#include <quick-lint-js/array.h>
#include <quick-lint-js/cli/cli-location.h>
#include <quick-lint-js/container/concat.h>
#include <quick-lint-js/container/padded-string.h>
#include <quick-lint-js/container/string-view.h>
#include <quick-lint-js/diag-collector.h>
#include <quick-lint-js/diag-matcher.h>
#include <quick-lint-js/diag/diagnostic-types.h>
#include <quick-lint-js/fe/language.h>
#include <quick-lint-js/fe/parse.h>
#include <quick-lint-js/parse-support.h>
#include <quick-lint-js/port/char8.h>
#include <quick-lint-js/spy-visitor.h>
#include <string>
#include <string_view>
#include <vector>

using ::testing::ElementsAreArray;

namespace quick_lint_js {
namespace {
class Test_Parse_TypeScript_Statement : public ::testing::Test {};

TEST_F(Test_Parse_TypeScript_Statement,
await_in_case_is_not_arrow_function_with_missing_parens) {
// This code used to confuse
// Diag_Arrow_Parameter_With_Type_Annotation_Requires_Parentheses detection.
{
Spy_Visitor p = test_parse_and_visit_statement(
u8"switch (x) { case await a: b => c; }"_sv, no_diags,
typescript_options);
EXPECT_THAT(p.variable_uses,
ElementsAreArray({u8"x"_sv, u8"a"_sv, u8"c"_sv}));
EXPECT_THAT(p.variable_declarations,
ElementsAreArray({arrow_param_decl(u8"b"_sv)}));
}
}
}
}

// quick-lint-js finds bugs in JavaScript programs.
// Copyright (C) 2020 Matthew "strager" Glazar
//
// This file is part of quick-lint-js.
//
// quick-lint-js is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// quick-lint-js is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with quick-lint-js. If not, see <https://www.gnu.org/licenses/>.

0 comments on commit 64ee83d

Please sign in to comment.