зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1773747 - Part 6: Add ESLint rule to check immediately-used lazy getter. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D149867
This commit is contained in:
Родитель
55a0bf7709
Коммит
ab853db23f
|
@ -2,8 +2,8 @@ valid-lazy
|
|||
==========
|
||||
|
||||
Ensures that definitions and uses of properties on the ``lazy`` object are valid.
|
||||
This rule checks for using unknown properties, duplicated symbols and unused
|
||||
symbols.
|
||||
This rule checks for using unknown properties, duplicated symbols, unused
|
||||
symbols, and also lazy getter used at top-level unconditionally.
|
||||
|
||||
Examples of incorrect code for this rule:
|
||||
-----------------------------------------
|
||||
|
@ -11,8 +11,10 @@ Examples of incorrect code for this rule:
|
|||
.. code-block:: js
|
||||
|
||||
const lazy = {};
|
||||
// Unknown lazy member property {{name}}
|
||||
lazy.bar.foo();
|
||||
if (x) {
|
||||
// Unknown lazy member property {{name}}
|
||||
lazy.bar.foo();
|
||||
}
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
|
@ -21,7 +23,9 @@ Examples of incorrect code for this rule:
|
|||
|
||||
// Duplicate symbol foo being added to lazy.
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", "foo1.jsm");
|
||||
lazy.foo3.bar();
|
||||
if (x) {
|
||||
lazy.foo3.bar();
|
||||
}
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
|
@ -29,6 +33,13 @@ Examples of incorrect code for this rule:
|
|||
// Unused lazy property foo
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", "foo.jsm");
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", "foo.jsm");
|
||||
// Used at top-level unconditionally.
|
||||
lazy.foo.bar();
|
||||
|
||||
Examples of correct code for this rule:
|
||||
---------------------------------------
|
||||
|
||||
|
@ -38,5 +49,7 @@ Examples of correct code for this rule:
|
|||
XPCOMUtils.defineLazyGetter(lazy, "foo1", () => {});
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, { foo2: "foo2.jsm" });
|
||||
|
||||
lazy.foo1.bar();
|
||||
lazy.foo2.bar();
|
||||
if (x) {
|
||||
lazy.foo1.bar();
|
||||
lazy.foo2.bar();
|
||||
}
|
||||
|
|
|
@ -533,6 +533,61 @@ module.exports = {
|
|||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the node is evaluated at top-level script unconditionally.
|
||||
*
|
||||
* @param {Array} ancestors
|
||||
* The parents of the current node.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True or false
|
||||
*/
|
||||
getIsTopLevelAndUnconditionallyExecuted(ancestors) {
|
||||
for (let parent of ancestors) {
|
||||
switch (parent.type) {
|
||||
// Control flow
|
||||
case "IfStatement":
|
||||
case "SwitchStatement":
|
||||
case "TryStatement":
|
||||
case "WhileStatement":
|
||||
case "DoWhileStatement":
|
||||
case "ForStatement":
|
||||
case "ForInStatement":
|
||||
case "ForOfStatement":
|
||||
return false;
|
||||
|
||||
// Function
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
case "ClassBody":
|
||||
return false;
|
||||
|
||||
// Branch
|
||||
case "LogicalExpression":
|
||||
case "ConditionalExpression":
|
||||
case "ChainExpression":
|
||||
return false;
|
||||
|
||||
case "AssignmentExpression":
|
||||
switch (parent.operator) {
|
||||
// Branch
|
||||
case "||=":
|
||||
case "&&=":
|
||||
case "??=":
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// Implicit branch (default value)
|
||||
case "ObjectPattern":
|
||||
case "ArrayPattern":
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether we might be in a test head file.
|
||||
*
|
||||
|
|
|
@ -59,6 +59,8 @@ module.exports = {
|
|||
incorrectType: "Unexpected literal for property name {{name}}",
|
||||
unknownProperty: "Unknown lazy member property {{name}}",
|
||||
unusedProperty: "Unused lazy property {{name}}",
|
||||
topLevelAndUnconditional:
|
||||
"Lazy property {{name}} is used at top-level unconditionally. It should be non-lazy.",
|
||||
},
|
||||
type: "problem",
|
||||
},
|
||||
|
@ -178,6 +180,17 @@ module.exports = {
|
|||
} else {
|
||||
property.used = true;
|
||||
}
|
||||
if (
|
||||
helpers.getIsTopLevelAndUnconditionallyExecuted(
|
||||
context.getAncestors()
|
||||
)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "topLevelAndUnconditional",
|
||||
data: { name },
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
"Program:exit": function() {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
var rule = require("../lib/rules/valid-lazy");
|
||||
var RuleTester = require("eslint").RuleTester;
|
||||
|
||||
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
|
||||
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 13 } });
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Tests
|
||||
|
@ -27,30 +27,30 @@ ruleTester.run("valid-lazy", rule, {
|
|||
`
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", () => {});
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
`
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
foo: "foo.jsm",
|
||||
});
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
`
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
foo: "foo.mjs",
|
||||
});
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
`
|
||||
const lazy = {};
|
||||
Integration.downloads.defineModuleGetter(lazy, "foo", "foo.jsm");
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
`
|
||||
const lazy = createLazyLoaders({ foo: () => {}});
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
`
|
||||
const lazy = {};
|
||||
|
@ -60,18 +60,57 @@ ruleTester.run("valid-lazy", rule, {
|
|||
"bar",
|
||||
true
|
||||
);
|
||||
lazy.foo1.bar();
|
||||
lazy.foo2.bar();
|
||||
if (x) {
|
||||
lazy.foo1.bar();
|
||||
lazy.foo2.bar();
|
||||
}
|
||||
`,
|
||||
// Test for top-level unconditional.
|
||||
`
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", () => {});
|
||||
if (x) { lazy.foo.bar(); }
|
||||
for (;;) { lazy.foo.bar(); }
|
||||
for (var x in y) { lazy.foo.bar(); }
|
||||
for (var x of y) { lazy.foo.bar(); }
|
||||
while (true) { lazy.foo.bar(); }
|
||||
do { lazy.foo.bar(); } while (true);
|
||||
switch (x) { case 1: lazy.foo.bar(); }
|
||||
try { lazy.foo.bar(); } catch (e) {}
|
||||
function f() { lazy.foo.bar(); }
|
||||
(function f() { lazy.foo.bar(); });
|
||||
() => { lazy.foo.bar(); };
|
||||
class C {
|
||||
constructor() { lazy.foo.bar(); }
|
||||
foo() { lazy.foo.bar(); }
|
||||
get x() { lazy.foo.bar(); }
|
||||
set x(v) { lazy.foo.bar(); }
|
||||
a = lazy.foo.bar();
|
||||
#b = lazy.foo.bar();
|
||||
static {
|
||||
lazy.foo.bar();
|
||||
}
|
||||
}
|
||||
a && lazy.foo.bar();
|
||||
a || lazy.foo.bar();
|
||||
a ?? lazy.foo.bar();
|
||||
a ? lazy.foo.bar() : b;
|
||||
a?.b[lazy.foo.bar()];
|
||||
a ||= lazy.foo.bar();
|
||||
a &&= lazy.foo.bar();
|
||||
a ??= lazy.foo.bar();
|
||||
var { x = lazy.foo.bar() } = {};
|
||||
var [ y = lazy.foo.bar() ] = [];
|
||||
`,
|
||||
],
|
||||
invalid: [
|
||||
invalidCode("lazy.bar", "bar", "unknownProperty"),
|
||||
invalidCode("if (x) { lazy.bar; }", "bar", "unknownProperty"),
|
||||
invalidCode(
|
||||
`
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", "foo.jsm");
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo", "foo1.jsm");
|
||||
lazy.foo.bar();
|
||||
if (x) { lazy.foo.bar(); }
|
||||
`,
|
||||
"foo",
|
||||
"duplicateSymbol"
|
||||
|
@ -82,7 +121,7 @@ ruleTester.run("valid-lazy", rule, {
|
|||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
"foo-bar": "foo.jsm",
|
||||
});
|
||||
lazy["foo-bar"].bar();
|
||||
if (x) { lazy["foo-bar"].bar(); }
|
||||
`,
|
||||
"foo-bar",
|
||||
"incorrectType"
|
||||
|
@ -94,5 +133,19 @@ ruleTester.run("valid-lazy", rule, {
|
|||
"foo",
|
||||
"unusedProperty"
|
||||
),
|
||||
invalidCode(
|
||||
`const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo1", () => {});
|
||||
lazy.foo1.bar();`,
|
||||
"foo1",
|
||||
"topLevelAndUnconditional"
|
||||
),
|
||||
invalidCode(
|
||||
`const lazy = {};
|
||||
XPCOMUtils.defineLazyGetter(lazy, "foo1", () => {});
|
||||
{ x = -f(1 + lazy.foo1.bar()); }`,
|
||||
"foo1",
|
||||
"topLevelAndUnconditional"
|
||||
),
|
||||
],
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче