• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/ast/source-range-ast-visitor.h"
6 
7 #include "src/ast/ast-source-ranges.h"
8 
9 namespace v8 {
10 namespace internal {
11 
SourceRangeAstVisitor(uintptr_t stack_limit,Expression * root,SourceRangeMap * source_range_map)12 SourceRangeAstVisitor::SourceRangeAstVisitor(uintptr_t stack_limit,
13                                              Expression* root,
14                                              SourceRangeMap* source_range_map)
15     : AstTraversalVisitor(stack_limit, root),
16       source_range_map_(source_range_map) {}
17 
VisitBlock(Block * stmt)18 void SourceRangeAstVisitor::VisitBlock(Block* stmt) {
19   AstTraversalVisitor::VisitBlock(stmt);
20   ZonePtrList<Statement>* stmts = stmt->statements();
21   AstNodeSourceRanges* enclosingSourceRanges = source_range_map_->Find(stmt);
22   if (enclosingSourceRanges != nullptr) {
23     CHECK(enclosingSourceRanges->HasRange(SourceRangeKind::kContinuation));
24     MaybeRemoveLastContinuationRange(stmts);
25   }
26 }
27 
VisitSwitchStatement(SwitchStatement * stmt)28 void SourceRangeAstVisitor::VisitSwitchStatement(SwitchStatement* stmt) {
29   AstTraversalVisitor::VisitSwitchStatement(stmt);
30   ZonePtrList<CaseClause>* clauses = stmt->cases();
31   for (CaseClause* clause : *clauses) {
32     MaybeRemoveLastContinuationRange(clause->statements());
33   }
34 }
35 
VisitFunctionLiteral(FunctionLiteral * expr)36 void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
37   AstTraversalVisitor::VisitFunctionLiteral(expr);
38   ZonePtrList<Statement>* stmts = expr->body();
39   MaybeRemoveLastContinuationRange(stmts);
40 }
41 
VisitTryCatchStatement(TryCatchStatement * stmt)42 void SourceRangeAstVisitor::VisitTryCatchStatement(TryCatchStatement* stmt) {
43   AstTraversalVisitor::VisitTryCatchStatement(stmt);
44   MaybeRemoveContinuationRange(stmt->try_block());
45   MaybeRemoveContinuationRangeOfAsyncReturn(stmt);
46 }
47 
VisitTryFinallyStatement(TryFinallyStatement * stmt)48 void SourceRangeAstVisitor::VisitTryFinallyStatement(
49     TryFinallyStatement* stmt) {
50   AstTraversalVisitor::VisitTryFinallyStatement(stmt);
51   MaybeRemoveContinuationRange(stmt->try_block());
52 }
53 
VisitNode(AstNode * node)54 bool SourceRangeAstVisitor::VisitNode(AstNode* node) {
55   AstNodeSourceRanges* range = source_range_map_->Find(node);
56 
57   if (range == nullptr) return true;
58   if (!range->HasRange(SourceRangeKind::kContinuation)) return true;
59 
60   // Called in pre-order. In case of conflicting continuation ranges, only the
61   // outermost range may survive.
62 
63   SourceRange continuation = range->GetRange(SourceRangeKind::kContinuation);
64   if (continuation_positions_.find(continuation.start) !=
65       continuation_positions_.end()) {
66     range->RemoveContinuationRange();
67   } else {
68     continuation_positions_.emplace(continuation.start);
69   }
70 
71   return true;
72 }
73 
MaybeRemoveContinuationRange(Statement * last_statement)74 void SourceRangeAstVisitor::MaybeRemoveContinuationRange(
75     Statement* last_statement) {
76   AstNodeSourceRanges* last_range = nullptr;
77 
78   if (last_statement->IsExpressionStatement() &&
79       last_statement->AsExpressionStatement()->expression()->IsThrow()) {
80     // For ThrowStatement, source range is tied to Throw expression not
81     // ExpressionStatement.
82     last_range = source_range_map_->Find(
83         last_statement->AsExpressionStatement()->expression());
84   } else {
85     last_range = source_range_map_->Find(last_statement);
86   }
87 
88   if (last_range == nullptr) return;
89 
90   if (last_range->HasRange(SourceRangeKind::kContinuation)) {
91     last_range->RemoveContinuationRange();
92   }
93 }
94 
MaybeRemoveLastContinuationRange(ZonePtrList<Statement> * statements)95 void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange(
96     ZonePtrList<Statement>* statements) {
97   if (statements->is_empty()) return;
98   MaybeRemoveContinuationRange(statements->last());
99 }
100 
101 namespace {
FindLastNonSyntheticStatement(ZonePtrList<Statement> * statements)102 Statement* FindLastNonSyntheticStatement(ZonePtrList<Statement>* statements) {
103   for (int i = statements->length() - 1; i >= 0; --i) {
104     Statement* stmt = statements->at(i);
105     if (stmt->IsReturnStatement() &&
106         stmt->AsReturnStatement()->is_synthetic_async_return()) {
107       continue;
108     }
109     return stmt;
110   }
111   return nullptr;
112 }
113 }  // namespace
114 
MaybeRemoveContinuationRangeOfAsyncReturn(TryCatchStatement * try_catch_stmt)115 void SourceRangeAstVisitor::MaybeRemoveContinuationRangeOfAsyncReturn(
116     TryCatchStatement* try_catch_stmt) {
117   // Detect try-catch inserted by NewTryCatchStatementForAsyncAwait in the
118   // parser (issued for async functions, including async generators), and
119   // remove the continuation range of the last statement, such that the
120   // range of the enclosing function body is used.
121   if (try_catch_stmt->is_try_catch_for_async()) {
122     Statement* last_non_synthetic =
123       FindLastNonSyntheticStatement(try_catch_stmt->try_block()->statements());
124     if (last_non_synthetic) {
125       MaybeRemoveContinuationRange(last_non_synthetic);
126     }
127   }
128 }
129 
130 }  // namespace internal
131 }  // namespace v8
132