Fixed generateUid creating clashing ids after scope re-crawling (#11375)
This commit is contained in:
parent
ca096c56aa
commit
70cc111b35
@ -155,6 +155,7 @@ const collectorVisitor = {
|
|||||||
For(path) {
|
For(path) {
|
||||||
for (const key of (t.FOR_INIT_KEYS: Array)) {
|
for (const key of (t.FOR_INIT_KEYS: Array)) {
|
||||||
const declar = path.get(key);
|
const declar = path.get(key);
|
||||||
|
// delegate block scope handling to the `BlockScoped` method
|
||||||
if (declar.isVar()) {
|
if (declar.isVar()) {
|
||||||
const parentScope =
|
const parentScope =
|
||||||
path.scope.getFunctionParent() || path.scope.getProgramParent();
|
path.scope.getFunctionParent() || path.scope.getProgramParent();
|
||||||
@ -253,6 +254,31 @@ const collectorVisitor = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
CatchClause(path) {
|
||||||
|
path.scope.registerBinding("let", path);
|
||||||
|
},
|
||||||
|
|
||||||
|
Function(path) {
|
||||||
|
if (
|
||||||
|
path.isFunctionExpression() &&
|
||||||
|
path.has("id") &&
|
||||||
|
!path.get("id").node[t.NOT_LOCAL_BINDING]
|
||||||
|
) {
|
||||||
|
path.scope.registerBinding("local", path.get("id"), path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: Array<NodePath> = path.get("params");
|
||||||
|
for (const param of params) {
|
||||||
|
path.scope.registerBinding("param", param);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ClassExpression(path) {
|
||||||
|
if (path.has("id") && !path.get("id").node[t.NOT_LOCAL_BINDING]) {
|
||||||
|
path.scope.registerBinding("local", path);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let uid = 0;
|
let uid = 0;
|
||||||
@ -279,6 +305,7 @@ export default class Scope {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
||||||
this.labels = new Map();
|
this.labels = new Map();
|
||||||
|
this.inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -755,7 +782,10 @@ export default class Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (!this.references) this.crawl();
|
if (!this.inited) {
|
||||||
|
this.inited = true;
|
||||||
|
this.crawl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crawl() {
|
crawl() {
|
||||||
@ -767,50 +797,24 @@ export default class Scope {
|
|||||||
this.uids = Object.create(null);
|
this.uids = Object.create(null);
|
||||||
this.data = Object.create(null);
|
this.data = Object.create(null);
|
||||||
|
|
||||||
// ForStatement - left, init
|
// TODO: explore removing this as it should be covered by collectorVisitor
|
||||||
|
if (path.isFunction()) {
|
||||||
if (path.isLoop()) {
|
if (
|
||||||
for (const key of (t.FOR_INIT_KEYS: Array<string>)) {
|
path.isFunctionExpression() &&
|
||||||
const node = path.get(key);
|
path.has("id") &&
|
||||||
if (node.isBlockScoped()) this.registerBinding(node.node.kind, node);
|
!path.get("id").node[t.NOT_LOCAL_BINDING]
|
||||||
}
|
) {
|
||||||
}
|
|
||||||
|
|
||||||
// FunctionExpression - id
|
|
||||||
|
|
||||||
if (path.isFunctionExpression() && path.has("id")) {
|
|
||||||
if (!path.get("id").node[t.NOT_LOCAL_BINDING]) {
|
|
||||||
this.registerBinding("local", path.get("id"), path);
|
this.registerBinding("local", path.get("id"), path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Class
|
|
||||||
|
|
||||||
if (path.isClassExpression() && path.has("id")) {
|
|
||||||
if (!path.get("id").node[t.NOT_LOCAL_BINDING]) {
|
|
||||||
this.registerBinding("local", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function - params, rest
|
|
||||||
|
|
||||||
if (path.isFunction()) {
|
|
||||||
const params: Array<NodePath> = path.get("params");
|
const params: Array<NodePath> = path.get("params");
|
||||||
for (const param of params) {
|
for (const param of params) {
|
||||||
this.registerBinding("param", param);
|
this.registerBinding("param", param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatchClause - param
|
const programParent = this.getProgramParent();
|
||||||
|
if (programParent.crawling) return;
|
||||||
if (path.isCatchClause()) {
|
|
||||||
this.registerBinding("let", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program
|
|
||||||
|
|
||||||
const parent = this.getProgramParent();
|
|
||||||
if (parent.crawling) return;
|
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
references: [],
|
references: [],
|
||||||
@ -826,11 +830,8 @@ export default class Scope {
|
|||||||
for (const path of state.assignments) {
|
for (const path of state.assignments) {
|
||||||
// register undeclared bindings as globals
|
// register undeclared bindings as globals
|
||||||
const ids = path.getBindingIdentifiers();
|
const ids = path.getBindingIdentifiers();
|
||||||
let programParent;
|
|
||||||
for (const name of Object.keys(ids)) {
|
for (const name of Object.keys(ids)) {
|
||||||
if (path.scope.getBinding(name)) continue;
|
if (path.scope.getBinding(name)) continue;
|
||||||
|
|
||||||
programParent = programParent || path.scope.getProgramParent();
|
|
||||||
programParent.addGlobal(ids[name]);
|
programParent.addGlobal(ids[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -844,7 +845,7 @@ export default class Scope {
|
|||||||
if (binding) {
|
if (binding) {
|
||||||
binding.reference(ref);
|
binding.reference(ref);
|
||||||
} else {
|
} else {
|
||||||
ref.scope.getProgramParent().addGlobal(ref.node);
|
programParent.addGlobal(ref.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -321,6 +321,42 @@ describe("scope", () => {
|
|||||||
|
|
||||||
expect(path.scope.generateUid("jsx")).toBe("_jsx2");
|
expect(path.scope.generateUid("jsx")).toBe("_jsx2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("generateUid collision check after re-crawling (function expression local id)", function() {
|
||||||
|
const path = getPath("var fn = function _name(){}");
|
||||||
|
|
||||||
|
path.scope.crawl();
|
||||||
|
path.scope.crawl();
|
||||||
|
|
||||||
|
expect(path.scope.generateUid("name")).toBe("_name2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generateUid collision check after re-crawling (function params)", function() {
|
||||||
|
const path = getPath("[].map(_unicorn => [_unicorn])");
|
||||||
|
|
||||||
|
path.scope.crawl();
|
||||||
|
path.scope.crawl();
|
||||||
|
|
||||||
|
expect(path.scope.generateUid("unicorn")).toBe("_unicorn2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generateUid collision check after re-crawling (catch clause)", function() {
|
||||||
|
const path = getPath("try {} catch (_err) {}");
|
||||||
|
|
||||||
|
path.scope.crawl();
|
||||||
|
path.scope.crawl();
|
||||||
|
|
||||||
|
expect(path.scope.generateUid("err")).toBe("_err2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generateUid collision check after re-crawling (class expression local id)", function() {
|
||||||
|
const path = getPath("var C = class _Cls{}");
|
||||||
|
|
||||||
|
path.scope.crawl();
|
||||||
|
path.scope.crawl();
|
||||||
|
|
||||||
|
expect(path.scope.generateUid("Cls")).toBe("_Cls2");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("duplicate bindings", () => {
|
describe("duplicate bindings", () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user