Skip to content

Commit

Permalink
refactor(core): register rules using visitor pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Jul 23, 2024
1 parent cbf3e77 commit c907590
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 149 deletions.
4 changes: 2 additions & 2 deletions crates/biome_analyze/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,15 @@ impl<'a> RuleFilter<'a> {
}
}
/// Return `true` if the group `G` matches this filter
fn match_group<G: RuleGroup>(self) -> bool {
pub fn match_group<G: RuleGroup>(self) -> bool {
match self {
RuleFilter::Group(group) => group == G::NAME,
RuleFilter::Rule(group, _) => group == G::NAME,
}
}

/// Return `true` if the rule `R` matches this filter
fn match_rule<R>(self) -> bool
pub fn match_rule<R>(self) -> bool
where
R: Rule,
{
Expand Down
9 changes: 9 additions & 0 deletions crates/biome_configuration/src/linter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,15 @@ impl From<RuleSelector> for RuleFilter<'static> {
}
}

impl<'a> From<&'a RuleSelector> for RuleFilter<'static> {
fn from(value: &'a RuleSelector) -> Self {
match value {
RuleSelector::Group(group) => RuleFilter::Group(group.as_str()),
RuleSelector::Rule(group, name) => RuleFilter::Rule(group.as_str(), name),
}
}
}

impl FromStr for RuleSelector {
type Err = &'static str;
fn from_str(selector: &str) -> Result<Self, Self::Err> {
Expand Down
53 changes: 19 additions & 34 deletions crates/biome_service/src/file_handlers/css.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
is_diagnostic_error, CodeActionsParams, ExtensionHandler, FixAllParams, LintParams,
LintResults, ParseResult, SearchCapabilities, SyntaxVisitor,
is_diagnostic_error, ActionVisitor, CodeActionsParams, ExtensionHandler, FixAllParams,
LintParams, LintResults, LintVisitor, ParseResult, SearchCapabilities, SyntaxVisitor,
};
use crate::configuration::to_analyzer_rules;
use crate::file_handlers::DebugCapabilities;
Expand All @@ -21,7 +21,7 @@ use biome_analyze::{
AnalysisFilter, AnalyzerConfiguration, AnalyzerOptions, ControlFlow, Never,
RuleCategoriesBuilder, RuleCategory, RuleError,
};
use biome_css_analyze::analyze;
use biome_css_analyze::{analyze, visit_registry};
use biome_css_formatter::context::CssFormatOptions;
use biome_css_formatter::format_node;
use biome_css_parser::CssParserOptions;
Expand All @@ -31,7 +31,6 @@ use biome_formatter::{
FormatError, IndentStyle, IndentWidth, LineEnding, LineWidth, Printed, QuoteStyle,
};
use biome_fs::BiomePath;
use biome_js_analyze::visit_registry;
use biome_parser::AnyParse;
use biome_rowan::{AstNode, NodeCache};
use biome_rowan::{TextRange, TextSize, TokenAtOffset};
Expand Down Expand Up @@ -338,42 +337,28 @@ fn lint(params: LintParams) -> LintResults {
let analyzer_options =
workspace_settings.analyzer_options::<CssLanguage>(params.path, &params.language);
let tree = params.parse.tree();
let mut diagnostics = params.parse.into_diagnostics();

let has_only_filter = !params.only.is_empty();
let mut rules = None;

let mut enabled_rules = if let Some(settings) = params.workspace.settings() {
// Compute final rules (taking `overrides` into account)
rules = settings.as_rules(params.path.as_path());

if has_only_filter {
params
.only
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>()
} else {
rules
.as_ref()
.map(|rules| rules.as_enabled_rules())
.unwrap_or_default()
.into_iter()
.collect::<Vec<_>>()
}
} else {
Vec::new()
};
let rules = params
.workspace
.settings()
.as_ref()
.and_then(|settings| settings.as_rules(params.path.as_path()));

let mut enabled_rules = vec![];
let mut disabled_rules = vec![];
let mut syntax_visitor = SyntaxVisitor::default();
let mut lint_visitor = LintVisitor::new(&params);
let mut action_visitor = ActionVisitor::new(&params);
visit_registry(&mut syntax_visitor);
visit_registry(&mut lint_visitor);
visit_registry(&mut action_visitor);
enabled_rules.extend(syntax_visitor.enabled_rules);

let disabled_rules = params
.skip
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>();
let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish();
enabled_rules.extend(lint_enabled_rules);
disabled_rules.extend(lint_disabled_rules);
enabled_rules.extend(action_visitor.enabled_rules);
let mut diagnostics = params.parse.into_diagnostics();

let filter = AnalysisFilter {
categories: params.categories,
Expand Down
54 changes: 20 additions & 34 deletions crates/biome_service/src/file_handlers/graphql.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{
is_diagnostic_error, CodeActionsParams, DocumentFileSource, ExtensionHandler, FixAllParams,
LintParams, LintResults, ParseResult, SearchCapabilities, SyntaxVisitor,
is_diagnostic_error, ActionVisitor, CodeActionsParams, DocumentFileSource, ExtensionHandler,
FixAllParams, LintParams, LintResults, LintVisitor, ParseResult, SearchCapabilities,
SyntaxVisitor,
};
use crate::file_handlers::DebugCapabilities;
use crate::file_handlers::{
Expand All @@ -24,12 +25,11 @@ use biome_formatter::{
QuoteStyle,
};
use biome_fs::BiomePath;
use biome_graphql_analyze::analyze;
use biome_graphql_analyze::{analyze, visit_registry};
use biome_graphql_formatter::context::GraphqlFormatOptions;
use biome_graphql_formatter::format_node;
use biome_graphql_parser::parse_graphql_with_cache;
use biome_graphql_syntax::{GraphqlLanguage, GraphqlRoot, GraphqlSyntaxNode, TextRange, TextSize};
use biome_js_analyze::visit_registry;
use biome_parser::AnyParse;
use biome_rowan::{AstNode, NodeCache, TokenAtOffset};
use std::borrow::Cow;
Expand Down Expand Up @@ -296,42 +296,28 @@ fn lint(params: LintParams) -> LintResults {
let analyzer_options = workspace_settings
.analyzer_options::<GraphqlLanguage>(params.path, &params.language);
let tree = params.parse.tree();
let mut diagnostics = params.parse.into_diagnostics();

let has_only_filter = !params.only.is_empty();
let mut rules = None;

let mut enabled_rules = if let Some(settings) = params.workspace.settings() {
// Compute final rules (taking `overrides` into account)
rules = settings.as_rules(params.path.as_path());

if has_only_filter {
params
.only
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>()
} else {
rules
.as_ref()
.map(|rules| rules.as_enabled_rules())
.unwrap_or_default()
.into_iter()
.collect::<Vec<_>>()
}
} else {
Vec::new()
};
let rules = params
.workspace
.settings()
.as_ref()
.and_then(|settings| settings.as_rules(params.path.as_path()));

let mut enabled_rules = vec![];
let mut disabled_rules = vec![];
let mut syntax_visitor = SyntaxVisitor::default();
let mut lint_visitor = LintVisitor::new(&params);
let mut action_visitor = ActionVisitor::new(&params);
visit_registry(&mut syntax_visitor);
visit_registry(&mut lint_visitor);
visit_registry(&mut action_visitor);
enabled_rules.extend(syntax_visitor.enabled_rules);

let disabled_rules = params
.skip
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>();
let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish();
enabled_rules.extend(lint_enabled_rules);
disabled_rules.extend(lint_disabled_rules);
enabled_rules.extend(action_visitor.enabled_rules);
let mut diagnostics = params.parse.into_diagnostics();

let filter = AnalysisFilter {
categories: params.categories,
Expand Down
61 changes: 20 additions & 41 deletions crates/biome_service/src/file_handlers/javascript.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{
search, AnalyzerCapabilities, CodeActionsParams, DebugCapabilities, ExtensionHandler,
FormatterCapabilities, LintParams, LintResults, ParseResult, ParserCapabilities,
SearchCapabilities, SyntaxVisitor,
search, ActionVisitor, AnalyzerCapabilities, CodeActionsParams, DebugCapabilities,
ExtensionHandler, FormatterCapabilities, LintParams, LintResults, LintVisitor, ParseResult,
ParserCapabilities, SearchCapabilities, SyntaxVisitor,
};
use crate::configuration::to_analyzer_rules;
use crate::diagnostics::extension_error;
Expand Down Expand Up @@ -416,48 +416,29 @@ pub(crate) fn lint(params: LintParams) -> LintResults {
};
};
let tree = params.parse.tree();
let mut diagnostics = params.parse.into_diagnostics();
let analyzer_options = &params
.workspace
.analyzer_options::<JsLanguage>(params.path, &params.language);

let mut rules = None;
let mut organize_imports_enabled = true;
if let Some(settings) = params.workspace.settings() {
// Compute final rules (taking `overrides` into account)
rules = settings.as_rules(params.path.as_path());
organize_imports_enabled = settings.organize_imports.enabled;
}

let has_only_filter = !params.only.is_empty();
let mut enabled_rules = if has_only_filter {
params
.only
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>()
} else {
let mut enabled_rules = rules
.as_ref()
.map(|rules| rules.as_enabled_rules())
.unwrap_or_default()
.into_iter()
.collect::<Vec<_>>();
if organize_imports_enabled && !params.categories.is_syntax() {
enabled_rules.push(RuleFilter::Rule("correctness", "organizeImports"));
}
enabled_rules
};
let rules = params
.workspace
.settings()
.as_ref()
.and_then(|settings| settings.as_rules(params.path.as_path()));

let mut enabled_rules = vec![];
let mut disabled_rules = vec![];
let mut syntax_visitor = SyntaxVisitor::default();
let mut lint_visitor = LintVisitor::new(&params);
let mut action_visitor = ActionVisitor::new(&params);
visit_registry(&mut syntax_visitor);
visit_registry(&mut lint_visitor);
visit_registry(&mut action_visitor);
enabled_rules.extend(syntax_visitor.enabled_rules);

let disabled_rules = params
.skip
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>();
let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish();
enabled_rules.extend(lint_enabled_rules);
disabled_rules.extend(lint_disabled_rules);
enabled_rules.extend(action_visitor.enabled_rules);

let filter = AnalysisFilter {
categories: params.categories,
Expand All @@ -466,12 +447,10 @@ pub(crate) fn lint(params: LintParams) -> LintResults {
range: None,
};

// Do not report unused suppression comment diagnostics if:
// - it is a syntax-only analyzer pass, or
// - if a single rule is run.
let ignores_suppression_comment =
!filter.categories.contains(RuleCategory::Lint) || has_only_filter;
!filter.categories.contains(RuleCategory::Lint) || !params.only.is_empty();

let mut diagnostics = params.parse.into_diagnostics();
let mut diagnostic_count = diagnostics.len() as u32;
let mut errors = diagnostics
.iter()
Expand Down
66 changes: 28 additions & 38 deletions crates/biome_service/src/file_handlers/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::borrow::Cow;
use std::ffi::OsStr;

use super::{
CodeActionsParams, DocumentFileSource, ExtensionHandler, ParseResult, SearchCapabilities,
SyntaxVisitor,
ActionVisitor, CodeActionsParams, DocumentFileSource, ExtensionHandler, LintVisitor,
ParseResult, SearchCapabilities, SyntaxVisitor,
};
use crate::configuration::to_analyzer_rules;
use crate::file_handlers::DebugCapabilities;
Expand All @@ -29,8 +29,7 @@ use biome_deserialize::json::deserialize_from_json_ast;
use biome_diagnostics::{category, Diagnostic, DiagnosticExt, Severity};
use biome_formatter::{FormatError, IndentStyle, IndentWidth, LineEnding, LineWidth, Printed};
use biome_fs::{BiomePath, ConfigName, ROME_JSON};
use biome_json_analyze::analyze;
use biome_json_analyze::visit_registry;
use biome_json_analyze::{analyze, visit_registry};
use biome_json_formatter::context::{JsonFormatOptions, TrailingCommas};
use biome_json_formatter::format_node;
use biome_json_parser::JsonParserOptions;
Expand Down Expand Up @@ -318,8 +317,32 @@ fn lint(params: LintParams) -> LintResults {
};
};
let root: JsonRoot = params.parse.tree();
let mut diagnostics = params.parse.into_diagnostics();

let analyzer_options = &params
.workspace
.analyzer_options::<JsonLanguage>(params.path, &params.language);

let has_only_filter = !params.only.is_empty();
let rules = params
.workspace
.settings()
.as_ref()
.and_then(|settings| settings.as_rules(params.path.as_path()));

let mut enabled_rules = vec![];
let mut disabled_rules = vec![];
let mut syntax_visitor = SyntaxVisitor::default();
let mut lint_visitor = LintVisitor::new(&params);
let mut action_visitor = ActionVisitor::new(&params);
visit_registry(&mut syntax_visitor);
visit_registry(&mut lint_visitor);
visit_registry(&mut action_visitor);
enabled_rules.extend(syntax_visitor.enabled_rules);
let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish();
enabled_rules.extend(lint_enabled_rules);
disabled_rules.extend(lint_disabled_rules);
enabled_rules.extend(action_visitor.enabled_rules);
let mut diagnostics = params.parse.into_diagnostics();
// if we're parsing the `biome.json` file, we deserialize it, so we can emit diagnostics for
// malformed configuration
if params.path.ends_with(ROME_JSON)
Expand All @@ -335,39 +358,6 @@ fn lint(params: LintParams) -> LintResults {
.collect::<Vec<_>>(),
);
}

let analyzer_options = &params
.workspace
.analyzer_options::<JsonLanguage>(params.path, &params.language);

let mut rules = None;
if let Some(settings) = params.workspace.settings() {
rules = settings.as_rules(params.path.as_path());
}

let has_only_filter = !params.only.is_empty();
let mut enabled_rules = if has_only_filter {
params
.only
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>()
} else {
rules
.as_ref()
.map(|rules| rules.as_enabled_rules())
.unwrap_or_default()
.into_iter()
.collect::<Vec<_>>()
};
let mut syntax_visitor = SyntaxVisitor::default();
biome_js_analyze::visit_registry(&mut syntax_visitor);
enabled_rules.extend(syntax_visitor.enabled_rules);
let disabled_rules = params
.skip
.into_iter()
.map(|selector| selector.into())
.collect::<Vec<_>>();
let filter = AnalysisFilter {
categories: params.categories,
enabled_rules: Some(enabled_rules.as_slice()),
Expand Down
Loading

0 comments on commit c907590

Please sign in to comment.