diff --git a/lib/rules/no-shadow.js b/lib/rules/no-shadow.js index 1be8590e47a..a0b1db50c0b 100644 --- a/lib/rules/no-shadow.js +++ b/lib/rules/no-shadow.js @@ -44,7 +44,8 @@ module.exports = { ], messages: { - noShadow: "'{{name}}' is already declared in the upper scope." + noShadow: "'{{name}}' is already declared in the upper scope on line {{shadowedLine}} column {{shadowedColumn}}.", + noShadowGlobal: "'{{name}}' is already a global variable." } }, @@ -117,6 +118,29 @@ module.exports = { return def && def.name.range; } + /** + * Get declared line and column of a variable. + * @param {eslint-scope.Variable} variable The variable to get. + * @returns {Object} The declared line and column of the variable. + */ + function getDeclaredLocation(variable) { + const identifier = variable.identifiers[0]; + let obj; + + if (identifier) { + obj = { + global: false, + line: identifier.loc.start.line, + column: identifier.loc.start.column + 1 + }; + } else { + obj = { + global: true + }; + } + return obj; + } + /** * Checks if a variable is in TDZ of scopeVar. * @param {Object} variable The variable to check. @@ -165,10 +189,18 @@ module.exports = { !isOnInitializer(variable, shadowed) && !(options.hoist !== "all" && isInTdz(variable, shadowed)) ) { + const location = getDeclaredLocation(shadowed); + const messageId = location.global ? "noShadowGlobal" : "noShadow"; + const data = { name: variable.name }; + + if (!location.global) { + data.shadowedLine = location.line; + data.shadowedColumn = location.column; + } context.report({ node: variable.identifiers[0], - messageId: "noShadow", - data: variable + messageId, + data }); } } diff --git a/tests/lib/rules/no-shadow.js b/tests/lib/rules/no-shadow.js index 365b2f5d5d3..dc2cc63c4de 100644 --- a/tests/lib/rules/no-shadow.js +++ b/tests/lib/rules/no-shadow.js @@ -64,7 +64,11 @@ ruleTester.run("no-shadow", rule, { code: "function a(x) { var b = function c() { var x = 'foo'; }; }", errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 12 + }, type: "Identifier", line: 1, column: 44 @@ -75,7 +79,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 10 + }, type: "Identifier", line: 1, column: 38 @@ -85,7 +93,11 @@ ruleTester.run("no-shadow", rule, { code: "function a(x) { var b = function () { var x = 'foo'; }; }", errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 12 + }, type: "Identifier", line: 1, column: 43 @@ -95,7 +107,11 @@ ruleTester.run("no-shadow", rule, { code: "var x = 1; function a(x) { return ++x; }", errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier", line: 1, column: 23 @@ -105,7 +121,11 @@ ruleTester.run("no-shadow", rule, { code: "var a=3; function b() { var a=10; }", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier" }] }, @@ -113,7 +133,11 @@ ruleTester.run("no-shadow", rule, { code: "var a=3; function b() { var a=10; }; setTimeout(function() { b(); }, 0);", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier" }] }, @@ -122,11 +146,19 @@ ruleTester.run("no-shadow", rule, { errors: [ { messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier" }, { messageId: "noShadow", - data: { name: "b" }, + data: { + name: "b", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" } ] @@ -136,7 +168,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier" }] }, @@ -145,7 +181,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "x" }, + data: { + name: "x", + shadowedLine: 1, + shadowedColumn: 5 + }, type: "Identifier" }] }, @@ -154,7 +194,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 21 + }, type: "Identifier" }] }, @@ -163,7 +207,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 27 + }, type: "Identifier" }] }, @@ -172,7 +220,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 36 + }, type: "Identifier" }] }, @@ -181,7 +233,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 36 + }, type: "Identifier" }] }, @@ -190,7 +246,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 30 + }, type: "Identifier" }] }, @@ -200,7 +260,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 16 + }, type: "Identifier" }] }, @@ -210,7 +274,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 16 + }, type: "Identifier" }] }, @@ -220,7 +288,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 21 + }, type: "Identifier" }] }, @@ -230,7 +302,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 24 + }, type: "Identifier" }] }, @@ -240,7 +316,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 22 + }, type: "Identifier" }] }, @@ -250,7 +330,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 27 + }, type: "Identifier" }] }, @@ -260,7 +344,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 31 + }, type: "Identifier" }] }, @@ -270,7 +358,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 31 + }, type: "Identifier" }] }, @@ -280,7 +372,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 36 + }, type: "Identifier" }] }, @@ -290,7 +386,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 31 + }, type: "Identifier" }] }, @@ -300,7 +400,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 31 + }, type: "Identifier" }] }, @@ -310,7 +414,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 36 + }, type: "Identifier" }] }, @@ -320,7 +428,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 25 + }, type: "Identifier" }] }, @@ -330,7 +442,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 25 + }, type: "Identifier" }] }, @@ -340,7 +456,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 30 + }, type: "Identifier" }] }, @@ -348,7 +468,11 @@ ruleTester.run("no-shadow", rule, { code: "(function a() { function a(){} })()", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 11 + }, type: "Identifier" }] }, @@ -357,7 +481,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 11 + }, type: "Identifier" }] }, @@ -365,7 +493,11 @@ ruleTester.run("no-shadow", rule, { code: "(function a() { (function a(){}); })()", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 11 + }, type: "Identifier" }] }, @@ -374,7 +506,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 11 + }, type: "Identifier" }] }, @@ -382,7 +518,11 @@ ruleTester.run("no-shadow", rule, { code: "(function() { var a = function(a) {}; })()", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -390,7 +530,11 @@ ruleTester.run("no-shadow", rule, { code: "(function() { var a = function() { function a() {} }; })()", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -399,7 +543,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -407,7 +555,11 @@ ruleTester.run("no-shadow", rule, { code: "(function() { var a = function() { (function a() {}); }; })()", errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -416,7 +568,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -425,7 +581,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 19 + }, type: "Identifier" }] }, @@ -434,7 +594,11 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "noShadow", - data: { name: "A" }, + data: { + name: "A", + shadowedLine: 1, + shadowedColumn: 7 + }, type: "Identifier" }] }, @@ -443,14 +607,22 @@ ruleTester.run("no-shadow", rule, { errors: [ { messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 11 + }, type: "Identifier", line: 1, column: 26 }, { messageId: "noShadow", - data: { name: "a" }, + data: { + name: "a", + shadowedLine: 1, + shadowedColumn: 26 + }, type: "Identifier", line: 1, column: 40 @@ -461,8 +633,10 @@ ruleTester.run("no-shadow", rule, { code: "function foo() { var Object = 0; }", options: [{ builtinGlobals: true }], errors: [{ - messageId: "noShadow", - data: { name: "Object" }, + messageId: "noShadowGlobal", + data: { + name: "Object" + }, type: "Identifier" }] }, @@ -471,8 +645,10 @@ ruleTester.run("no-shadow", rule, { options: [{ builtinGlobals: true }], env: { browser: true }, errors: [{ - messageId: "noShadow", - data: { name: "top" }, + messageId: "noShadowGlobal", + data: { + name: "top" + }, type: "Identifier" }] }, @@ -481,8 +657,10 @@ ruleTester.run("no-shadow", rule, { options: [{ builtinGlobals: true }], parserOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [{ - messageId: "noShadow", - data: { name: "Object" }, + messageId: "noShadowGlobal", + data: { + name: "Object" + }, type: "Identifier" }] }, @@ -492,8 +670,10 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaVersion: 6, sourceType: "module" }, env: { browser: true }, errors: [{ - messageId: "noShadow", - data: { name: "top" }, + messageId: "noShadowGlobal", + data: { + name: "top" + }, type: "Identifier" }] }, @@ -502,8 +682,10 @@ ruleTester.run("no-shadow", rule, { options: [{ builtinGlobals: true }], parserOptions: { ecmaFeatures: { globalReturn: true } }, errors: [{ - messageId: "noShadow", - data: { name: "Object" }, + messageId: "noShadowGlobal", + data: { + name: "Object" + }, type: "Identifier" }] }, @@ -513,8 +695,10 @@ ruleTester.run("no-shadow", rule, { parserOptions: { ecmaFeatures: { globalReturn: true } }, env: { browser: true }, errors: [{ - messageId: "noShadow", - data: { name: "top" }, + messageId: "noShadowGlobal", + data: { + name: "top" + }, type: "Identifier" }] }, @@ -522,7 +706,11 @@ ruleTester.run("no-shadow", rule, { code: "function foo(cb) { (function (cb) { cb(42); })(cb); }", errors: [{ messageId: "noShadow", - data: { name: "cb" }, + data: { + name: "cb", + shadowedLine: 1, + shadowedColumn: 14 + }, type: "Identifier", line: 1, column: 31