Skip to content

Commit 9c8e1bd

Browse files
committed
Fix: ReferenceTracker
- `iterateGlobalReferences` should not iterate modified globals. - `iterateCjsReferences` should iterate global object members. (e.g. `global.require`)
1 parent 2fc445d commit 9c8e1bd

File tree

2 files changed

+40
-23
lines changed

2 files changed

+40
-23
lines changed

src/reference-tracker.js

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ export const CALL = Symbol("call")
1111
export const CONSTRUCT = Symbol("construct")
1212
export const ESM = Symbol("esm")
1313

14+
const requireCall = { require: { [CALL]: true } }
15+
16+
/**
17+
* Check whether a given variable is modified or not.
18+
* @param {Variable} variable The variable to check.
19+
* @returns {boolean} `true` if the variable is modified.
20+
*/
21+
function isModifiedGlobal(variable) {
22+
return (
23+
variable == null ||
24+
variable.defs.length !== 0 ||
25+
variable.references.some(r => r.isWrite())
26+
)
27+
}
28+
1429
/**
1530
* The reference tracker.
1631
*/
@@ -46,7 +61,7 @@ export class ReferenceTracker {
4661
const path = [key]
4762
const variable = this.globalScope.set.get(key)
4863

49-
if (variable == null || variable.defs.length !== 0) {
64+
if (isModifiedGlobal(variable)) {
5065
continue
5166
}
5267

@@ -62,7 +77,7 @@ export class ReferenceTracker {
6277
const path = []
6378
const variable = this.globalScope.set.get(key)
6479

65-
if (variable == null || variable.defs.length !== 0) {
80+
if (isModifiedGlobal(variable)) {
6681
continue
6782
}
6883

@@ -81,40 +96,24 @@ export class ReferenceTracker {
8196
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
8297
*/
8398
*iterateCjsReferences(traceMap) {
84-
const variable = this.globalScope.set.get("require")
85-
86-
if (variable == null || variable.defs.length !== 0) {
87-
return
88-
}
89-
90-
for (const reference of variable.references) {
91-
const reqNode = reference.identifier
92-
const callNode = reqNode.parent
93-
94-
if (
95-
!reference.isRead() ||
96-
callNode.type !== "CallExpression" ||
97-
callNode.callee !== reqNode
98-
) {
99-
continue
100-
}
101-
const key = getStringIfConstant(callNode.arguments[0])
102-
99+
for (const { node } of this.iterateGlobalReferences(requireCall)) {
100+
const key = getStringIfConstant(node.arguments[0])
103101
if (key == null || !has(traceMap, key)) {
104102
continue
105103
}
104+
106105
const nextTraceMap = traceMap[key]
107106
const path = [key]
108107

109108
if (nextTraceMap[READ]) {
110109
yield {
111-
node: callNode,
110+
node,
112111
path,
113112
type: READ,
114113
info: nextTraceMap[READ],
115114
}
116115
}
117-
yield* this._iteratePropertyReferences(callNode, path, nextTraceMap)
116+
yield* this._iteratePropertyReferences(node, path, nextTraceMap)
118117
}
119118
}
120119

test/reference-tracker.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,24 @@ describe("The 'ReferenceTracker' class:", () => {
351351
},
352352
],
353353
},
354+
{
355+
description:
356+
"should not iterate the references of a given global variable if it's modified.",
357+
code: [
358+
"Object = {}",
359+
"Object.a",
360+
"Object.b()",
361+
"new Object.c()",
362+
].join("\n"),
363+
traceMap: {
364+
Object: {
365+
a: { [READ]: 1 },
366+
b: { [CALL]: 2 },
367+
c: { [CONSTRUCT]: 3 },
368+
},
369+
},
370+
expected: [],
371+
},
354372
]) {
355373
it(description, () => {
356374
const linter = new eslint.Linter()

0 commit comments

Comments
 (0)