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 9namespace v8 { 10namespace internal { 11 12SourceRangeAstVisitor::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 18void 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 28void 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 36void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) { 37 AstTraversalVisitor::VisitFunctionLiteral(expr); 38 ZonePtrList<Statement>* stmts = expr->body(); 39 MaybeRemoveLastContinuationRange(stmts); 40} 41 42void SourceRangeAstVisitor::VisitTryCatchStatement(TryCatchStatement* stmt) { 43 AstTraversalVisitor::VisitTryCatchStatement(stmt); 44 MaybeRemoveContinuationRange(stmt->try_block()); 45 MaybeRemoveContinuationRangeOfAsyncReturn(stmt); 46} 47 48void SourceRangeAstVisitor::VisitTryFinallyStatement( 49 TryFinallyStatement* stmt) { 50 AstTraversalVisitor::VisitTryFinallyStatement(stmt); 51 MaybeRemoveContinuationRange(stmt->try_block()); 52} 53 54bool 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 74void 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 95void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange( 96 ZonePtrList<Statement>* statements) { 97 if (statements->is_empty()) return; 98 MaybeRemoveContinuationRange(statements->last()); 99} 100 101namespace { 102Statement* 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 115void 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