Skip to content

Commit 843bdbb

Browse files
committed
Fix the breakpoints in For Of destructuring
1 parent c5407a3 commit 843bdbb

5 files changed

Lines changed: 326 additions & 1045 deletions

src/services/breakpoints.ts

Lines changed: 72 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ namespace ts.BreakpointResolver {
4545
return createTextSpanFromBounds(start, (endNode || startNode).getEnd());
4646
}
4747

48+
function textSpanEndingAtNextToken(startNode: Node, previousTokenToFindNextEndToken: Node): TextSpan {
49+
return textSpan(startNode, findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent));
50+
}
51+
4852
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
4953
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line) {
5054
return spanInNode(node);
@@ -67,29 +71,33 @@ namespace ts.BreakpointResolver {
6771
function spanInNode(node: Node): TextSpan {
6872
if (node) {
6973
if (isExpression(node)) {
70-
if (node.parent.kind === SyntaxKind.DoStatement) {
71-
// Set span as if on while keyword
72-
return spanInPreviousNode(node);
73-
}
74+
switch (node.parent.kind) {
75+
case SyntaxKind.DoStatement:
76+
// Set span as if on while keyword
77+
return spanInPreviousNode(node);
7478

75-
if (node.parent.kind === SyntaxKind.Decorator) {
76-
// Set breakpoint on the decorator emit
77-
return spanInNode(node.parent);
78-
}
79+
case SyntaxKind.Decorator:
80+
// Set breakpoint on the decorator emit
81+
return spanInNode(node.parent);
7982

80-
if (node.parent.kind === SyntaxKind.ForStatement) {
81-
// For now lets set the span on this expression, fix it later
82-
return textSpan(node);
83-
}
83+
case SyntaxKind.ForStatement:
84+
case SyntaxKind.ForOfStatement:
85+
// For now lets set the span on this expression, fix it later
86+
return textSpan(node);
8487

85-
if (node.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.CommaToken) {
86-
// if this is comma expression, the breakpoint is possible in this expression
87-
return textSpan(node);
88-
}
88+
case SyntaxKind.BinaryExpression:
89+
if ((<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.CommaToken) {
90+
// if this is comma expression, the breakpoint is possible in this expression
91+
return textSpan(node);
92+
}
93+
break;
8994

90-
if (node.parent.kind === SyntaxKind.ArrowFunction && (<FunctionLikeDeclaration>node.parent).body === node) {
91-
// If this is body of arrow function, it is allowed to have the breakpoint
92-
return textSpan(node);
95+
case SyntaxKind.ArrowFunction:
96+
if ((<FunctionLikeDeclaration>node.parent).body === node) {
97+
// If this is body of arrow function, it is allowed to have the breakpoint
98+
return textSpan(node);
99+
}
100+
break;
93101
}
94102
}
95103

@@ -137,7 +145,7 @@ namespace ts.BreakpointResolver {
137145

138146
case SyntaxKind.WhileStatement:
139147
// Span on while(...)
140-
return textSpan(node, findNextToken((<WhileStatement>node).expression, node));
148+
return textSpanEndingAtNextToken(node, (<WhileStatement>node).expression);
141149

142150
case SyntaxKind.DoStatement:
143151
// span in statement of the do statement
@@ -149,7 +157,7 @@ namespace ts.BreakpointResolver {
149157

150158
case SyntaxKind.IfStatement:
151159
// set on if(..) span
152-
return textSpan(node, findNextToken((<IfStatement>node).expression, node));
160+
return textSpanEndingAtNextToken(node, (<IfStatement>node).expression);
153161

154162
case SyntaxKind.LabeledStatement:
155163
// span in statement
@@ -164,13 +172,16 @@ namespace ts.BreakpointResolver {
164172
return spanInForStatement(<ForStatement>node);
165173

166174
case SyntaxKind.ForInStatement:
175+
// span of for (a in ...)
176+
return textSpanEndingAtNextToken(node, (<ForInStatement>node).expression);
177+
167178
case SyntaxKind.ForOfStatement:
168-
// span on for (a in ...)
169-
return textSpan(node, findNextToken((<ForInStatement | ForOfStatement>node).expression, node));
179+
// span in initializer
180+
return spanInInitializerOfForLike(<ForOfStatement | ForInStatement>node);
170181

171182
case SyntaxKind.SwitchStatement:
172183
// span on switch(...)
173-
return textSpan(node, findNextToken((<SwitchStatement>node).expression, node));
184+
return textSpanEndingAtNextToken(node, (<SwitchStatement>node).expression);
174185

175186
case SyntaxKind.CaseClause:
176187
case SyntaxKind.DefaultClause:
@@ -271,6 +282,9 @@ namespace ts.BreakpointResolver {
271282
case SyntaxKind.FinallyKeyword:
272283
return spanInNextNode(node);
273284

285+
case SyntaxKind.OfKeyword:
286+
return spanInOfKeyword(node);
287+
274288
default:
275289
// If this is name of property assignment, set breakpoint in the initializer
276290
if (node.parent.kind === SyntaxKind.PropertyAssignment && (<PropertyDeclaration>node.parent).name === node) {
@@ -317,18 +331,20 @@ namespace ts.BreakpointResolver {
317331

318332
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
319333
// If declaration of for in statement, just set the span in parent
320-
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement ||
321-
variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
334+
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
322335
return spanInNode(variableDeclaration.parent.parent);
323336
}
324-
337+
325338
// If this is a destructuring pattern set breakpoint in binding pattern
326339
if (isBindingPattern(variableDeclaration.name)) {
327340
return spanInBindingPattern(<BindingPattern>variableDeclaration.name);
328341
}
329342

330343
// Breakpoint is possible in variableDeclaration only if there is initialization
331-
if (variableDeclaration.initializer || (variableDeclaration.flags & NodeFlags.Export)) {
344+
// or its declaration from 'for of'
345+
if (variableDeclaration.initializer ||
346+
(variableDeclaration.flags & NodeFlags.Export) ||
347+
variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
332348
return textSpanFromVariableDeclaration(variableDeclaration);
333349
}
334350

@@ -410,29 +426,35 @@ namespace ts.BreakpointResolver {
410426
case SyntaxKind.WhileStatement:
411427
case SyntaxKind.IfStatement:
412428
case SyntaxKind.ForInStatement:
413-
case SyntaxKind.ForOfStatement:
414429
return spanInNodeIfStartsOnSameLine(block.parent, block.statements[0]);
415430

416431
// Set span on previous token if it starts on same line otherwise on the first statement of the block
417432
case SyntaxKind.ForStatement:
433+
case SyntaxKind.ForOfStatement:
418434
return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]);
419435
}
420436

421437
// Default action is to set on first statement
422438
return spanInNode(block.statements[0]);
423439
}
424440

441+
function spanInInitializerOfForLike(forLikeStaement: ForStatement | ForOfStatement | ForInStatement): TextSpan {
442+
if (forLikeStaement.initializer.kind === SyntaxKind.VariableDeclarationList) {
443+
// declaration list, set breakpoint in first declaration
444+
let variableDeclarationList = <VariableDeclarationList>forLikeStaement.initializer;
445+
if (variableDeclarationList.declarations.length > 0) {
446+
return spanInNode(variableDeclarationList.declarations[0]);
447+
}
448+
}
449+
else {
450+
// Expression - set breakpoint in it
451+
return spanInNode(forLikeStaement.initializer);
452+
}
453+
}
454+
425455
function spanInForStatement(forStatement: ForStatement): TextSpan {
426456
if (forStatement.initializer) {
427-
if (forStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
428-
let variableDeclarationList = <VariableDeclarationList>forStatement.initializer;
429-
if (variableDeclarationList.declarations.length > 0) {
430-
return spanInNode(variableDeclarationList.declarations[0]);
431-
}
432-
}
433-
else {
434-
return spanInNode(forStatement.initializer);
435-
}
457+
return spanInInitializerOfForLike(forStatement);
436458
}
437459

438460
if (forStatement.condition) {
@@ -560,6 +582,7 @@ namespace ts.BreakpointResolver {
560582
case SyntaxKind.WhileStatement:
561583
case SyntaxKind.DoStatement:
562584
case SyntaxKind.ForStatement:
585+
case SyntaxKind.ForOfStatement:
563586
return spanInPreviousNode(node);
564587

565588
// Default to parent node
@@ -590,7 +613,17 @@ namespace ts.BreakpointResolver {
590613
function spanInWhileKeyword(node: Node): TextSpan {
591614
if (node.parent.kind === SyntaxKind.DoStatement) {
592615
// Set span on while expression
593-
return textSpan(node, findNextToken((<DoStatement>node.parent).expression, node.parent));
616+
return textSpanEndingAtNextToken(node, (<DoStatement>node.parent).expression);
617+
}
618+
619+
// Default to parent node
620+
return spanInNode(node.parent);
621+
}
622+
623+
function spanInOfKeyword(node: Node): TextSpan {
624+
if (node.parent.kind === SyntaxKind.ForOfStatement) {
625+
// set using next token
626+
return spanInNextNode(node);
594627
}
595628

596629
// Default to parent node

0 commit comments

Comments
 (0)