Skip to content

Commit

Permalink
🐛 fix reference tracker false positive
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Oct 20, 2019
1 parent 6633278 commit 8f9e481
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
25 changes: 23 additions & 2 deletions src/reference-tracker.js
Expand Up @@ -2,7 +2,6 @@ import { findVariable } from "./find-variable"
import { getPropertyName } from "./get-property-name" import { getPropertyName } from "./get-property-name"
import { getStringIfConstant } from "./get-string-if-constant" import { getStringIfConstant } from "./get-string-if-constant"


const SENTINEL_TYPE = /^(?:.+?Statement|.+?Declaration|(?:Array|ArrowFunction|Assignment|Call|Class|Function|Member|New|Object)Expression|AssignmentPattern|Program|VariableDeclarator)$/u
const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u
const has = Function.call.bind(Object.hasOwnProperty) const has = Function.call.bind(Object.hasOwnProperty)


Expand All @@ -26,6 +25,28 @@ function isModifiedGlobal(variable) {
) )
} }


/**
* Check if the value of a given node is passed through to the parent syntax as-is.
* For example, `a` and `b` in (`a || b` and `c ? a : b`) are passed through.
* @param {Node} node A node to check.
* @returns {boolean} `true` if the node is passed through.
*/
function isPassThrough(node) {
const parent = node.parent

switch (parent && parent.type) {
case "ConditionalExpression":
return parent.consequent === node || parent.alternate === node
case "LogicalExpression":
return true
case "SequenceExpression":
return parent.expressions[parent.expressions.length - 1] === node

default:
return false
}
}

/** /**
* The reference tracker. * The reference tracker.
*/ */
Expand Down Expand Up @@ -227,7 +248,7 @@ export class ReferenceTracker {
//eslint-disable-next-line complexity //eslint-disable-next-line complexity
*_iteratePropertyReferences(rootNode, path, traceMap) { *_iteratePropertyReferences(rootNode, path, traceMap) {
let node = rootNode let node = rootNode
while (!SENTINEL_TYPE.test(node.parent.type)) { while (isPassThrough(node)) {
node = node.parent node = node.parent
} }


Expand Down
13 changes: 13 additions & 0 deletions test/reference-tracker.js
Expand Up @@ -4,6 +4,7 @@ import { CALL, CONSTRUCT, ESM, READ, ReferenceTracker } from "../src/"


const config = { const config = {
parserOptions: { ecmaVersion: 2018, sourceType: "module" }, parserOptions: { ecmaVersion: 2018, sourceType: "module" },
globals: { Reflect: false },
rules: { test: "error" }, rules: { test: "error" },
} }


Expand Down Expand Up @@ -369,6 +370,18 @@ describe("The 'ReferenceTracker' class:", () => {
}, },
expected: [], expected: [],
}, },
{
description:
"should not iterate the references through unary/binary expressions.",
code: [
'var construct = typeof Reflect !== "undefined" ? Reflect.construct : undefined',
"construct()",
].join("\n"),
traceMap: {
Reflect: { [CALL]: 1 },
},
expected: [],
},
]) { ]) {
it(description, () => { it(description, () => {
const linter = new eslint.Linter() const linter = new eslint.Linter()
Expand Down

0 comments on commit 8f9e481

Please sign in to comment.