Skip to content

Commit 38d0cb2

Browse files
mysticateailyavolodin
authored andcommittedSep 27, 2017
Fix: fix wrong code-path about try-for-in (fixes #8848) (#9348)
1 parent 434d9e2 commit 38d0cb2

File tree

6 files changed

+141
-41
lines changed

6 files changed

+141
-41
lines changed
 

‎lib/code-path-analysis/code-path-segment.js

+39-39
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,6 @@ const debug = require("./debug-helpers");
1515
// Helpers
1616
//------------------------------------------------------------------------------
1717

18-
/**
19-
* Replaces unused segments with the previous segments of each unused segment.
20-
*
21-
* @param {CodePathSegment[]} segments - An array of segments to replace.
22-
* @returns {CodePathSegment[]} The replaced array.
23-
*/
24-
function flattenUnusedSegments(segments) {
25-
const done = Object.create(null);
26-
const retv = [];
27-
28-
for (let i = 0; i < segments.length; ++i) {
29-
const segment = segments[i];
30-
31-
// Ignores duplicated.
32-
if (done[segment.id]) {
33-
continue;
34-
}
35-
36-
// Use previous segments if unused.
37-
if (!segment.internal.used) {
38-
for (let j = 0; j < segment.allPrevSegments.length; ++j) {
39-
const prevSegment = segment.allPrevSegments[j];
40-
41-
if (!done[prevSegment.id]) {
42-
done[prevSegment.id] = true;
43-
retv.push(prevSegment);
44-
}
45-
}
46-
} else {
47-
done[segment.id] = true;
48-
retv.push(segment);
49-
}
50-
}
51-
52-
return retv;
53-
}
54-
5518
/**
5619
* Checks whether or not a given segment is reachable.
5720
*
@@ -163,7 +126,7 @@ class CodePathSegment {
163126
static newNext(id, allPrevSegments) {
164127
return new CodePathSegment(
165128
id,
166-
flattenUnusedSegments(allPrevSegments),
129+
CodePathSegment.flattenUnusedSegments(allPrevSegments),
167130
allPrevSegments.some(isReachable)
168131
);
169132
}
@@ -176,7 +139,7 @@ class CodePathSegment {
176139
* @returns {CodePathSegment} The created segment.
177140
*/
178141
static newUnreachable(id, allPrevSegments) {
179-
const segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false);
142+
const segment = new CodePathSegment(id, CodePathSegment.flattenUnusedSegments(allPrevSegments), false);
180143

181144
// In `if (a) return a; foo();` case, the unreachable segment preceded by
182145
// the return statement is not used but must not be remove.
@@ -238,6 +201,43 @@ class CodePathSegment {
238201
static markPrevSegmentAsLooped(segment, prevSegment) {
239202
segment.internal.loopedPrevSegments.push(prevSegment);
240203
}
204+
205+
/**
206+
* Replaces unused segments with the previous segments of each unused segment.
207+
*
208+
* @param {CodePathSegment[]} segments - An array of segments to replace.
209+
* @returns {CodePathSegment[]} The replaced array.
210+
*/
211+
static flattenUnusedSegments(segments) {
212+
const done = Object.create(null);
213+
const retv = [];
214+
215+
for (let i = 0; i < segments.length; ++i) {
216+
const segment = segments[i];
217+
218+
// Ignores duplicated.
219+
if (done[segment.id]) {
220+
continue;
221+
}
222+
223+
// Use previous segments if unused.
224+
if (!segment.internal.used) {
225+
for (let j = 0; j < segment.allPrevSegments.length; ++j) {
226+
const prevSegment = segment.allPrevSegments[j];
227+
228+
if (!done[prevSegment.id]) {
229+
done[prevSegment.id] = true;
230+
retv.push(prevSegment);
231+
}
232+
}
233+
} else {
234+
done[segment.id] = true;
235+
retv.push(segment);
236+
}
237+
}
238+
239+
return retv;
240+
}
241241
}
242242

243243
module.exports = CodePathSegment;

‎lib/code-path-analysis/code-path-state.js

+3
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ function removeConnection(prevSegments, nextSegments) {
169169
* @returns {void}
170170
*/
171171
function makeLooped(state, fromSegments, toSegments) {
172+
fromSegments = CodePathSegment.flattenUnusedSegments(fromSegments);
173+
toSegments = CodePathSegment.flattenUnusedSegments(toSegments);
174+
172175
const end = Math.min(fromSegments.length, toSegments.length);
173176

174177
for (let i = 0; i < end; ++i) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*expected
2+
initial->s1_1->s1_3->s1_2->s1_5->s1_2;
3+
s1_3->s1_6->s1_7->s1_8;
4+
s1_5->s1_6;
5+
s1_3->s1_7;
6+
s1_6->s1_8->final;
7+
*/
8+
9+
try {
10+
for (let x of xs) {
11+
}
12+
} catch (err) {
13+
}
14+
15+
/*DOT
16+
digraph {
17+
node[shape=box,style="rounded,filled",fillcolor=white];
18+
initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
19+
final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
20+
s1_1[label="Program\nTryStatement\nBlockStatement\nForOfStatement"];
21+
s1_3[label="Identifier (xs)\nIdentifier:exit (xs)"];
22+
s1_2[label="VariableDeclaration\nVariableDeclarator\nIdentifier (x)\nIdentifier:exit (x)\nVariableDeclarator:exit\nVariableDeclaration:exit"];
23+
s1_5[label="BlockStatement\nBlockStatement:exit"];
24+
s1_6[label="ForOfStatement:exit\nBlockStatement:exit"];
25+
s1_7[label="CatchClause\nIdentifier (err)\nBlockStatement\nIdentifier:exit (err)\nBlockStatement:exit\nCatchClause:exit"];
26+
s1_8[label="TryStatement:exit\nProgram:exit"];
27+
initial->s1_1->s1_3->s1_2->s1_5->s1_2;
28+
s1_3->s1_6->s1_7->s1_8;
29+
s1_5->s1_6;
30+
s1_3->s1_7;
31+
s1_6->s1_8->final;
32+
}
33+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*expected
2+
initial->s1_1->s1_3->s1_4->s1_2->s1_5->s1_2;
3+
s1_3->s1_7->s1_8;
4+
s1_4->s1_6->s1_7;
5+
s1_5->s1_6->s1_8->final;
6+
*/
7+
8+
try {
9+
for (let x of obj.xs) {
10+
}
11+
} catch (err) {
12+
}
13+
14+
/*DOT
15+
digraph {
16+
node[shape=box,style="rounded,filled",fillcolor=white];
17+
initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
18+
final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
19+
s1_1[label="Program\nTryStatement\nBlockStatement\nForOfStatement"];
20+
s1_3[label="MemberExpression\nIdentifier (obj)\nIdentifier:exit (obj)"];
21+
s1_4[label="Identifier (xs)\nIdentifier:exit (xs)\nMemberExpression:exit"];
22+
s1_2[label="VariableDeclaration\nVariableDeclarator\nIdentifier (x)\nIdentifier:exit (x)\nVariableDeclarator:exit\nVariableDeclaration:exit"];
23+
s1_5[label="BlockStatement\nBlockStatement:exit"];
24+
s1_7[label="CatchClause\nIdentifier (err)\nBlockStatement\nIdentifier:exit (err)\nBlockStatement:exit\nCatchClause:exit"];
25+
s1_8[label="TryStatement:exit\nProgram:exit"];
26+
s1_6[label="ForOfStatement:exit\nBlockStatement:exit"];
27+
initial->s1_1->s1_3->s1_4->s1_2->s1_5->s1_2;
28+
s1_3->s1_7->s1_8;
29+
s1_4->s1_6->s1_7;
30+
s1_5->s1_6->s1_8->final;
31+
}
32+
*/

‎tests/lib/rules/constructor-super.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,23 @@ ruleTester.run("constructor-super", rule, {
7777
].join("\n"),
7878

7979
// https://github.com/eslint/eslint/issues/5894
80-
"class A { constructor() { return; super(); } }"
80+
"class A { constructor() { return; super(); } }",
81+
82+
// https://github.com/eslint/eslint/issues/8848
83+
`
84+
class A extends B {
85+
constructor(props) {
86+
super(props);
87+
88+
try {
89+
let arr = [];
90+
for (let a of arr) {
91+
}
92+
} catch (err) {
93+
}
94+
}
95+
}
96+
`
8197
],
8298
invalid: [
8399

‎tests/lib/rules/no-this-before-super.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,23 @@ ruleTester.run("no-this-before-super", rule, {
7777

7878
// https://github.com/eslint/eslint/issues/5894
7979
"class A { constructor() { return; this; } }",
80-
"class A extends B { constructor() { return; this; } }"
80+
"class A extends B { constructor() { return; this; } }",
81+
82+
// https://github.com/eslint/eslint/issues/8848
83+
`
84+
class A extends B {
85+
constructor(props) {
86+
super(props);
87+
88+
try {
89+
let arr = [];
90+
for (let a of arr) {
91+
}
92+
} catch (err) {
93+
}
94+
}
95+
}
96+
`
8197
],
8298
invalid: [
8399

0 commit comments

Comments
 (0)
Please sign in to comment.