| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 68ffe5a commit fdb9812
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -47,6 +47,7 @@ struct SourceRange { | |||
| 47 | 47 | V(Block) \ | |
| 48 | 48 | V(CaseClause) \ | |
| 49 | 49 | V(Conditional) \ | |
| 50 | + V(Expression) \ | ||
| 50 | 51 | V(FunctionLiteral) \ | |
| 51 | 52 | V(IfStatement) \ | |
| 52 | 53 | V(IterationStatement) \ | |
@@ -281,6 +282,24 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges { | |||
| 281 | 282 | ZoneVector<SourceRange> ranges_; | |
| 282 | 283 | }; | |
| 283 | 284 | ||
| 285 | + class ExpressionSourceRanges final : public AstNodeSourceRanges { | ||
| 286 | + public: | ||
| 287 | + explicit ExpressionSourceRanges(const SourceRange& right_range) | ||
| 288 | + : right_range_(right_range) {} | ||
| 289 | + | ||
| 290 | + SourceRange GetRange(SourceRangeKind kind) override { | ||
| 291 | + DCHECK(HasRange(kind)); | ||
| 292 | + return right_range_; | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + bool HasRange(SourceRangeKind kind) override { | ||
| 296 | + return kind == SourceRangeKind::kRight; | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + private: | ||
| 300 | + SourceRange right_range_; | ||
| 301 | + }; | ||
| 302 | + | ||
| 284 | 303 | class SuspendSourceRanges final : public ContinuationSourceRanges { | |
| 285 | 304 | public: | |
| 286 | 305 | explicit SuspendSourceRanges(int32_t continuation_position) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4575,8 +4575,11 @@ void BytecodeGenerator::VisitThrow(Throw* expr) { | |||
| 4575 | 4575 | void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { | |
| 4576 | 4576 | if (property->is_optional_chain_link()) { | |
| 4577 | 4577 | DCHECK_NOT_NULL(optional_chaining_null_labels_); | |
| 4578 | + int right_range = | ||
| 4579 | + AllocateBlockCoverageSlotIfEnabled(property, SourceRangeKind::kRight); | ||
| 4578 | 4580 | builder()->LoadAccumulatorWithRegister(obj).JumpIfUndefinedOrNull( | |
| 4579 | 4581 | optional_chaining_null_labels_->New()); | |
| 4582 | + BuildIncrementBlockCoverageCounterIfEnabled(right_range); | ||
| 4580 | 4583 | } | |
| 4581 | 4584 | ||
| 4582 | 4585 | AssignType property_kind = Property::GetAssignType(property); | |
@@ -4902,8 +4905,11 @@ void BytecodeGenerator::VisitCall(Call* expr) { | |||
| 4902 | 4905 | ||
| 4903 | 4906 | if (expr->is_optional_chain_link()) { | |
| 4904 | 4907 | DCHECK_NOT_NULL(optional_chaining_null_labels_); | |
| 4908 | + int right_range = | ||
| 4909 | + AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kRight); | ||
| 4905 | 4910 | builder()->LoadAccumulatorWithRegister(callee).JumpIfUndefinedOrNull( | |
| 4906 | 4911 | optional_chaining_null_labels_->New()); | |
| 4912 | + BuildIncrementBlockCoverageCounterIfEnabled(right_range); | ||
| 4907 | 4913 | } | |
| 4908 | 4914 | ||
| 4909 | 4915 | // Evaluate all arguments to the function call and store in sequential args | |
@@ -5175,7 +5181,10 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) { | |||
| 5175 | 5181 | OptionalChainNullLabelScope label_scope(this); | |
| 5176 | 5182 | VisitForAccumulatorValue(property->obj()); | |
| 5177 | 5183 | if (property->is_optional_chain_link()) { | |
| 5184 | + int right_range = AllocateBlockCoverageSlotIfEnabled( | ||
| 5185 | + property, SourceRangeKind::kRight); | ||
| 5178 | 5186 | builder()->JumpIfUndefinedOrNull(label_scope.labels()->New()); | |
| 5187 | + BuildIncrementBlockCoverageCounterIfEnabled(right_range); | ||
| 5179 | 5188 | } | |
| 5180 | 5189 | Register object = register_allocator()->NewRegister(); | |
| 5181 | 5190 | builder()->StoreAccumulatorInRegister(object); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3289,17 +3289,24 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { | |||
| 3289 | 3289 | ||
| 3290 | 3290 | bool optional_chaining = false; | |
| 3291 | 3291 | bool is_optional = false; | |
| 3292 | + int optional_link_begin; | ||
| 3292 | 3293 | do { | |
| 3293 | 3294 | switch (peek()) { | |
| 3294 | 3295 | case Token::QUESTION_PERIOD: { | |
| 3295 | 3296 | if (is_optional) { | |
| 3296 | 3297 | ReportUnexpectedToken(peek()); | |
| 3297 | 3298 | return impl()->FailureExpression(); | |
| 3298 | 3299 | } | |
| 3300 | + // Include the ?. in the source range position. | ||
| 3301 | + optional_link_begin = scanner()->peek_location().beg_pos; | ||
| 3299 | 3302 | Consume(Token::QUESTION_PERIOD); | |
| 3300 | 3303 | is_optional = true; | |
| 3301 | 3304 | optional_chaining = true; | |
| 3302 | - continue; | ||
| 3305 | + if (Token::IsPropertyOrCall(peek())) continue; | ||
| 3306 | + int pos = position(); | ||
| 3307 | + ExpressionT key = ParsePropertyOrPrivatePropertyName(); | ||
| 3308 | + result = factory()->NewProperty(result, key, pos, is_optional); | ||
| 3309 | + break; | ||
| 3303 | 3310 | } | |
| 3304 | 3311 | ||
| 3305 | 3312 | /* Property */ | |
@@ -3379,14 +3386,7 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { | |||
| 3379 | 3386 | } | |
| 3380 | 3387 | ||
| 3381 | 3388 | default: | |
| 3382 | - /* Optional Property */ | ||
| 3383 | - if (is_optional) { | ||
| 3384 | - DCHECK_EQ(scanner()->current_token(), Token::QUESTION_PERIOD); | ||
| 3385 | - int pos = position(); | ||
| 3386 | - ExpressionT key = ParsePropertyOrPrivatePropertyName(); | ||
| 3387 | - result = factory()->NewProperty(result, key, pos, is_optional); | ||
| 3388 | - break; | ||
| 3389 | - } | ||
| 3389 | + // Template literals in/after an Optional Chain not supported: | ||
| 3390 | 3390 | if (optional_chaining) { | |
| 3391 | 3391 | impl()->ReportMessageAt(scanner()->peek_location(), | |
| 3392 | 3392 | MessageTemplate::kOptionalChainingNoTemplate); | |
@@ -3397,8 +3397,12 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { | |||
| 3397 | 3397 | result = ParseTemplateLiteral(result, position(), true); | |
| 3398 | 3398 | break; | |
| 3399 | 3399 | } | |
| 3400 | - is_optional = false; | ||
| 3401 | - } while (is_optional || Token::IsPropertyOrCall(peek())); | ||
| 3400 | + if (is_optional) { | ||
| 3401 | + SourceRange chain_link_range(optional_link_begin, end_position()); | ||
| 3402 | + impl()->RecordExpressionSourceRange(result, chain_link_range); | ||
| 3403 | + is_optional = false; | ||
| 3404 | + } | ||
| 3405 | + } while (Token::IsPropertyOrCall(peek())); | ||
| 3402 | 3406 | if (optional_chaining) return factory()->NewOptionalChain(result); | |
| 3403 | 3407 | return result; | |
| 3404 | 3408 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -997,6 +997,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { | |||
| 997 | 997 | node, zone()->New<IterationStatementSourceRanges>(body_range)); | |
| 998 | 998 | } | |
| 999 | 999 | ||
| 1000 | + // Used to record source ranges of expressions associated with optional chain: | ||
| 1001 | + V8_INLINE void RecordExpressionSourceRange(Expression* node, | ||
| 1002 | + const SourceRange& right_range) { | ||
| 1003 | + if (source_range_map_ == nullptr) return; | ||
| 1004 | + source_range_map_->Insert(node, | ||
| 1005 | + zone()->New<ExpressionSourceRanges>(right_range)); | ||
| 1006 | + } | ||
| 1007 | + | ||
| 1000 | 1008 | V8_INLINE void RecordSuspendSourceRange(Expression* node, | |
| 1001 | 1009 | int32_t continuation_position) { | |
| 1002 | 1010 | if (source_range_map_ == nullptr) return; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1177,7 +1177,7 @@ a(true); // 0500 | |||
| 1177 | 1177 | {"start":0,"end":401,"count":2}, | |
| 1178 | 1178 | {"start":154,"end":254,"count":0}]); | |
| 1179 | 1179 | ||
| 1180 | - TestCoverage( | ||
| 1180 | + TestCoverage( | ||
| 1181 | 1181 | "https://crbug.com/v8/11231 - nullish coalescing", | |
| 1182 | 1182 | ` | |
| 1183 | 1183 | const a = true // 0000 | |
@@ -1195,4 +1195,41 @@ const i = c ?? b ?? 'hello' // 0400 | |||
| 1195 | 1195 | {"start":262,"end":274,"count":0}, | |
| 1196 | 1196 | {"start":417,"end":427,"count":0}]); | |
| 1197 | 1197 | ||
| 1198 | + TestCoverage( | ||
| 1199 | + "Optional Chaining", | ||
| 1200 | + ` | ||
| 1201 | + const a = undefined || null // 0000 | ||
| 1202 | + const b = a?.b // 0050 | ||
| 1203 | + const c = a?.['b'] // 0100 | ||
| 1204 | + const d = { // 0150 | ||
| 1205 | + e: {f: 99, g: () => {return undefined}} // 0200 | ||
| 1206 | + } // 0250 | ||
| 1207 | + const e = d?.e?.f // 0300 | ||
| 1208 | + const f = d?.e?.['f'] // 0350 | ||
| 1209 | + const g = d?.e?.f?.g // 0400 | ||
| 1210 | + const h = d?.e?.f?.g?.h // 0450 | ||
| 1211 | + const i = d?.['d']?.['e']?.['h'] // 0500 | ||
| 1212 | + const k = a?.('b') // 0550 | ||
| 1213 | + const l = d?.e?.g?.() // 0600 | ||
| 1214 | + const m = d?.e?.g?.()?.a?.b // 0650 | ||
| 1215 | + delete a?.b // 0700 | ||
| 1216 | + const n = d?.[d?.x?.f] // 0750 | ||
| 1217 | + if (a?.[d?.x?.f]) { const p = 99 } else {}// 0800 | ||
| 1218 | + const p = d?.[d?.x?.f]?.x // 0850 | ||
| 1219 | + `, | ||
| 1220 | + [{"start":0,"end":899,"count":1}, | ||
| 1221 | + {"start":61,"end":64,"count":0}, | ||
| 1222 | + {"start":111,"end":118,"count":0}, | ||
| 1223 | + {"start":470,"end":473,"count":0}, | ||
| 1224 | + {"start":518,"end":532,"count":0}, | ||
| 1225 | + {"start":561,"end":568,"count":0}, | ||
| 1226 | + {"start":671,"end":677,"count":0}, | ||
| 1227 | + {"start":708,"end":711,"count":0}, | ||
| 1228 | + {"start":768,"end":771,"count":0}, | ||
| 1229 | + {"start":805,"end":816,"count":0}, | ||
| 1230 | + {"start":818,"end":834,"count":0}, | ||
| 1231 | + {"start":868,"end":871,"count":0}, | ||
| 1232 | + {"start":872,"end":875,"count":0}, | ||
| 1233 | + {"start":216,"end":240,"count":2}]); | ||
| 1234 | + | ||
| 1198 | 1235 | %DebugToggleBlockCoverage(false); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments