Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/AST/SemanticValidator.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#include "SemanticValidator.h"
9
10
#include "hermes/AST/ESTree.h"
11
#include "hermes/Regex/RegexSerialization.h"
12
13
#include "llvh/ADT/ScopeExit.h"
14
#include "llvh/ADT/SmallSet.h"
15
#include "llvh/Support/SaveAndRestore.h"
16
17
using llvh::cast_or_null;
18
using llvh::dyn_cast;
19
using llvh::isa;
20
using llvh::SaveAndRestore;
21
22
namespace hermes {
23
namespace sem {
24
25
//===----------------------------------------------------------------------===//
26
// Keywords
27
28
Keywords::Keywords(Context &astContext)
29
    : identArguments(
30
154
          astContext.getIdentifier("arguments").getUnderlyingPointer()),
31
154
      identEval(astContext.getIdentifier("eval").getUnderlyingPointer()),
32
154
      identDelete(astContext.getIdentifier("delete").getUnderlyingPointer()),
33
154
      identThis(astContext.getIdentifier("this").getUnderlyingPointer()),
34
      identUseStrict(
35
154
          astContext.getIdentifier("use strict").getUnderlyingPointer()),
36
      identShowSource(
37
154
          astContext.getIdentifier("show source").getUnderlyingPointer()),
38
      identHideSource(
39
154
          astContext.getIdentifier("hide source").getUnderlyingPointer()),
40
      identSensitive(
41
154
          astContext.getIdentifier("sensitive").getUnderlyingPointer()),
42
154
      identVar(astContext.getIdentifier("var").getUnderlyingPointer()),
43
154
      identLet(astContext.getIdentifier("let").getUnderlyingPointer()),
44
154
      identConst(astContext.getIdentifier("const").getUnderlyingPointer()),
45
154
      identPlus(astContext.getIdentifier("+").getUnderlyingPointer()),
46
154
      identMinus(astContext.getIdentifier("-").getUnderlyingPointer()),
47
154
      identAssign(astContext.getIdentifier("=").getUnderlyingPointer()) {}
48
49
//===----------------------------------------------------------------------===//
50
// SemanticValidator
51
52
SemanticValidator::SemanticValidator(
53
    Context &astContext,
54
    sem::SemContext &semCtx,
55
    bool compile)
56
154
    : astContext_(astContext),
57
154
      sm_(astContext.getSourceErrorManager()),
58
154
      bufferMessages_{&sm_},
59
154
      semCtx_(semCtx),
60
154
      initialErrorCount_(sm_.getErrorCount()),
61
154
      kw_(astContext),
62
154
      compile_(compile) {}
63
64
154
bool SemanticValidator::doIt(Node *rootNode) {
65
154
  visitESTreeNode(*this, rootNode);
66
154
  return sm_.getErrorCount() == initialErrorCount_;
67
154
}
68
69
0
bool SemanticValidator::doFunction(Node *function, bool strict) {
70
  // Create a wrapper context since a function always assumes there is an
71
  // existing context.
72
0
  FunctionContext wrapperContext(this, strict, nullptr, nullptr);
73
74
0
  assert(
75
0
      wrapperContext.scopedClosures == nullptr &&
76
0
      "current context doesnt have a body, so it shouldn't have closures.");
77
78
  // Create a dummy closures array that will contain the closure for \p
79
  // function.
80
0
  FunctionInfo::BlockClosures dummyClosures;
81
0
  wrapperContext.scopedClosures = &dummyClosures;
82
0
  FunctionInfo::BlockDecls dummyDecls;
83
0
  wrapperContext.scopedDecls = &dummyDecls;
84
85
0
  visitESTreeNode(*this, function);
86
0
  return sm_.getErrorCount() == initialErrorCount_;
87
0
}
88
89
154
void SemanticValidator::visit(ProgramNode *node) {
90
154
  FunctionContext newFuncCtx{this, astContext_.isStrictMode(), node, node};
91
92
154
  scanDirectivePrologue(node->_body);
93
154
  setDirectiveDerivedInfo(node);
94
95
154
  visitESTreeChildren(*this, node);
96
154
}
97
98
69
void SemanticValidator::visit(VariableDeclaratorNode *varDecl, Node *parent) {
99
69
  auto *declaration = cast<VariableDeclarationNode>(parent);
100
101
69
  FunctionInfo::VarDecl::Kind declKind;
102
69
  if (declaration->_kind == kw_.identLet)
103
67
    declKind = FunctionInfo::VarDecl::Kind::Let;
104
2
  else if (declaration->_kind == kw_.identConst)
105
0
    declKind = FunctionInfo::VarDecl::Kind::Const;
106
2
  else {
107
2
    assert(declaration->_kind == kw_.identVar);
108
2
    declKind = FunctionInfo::VarDecl::Kind::Var;
109
2
  }
110
111
69
  validateDeclarationNames(
112
69
      declKind,
113
69
      varDecl->_id,
114
69
      curFunction()->varDecls,
115
69
      curFunction()->scopedDecls);
116
69
  visitESTreeChildren(*this, varDecl);
117
69
}
118
119
0
void SemanticValidator::visit(MetaPropertyNode *metaProp) {
120
0
  auto *meta = cast<IdentifierNode>(metaProp->_meta);
121
0
  auto *property = cast<IdentifierNode>(metaProp->_property);
122
123
0
  if (meta->_name->str() == "new" && property->_name->str() == "target") {
124
0
    if (curFunction()->isGlobalScope()) {
125
      // ES9.0 15.1.1:
126
      // It is a Syntax Error if StatementList Contains NewTarget unless the
127
      // source code containing NewTarget is eval code that is being processed
128
      // by a direct eval.
129
      // Hermes does not support local eval, so we assume that this is not
130
      // inside a local eval call.
131
0
      sm_.error(metaProp->getSourceRange(), "'new.target' not in a function");
132
0
    }
133
0
    return;
134
0
  }
135
136
0
  if (meta->_name->str() == "import" && property->_name->str() == "meta") {
137
0
    if (compile_) {
138
0
      sm_.error(
139
0
          metaProp->getSourceRange(), "'import.meta' is currently unsupported");
140
0
    }
141
0
    return;
142
0
  }
143
144
0
  sm_.error(
145
0
      metaProp->getSourceRange(),
146
0
      "invalid meta property " + meta->_name->str() + "." +
147
0
          property->_name->str());
148
0
}
149
150
521k
void SemanticValidator::visit(IdentifierNode *identifier) {
151
521k
  if (identifier->_name == kw_.identEval && !astContext_.getEnableEval())
152
0
    sm_.error(identifier->getSourceRange(), "'eval' is disabled");
153
154
521k
  if (identifier->_name == kw_.identArguments) {
155
15
    if (forbidArguments_)
156
0
      sm_.error(identifier->getSourceRange(), "invalid use of 'arguments'");
157
15
    curFunction()->semInfo->usesArguments = true;
158
15
  }
159
521k
}
160
161
/// Process a function declaration by creating a new FunctionContext.
162
0
void SemanticValidator::visit(FunctionDeclarationNode *funcDecl) {
163
0
  curFunction()->addHoistingCandidate(funcDecl);
164
0
  visitFunction(funcDecl, funcDecl->_id, funcDecl->_params, funcDecl->_body);
165
0
}
166
167
/// Process a function expression by creating a new FunctionContext.
168
80
void SemanticValidator::visit(FunctionExpressionNode *funcExpr) {
169
80
  visitFunction(funcExpr, funcExpr->_id, funcExpr->_params, funcExpr->_body);
170
80
}
171
172
23.0k
void SemanticValidator::visit(ArrowFunctionExpressionNode *arrowFunc) {
173
  // Convert expression functions to a full-body to simplify IRGen.
174
23.0k
  if (compile_ && arrowFunc->_expression) {
175
23.0k
    auto *retStmt = new (astContext_) ReturnStatementNode(arrowFunc->_body);
176
23.0k
    retStmt->copyLocationFrom(arrowFunc->_body);
177
178
23.0k
    ESTree::NodeList stmtList;
179
23.0k
    stmtList.push_back(*retStmt);
180
181
23.0k
    auto *blockStmt = new (astContext_) BlockStatementNode(std::move(stmtList));
182
23.0k
    blockStmt->copyLocationFrom(arrowFunc->_body);
183
184
23.0k
    arrowFunc->_body = blockStmt;
185
23.0k
    arrowFunc->_expression = false;
186
23.0k
  }
187
188
23.0k
  visitFunction(arrowFunc, nullptr, arrowFunc->_params, arrowFunc->_body);
189
190
23.0k
  curFunction()->semInfo->containsArrowFunctions = true;
191
23.0k
  curFunction()->semInfo->containsArrowFunctionsUsingArguments =
192
23.0k
      curFunction()->semInfo->containsArrowFunctionsUsingArguments ||
193
23.0k
      arrowFunc->getSemInfo()->containsArrowFunctionsUsingArguments ||
194
23.0k
      arrowFunc->getSemInfo()->usesArguments;
195
23.0k
}
196
197
#if HERMES_PARSE_FLOW
198
/// Process a component declaration by creating a new FunctionContext.
199
0
void SemanticValidator::visit(ComponentDeclarationNode *componentDecl) {
200
0
  visitFunction(
201
0
      componentDecl,
202
0
      componentDecl->_id,
203
0
      componentDecl->_params,
204
0
      componentDecl->_body);
205
0
}
206
/// Process a hook declaration by creating a new FunctionContext.
207
0
void SemanticValidator::visit(HookDeclarationNode *hookDecl) {
208
0
  visitFunction(hookDecl, hookDecl->_id, hookDecl->_params, hookDecl->_body);
209
0
}
210
#endif
211
212
/// Ensure that the left side of for-in is an l-value.
213
9
void SemanticValidator::visit(ForInStatementNode *forIn) {
214
9
  visitForInOf(forIn, forIn->_left);
215
9
}
216
1
void SemanticValidator::visit(ForOfStatementNode *forOf) {
217
1
  if (compile_ && forOf->_await)
218
0
    sm_.error(
219
0
        forOf->getSourceRange(),
220
0
        "for await..of loops are currently unsupported");
221
222
1
  visitForInOf(forOf, forOf->_left);
223
1
}
224
225
10
void SemanticValidator::visitForInOf(LoopStatementNode *loopNode, Node *left) {
226
10
  loopNode->setLabelIndex(curFunction()->allocateLabel());
227
228
10
  SaveAndRestore<LoopStatementNode *> saveLoop(
229
10
      curFunction()->activeLoop, loopNode);
230
10
  SaveAndRestore<StatementNode *> saveSwitch(
231
10
      curFunction()->activeSwitchOrLoop, loopNode);
232
233
10
  if (auto *VD = dyn_cast<VariableDeclarationNode>(left)) {
234
0
    assert(
235
0
        VD->_declarations.size() == 1 &&
236
0
        "for-in/for-of must have a single binding");
237
238
0
    auto *declarator =
239
0
        cast<ESTree::VariableDeclaratorNode>(&VD->_declarations.front());
240
241
0
    if (declarator->_init) {
242
0
      if (isa<ESTree::PatternNode>(declarator->_id)) {
243
0
        sm_.error(
244
0
            declarator->_init->getSourceRange(),
245
0
            "destructuring declaration cannot be initialized in for-in/for-of loop");
246
0
      } else if (!(isa<ForInStatementNode>(loopNode) &&
247
0
                   !curFunction()->strictMode && VD->_kind == kw_.identVar)) {
248
0
        sm_.error(
249
0
            declarator->_init->getSourceRange(),
250
0
            "for-in/for-of variable declaration may not be initialized");
251
0
      }
252
0
    }
253
10
  } else {
254
10
    validateAssignmentTarget(left);
255
10
  }
256
10
  visitESTreeChildren(*this, loopNode);
257
10
}
258
259
83.7k
void SemanticValidator::visit(BinaryExpressionNode *bin) {
260
  // Handle nested +/- non-recursively.
261
83.7k
  if (bin->_operator == kw_.identPlus || bin->_operator == kw_.identMinus) {
262
17.2k
    auto list = linearizeLeft(bin, {"+", "-"});
263
17.2k
    if (list.size() > MAX_NESTED_BINARY) {
264
3
      recursionDepthExceeded(bin);
265
3
      return;
266
3
    }
267
268
17.2k
    visitESTreeNode(*this, list[0]->_left, list[0]);
269
93.3k
    for (auto *e : list) {
270
93.3k
      visitESTreeNode(*this, e->_right, e);
271
93.3k
    }
272
17.2k
    return;
273
17.2k
  }
274
275
66.4k
  visitESTreeChildren(*this, bin);
276
66.4k
}
277
278
/// Ensure that the left side of assgnments is an l-value.
279
3.82k
void SemanticValidator::visit(AssignmentExpressionNode *assignment) {
280
  // Handle nested "=" non-recursively.
281
3.82k
  if (assignment->_operator == kw_.identAssign) {
282
3.78k
    auto list = linearizeRight(assignment, {"="});
283
3.78k
    if (list.size() > MAX_NESTED_ASSIGNMENTS) {
284
0
      recursionDepthExceeded(assignment);
285
0
      return;
286
0
    }
287
288
4.46k
    for (auto *e : list) {
289
4.46k
      validateAssignmentTarget(e->_left);
290
4.46k
      visitESTreeNode(*this, e->_left, e);
291
4.46k
    }
292
3.78k
    visitESTreeNode(*this, list.back()->_right, list.back());
293
3.78k
    return;
294
3.78k
  }
295
296
44
  validateAssignmentTarget(assignment->_left);
297
44
  visitESTreeChildren(*this, assignment);
298
44
}
299
300
/// Ensure that the operand of ++/-- is an l-value.
301
17
void SemanticValidator::visit(UpdateExpressionNode *update) {
302
  // Check if the left-hand side is valid.
303
17
  if (!isLValue(update->_argument)) {
304
0
    sm_.error(
305
0
        update->_argument->getSourceRange(),
306
0
        "invalid operand in update operation");
307
0
  }
308
17
  visitESTreeChildren(*this, update);
309
17
}
310
311
/// Declare named labels, checking for duplicates, etc.
312
66.5k
void SemanticValidator::visit(LabeledStatementNode *labelStmt) {
313
66.5k
  auto id = cast<IdentifierNode>(labelStmt->_label);
314
315
66.5k
  labelStmt->setLabelIndex(curFunction()->allocateLabel());
316
317
  // Determine the target statement. We need to check if it directly encloses
318
  // a loop or another label enclosing a loop.
319
66.5k
  StatementNode *targetStmt = labelStmt;
320
66.5k
  {
321
66.5k
    LabeledStatementNode *curStmt = labelStmt;
322
67.4k
    do {
323
67.4k
      if (auto *LS = dyn_cast<LoopStatementNode>(curStmt->_body)) {
324
0
        targetStmt = LS;
325
0
        break;
326
0
      }
327
67.4k
    } while ((curStmt = dyn_cast<LabeledStatementNode>(curStmt->_body)));
328
66.5k
  }
329
330
  // Define the new label, checking for a previous definition.
331
66.5k
  auto insertRes =
332
66.5k
      curFunction()->labelMap.insert({id->_name, {id, targetStmt}});
333
66.5k
  if (!insertRes.second) {
334
1
    sm_.error(
335
1
        id->getSourceRange(),
336
1
        llvh::Twine("label '") + id->_name->str() + "' is already defined");
337
1
    sm_.note(
338
1
        insertRes.first->second.declarationNode->getSourceRange(),
339
1
        "previous definition");
340
1
  }
341
  // Auto-erase the label on exit, if we inserted it.
342
66.5k
  const auto &deleter = llvh::make_scope_exit(
343
66.5k
      [this, inserted = insertRes.second, name = id->_name]() {
344
66.5k
        if (inserted)
345
66.5k
          curFunction()->labelMap.erase(name);
346
66.5k
      });
347
66.5k
  (void)deleter;
348
349
66.5k
  visitESTreeChildren(*this, labelStmt);
350
66.5k
}
351
352
/// Check RegExp syntax.
353
1.82k
void SemanticValidator::visit(RegExpLiteralNode *regexp) {
354
1.82k
  llvh::StringRef regexpError;
355
1.82k
  if (compile_) {
356
1.82k
    if (auto compiled = CompiledRegExp::tryCompile(
357
1.82k
            regexp->_pattern->str(), regexp->_flags->str(), &regexpError)) {
358
1.82k
      astContext_.addCompiledRegExp(
359
1.82k
          regexp->_pattern, regexp->_flags, std::move(*compiled));
360
1.82k
    } else {
361
2
      sm_.error(
362
2
          regexp->getSourceRange(),
363
2
          "Invalid regular expression: " + Twine(regexpError));
364
2
    }
365
1.82k
  }
366
1.82k
  visitESTreeChildren(*this, regexp);
367
1.82k
}
368
369
0
void SemanticValidator::validateCatchClause(const Node *catchClause) {
370
  // The catch clause is optional, so bail early if it doesn't exist.
371
0
  if (!catchClause) {
372
0
    return;
373
0
  }
374
0
  auto *castedCatch = llvh::dyn_cast<ESTree::CatchClauseNode>(catchClause);
375
0
  if (!castedCatch) {
376
0
    return;
377
0
  }
378
  // Bail early if there is no identifier in the parameter of the catch.
379
0
  if (!castedCatch->_param ||
380
0
      !llvh::isa<ESTree::IdentifierNode>(castedCatch->_param)) {
381
0
    return;
382
0
  }
383
0
  auto *idNode = cast<ESTree::IdentifierNode>(castedCatch->_param);
384
0
  if (!isValidDeclarationName(idNode)) {
385
0
    sm_.error(
386
0
        idNode->getSourceRange(),
387
0
        "cannot bind to " + idNode->_name->str() +
388
0
            " in the catch clause in strict mode");
389
0
  }
390
0
}
391
392
0
void SemanticValidator::visit(TryStatementNode *tryStatement) {
393
0
  if (curFunction()->strictMode) {
394
0
    validateCatchClause(tryStatement->_handler);
395
0
  }
396
  // The catch parameter cannot bind to 'eval' or 'arguments' in strict mode.
397
  // A try statement with both catch and finally handlers is technically
398
  // two nested try statements. Transform:
399
  //
400
  //    try {
401
  //      tryBody;
402
  //    } catch {
403
  //      catchBody;
404
  //    } finally {
405
  //      finallyBody;
406
  //    }
407
  //
408
  // into
409
  //
410
  //    try {
411
  //      try {
412
  //        tryBody;
413
  //      } catch {
414
  //        catchBody;
415
  //      }
416
  //    } finally {
417
  //      finallyBody;
418
  //    }
419
0
  if (compile_ && tryStatement->_handler && tryStatement->_finalizer) {
420
0
    auto *nestedTry = new (astContext_)
421
0
        TryStatementNode(tryStatement->_block, tryStatement->_handler, nullptr);
422
0
    nestedTry->copyLocationFrom(tryStatement);
423
0
    nestedTry->setEndLoc(nestedTry->_handler->getEndLoc());
424
425
0
    ESTree::NodeList stmtList;
426
0
    stmtList.push_back(*nestedTry);
427
0
    tryStatement->_block =
428
0
        new (astContext_) BlockStatementNode(std::move(stmtList));
429
0
    tryStatement->_block->copyLocationFrom(nestedTry);
430
0
    tryStatement->_handler = nullptr;
431
0
  }
432
433
0
  visitESTreeNode(*this, tryStatement->_block, tryStatement);
434
0
  if (!blockScopingEnabled()) {
435
0
    visitESTreeNode(*this, tryStatement->_handler, tryStatement);
436
0
  } else {
437
0
    visitTryHandler(tryStatement);
438
0
  }
439
440
0
  visitESTreeNode(*this, tryStatement->_finalizer, tryStatement);
441
0
}
442
443
0
void SemanticValidator::visitTryHandler(TryStatementNode *tryStatement) {
444
0
  if (auto *handler =
445
0
          llvh::dyn_cast_or_null<CatchClauseNode>(tryStatement->_handler)) {
446
0
    auto *param = llvh::dyn_cast_or_null<IdentifierNode>(handler->_param);
447
448
0
    BlockContext blockScope(this, curFunction(), handler);
449
450
0
    if (auto *block = llvh::dyn_cast<BlockStatementNode>(handler->_body)) {
451
0
      for (auto &stmt : block->_body) {
452
0
        visitESTreeNode(*this, &stmt, block);
453
0
      }
454
0
    } else {
455
0
      visitESTreeNode(*this, tryStatement->_handler, tryStatement);
456
0
    }
457
458
0
    blockScope.ensureScopedNamesAreUnique(
459
0
        BlockContext::IsFunctionBody::No, param);
460
461
    // Delay adding the catch param until now to prevent Syntax Errors if the
462
    // handler has a var that with the same ID as the catch param (as specified
463
    // in ES2023 B.3.4).
464
0
    validateDeclarationNames(
465
0
        FunctionInfo::VarDecl::Kind::Let,
466
0
        param,
467
0
        curFunction()->varDecls,
468
0
        curFunction()->scopedDecls);
469
0
  }
470
0
}
471
472
0
void SemanticValidator::visit(BlockStatementNode *block) {
473
0
  BlockContext blockScope(this, curFunction(), block);
474
0
  visitESTreeChildren(*this, block);
475
476
0
  blockScope.ensureScopedNamesAreUnique(BlockContext::IsFunctionBody::No);
477
0
}
478
479
0
void SemanticValidator::visit(DoWhileStatementNode *loop) {
480
0
  loop->setLabelIndex(curFunction()->allocateLabel());
481
482
0
  SaveAndRestore<LoopStatementNode *> saveLoop(curFunction()->activeLoop, loop);
483
0
  SaveAndRestore<StatementNode *> saveSwitch(
484
0
      curFunction()->activeSwitchOrLoop, loop);
485
486
0
  visitESTreeChildren(*this, loop);
487
0
}
488
0
void SemanticValidator::visit(ForStatementNode *loop) {
489
0
  loop->setLabelIndex(curFunction()->allocateLabel());
490
491
0
  SaveAndRestore<LoopStatementNode *> saveLoop(curFunction()->activeLoop, loop);
492
0
  SaveAndRestore<StatementNode *> saveSwitch(
493
0
      curFunction()->activeSwitchOrLoop, loop);
494
495
0
  visitESTreeChildren(*this, loop);
496
0
}
497
0
void SemanticValidator::visit(WhileStatementNode *loop) {
498
0
  loop->setLabelIndex(curFunction()->allocateLabel());
499
500
0
  SaveAndRestore<LoopStatementNode *> saveLoop(curFunction()->activeLoop, loop);
501
0
  SaveAndRestore<StatementNode *> saveSwitch(
502
0
      curFunction()->activeSwitchOrLoop, loop);
503
504
0
  visitESTreeChildren(*this, loop);
505
0
}
506
0
void SemanticValidator::visit(SwitchStatementNode *switchStmt) {
507
0
  switchStmt->setLabelIndex(curFunction()->allocateLabel());
508
509
0
  BlockContext switchContext(this, curFunction(), switchStmt);
510
511
0
  SaveAndRestore<StatementNode *> saveSwitch(
512
0
      curFunction()->activeSwitchOrLoop, switchStmt);
513
514
0
  visitESTreeChildren(*this, switchStmt);
515
516
0
  switchContext.ensureScopedNamesAreUnique(BlockContext::IsFunctionBody::No);
517
0
}
518
519
0
void SemanticValidator::visit(BreakStatementNode *breakStmt) {
520
0
  if (auto id = cast_or_null<IdentifierNode>(breakStmt->_label)) {
521
    // A labeled break.
522
    // Find the label in the label map.
523
0
    auto labelIt = curFunction()->labelMap.find(id->_name);
524
0
    if (labelIt != curFunction()->labelMap.end()) {
525
0
      auto labelIndex = getLabelDecorationBase(labelIt->second.targetStatement)
526
0
                            ->getLabelIndex();
527
0
      breakStmt->setLabelIndex(labelIndex);
528
0
    } else {
529
0
      sm_.error(
530
0
          id->getSourceRange(),
531
0
          Twine("label '") + id->_name->str() + "' is not defined");
532
0
    }
533
0
  } else {
534
    // Anonymous break.
535
0
    if (curFunction()->activeSwitchOrLoop) {
536
0
      auto labelIndex =
537
0
          getLabelDecorationBase(curFunction()->activeSwitchOrLoop)
538
0
              ->getLabelIndex();
539
0
      breakStmt->setLabelIndex(labelIndex);
540
0
    } else {
541
0
      sm_.error(
542
0
          breakStmt->getSourceRange(), "'break' not within a loop or a switch");
543
0
    }
544
0
  }
545
546
0
  visitESTreeChildren(*this, breakStmt);
547
0
}
548
549
0
void SemanticValidator::visit(ContinueStatementNode *continueStmt) {
550
0
  if (auto id = cast_or_null<IdentifierNode>(continueStmt->_label)) {
551
    // A labeled continue.
552
    // Find the label in the label map.
553
0
    auto labelIt = curFunction()->labelMap.find(id->_name);
554
0
    if (labelIt != curFunction()->labelMap.end()) {
555
0
      if (isa<LoopStatementNode>(labelIt->second.targetStatement)) {
556
0
        auto labelIndex =
557
0
            getLabelDecorationBase(labelIt->second.targetStatement)
558
0
                ->getLabelIndex();
559
0
        continueStmt->setLabelIndex(labelIndex);
560
0
      } else {
561
0
        sm_.error(
562
0
            id->getSourceRange(),
563
0
            llvh::Twine("continue label '") + id->_name->str() +
564
0
                "' is not a loop label");
565
0
        sm_.note(
566
0
            labelIt->second.declarationNode->getSourceRange(),
567
0
            "label defined here");
568
0
      }
569
0
    } else {
570
0
      sm_.error(
571
0
          id->getSourceRange(),
572
0
          Twine("label '") + id->_name->str() + "' is not defined");
573
0
    }
574
0
  } else {
575
    // Anonymous continue.
576
0
    if (curFunction()->activeLoop) {
577
0
      auto labelIndex = curFunction()->activeLoop->getLabelIndex();
578
0
      continueStmt->setLabelIndex(labelIndex);
579
0
    } else {
580
0
      sm_.error(continueStmt->getSourceRange(), "'continue' not within a loop");
581
0
    }
582
0
  }
583
0
  visitESTreeChildren(*this, continueStmt);
584
0
}
585
586
23.0k
void SemanticValidator::visit(ReturnStatementNode *returnStmt) {
587
23.0k
  if (curFunction()->isGlobalScope() &&
588
0
      !astContext_.allowReturnOutsideFunction())
589
0
    sm_.error(returnStmt->getSourceRange(), "'return' not in a function");
590
23.0k
  visitESTreeChildren(*this, returnStmt);
591
23.0k
}
592
593
0
void SemanticValidator::visit(YieldExpressionNode *yieldExpr) {
594
0
  if (curFunction()->isGlobalScope() ||
595
0
      (curFunction()->node && !ESTree::isGenerator(curFunction()->node)))
596
0
    sm_.error(
597
0
        yieldExpr->getSourceRange(), "'yield' not in a generator function");
598
599
0
  if (isFormalParams_) {
600
    // For generators functions (the only time YieldExpression is parsed):
601
    // It is a Syntax Error if UniqueFormalParameters Contains YieldExpression
602
    // is true.
603
0
    sm_.error(
604
0
        yieldExpr->getSourceRange(),
605
0
        "'yield' not allowed in a formal parameter");
606
0
  }
607
608
0
  visitESTreeChildren(*this, yieldExpr);
609
0
}
610
611
0
void SemanticValidator::visit(AwaitExpressionNode *awaitExpr) {
612
0
  if (forbidAwaitExpression_)
613
0
    sm_.error(awaitExpr->getSourceRange(), "'await' not in an async function");
614
615
0
  visitESTreeChildren(*this, awaitExpr);
616
0
}
617
618
93.6k
void SemanticValidator::visit(UnaryExpressionNode *unaryExpr) {
619
  // Check for unqualified delete in strict mode.
620
93.6k
  if (unaryExpr->_operator == kw_.identDelete) {
621
84.9k
    if (curFunction()->strictMode &&
622
0
        isa<IdentifierNode>(unaryExpr->_argument)) {
623
0
      sm_.error(
624
0
          unaryExpr->getSourceRange(),
625
0
          "'delete' of a variable is not allowed in strict mode");
626
0
    }
627
84.9k
  }
628
93.6k
  visitESTreeChildren(*this, unaryExpr);
629
93.6k
}
630
631
825
void SemanticValidator::visit(ArrayPatternNode *AP) {
632
825
  visitESTreeChildren(*this, AP);
633
825
}
634
635
2
void SemanticValidator::visit(SpreadElementNode *S, Node *parent) {
636
2
  if (!isa<ESTree::ObjectExpressionNode>(parent) &&
637
2
      !isa<ESTree::ArrayExpressionNode>(parent) &&
638
0
      !isa<ESTree::CallExpressionNode>(parent) &&
639
0
      !isa<ESTree::OptionalCallExpressionNode>(parent) &&
640
0
      !isa<ESTree::NewExpressionNode>(parent))
641
0
    sm_.error(S->getSourceRange(), "spread operator is not supported");
642
2
  visitESTreeChildren(*this, S);
643
2
}
644
645
0
void SemanticValidator::visit(ClassExpressionNode *node) {
646
0
  SaveAndRestore<bool> oldStrictMode{curFunction()->strictMode, true};
647
0
  visitESTreeChildren(*this, node);
648
0
}
649
650
0
void SemanticValidator::visit(ClassDeclarationNode *node) {
651
0
  SaveAndRestore<bool> oldStrictMode{curFunction()->strictMode, true};
652
0
  visitESTreeChildren(*this, node);
653
0
}
654
655
0
void SemanticValidator::visit(PrivateNameNode *node) {
656
0
  if (compile_)
657
0
    sm_.error(node->getSourceRange(), "private properties are not supported");
658
0
  visitESTreeChildren(*this, node);
659
0
}
660
661
0
void SemanticValidator::visit(ClassPrivatePropertyNode *node) {
662
0
  if (compile_)
663
0
    sm_.error(node->getSourceRange(), "private properties are not supported");
664
0
  visitESTreeNode(*this, node->_key);
665
0
  {
666
0
    SaveAndRestore<bool> oldForbidAwait{forbidAwaitExpression_, true};
667
    // ES14.0 15.7.1
668
    // It is a Syntax Error if Initializer is present and ContainsArguments of
669
    // Initializer is true.
670
0
    SaveAndRestore<bool> oldForbidArguments{forbidArguments_, true};
671
0
    visitESTreeNode(*this, node->_value);
672
0
  }
673
0
}
674
675
0
void SemanticValidator::visit(ClassPropertyNode *node) {
676
0
  visitESTreeNode(*this, node->_key);
677
0
  {
678
0
    SaveAndRestore<bool> oldForbidAwait{forbidAwaitExpression_, true};
679
    // ES14.0 15.7.1
680
    // It is a Syntax Error if Initializer is present and ContainsArguments of
681
    // Initializer is true.
682
0
    SaveAndRestore<bool> oldForbidArguments{forbidArguments_, true};
683
0
    visitESTreeNode(*this, node->_value);
684
0
  }
685
0
}
686
687
0
void SemanticValidator::visit(StaticBlockNode *node) {
688
0
  if (compile_)
689
0
    sm_.error(node->getSourceRange(), "class static blocks are not supported");
690
  // ES14.0 15.7.1
691
  // It is a Syntax Error if ClassStaticBlockStatementList Contains await is
692
  // true.
693
0
  llvh::SaveAndRestore<bool> oldForbidAwait{forbidAwaitExpression_, true};
694
0
  visitESTreeChildren(*this, node);
695
0
}
696
697
0
void SemanticValidator::visit(ImportDeclarationNode *importDecl) {
698
  // Like variable declarations, imported names must be hoisted.
699
0
  if (!astContext_.getTransformCJSModules()) {
700
0
    sm_.error(
701
0
        importDecl->getSourceRange(),
702
0
        "'import' statement requires module mode");
703
0
  }
704
705
0
  if (compile_ && !importDecl->_assertions.empty()) {
706
0
    sm_.error(
707
0
        importDecl->getSourceRange(), "import assertions are not supported");
708
0
  }
709
710
0
  curFunction()->semInfo->imports.push_back(importDecl);
711
0
  visitESTreeChildren(*this, importDecl);
712
0
}
713
714
0
void SemanticValidator::visit(ImportDefaultSpecifierNode *importDecl) {
715
  // import defaultProperty from 'file.js';
716
0
  validateDeclarationNames(
717
0
      FunctionInfo::VarDecl::Kind::Var,
718
0
      importDecl->_local,
719
0
      curFunction()->varDecls,
720
0
      curFunction()->scopedDecls);
721
0
  visitESTreeChildren(*this, importDecl);
722
0
}
723
724
0
void SemanticValidator::visit(ImportNamespaceSpecifierNode *importDecl) {
725
  // import * as File from 'file.js';
726
0
  validateDeclarationNames(
727
0
      FunctionInfo::VarDecl::Kind::Var,
728
0
      importDecl->_local,
729
0
      curFunction()->varDecls,
730
0
      curFunction()->scopedDecls);
731
0
  visitESTreeChildren(*this, importDecl);
732
0
}
733
734
0
void SemanticValidator::visit(ImportSpecifierNode *importDecl) {
735
  // import {x as y} as File from 'file.js';
736
  // import {x} as File from 'file.js';
737
0
  validateDeclarationNames(
738
0
      FunctionInfo::VarDecl::Kind::Var,
739
0
      importDecl->_local,
740
0
      curFunction()->varDecls,
741
0
      curFunction()->scopedDecls);
742
0
  visitESTreeChildren(*this, importDecl);
743
0
}
744
745
0
void SemanticValidator::visit(ExportNamedDeclarationNode *exportDecl) {
746
0
  if (!astContext_.getTransformCJSModules()) {
747
0
    sm_.error(
748
0
        exportDecl->getSourceRange(),
749
0
        "'export' statement requires module mode");
750
0
  }
751
752
0
  visitESTreeChildren(*this, exportDecl);
753
0
}
754
755
0
void SemanticValidator::visit(ExportDefaultDeclarationNode *exportDecl) {
756
0
  if (!astContext_.getTransformCJSModules() &&
757
0
      !astContext_.getTransformCJSModules()) {
758
0
    sm_.error(
759
0
        exportDecl->getSourceRange(),
760
0
        "'export' statement requires module mode");
761
0
  }
762
763
0
  if (auto *funcDecl =
764
0
          dyn_cast<ESTree::FunctionDeclarationNode>(exportDecl->_declaration)) {
765
0
    if (compile_ && !funcDecl->_id) {
766
      // If the default function declaration has no name, then change it to a
767
      // FunctionExpression node for cleaner IRGen.
768
0
      auto *funcExpr = new (astContext_) ESTree::FunctionExpressionNode(
769
0
          funcDecl->_id,
770
0
          std::move(funcDecl->_params),
771
0
          funcDecl->_body,
772
0
          funcDecl->_typeParameters,
773
0
          funcDecl->_returnType,
774
0
          funcDecl->_predicate,
775
0
          funcDecl->_generator,
776
0
          /* async */ false);
777
0
      funcExpr->strictness = funcDecl->strictness;
778
0
      funcExpr->copyLocationFrom(funcDecl);
779
780
0
      exportDecl->_declaration = funcExpr;
781
0
    }
782
0
  }
783
784
0
  visitESTreeChildren(*this, exportDecl);
785
0
}
786
787
0
void SemanticValidator::visit(ExportAllDeclarationNode *exportDecl) {
788
0
  if (!astContext_.getTransformCJSModules()) {
789
0
    sm_.error(
790
0
        exportDecl->getSourceRange(),
791
0
        "'export' statement requires CommonJS module mode");
792
0
  }
793
0
  visitESTreeChildren(*this, exportDecl);
794
0
}
795
796
0
void SemanticValidator::visit(CoverEmptyArgsNode *CEA) {
797
0
  sm_.error(CEA->getSourceRange(), "invalid empty parentheses '( )'");
798
0
}
799
800
0
void SemanticValidator::visit(CoverTrailingCommaNode *CTC) {
801
0
  sm_.error(CTC->getSourceRange(), "expression expected after ','");
802
0
}
803
804
0
void SemanticValidator::visit(CoverInitializerNode *CI) {
805
0
  sm_.error(CI->getStartLoc(), "':' expected in property initialization");
806
0
}
807
808
0
void SemanticValidator::visit(CoverRestElementNode *R) {
809
0
  sm_.error(R->getSourceRange(), "'...' not allowed in this context");
810
0
}
811
812
#if HERMES_PARSE_FLOW
813
0
void SemanticValidator::visit(CoverTypedIdentifierNode *CTI) {
814
0
  sm_.error(CTI->getSourceRange(), "typecast not allowed in this context");
815
0
}
816
#endif
817
818
void SemanticValidator::visitFunction(
819
    FunctionLikeNode *node,
820
    Node *id,
821
    NodeList &params,
822
23.1k
    Node *body) {
823
23.1k
  FunctionContext newFuncCtx{
824
23.1k
      this,
825
23.1k
      haveActiveContext() && curFunction()->strictMode,
826
23.1k
      node,
827
23.1k
      body,
828
23.1k
      haveActiveContext() ? curFunction()->sourceVisibility
829
23.1k
                          : SourceVisibility::Default};
830
831
23.1k
  if (compile_ && ESTree::isAsync(node) && ESTree::isGenerator(node)) {
832
0
    sm_.error(node->getSourceRange(), "async generators are unsupported");
833
0
  }
834
835
  // It is a Syntax Error if UniqueFormalParameters Contains YieldExpression
836
  // is true.
837
  // NOTE: isFormalParams_ is reset to false on encountering a new function,
838
  // because the semantics for "x Contains y" always return `false` when "x" is
839
  // a function definition.
840
23.1k
  llvh::SaveAndRestore<bool> oldIsFormalParamsFn{isFormalParams_, false};
841
842
23.1k
  Node *useStrictNode = nullptr;
843
844
  // Note that body might me empty (for lazy functions) or an expression (for
845
  // arrow functions).
846
23.1k
  if (auto *bodyNode = dyn_cast<ESTree::BlockStatementNode>(body)) {
847
23.1k
    if (bodyNode->isLazyFunctionBody) {
848
      // If it is a lazy function body, then the directive nodes in the body are
849
      // fabricated without location, so don't set useStrictNode.
850
80
      scanDirectivePrologue(bodyNode->_body);
851
23.0k
    } else {
852
23.0k
      useStrictNode = scanDirectivePrologue(bodyNode->_body);
853
23.0k
    }
854
23.1k
    setDirectiveDerivedInfo(node);
855
23.1k
  }
856
857
23.1k
  if (id)
858
0
    validateDeclarationNames(
859
0
        FunctionInfo::VarDecl::Kind::Var, id, nullptr, nullptr);
860
861
23.1k
#if HERMES_PARSE_FLOW
862
23.1k
  if (astContext_.getParseFlow() && !params.empty()) {
863
    // Skip 'this' parameter annotation, and error if it's an arrow parameter,
864
    // because arrow functions inherit 'this'.
865
0
    if (auto *ident = dyn_cast<ESTree::IdentifierNode>(&params.front())) {
866
0
      if (ident->_name == kw_.identThis) {
867
0
        if (isa<ArrowFunctionExpressionNode>(node)) {
868
0
          sm_.error(
869
0
              ident->getSourceRange(), "'this' not allowed as parameter name");
870
0
        }
871
0
        if (compile_) {
872
          // Delete the node because it cannot be compiled.
873
0
          params.erase(params.begin());
874
0
        }
875
0
      }
876
0
    }
877
0
  }
878
23.1k
#endif
879
880
23.1k
  for (auto &param : params) {
881
23.0k
#if HERMES_PARSE_FLOW
882
23.0k
    if (isa<ComponentParameterNode>(param)) {
883
0
      validateDeclarationNames(
884
0
          FunctionInfo::VarDecl::Kind::Var,
885
0
          dyn_cast<ComponentParameterNode>(&param)->_local,
886
0
          &newFuncCtx.semInfo->paramNames,
887
0
          nullptr);
888
0
      continue;
889
0
    }
890
23.0k
#endif
891
23.0k
    validateDeclarationNames(
892
23.0k
        FunctionInfo::VarDecl::Kind::Var,
893
23.0k
        &param,
894
23.0k
        &newFuncCtx.semInfo->paramNames,
895
23.0k
        nullptr);
896
23.0k
  }
897
898
23.1k
  bool simpleParameterList = ESTree::hasSimpleParams(node);
899
23.1k
  if (!simpleParameterList && useStrictNode) {
900
0
    sm_.error(
901
0
        useStrictNode->getSourceRange(),
902
0
        "'use strict' not allowed inside function with non-simple parameter list");
903
0
  }
904
905
  // Check repeated parameter names when they are supposed to be unique.
906
23.1k
  if (!simpleParameterList || curFunction()->strictMode ||
907
23.1k
      isa<ArrowFunctionExpressionNode>(node)) {
908
23.0k
    llvh::SmallSet<NodeLabel, 8> paramNameSet;
909
23.0k
    for (const auto &curIdNode : newFuncCtx.semInfo->paramNames) {
910
23.0k
      auto insert_result = paramNameSet.insert(curIdNode.identifier->_name);
911
23.0k
      if (insert_result.second == false) {
912
0
        sm_.error(
913
0
            curIdNode.identifier->getSourceRange(),
914
0
            "cannot declare two parameters with the same name '" +
915
0
                curIdNode.identifier->_name->str() + "'");
916
0
      }
917
23.0k
    }
918
23.0k
  }
919
920
  // 'await' forbidden outside async functions.
921
23.1k
  llvh::SaveAndRestore<bool> oldForbidAwait{
922
23.1k
      forbidAwaitExpression_, !ESTree::isAsync(node)};
923
  // Forbidden-ness of 'arguments' passes through arrow functions because they
924
  // use the same 'arguments'.
925
23.1k
  llvh::SaveAndRestore<bool> oldForbidArguments{
926
23.1k
      forbidArguments_,
927
23.1k
      llvh::isa<ESTree::ArrowFunctionExpressionNode>(node) ? forbidArguments_
928
23.1k
                                                           : false};
929
930
23.1k
  visitParamsAndBody(node);
931
23.1k
}
932
933
23.1k
void SemanticValidator::visitParamsAndBody(FunctionLikeNode *node) {
934
23.1k
  switch (node->getKind()) {
935
80
    case NodeKind::FunctionExpression: {
936
80
      auto *fe = cast<ESTree::FunctionExpressionNode>(node);
937
80
      visitESTreeNode(*this, fe->_id, fe);
938
80
      for (auto &param : fe->_params) {
939
0
        llvh::SaveAndRestore<bool> oldIsFormalParams{isFormalParams_, true};
940
0
        visitESTreeNode(*this, &param, fe);
941
0
      }
942
80
      visitBody(fe->_body, fe);
943
80
      break;
944
0
    }
945
23.0k
    case NodeKind::ArrowFunctionExpression: {
946
23.0k
      auto *fe = cast<ESTree::ArrowFunctionExpressionNode>(node);
947
23.0k
      visitESTreeNode(*this, fe->_id, fe);
948
23.0k
      for (auto &param : fe->_params) {
949
23.0k
        llvh::SaveAndRestore<bool> oldIsFormalParams{isFormalParams_, true};
950
23.0k
        visitESTreeNode(*this, &param, fe);
951
23.0k
      }
952
23.0k
      visitBody(fe->_body, fe);
953
23.0k
      break;
954
0
    }
955
0
    case NodeKind::FunctionDeclaration: {
956
0
      auto *fe = cast<ESTree::FunctionDeclarationNode>(node);
957
0
      visitESTreeNode(*this, fe->_id, fe);
958
0
      for (auto &param : fe->_params) {
959
0
        llvh::SaveAndRestore<bool> oldIsFormalParams{isFormalParams_, true};
960
0
        visitESTreeNode(*this, &param, fe);
961
0
      }
962
0
      visitBody(fe->_body, fe);
963
0
      visitESTreeNode(*this, fe->_returnType, fe);
964
0
      break;
965
0
    }
966
0
#if HERMES_PARSE_FLOW
967
0
    case NodeKind::ComponentDeclaration: {
968
0
      auto *fe = cast<ESTree::ComponentDeclarationNode>(node);
969
0
      visitESTreeNode(*this, fe->_id, fe);
970
0
      for (auto &param : fe->_params) {
971
0
        llvh::SaveAndRestore<bool> oldIsFormalParams{isFormalParams_, true};
972
0
        visitESTreeNode(*this, &param, fe);
973
0
      }
974
0
      visitBody(fe->_body, fe);
975
0
      visitESTreeNode(*this, fe->_rendersType, fe);
976
0
      break;
977
0
    }
978
0
    case NodeKind::HookDeclaration: {
979
0
      auto *fe = cast<ESTree::HookDeclarationNode>(node);
980
0
      visitESTreeNode(*this, fe->_id, fe);
981
0
      for (auto &param : fe->_params) {
982
0
        llvh::SaveAndRestore<bool> oldIsFormalParams{isFormalParams_, true};
983
0
        visitESTreeNode(*this, &param, fe);
984
0
      }
985
0
      visitBody(fe->_body, fe);
986
0
      visitESTreeNode(*this, fe->_returnType, fe);
987
0
      break;
988
0
    }
989
0
#endif
990
0
    default:
991
0
      visitESTreeChildren(*this, node);
992
23.1k
  }
993
23.1k
}
994
995
23.1k
void SemanticValidator::visitBody(Node *body, FunctionLikeNode *func) {
996
23.1k
  if (auto *block = dyn_cast<ESTree::BlockStatementNode>(body)) {
997
    // Avoid creating yet another block scope for function declarations like
998
    //
999
    // (function func() { ... })
1000
    //                  ^ BlockStatementNode
1001
    //
1002
    // In those cases, the scope for the BlockStatementNode is the same as
1003
    // func's.
1004
23.1k
    for (auto &stmt : block->_body) {
1005
23.0k
      visitESTreeNode(*this, &stmt, block);
1006
23.0k
    }
1007
23.1k
    return;
1008
23.1k
  }
1009
1010
0
  visitESTreeNode(*this, body, func);
1011
0
}
1012
1013
void SemanticValidator::tryOverrideSourceVisibility(
1014
0
    SourceVisibility newSourceVisibility) {
1015
0
  if (newSourceVisibility > curFunction()->sourceVisibility) {
1016
0
    curFunction()->sourceVisibility = newSourceVisibility;
1017
0
  }
1018
0
}
1019
1020
23.2k
Node *SemanticValidator::scanDirectivePrologue(NodeList &body) {
1021
23.2k
  Node *result = nullptr;
1022
23.2k
  for (auto &nodeRef : body) {
1023
23.1k
    auto *exprSt = dyn_cast<ESTree::ExpressionStatementNode>(&nodeRef);
1024
23.1k
    if (!exprSt || !exprSt->_directive)
1025
23.1k
      break;
1026
1027
0
    auto *directive = exprSt->_directive;
1028
1029
0
    if (directive == kw_.identUseStrict) {
1030
0
      curFunction()->strictMode = true;
1031
0
      if (!result)
1032
0
        result = &nodeRef;
1033
0
    }
1034
0
    if (directive == kw_.identShowSource) {
1035
0
      tryOverrideSourceVisibility(SourceVisibility::ShowSource);
1036
0
    }
1037
0
    if (directive == kw_.identHideSource) {
1038
0
      tryOverrideSourceVisibility(SourceVisibility::HideSource);
1039
0
    }
1040
0
    if (directive == kw_.identSensitive) {
1041
0
      tryOverrideSourceVisibility(SourceVisibility::Sensitive);
1042
0
    }
1043
0
  }
1044
1045
23.2k
  return result;
1046
23.2k
}
1047
1048
5.22k
bool SemanticValidator::isLValue(const Node *node) const {
1049
5.22k
  if (isa<MemberExpressionNode>(node))
1050
118
    return true;
1051
5.10k
  if (!isa<IdentifierNode>(node))
1052
715
    return false;
1053
1054
4.38k
  auto *idNode = cast<IdentifierNode>(node);
1055
1056
  /// 'arguments' cannot be modified in strict mode, but we also don't
1057
  /// support modifying it in non-strict mode yet.
1058
4.38k
  if (idNode->_name == kw_.identArguments)
1059
0
    return false;
1060
1061
  // 'eval' cannot be used as a variable in strict mode. If it is disabled we
1062
  // we don't report an error because it will be reported separately.
1063
4.38k
  if (idNode->_name == kw_.identEval && curFunction()->strictMode &&
1064
0
      astContext_.getEnableEval())
1065
0
    return false;
1066
1067
4.38k
  return true;
1068
4.38k
}
1069
1070
bool SemanticValidator::isValidDeclarationName(
1071
23.1k
    const IdentifierNode *idNode) const {
1072
  // 'arguments' cannot be redeclared in strict mode.
1073
23.1k
  if (idNode->_name == kw_.identArguments && curFunction()->strictMode)
1074
0
    return false;
1075
1076
  // 'eval' cannot be redeclared in strict mode. If it is disabled we
1077
  // we don't report an error because it will be reported separately.
1078
23.1k
  if (idNode->_name == kw_.identEval && curFunction()->strictMode &&
1079
0
      astContext_.getEnableEval())
1080
0
    return false;
1081
1082
23.1k
  return true;
1083
23.1k
}
1084
1085
void SemanticValidator::validateDeclarationNames(
1086
    FunctionInfo::VarDecl::Kind declKind,
1087
    Node *node,
1088
    FunctionInfo::BlockDecls *varIdents,
1089
23.2k
    FunctionInfo::BlockDecls *scopedIdents) {
1090
23.2k
  assert(
1091
23.2k
      (varIdents || !scopedIdents) &&
1092
23.2k
      "Variable scope must always be provided if a scoped scope is provided.");
1093
  // The identifier is sometimes optional, in which case it is valid.
1094
23.2k
  if (!node)
1095
0
    return;
1096
1097
23.2k
  if (auto *idNode = dyn_cast<IdentifierNode>(node)) {
1098
23.1k
    if (!blockScopingEnabled()) {
1099
      // Block scoping is disabled, so short-circuit both BlockDecls to use the
1100
      // var environment.
1101
23.1k
      scopedIdents = varIdents;
1102
23.1k
    }
1103
23.1k
    if (varIdents) {
1104
23.1k
      if (declKind == FunctionInfo::VarDecl::Kind::Var) {
1105
23.0k
        varIdents->emplace_back(FunctionInfo::VarDecl{declKind, idNode});
1106
23.0k
      } else {
1107
67
        assert(
1108
67
            scopedIdents &&
1109
67
            "const/let declaration, but no scopedIdents array.");
1110
67
        scopedIdents->emplace_back(FunctionInfo::VarDecl{declKind, idNode});
1111
67
      }
1112
23.1k
    }
1113
23.1k
    if (!isValidDeclarationName(idNode)) {
1114
0
      sm_.error(
1115
0
          node->getSourceRange(),
1116
0
          "cannot declare '" + cast<IdentifierNode>(node)->_name->str() + "'");
1117
0
    }
1118
1119
23.1k
    if (declKind != FunctionInfo::VarDecl::Kind::Var &&
1120
67
        idNode->_name == kw_.identLet) {
1121
      // ES9.0 13.3.1.1
1122
      // LexicalDeclaration : LetOrConst BindingList
1123
      // It is a Syntax Error if the BoundNames of BindingList
1124
      // contains "let".
1125
0
      sm_.error(
1126
0
          node->getSourceRange(),
1127
0
          "'let' is disallowed as a lexically bound name");
1128
0
    }
1129
1130
23.1k
    return;
1131
23.1k
  }
1132
1133
118
  if (isa<EmptyNode>(node))
1134
0
    return;
1135
1136
118
  if (auto *assign = dyn_cast<AssignmentPatternNode>(node))
1137
0
    return validateDeclarationNames(
1138
0
        declKind, assign->_left, varIdents, scopedIdents);
1139
1140
118
  if (auto *array = dyn_cast<ArrayPatternNode>(node)) {
1141
118
    for (auto &elem : array->_elements) {
1142
116
      validateDeclarationNames(declKind, &elem, varIdents, scopedIdents);
1143
116
    }
1144
118
    return;
1145
118
  }
1146
1147
0
  if (auto *restElem = dyn_cast<RestElementNode>(node)) {
1148
0
    return validateDeclarationNames(
1149
0
        declKind, restElem->_argument, varIdents, scopedIdents);
1150
0
  }
1151
1152
0
  if (auto *obj = dyn_cast<ObjectPatternNode>(node)) {
1153
0
    for (auto &propNode : obj->_properties) {
1154
0
      if (auto *prop = dyn_cast<PropertyNode>(&propNode)) {
1155
0
        validateDeclarationNames(
1156
0
            declKind, prop->_value, varIdents, scopedIdents);
1157
0
      } else {
1158
0
        auto *rest = cast<RestElementNode>(&propNode);
1159
0
        validateDeclarationNames(
1160
0
            declKind, rest->_argument, varIdents, scopedIdents);
1161
0
      }
1162
0
    }
1163
0
    return;
1164
0
  }
1165
1166
0
  sm_.error(node->getSourceRange(), "invalid destructuring target");
1167
0
}
1168
1169
5.31k
void SemanticValidator::validateAssignmentTarget(const Node *node) {
1170
5.31k
  if (isa<EmptyNode>(node) || isLValue(node)) {
1171
4.60k
    return;
1172
4.60k
  }
1173
1174
715
  if (auto *assign = dyn_cast<AssignmentPatternNode>(node)) {
1175
8
    return validateAssignmentTarget(assign->_left);
1176
8
  }
1177
1178
707
  if (auto *APN = dyn_cast<ArrayPatternNode>(node)) {
1179
789
    for (auto &elem : APN->_elements) {
1180
789
      validateAssignmentTarget(&elem);
1181
789
    }
1182
707
    return;
1183
707
  }
1184
1185
0
  if (auto *RP = dyn_cast<RestElementNode>(node)) {
1186
0
    return validateAssignmentTarget(RP->_argument);
1187
0
  }
1188
1189
0
  if (auto *obj = dyn_cast<ObjectPatternNode>(node)) {
1190
0
    for (auto &propNode : obj->_properties) {
1191
0
      if (auto *prop = dyn_cast<PropertyNode>(&propNode)) {
1192
0
        assert(
1193
0
            prop->_kind->str() == "init" &&
1194
0
            "getters and setters must have been reported by the parser");
1195
0
        validateAssignmentTarget(prop->_value);
1196
0
      } else {
1197
0
        auto *rest = cast<RestElementNode>(&propNode);
1198
0
        validateAssignmentTarget(rest->_argument);
1199
0
      }
1200
0
    }
1201
0
    return;
1202
0
  }
1203
1204
0
  sm_.error(node->getSourceRange(), "invalid assignment left-hand side");
1205
0
}
1206
1207
23.2k
void SemanticValidator::setDirectiveDerivedInfo(FunctionLikeNode *node) {
1208
23.2k
  node->strictness = ESTree::makeStrictness(curFunction()->strictMode);
1209
23.2k
  node->sourceVisibility = curFunction()->sourceVisibility;
1210
23.2k
}
1211
1212
LabelDecorationBase *SemanticValidator::getLabelDecorationBase(
1213
0
    StatementNode *node) {
1214
0
  if (auto *LS = dyn_cast<LoopStatementNode>(node))
1215
0
    return LS;
1216
0
  if (auto *SS = dyn_cast<SwitchStatementNode>(node))
1217
0
    return SS;
1218
0
  if (auto *BS = dyn_cast<BreakStatementNode>(node))
1219
0
    return BS;
1220
0
  if (auto *CS = dyn_cast<ContinueStatementNode>(node))
1221
0
    return CS;
1222
0
  if (auto *LabS = dyn_cast<LabeledStatementNode>(node))
1223
0
    return LabS;
1224
0
  llvm_unreachable("invalid node type");
1225
0
  return nullptr;
1226
0
}
1227
1228
4
void SemanticValidator::recursionDepthExceeded(Node *n) {
1229
4
  sm_.error(
1230
4
      n->getEndLoc(), "Too many nested expressions/statements/declarations");
1231
4
}
1232
1233
void SemanticValidator::reportRedeclaredIdentifier(
1234
    const IdentifierNode &id1,
1235
0
    const IdentifierNode &id2) {
1236
  // The redeclared ID is the one that appears later in the source code.
1237
0
  const IdentifierNode &redeclaredId = id1.getSourceRange().Start.getPointer() <
1238
0
          id2.getSourceRange().Start.getPointer()
1239
0
      ? id2
1240
0
      : id1;
1241
  // The original ID is the one that appears first in the source code.
1242
0
  const IdentifierNode &originalId = &redeclaredId == &id2 ? id1 : id2;
1243
1244
0
  sm_.error(
1245
0
      redeclaredId.getSourceRange(),
1246
0
      "Identifier '" + redeclaredId._name->str() +
1247
0
          "' has already been declared");
1248
0
  sm_.note(
1249
0
      originalId.getSourceRange(),
1250
0
      "'" + redeclaredId._name->str() + "' previously defined here.");
1251
0
  return;
1252
0
}
1253
1254
//===----------------------------------------------------------------------===//
1255
// BlockContext
1256
1257
/// Helper function that ensures the given \p ptr is not nullptr. If it is,
1258
/// \p ptr will be initialized to a new \p T. \return \p ptr.
1259
template <typename T>
1260
46.5k
std::unique_ptr<T> &initializeIfNull(std::unique_ptr<T> &ptr) {
1261
46.5k
  if (!ptr) {
1262
46.5k
    ptr.reset(new T);
1263
46.5k
  }
1264
46.5k
  return ptr;
1265
46.5k
}
std::__1::unique_ptr<llvh::SmallVector<hermes::sem::FunctionInfo::VarDecl, 4u>, std::__1::default_delete<llvh::SmallVector<hermes::sem::FunctionInfo::VarDecl, 4u> > >& hermes::sem::initializeIfNull<llvh::SmallVector<hermes::sem::FunctionInfo::VarDecl, 4u> >(std::__1::unique_ptr<llvh::SmallVector<hermes::sem::FunctionInfo::VarDecl, 4u>, std::__1::default_delete<llvh::SmallVector<hermes::sem::FunctionInfo::VarDecl, 4u> > >&)
Line
Count
Source
1260
23.2k
std::unique_ptr<T> &initializeIfNull(std::unique_ptr<T> &ptr) {
1261
23.2k
  if (!ptr) {
1262
23.2k
    ptr.reset(new T);
1263
23.2k
  }
1264
23.2k
  return ptr;
1265
23.2k
}
std::__1::unique_ptr<llvh::SmallVector<hermes::ESTree::FunctionDeclarationNode*, 2u>, std::__1::default_delete<llvh::SmallVector<hermes::ESTree::FunctionDeclarationNode*, 2u> > >& hermes::sem::initializeIfNull<llvh::SmallVector<hermes::ESTree::FunctionDeclarationNode*, 2u> >(std::__1::unique_ptr<llvh::SmallVector<hermes::ESTree::FunctionDeclarationNode*, 2u>, std::__1::default_delete<llvh::SmallVector<hermes::ESTree::FunctionDeclarationNode*, 2u> > >&)
Line
Count
Source
1260
23.2k
std::unique_ptr<T> &initializeIfNull(std::unique_ptr<T> &ptr) {
1261
23.2k
  if (!ptr) {
1262
23.2k
    ptr.reset(new T);
1263
23.2k
  }
1264
23.2k
  return ptr;
1265
23.2k
}
1266
1267
BlockContext::BlockContext(
1268
    SemanticValidator *validator,
1269
    FunctionContext *curFunction,
1270
    Node *nextScopeNode)
1271
23.2k
    : validator_(validator),
1272
23.2k
      curFunction_(curFunction),
1273
23.2k
      previousScopedDecls_(curFunction_->scopedDecls),
1274
23.2k
      previousScopedClosures_(curFunction_->scopedClosures),
1275
23.2k
      varDeclaredBegin_(curFunction_->semInfo->varScoped.size()) {
1276
23.2k
  if (nextScopeNode) {
1277
    // nextScopeNode is nullptr for lazy compilation's wrapper context -- in
1278
    // which case there is no need for setting up the block environment.
1279
1280
23.2k
    if (!validator->blockScopingEnabled()) {
1281
      // Block scope is disabled, so short-circuit nextScopeNode to be the
1282
      // function body (or the Program node if the semantic validator is
1283
      // currently traversing the global scope). This means all declarations
1284
      // will be placed in the top-level function/global scope.
1285
23.2k
      nextScopeNode = curFunction->body;
1286
23.2k
    }
1287
1288
    // Now set up curFunction_'s scopedDecls and scopedClosures pointer. Note
1289
    // that this will either create new containers (when block scoping is
1290
    // enabled), or reuse the existing containers for the function's top-level
1291
    // scope
1292
23.2k
    curFunction_->scopedDecls =
1293
23.2k
        initializeIfNull(curFunction_->semInfo->lexicallyScoped[nextScopeNode])
1294
23.2k
            .get();
1295
23.2k
    curFunction_->scopedClosures =
1296
23.2k
        initializeIfNull(curFunction_->semInfo->closures[nextScopeNode]).get();
1297
23.2k
  }
1298
23.2k
}
1299
1300
23.2k
BlockContext::~BlockContext() {
1301
23.2k
  curFunction_->scopedDecls = previousScopedDecls_;
1302
23.2k
  curFunction_->scopedClosures = previousScopedClosures_;
1303
23.2k
}
1304
1305
0
void BlockContext::stopHoisting(IdentifierNode *id) {
1306
  // The hoisting candidates are stored in a map of name to list of all known
1307
  // functions with that name. Therefore, if name is in hoistingCandidates_,
1308
  // clearing the list is all that's needed to stop function hoisting. Note
1309
  // that the code __clears__ the list instead of removing it from the map, thus
1310
  // preserving any memory allocated by the list (so, in case the same
1311
  // identifier appears again the compiler won't incur in (possibly) heap
1312
  // allocating memory).
1313
0
  auto it = curFunction_->hoistingCandidates_.find(id->_name);
1314
0
  if (it != curFunction_->hoistingCandidates_.end()) {
1315
0
    curFunction_->hoistingCandidates_.erase(it);
1316
0
  }
1317
0
}
1318
1319
void BlockContext::ensureScopedNamesAreUnique(
1320
    IsFunctionBody isFunctionBody,
1321
23.2k
    IdentifierNode *catchParam) {
1322
23.2k
  if (!validator_->blockScopingEnabled()) {
1323
23.2k
    return;
1324
23.2k
  }
1325
1326
0
  if (isFunctionBody == IsFunctionBody::Yes) {
1327
0
    if (!curFunction_->scopedClosures) {
1328
      // This happens during semantic validation for lazy compilation.
1329
0
      return;
1330
0
    }
1331
0
  }
1332
1333
0
  llvh::SmallDenseMap<UniqueString *, IdentifierNode *, 8>
1334
0
      lexicallyDeclaredNames;
1335
1336
  // It is a Syntax Error if the LexicallyDeclaredNames of StatementList
1337
  // contains any duplicate entries. LexicallyDeclaredNames includes let/const
1338
  // declarations. Function identifiers are not considered
1339
  // LexicallyDeclaredNames in function scopes.
1340
0
  if (isFunctionBody != IsFunctionBody::Yes) {
1341
    // Keep track of all scopedClosures that are not regular functions (i.e.,
1342
    // generators and async functions).
1343
0
    llvh::SmallDenseSet<UniqueString *, 8> generatorOrAsync;
1344
0
    for (FunctionDeclarationNode *scopedClosure :
1345
0
         *curFunction_->scopedClosures) {
1346
0
      auto *funName =
1347
0
          llvh::dyn_cast_or_null<IdentifierNode>(scopedClosure->_id);
1348
1349
0
      if (!funName) {
1350
        // Anonymous function names are always unique.
1351
0
        assert(
1352
0
            !scopedClosure->_id &&
1353
0
            "FunctionLikeNode's _id is not an IdentifierNode");
1354
0
        continue;
1355
0
      }
1356
1357
      // ES2023 B.3.2.4 requires that duplicate identifiers within
1358
      // FunctionDeclarations is not an error in non-strict mode. Thus, keep
1359
      // track of the closures that are not regular function declarations so the
1360
      // error can be reported. N.B.: adding the name here ensures that, should
1361
      // the check for duplicate below fail, an error would still be reported
1362
      // even if all previous instances of the duplicate symbol were
1363
      // FunctionDeclarations and scopedClosure was not.
1364
0
      if (ESTree::isAsync(scopedClosure) || scopedClosure->_generator) {
1365
0
        generatorOrAsync.insert(funName->_name);
1366
0
      }
1367
1368
0
      auto res = lexicallyDeclaredNames.insert(
1369
0
          std::make_pair(funName->_name, funName));
1370
0
      if (!res.second) {
1371
        // ES2023 B.3.2.4 Changes to Block Static Semantics: Early Errors
1372
        //
1373
        // Block: {StatementList}
1374
        //     It is a Syntax Error if the LexicallyDeclaredNames of
1375
        //     StatementList contains any duplicate entries, **unless the
1376
        //     source code matching this production is not strict mode code
1377
        //     and the duplicate entries are only bound by
1378
        //     FunctionDeclarations**.
1379
0
        if (ESTree::isStrict(scopedClosure->strictness) ||
1380
0
            generatorOrAsync.count(funName->_name)) {
1381
0
          validator_->reportRedeclaredIdentifier(*res.first->second, *funName);
1382
0
          return;
1383
0
        }
1384
1385
        // Keep the ID that was declared earliest in the JS source. This is fine
1386
        // since the validation stops on the first duplicate ID found.
1387
0
        if (funName->getSourceRange().Start.getPointer() <
1388
0
            res.first->second->getSourceRange().Start.getPointer()) {
1389
0
          res.first->second = funName;
1390
0
        }
1391
0
      }
1392
0
    }
1393
0
  }
1394
1395
  // Nothing special for const/let declarations -- thus, just iterate over them,
1396
  // and complain about duplicates.
1397
0
  for (const FunctionInfo::VarDecl &scopedDecl : *curFunction_->scopedDecls) {
1398
    // According to ES2023 B.3.2.1 and ES2023 B.3.2.2 functions should not be
1399
    // hoisted if doing so would cause early errors. Therefore, any functions
1400
    // that share its ID with scopedDecl cannot possibly be hoisted past this
1401
    // scope.
1402
0
    stopHoisting(scopedDecl.identifier);
1403
1404
0
    auto res = lexicallyDeclaredNames.insert(
1405
0
        std::make_pair(scopedDecl.identifier->_name, scopedDecl.identifier));
1406
0
    if (!res.second) {
1407
0
      validator_->reportRedeclaredIdentifier(
1408
0
          *res.first->second, *scopedDecl.identifier);
1409
0
      return;
1410
0
    }
1411
0
  }
1412
1413
0
  if (catchParam) {
1414
0
    auto it = lexicallyDeclaredNames.find(catchParam->_name);
1415
0
    if (it != lexicallyDeclaredNames.end()) {
1416
0
      validator_->reportRedeclaredIdentifier(*it->second, *catchParam);
1417
0
      return;
1418
0
    }
1419
0
  }
1420
1421
  // Now ensure that the var decls in this scope don't clash with its
1422
  // LexicallyDeclaredNames.
1423
0
  for (auto it = curFunction_->semInfo->varScoped.begin() + varDeclaredBegin_,
1424
0
            end = curFunction_->semInfo->varScoped.end();
1425
0
       it != end;
1426
0
       ++it) {
1427
0
    IdentifierNode *name = it->identifier;
1428
0
    auto pos = lexicallyDeclaredNames.find(name->_name);
1429
0
    if (pos != lexicallyDeclaredNames.end()) {
1430
0
      validator_->reportRedeclaredIdentifier(*pos->second, *name);
1431
0
      return;
1432
0
    }
1433
0
  }
1434
0
}
1435
1436
//===----------------------------------------------------------------------===//
1437
// FunctionContext
1438
1439
FunctionContext::FunctionContext(
1440
    SemanticValidator *validator,
1441
    bool strictMode,
1442
    FunctionLikeNode *node,
1443
    Node *body,
1444
    SourceVisibility sourceVisibility)
1445
23.2k
    : validator_(validator),
1446
23.2k
      oldContextValue_(validator->funcCtx_),
1447
23.2k
      node(node),
1448
23.2k
      body(body),
1449
23.2k
      semInfo(validator->semCtx_.createFunction()),
1450
23.2k
      varDecls(&semInfo->varScoped),
1451
23.2k
      strictMode(strictMode),
1452
23.2k
      sourceVisibility(sourceVisibility),
1453
23.2k
      functionScope_(validator, this, body) {
1454
23.2k
  validator->funcCtx_ = this;
1455
1456
23.2k
  if (node)
1457
23.2k
    node->setSemInfo(semInfo);
1458
23.2k
}
1459
1460
23.2k
FunctionContext::~FunctionContext() {
1461
23.2k
  functionScope_.ensureScopedNamesAreUnique(BlockContext::IsFunctionBody::Yes);
1462
23.2k
  validator_->funcCtx_ = oldContextValue_;
1463
23.2k
  finalizeHoisting();
1464
23.2k
}
1465
1466
0
void FunctionContext::addHoistingCandidate(FunctionDeclarationNode *funDecl) {
1467
0
  auto *funDeclId = llvh::cast<IdentifierNode>(funDecl->_id);
1468
1469
0
  if (functionHoistingEnabled()) {
1470
0
    hoistingCandidates_[funDeclId->_name].emplace_back(funDecl);
1471
0
  }
1472
1473
0
  scopedClosures->emplace_back(funDecl);
1474
0
}
1475
1476
23.2k
void FunctionContext::finalizeHoisting() {
1477
23.2k
  assert(
1478
23.2k
      (functionHoistingEnabled() || hoistingCandidates_.size() == 0) &&
1479
23.2k
      "should not have hoisting candidates in strict mode.");
1480
1481
23.2k
  if (node && !ESTree::isStrict(node->strictness)) {
1482
    // Hoisting only happens in non-strict mode per ES2023 B.3.2.1 and
1483
    // ES2023 B.3.2.2;
1484
23.2k
    for (const auto &[name, nodes] : hoistingCandidates_) {
1485
0
      assert(
1486
0
          !nodes.empty() && "empty vectors should be removed by stopHoisting");
1487
1488
      // Add a new var declaration to this function's varDecls. Only one
1489
      // declaration per identifier is needed regardless of how many
1490
      // functions with that id are hoisted.
1491
0
      FunctionDeclarationNode *first = nodes[0];
1492
0
      varDecls->emplace_back(
1493
0
          FunctionInfo::VarDecl::withoutInitializer(
1494
0
              FunctionInfo::VarDecl::Kind::Var,
1495
0
              cast<ESTree::IdentifierNode>(first->_id)));
1496
1497
      // Now mark all functions as hoisted, which prevents creation of the
1498
      // binding identifier below.
1499
0
      for (FunctionDeclarationNode *fdn : nodes) {
1500
0
        fdn->getSemInfo()->hoisted = true;
1501
0
      }
1502
0
    }
1503
23.2k
  }
1504
1505
  // Now add a scoped var decl (in the proper scope) for all functions that
1506
  // weren't hoisted.
1507
23.2k
  assert(
1508
23.2k
      (validator_->astContext_.getCodeGenerationSettings().enableBlockScoping ||
1509
23.2k
       semInfo->closures.size() <= 1) &&
1510
23.2k
      "All closures should be added to the same container when block scoping "
1511
23.2k
      "is disabled");
1512
23.2k
  for (auto &[containingNode, containingNodeClosures] : semInfo->closures) {
1513
23.2k
    if (containingNodeClosures->empty()) {
1514
23.2k
      continue;
1515
23.2k
    }
1516
1517
    // For nested functions at the top level of an enclosing function,
1518
    // the nested function is added to the enclosing function's
1519
    // var list.  For nested functions in blocks in an enclosing
1520
    // function, the nested function is added to the scope's
1521
    // list.  For functions in the global scope, the function
1522
    // is added to the global scope var list.  For functions
1523
    // in a scope nested in the global scope, the function is added
1524
    // to the scope's list.
1525
0
    FunctionInfo::BlockDecls *decls =
1526
0
        (containingNode == body && functionHoistingEnabled())
1527
0
        ? &semInfo->varScoped
1528
0
        : semInfo->lexicallyScoped[containingNode].get();
1529
1530
0
    for (auto it = containingNodeClosures->begin(),
1531
0
              end = containingNodeClosures->end();
1532
0
         it < end;
1533
0
         ++it) {
1534
0
      if (!(*it)->getSemInfo()->hoisted) {
1535
0
        decls->emplace_back(
1536
0
            FunctionInfo::VarDecl::withoutInitializer(
1537
0
                FunctionInfo::VarDecl::Kind::Var,
1538
0
                cast<ESTree::IdentifierNode>((*it)->_id)));
1539
0
      }
1540
0
    }
1541
0
  }
1542
23.2k
}
1543
} // namespace sem
1544
} // namespace hermes