Changed logic for break/continue search in switch statements and loops.
Now if a labeled break in a switch refers to its original switch statement, we also highlight the 'switch' keyword. Also added tests for loop/break/continue.
This commit is contained in:
parent
69803d4d3c
commit
90dd327635
9 changed files with 561 additions and 37 deletions
|
@ -1359,11 +1359,19 @@ module ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SearchMeaning {
|
enum SearchMeaning {
|
||||||
|
None = 0x0,
|
||||||
Value = 0x1,
|
Value = 0x1,
|
||||||
Type = 0x2,
|
Type = 0x2,
|
||||||
Namespace = 0x4
|
Namespace = 0x4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum BreakContinueSearchType {
|
||||||
|
None = 0x0,
|
||||||
|
Unlabeled = 0x1,
|
||||||
|
Labeled = 0x2,
|
||||||
|
All = Unlabeled | Labeled
|
||||||
|
}
|
||||||
|
|
||||||
// A cache of completion entries for keywords, these do not change between sessions
|
// A cache of completion entries for keywords, these do not change between sessions
|
||||||
var keywordCompletions:CompletionEntry[] = [];
|
var keywordCompletions:CompletionEntry[] = [];
|
||||||
for (var i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) {
|
for (var i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) {
|
||||||
|
@ -2318,49 +2326,45 @@ module ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These track whether we can own unlabeled break/continues.
|
||||||
|
var breakSearchType = BreakContinueSearchType.All;
|
||||||
|
var continueSearchType = BreakContinueSearchType.All;
|
||||||
|
|
||||||
// This switch tracks whether or not we're traversing into a construct that takes
|
(function aggregateBreakContinues(node: Node) {
|
||||||
// ownership over unlabelled 'break'/'continue' statements.
|
// Remember the statuses of the flags before diving into the next node.
|
||||||
var onlyCheckLabelled = false;
|
var prevBreakSearchType = breakSearchType;
|
||||||
|
var prevContinueSearchType = continueSearchType;
|
||||||
forEachChild(loopNode.statement, function aggregateBreakContinues(node: Node) {
|
|
||||||
// This tracks the status of the flag before diving into the next node.
|
|
||||||
var lastOnlyCheckLabelled = onlyCheckLabelled;
|
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.BreakStatement:
|
case SyntaxKind.BreakStatement:
|
||||||
case SyntaxKind.ContinueStatement:
|
case SyntaxKind.ContinueStatement:
|
||||||
// If the 'break'/'continue' statement has a label, it must be one of our tracked labels.
|
if (ownsBreakOrContinue(loopNode, <BreakOrContinueStatement>node, breakSearchType, continueSearchType)) {
|
||||||
if ((<BreakOrContinueStatement>node).label) {
|
|
||||||
var labelName = (<BreakOrContinueStatement>node).label.text;
|
|
||||||
if (isLabelledBy(loopNode, labelName)) {
|
|
||||||
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If not, we are free to add it if we haven't lost ownership of unlabeled break/continue statements.
|
|
||||||
else if (!onlyCheckLabelled) {
|
|
||||||
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword);
|
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SyntaxKind.ForStatement:
|
case SyntaxKind.ForStatement:
|
||||||
case SyntaxKind.ForInStatement:
|
case SyntaxKind.ForInStatement:
|
||||||
case SyntaxKind.DoStatement:
|
case SyntaxKind.DoStatement:
|
||||||
case SyntaxKind.WhileStatement:
|
case SyntaxKind.WhileStatement:
|
||||||
case SyntaxKind.SwitchStatement:
|
continueSearchType = BreakContinueSearchType.Labeled;
|
||||||
onlyCheckLabelled = true;
|
|
||||||
// Fall through
|
// Fall through
|
||||||
default:
|
case SyntaxKind.SwitchStatement:
|
||||||
// Do not cross function boundaries.
|
breakSearchType = BreakContinueSearchType.Labeled;
|
||||||
if (!isAnyFunction(node)) {
|
|
||||||
forEachChild(node, aggregateBreakContinues);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Restore the last state.
|
|
||||||
onlyCheckLabelled = lastOnlyCheckLabelled;
|
|
||||||
});
|
|
||||||
|
|
||||||
return map(keywords, keywordToReferenceEntry);
|
// Do not cross function boundaries.
|
||||||
|
if (!isAnyFunction(node)) {
|
||||||
|
forEachChild(node, aggregateBreakContinues);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the last state.
|
||||||
|
breakSearchType = prevBreakSearchType;
|
||||||
|
continueSearchType = prevContinueSearchType;
|
||||||
|
})(loopNode.statement);
|
||||||
|
|
||||||
|
return map(keywords, getReferenceEntryFromNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) {
|
function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) {
|
||||||
|
@ -2368,38 +2372,50 @@ module ts {
|
||||||
|
|
||||||
pushKeywordIf(keywords, switchStatement.getFirstToken(), SyntaxKind.SwitchKeyword);
|
pushKeywordIf(keywords, switchStatement.getFirstToken(), SyntaxKind.SwitchKeyword);
|
||||||
|
|
||||||
// Go through each clause in the switch statement, collecting the clause keywords.
|
// Types of break statements we can grab on to.
|
||||||
|
var breakSearchType = BreakContinueSearchType.All;
|
||||||
|
|
||||||
|
// Go through each clause in the switch statement, collecting the case/default keywords.
|
||||||
forEach(switchStatement.clauses, clause => {
|
forEach(switchStatement.clauses, clause => {
|
||||||
pushKeywordIf(keywords, clause.getFirstToken(), SyntaxKind.CaseKeyword, SyntaxKind.DefaultKeyword);
|
pushKeywordIf(keywords, clause.getFirstToken(), SyntaxKind.CaseKeyword, SyntaxKind.DefaultKeyword);
|
||||||
|
|
||||||
// For each clause, also recursively traverse the statements where we can find analogous breaks.
|
// For each clause, also recursively traverse the statements where we can find analogous breaks.
|
||||||
forEachChild(clause, function aggregateBreakKeywords(node: Node): void {
|
forEachChild(clause, function aggregateBreakKeywords(node: Node): void {
|
||||||
|
// Back the old search value up.
|
||||||
|
var oldBreakSearchType = breakSearchType;
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.BreakStatement:
|
case SyntaxKind.BreakStatement:
|
||||||
// If the break statement has a label, it cannot be part of a switch block.
|
// If the break statement has a label, it cannot be part of a switch block.
|
||||||
if (!(<BreakOrContinueStatement>node).label) {
|
if (ownsBreakOrContinue(switchStatement,
|
||||||
|
<BreakOrContinueStatement>node,
|
||||||
|
breakSearchType,
|
||||||
|
/*continuesSearchType*/ BreakContinueSearchType.None)) {
|
||||||
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword);
|
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword);
|
||||||
}
|
}
|
||||||
// Fall through
|
break;
|
||||||
case SyntaxKind.ForStatement:
|
case SyntaxKind.ForStatement:
|
||||||
case SyntaxKind.ForInStatement:
|
case SyntaxKind.ForInStatement:
|
||||||
case SyntaxKind.DoStatement:
|
case SyntaxKind.DoStatement:
|
||||||
case SyntaxKind.WhileStatement:
|
case SyntaxKind.WhileStatement:
|
||||||
case SyntaxKind.SwitchStatement:
|
case SyntaxKind.SwitchStatement:
|
||||||
return;
|
breakSearchType = BreakContinueSearchType.Labeled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not cross function boundaries.
|
// Do not cross function boundaries.
|
||||||
if (!isAnyFunction(node)) {
|
if (!isAnyFunction(node)) {
|
||||||
forEachChild(node, aggregateBreakKeywords);
|
forEachChild(node, aggregateBreakKeywords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore the last state.
|
||||||
|
breakSearchType = oldBreakSearchType;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return map(keywords, getReferenceEntryFromNode);
|
return map(keywords, getReferenceEntryFromNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBreakOrContinueStatementOccurences(breakOrContinueStatement: BreakOrContinueStatement): ReferenceEntry[]{
|
function getBreakOrContinueStatementOccurences(breakOrContinueStatement: BreakOrContinueStatement): ReferenceEntry[] {
|
||||||
for (var owner = node.parent; owner; owner = owner.parent) {
|
for (var owner = node.parent; owner; owner = owner.parent) {
|
||||||
switch (owner.kind) {
|
switch (owner.kind) {
|
||||||
case SyntaxKind.ForStatement:
|
case SyntaxKind.ForStatement:
|
||||||
|
@ -2413,8 +2429,8 @@ module ts {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SyntaxKind.SwitchStatement:
|
case SyntaxKind.SwitchStatement:
|
||||||
// A switch statement can only be the owner of an unlabeled break statement.
|
// A switch statement can only be the owner of an break statement.
|
||||||
if (breakOrContinueStatement.kind === SyntaxKind.BreakStatement && !breakOrContinueStatement.label) {
|
if (breakOrContinueStatement.kind === SyntaxKind.BreakStatement && (!breakOrContinueStatement.label || isLabelledBy(owner, breakOrContinueStatement.label.text))) {
|
||||||
return getSwitchCaseDefaultOccurrences(<SwitchStatement>owner);
|
return getSwitchCaseDefaultOccurrences(<SwitchStatement>owner);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2429,6 +2445,25 @@ module ts {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: 'statement' must be a descendant of 'root'.
|
||||||
|
// Reasonable logic for restricting traversal prior to arriving at the
|
||||||
|
// 'statement' node is beyond the scope of this function.
|
||||||
|
function ownsBreakOrContinue(root: Node,
|
||||||
|
statement: BreakOrContinueStatement,
|
||||||
|
breakSearchType: BreakContinueSearchType,
|
||||||
|
continueSearchType: BreakContinueSearchType): boolean {
|
||||||
|
var searchType = statement.kind === SyntaxKind.BreakStatement ?
|
||||||
|
breakSearchType :
|
||||||
|
continueSearchType;
|
||||||
|
|
||||||
|
if (statement.label) {
|
||||||
|
return isLabelledBy(root, statement.label.text);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return !!(searchType & BreakContinueSearchType.Unlabeled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns true if 'node' is defined and has a matching 'kind'.
|
// returns true if 'node' is defined and has a matching 'kind'.
|
||||||
function hasKind(node: Node, kind: SyntaxKind) {
|
function hasKind(node: Node, kind: SyntaxKind) {
|
||||||
return node !== undefined && node.kind === kind;
|
return node !== undefined && node.kind === kind;
|
||||||
|
|
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue.ts
Normal file
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: [|for|] (var n in arr) {
|
||||||
|
//// [|break|];
|
||||||
|
//// [|continue|];
|
||||||
|
//// [|br/**/eak|] label1;
|
||||||
|
//// [|continue|] label1;
|
||||||
|
////
|
||||||
|
//// label2: for (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// [|break|] label1;
|
||||||
|
//// [|continue|] label1;
|
||||||
|
////
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: while (true) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// label4: do {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label4;
|
||||||
|
//// continue label4;
|
||||||
|
////
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// break label4;
|
||||||
|
//// default:
|
||||||
|
//// continue;
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
//// () => { break; }
|
||||||
|
//// } while (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: while (true) break label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) continue label5;
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
goTo.marker();
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue2.ts
Normal file
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue2.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: for (var n in arr) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// label2: [|f/**/or|] (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// [|break|];
|
||||||
|
//// [|continue|];
|
||||||
|
//// [|break|] label2;
|
||||||
|
//// [|continue|] label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: while (true) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// label4: do {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label4;
|
||||||
|
//// continue label4;
|
||||||
|
////
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// break label4;
|
||||||
|
//// default:
|
||||||
|
//// continue;
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
//// () => { break;
|
||||||
|
//// } while (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: while (true) break label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) continue label5;
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
goTo.marker();
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue3.ts
Normal file
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue3.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: for (var n in arr) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// label2: for (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: [|w/**/hile|] (true) {
|
||||||
|
//// [|break|];
|
||||||
|
//// [|continue|];
|
||||||
|
//// [|break|] label3;
|
||||||
|
//// [|continue|] label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// label4: do {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label4;
|
||||||
|
//// continue label4;
|
||||||
|
////
|
||||||
|
//// [|break|] label3;
|
||||||
|
//// [|continue|] label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// break label4;
|
||||||
|
//// default:
|
||||||
|
//// continue;
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
//// () => { break; }
|
||||||
|
//// } while (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: while (true) break label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) continue label5;
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
goTo.marker();
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue4.ts
Normal file
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue4.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: for (var n in arr) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// label2: for (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: while (true) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// label4: [|do|] {
|
||||||
|
//// [|break|];
|
||||||
|
//// [|continue|];
|
||||||
|
//// [|break|] label4;
|
||||||
|
//// [|continue|] label4;
|
||||||
|
////
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// [|break|] label4;
|
||||||
|
//// default:
|
||||||
|
//// [|continue|];
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
//// () => { break; }
|
||||||
|
//// } [|wh/**/ile|] (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: while (true) break label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) continue label5;
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
goTo.marker();
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue5.ts
Normal file
77
tests/cases/fourslash/getOccurrencesLoopBreakContinue5.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: for (var n in arr) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// label2: for (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: while (true) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// label4: do {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label4;
|
||||||
|
//// continue label4;
|
||||||
|
////
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// break label4;
|
||||||
|
//// default:
|
||||||
|
//// continue;
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
//// () => { break; }
|
||||||
|
//// } while (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: [|while|] (true) [|br/**/eak|] label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) continue label5;
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
goTo.marker();
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
|
@ -0,0 +1,70 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////var arr = [1, 2, 3, 4];
|
||||||
|
////label1: for (var n in arr) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// label2: for (var i = 0; i < arr[n]; i++) {
|
||||||
|
//// break label1;
|
||||||
|
//// continue label1;
|
||||||
|
////
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label2;
|
||||||
|
//// continue label2;
|
||||||
|
////
|
||||||
|
//// function foo() {
|
||||||
|
//// label3: while (true) {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// br/*1*/eak label1;
|
||||||
|
//// cont/*2*/inue label1;
|
||||||
|
//// bre/*3*/ak label2;
|
||||||
|
//// c/*4*/ontinue label2;
|
||||||
|
////
|
||||||
|
//// label4: do {
|
||||||
|
//// break;
|
||||||
|
//// continue;
|
||||||
|
//// break label4;
|
||||||
|
//// continue label4;
|
||||||
|
////
|
||||||
|
//// break label3;
|
||||||
|
//// continue label3;
|
||||||
|
////
|
||||||
|
//// switch (10) {
|
||||||
|
//// case 1:
|
||||||
|
//// case 2:
|
||||||
|
//// break;
|
||||||
|
//// break label4;
|
||||||
|
//// default:
|
||||||
|
//// continue;
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// // these cross function boundaries
|
||||||
|
//// br/*5*/eak label1;
|
||||||
|
//// co/*6*/ntinue label1;
|
||||||
|
//// br/*7*/eak label2;
|
||||||
|
//// con/*8*/tinue label2;
|
||||||
|
//// () => { b/*9*/reak; }
|
||||||
|
//// } while (true)
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
////
|
||||||
|
////label5: while (true) break label5;
|
||||||
|
////
|
||||||
|
////label7: while (true) co/*10*/ntinue label5;
|
||||||
|
|
||||||
|
test.markers().forEach(m => {
|
||||||
|
goTo.position(m.position);
|
||||||
|
|
||||||
|
verify.occurrencesAtPositionCount(0);
|
||||||
|
});
|
|
@ -10,7 +10,7 @@
|
||||||
//// [|cas/*3*/e|] 2:
|
//// [|cas/*3*/e|] 2:
|
||||||
//// [|b/*4*/reak|];
|
//// [|b/*4*/reak|];
|
||||||
//// [|defaul/*5*/t|]:
|
//// [|defaul/*5*/t|]:
|
||||||
//// break foo;
|
//// [|break|] foo;
|
||||||
//// }
|
//// }
|
||||||
//// case 0xBEEF:
|
//// case 0xBEEF:
|
||||||
//// default:
|
//// default:
|
||||||
|
@ -19,9 +19,18 @@
|
||||||
////}
|
////}
|
||||||
|
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
for (var i = 1; i <= test.markers().length; i++) {
|
for (var i = 1; i <= test.markers().length; i++) {
|
||||||
goTo.marker("" + i);
|
goTo.marker("" + i);
|
||||||
verify.occurrencesAtPositionCount(5);
|
verify.occurrencesAtPositionCount(6);
|
||||||
|
|
||||||
test.ranges().forEach(range => {
|
test.ranges().forEach(range => {
|
||||||
verify.occurrencesAtPositionContains(range, false);
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
|
25
tests/cases/fourslash/getOccurrencesSwitchCaseDefault3.ts
Normal file
25
tests/cases/fourslash/getOccurrencesSwitchCaseDefault3.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////foo: [|switch|] (1) {
|
||||||
|
//// [|case|] 1:
|
||||||
|
//// [|case|] 2:
|
||||||
|
//// [|break|];
|
||||||
|
//// [|case|] 3:
|
||||||
|
//// switch (2) {
|
||||||
|
//// case 1:
|
||||||
|
//// [|break|] foo;
|
||||||
|
//// continue; // invalid
|
||||||
|
//// default:
|
||||||
|
//// break;
|
||||||
|
//// }
|
||||||
|
//// [|default|]:
|
||||||
|
//// [|break|];
|
||||||
|
////}
|
||||||
|
|
||||||
|
test.ranges().forEach(r => {
|
||||||
|
goTo.position(r.start);
|
||||||
|
|
||||||
|
test.ranges().forEach(range => {
|
||||||
|
verify.occurrencesAtPositionContains(range, false);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue