context.markVariableAsUsed does not work consistently
See original GitHub issueTell us about your environment
- ESLint Version: master
- Node Version: 9.2.1
- npm Version: 5.6.0
What parser (default, Babel-ESLint, etc.) are you using?
default
What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.
'use strict';
const { Linter } = require('eslint');
const linter = new Linter();
linter.defineRule('test-rule', context => ({
'Program:exit'() {
const ast = context.getSourceCode().ast;
context.getDeclaredVariables(ast.body[0])
.forEach(variable => context.markVariableAsUsed(variable.name));
}
}));
const lintResults = linter.verify(
'function foo() {}',
{
rules: {
'no-unused-vars': 'error',
'test-rule': 'error'
},
parserOptions: {
sourceType: 'module'
}
}
);
console.log(lintResults);
node thatFile.js
What did you expect to happen?
I expected the list of lint results to be empty, because there is an unused variable in the program which gets marked with context.markVariableAsUsed
.
What actually happened? Please include the actual, raw output from ESLint.
An error is reported:
[ { ruleId: 'no-unused-vars',
severity: 2,
message: '\'foo\' is defined but never used.',
line: 1,
column: 10,
nodeType: 'Identifier',
source: 'function foo() {}',
endLine: 1,
endColumn: 13 } ]
Applying either of the following changes causes the error to disappear:
- Changing the
Program:exit
listener intest-rule
to aProgram
listener - Changing the order of
no-unused-vars
andtest-rule
in the config object
This is happening as a result of a design flaw in the context.markVariableAsUsed
API. When a rule uses context.markVarkableAsUsed
, it mutates a shared scope analysis object. The no-unused-vars
rule checks the scope analysis object in a Program:exit
listener, and avoids reporting an unused variable if the corresponding object has been marked by another rule. The problem is that another rule could call context.markVarkableAsUsed
after the Program:exit
listener in no-unused-vars
has already run.
ESLint does not make any guarantees about rule ordering, because rules are not supposed to be able to communicate with each other. (context.markVarkableAsUsed
is an exception to this.) Given that we now allow parsers to provide custom scope analysis, I think the best solution might just involve deprecating context.markVariableAsUsed
in favor of custom scope analysis. However, if we do take that route, we would probably need to provide a way for plugins to provide scope analysis info as well, so that (e.g.) the react/jsx-uses-vars
rule can be replaced with a scope analysis modification.
Issue Analytics
- State:
- Created 6 years ago
- Comments:13 (13 by maintainers)
Top GitHub Comments
I’m not sure I like the idea of plugins being able to cancel arbitrary reports from rules. It seems like that could cause confusion if a plugin is silencing a message from a rule that the user explicitly enables. I think it would be better to use
eslint-rule-composer
instead.(Having said that, I suppose plugins can already do this by using a processor.)
No, I’ll close this.