Skip to content

linter: dynamically skip running rules that do not have the relevant node types #12223

@camchenry

Description

@camchenry

Context

In #8854, we experimented with adding improved metadata for rules to allow us to skip executing rules that don't apply. This yielded up to +8% performance improvements across small and big files. But the amount of code we needed to change didn't seem worth the performance improvement, so we gave up on the approach for now.

In #12178, I experimented with a different approach from the previous PR. Instead of modifying the return type of should_run: we can add or improve should_run for more rules which are currently run unconditionally. Using a fast lookup method to check if a node kind is in the AST, we can skip running rules on files that don't contain any nodes which are relevant to the rule.

Why we are doing this

Suppose that a file has 10,000 AST nodes, and we are running the linter with 100 rules enabled. The main loop of the linter will: iterate over all rules, and then iterate over all nodes, for each rule (ignoring jest nodes, symbols, and run-once rules for simplicity). This means that we will do 100 rules * 10,000 nodes = 1,000,000 iterations.

Now suppose this file doesn't contain any class definitions. There are a number of rules that check for class-specific behavior, like typescript/no-unnecessary-parameter-property-assignment, eslint/max-classes-per-file, and typescript/no-extraneous-class which we know will not report any diagnostics, because they can only report diagnostics if a class is in the AST. So, we know that some rules can be skipped just based on the types of AST nodes that are in the file. Assuming that we can quickly compute what types of AST nodes are in a given file, assume we're able to automatically skip 10 rules from the linter, so now we're only running 90 rules, down from 100. Now, we only need to do 90 rules * 10,000 nodes = 900,000 iterations.

So, by eliminating 10 rules out of the set of 100 rules that are enabled, we are able to reduce the number of iterations needed by 10%, which does somewhat correlate with walltime performance.

Process

  1. Identify a lint rule that has no should_run, or only has a simple should_run, such as checking the source type or checking that TypeScript is enabled.
  2. Update the rule to contain a check on the file's node types, so that if no relevant node types are in the file, the method returns false.

Example PR: #12228

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-linterArea - LinterC-performanceCategory - Solution not expected to change functional behavior, only performance

    Type

    Priority

    None yet

    Effort

    None yet

    Start date

    None yet

    Target date

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions