diff --git a/crates/ruff_linter/src/registry/rule_set.rs b/crates/ruff_linter/src/registry/rule_set.rs index a20f4ba0fd..7889ed81b5 100644 --- a/crates/ruff_linter/src/registry/rule_set.rs +++ b/crates/ruff_linter/src/registry/rule_set.rs @@ -207,6 +207,15 @@ impl RuleSet { *self = set.union(&RuleSet::from_rule(rule)); } + #[inline] + pub fn set(&mut self, rule: Rule, enabled: bool) { + if enabled { + self.insert(rule); + } else { + self.remove(rule); + } + } + /// Removes `rule` from the set. /// /// ## Examples diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 7d175bf673..ec3bdbb228 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -867,11 +867,7 @@ impl LintConfiguration { } else { // Otherwise we apply the updates on top of the existing select_set. for (rule, enabled) in select_map_updates { - if enabled { - select_set.insert(rule); - } else { - select_set.remove(rule); - } + select_set.set(rule, enabled); } for rule in docstring_override_updates { @@ -894,11 +890,7 @@ impl LintConfiguration { } } else { for (rule, enabled) in fixable_map_updates { - if enabled { - fixable_set.insert(rule); - } else { - fixable_set.remove(rule); - } + fixable_set.set(rule, enabled); } } @@ -1095,31 +1087,27 @@ impl LintConfiguration { #[must_use] pub fn combine(self, config: Self) -> Self { + let mut rule_selections = config.rule_selections; + rule_selections.extend(self.rule_selections); + + let mut extend_safe_fixes = config.extend_safe_fixes; + extend_safe_fixes.extend(self.extend_safe_fixes); + + let mut extend_unsafe_fixes = config.extend_unsafe_fixes; + extend_unsafe_fixes.extend(self.extend_unsafe_fixes); + + let mut extend_per_file_ignores = config.extend_per_file_ignores; + extend_per_file_ignores.extend(self.extend_per_file_ignores); + Self { exclude: self.exclude.or(config.exclude), preview: self.preview.or(config.preview), - rule_selections: config - .rule_selections - .into_iter() - .chain(self.rule_selections) - .collect(), - extend_safe_fixes: config - .extend_safe_fixes - .into_iter() - .chain(self.extend_safe_fixes) - .collect(), - extend_unsafe_fixes: config - .extend_unsafe_fixes - .into_iter() - .chain(self.extend_unsafe_fixes) - .collect(), + rule_selections, + extend_safe_fixes, + extend_unsafe_fixes, allowed_confusables: self.allowed_confusables.or(config.allowed_confusables), dummy_variable_rgx: self.dummy_variable_rgx.or(config.dummy_variable_rgx), - extend_per_file_ignores: config - .extend_per_file_ignores - .into_iter() - .chain(self.extend_per_file_ignores) - .collect(), + extend_per_file_ignores, external: self.external.or(config.external), ignore_init_module_imports: self .ignore_init_module_imports diff --git a/crates/ruff_workspace/src/resolver.rs b/crates/ruff_workspace/src/resolver.rs index bc5ec2e715..26791117fe 100644 --- a/crates/ruff_workspace/src/resolver.rs +++ b/crates/ruff_workspace/src/resolver.rs @@ -335,6 +335,12 @@ pub fn python_files_in_path<'a>( // Search for `pyproject.toml` files in all parent directories. let mut resolver = Resolver::new(pyproject_config); let mut seen = FxHashSet::default(); + + // Insert the path to the root configuration to avoid parsing the configuration a second time. + if let Some(config_path) = &pyproject_config.path { + seen.insert(config_path.parent().unwrap()); + } + if resolver.is_hierarchical() { for path in &paths { for ancestor in path.ancestors() { @@ -343,8 +349,12 @@ pub fn python_files_in_path<'a>( let (root, settings) = resolve_scoped_settings(&pyproject, Relativity::Parent, transformer)?; resolver.add(root, settings); + // We found the closest configuration. break; } + } else { + // We already visited this ancestor, we can stop here. + break; } } }