瀏覽代碼

LibJS: Replace the verify in private identifier with a syntax error

Since sometimes expressions are parsed without checking we can hit this
expression without it being followed by an 'in'.
davidot 3 年之前
父節點
當前提交
c2ebaa9d87
共有 2 個文件被更改,包括 15 次插入2 次删除
  1. 3 2
      Userland/Libraries/LibJS/Parser.cpp
  2. 12 0
      Userland/Libraries/LibJS/Tests/classes/class-private-fields.js

+ 3 - 2
Userland/Libraries/LibJS/Parser.cpp

@@ -1439,7 +1439,8 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
             goto read_as_identifier;
         return { parse_await_expression() };
     case TokenType::PrivateIdentifier:
-        VERIFY(next_token().type() == TokenType::In);
+        if (next_token().type() != TokenType::In)
+            syntax_error("Cannot have a private identifier in expression if not followed by 'in'");
         if (!is_private_identifier_valid())
             syntax_error(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token.value()));
         return { create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().value()) };
@@ -3483,7 +3484,7 @@ bool Parser::match_expression() const
         || type == TokenType::TemplateLiteralStart
         || type == TokenType::NullLiteral
         || match_identifier()
-        || (type == TokenType::PrivateIdentifier && next_token().type() == TokenType::In)
+        || type == TokenType::PrivateIdentifier
         || type == TokenType::Await
         || type == TokenType::New
         || type == TokenType::Class

+ 12 - 0
Userland/Libraries/LibJS/Tests/classes/class-private-fields.js

@@ -96,6 +96,18 @@ test("slash after private identifier is treated as division", () => {
     expect(A.getDivided()).toBe(2);
 });
 
+test("private identifier not followed by 'in' throws", () => {
+    expect(`class A { #field = 2; method() { return #field instanceof 1; }}`).not.toEval();
+    expect(`class A { #field = 2; method() { return #field < 1; }}`).not.toEval();
+    expect(`class A { #field = 2; method() { return #field + 1; }}`).not.toEval();
+    expect(`class A { #field = 2; method() { return #field ** 1; }}`).not.toEval();
+    expect(`class A { #field = 2; method() { return !#field; } }`).not.toEval();
+    expect(`class A { #field = 2; method() { return ~#field; } }`).not.toEval();
+    expect(`class A { #field = 2; method() { return ++#field; } }`).not.toEval();
+
+    expect(`class A { #field = 2; method() { return #field in 1; }}`).toEval();
+});
+
 test("cannot have static and non static field with the same description", () => {
     expect("class A { static #simple; #simple; }").not.toEval();
 });