Skip to content

Commit 3a430fa

Browse files
authored
[ty] Allow overriding rules for specific files (#18648)
1 parent 782363b commit 3a430fa

File tree

31 files changed

+1948
-315
lines changed

31 files changed

+1948
-315
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ruff_db/src/diagnostic/mod.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,73 @@ pub enum DiagnosticId {
668668

669669
/// A glob pattern doesn't follow the expected syntax.
670670
InvalidGlob,
671+
672+
/// An `include` glob without any patterns.
673+
///
674+
/// ## Why is this bad?
675+
/// An `include` glob without any patterns won't match any files. This is probably a mistake and
676+
/// either the `include` should be removed or a pattern should be added.
677+
///
678+
/// ## Example
679+
/// ```toml
680+
/// [src]
681+
/// include = []
682+
/// ```
683+
///
684+
/// Use instead:
685+
///
686+
/// ```toml
687+
/// [src]
688+
/// include = ["src"]
689+
/// ```
690+
///
691+
/// or remove the `include` option.
692+
EmptyInclude,
693+
694+
/// An override configuration is unnecessary because it applies to all files.
695+
///
696+
/// ## Why is this bad?
697+
/// An overrides section that applies to all files is probably a mistake and can be rolled-up into the root configuration.
698+
///
699+
/// ## Example
700+
/// ```toml
701+
/// [[overrides]]
702+
/// [overrides.rules]
703+
/// unused-reference = "ignore"
704+
/// ```
705+
///
706+
/// Use instead:
707+
///
708+
/// ```toml
709+
/// [rules]
710+
/// unused-reference = "ignore"
711+
/// ```
712+
///
713+
/// or
714+
///
715+
/// ```toml
716+
/// [[overrides]]
717+
/// include = ["test"]
718+
///
719+
/// [overrides.rules]
720+
/// unused-reference = "ignore"
721+
/// ```
722+
UnnecessaryOverridesSection,
723+
724+
/// An `overrides` section in the configuration that doesn't contain any overrides.
725+
///
726+
/// ## Why is this bad?
727+
/// An `overrides` section without any configuration overrides is probably a mistake.
728+
/// It is either a leftover after removing overrides, or a user forgot to add any overrides,
729+
/// or used an incorrect syntax to do so (e.g. used `rules` instead of `overrides.rules`).
730+
///
731+
/// ## Example
732+
/// ```toml
733+
/// [[overrides]]
734+
/// include = ["test"]
735+
/// # no `[overrides.rules]`
736+
/// ```
737+
UselessOverridesSection,
671738
}
672739

673740
impl DiagnosticId {
@@ -703,6 +770,9 @@ impl DiagnosticId {
703770
DiagnosticId::RevealedType => "revealed-type",
704771
DiagnosticId::UnknownRule => "unknown-rule",
705772
DiagnosticId::InvalidGlob => "invalid-glob",
773+
DiagnosticId::EmptyInclude => "empty-include",
774+
DiagnosticId::UnnecessaryOverridesSection => "unnecessary-overrides-section",
775+
DiagnosticId::UselessOverridesSection => "useless-overrides-section",
706776
}
707777
}
708778

crates/ruff_db/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ pub fn max_parallelism() -> NonZeroUsize {
5959
})
6060
}
6161

62+
/// Trait for types that can provide Rust documentation.
63+
///
64+
/// Use `derive(RustDoc)` to automatically implement this trait for types that have a static string documentation.
65+
pub trait RustDoc {
66+
fn rust_doc() -> &'static str;
67+
}
68+
6269
#[cfg(test)]
6370
mod tests {
6471
use std::sync::{Arc, Mutex};

crates/ruff_graph/src/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl Db for ModuleDb {
9292
!file.path(self).is_vendored_path()
9393
}
9494

95-
fn rule_selection(&self) -> &RuleSelection {
95+
fn rule_selection(&self, _file: File) -> &RuleSelection {
9696
&self.rule_selection
9797
}
9898

crates/ruff_macros/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod map_codes;
1616
mod newtype_index;
1717
mod rule_code_prefix;
1818
mod rule_namespace;
19+
mod rust_doc;
1920
mod violation_metadata;
2021

2122
#[proc_macro_derive(OptionsMetadata, attributes(option, doc, option_group))]
@@ -27,6 +28,15 @@ pub fn derive_options_metadata(input: TokenStream) -> TokenStream {
2728
.into()
2829
}
2930

31+
#[proc_macro_derive(RustDoc)]
32+
pub fn derive_rust_doc(input: TokenStream) -> TokenStream {
33+
let input = parse_macro_input!(input as DeriveInput);
34+
35+
rust_doc::derive_impl(input)
36+
.unwrap_or_else(syn::Error::into_compile_error)
37+
.into()
38+
}
39+
3040
#[proc_macro_derive(CombineOptions)]
3141
pub fn derive_combine_options(input: TokenStream) -> TokenStream {
3242
let input = parse_macro_input!(input as DeriveInput);

crates/ruff_macros/src/rust_doc.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use proc_macro2::TokenStream;
2+
use quote::quote;
3+
use syn::{Attribute, DeriveInput, Error, Lit, LitStr, Meta};
4+
5+
pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result<TokenStream> {
6+
let docs = get_docs(&input.attrs)?;
7+
8+
let name = input.ident;
9+
10+
let (impl_generics, ty_generics, where_clause) = &input.generics.split_for_impl();
11+
12+
Ok(quote! {
13+
#[automatically_derived]
14+
impl #impl_generics ruff_db::RustDoc for #name #ty_generics #where_clause {
15+
fn rust_doc() -> &'static str {
16+
#docs
17+
}
18+
}
19+
})
20+
}
21+
/// Collect all doc comment attributes into a string
22+
fn get_docs(attrs: &[Attribute]) -> syn::Result<String> {
23+
let mut explanation = String::new();
24+
for attr in attrs {
25+
if attr.path().is_ident("doc") {
26+
if let Some(lit) = parse_attr(["doc"], attr) {
27+
let value = lit.value();
28+
// `/// ` adds
29+
let line = value.strip_prefix(' ').unwrap_or(&value);
30+
explanation.push_str(line);
31+
explanation.push('\n');
32+
} else {
33+
return Err(Error::new_spanned(attr, "unimplemented doc comment style"));
34+
}
35+
}
36+
}
37+
Ok(explanation)
38+
}
39+
40+
fn parse_attr<'a, const LEN: usize>(
41+
path: [&'static str; LEN],
42+
attr: &'a Attribute,
43+
) -> Option<&'a LitStr> {
44+
if let Meta::NameValue(name_value) = &attr.meta {
45+
let path_idents = name_value
46+
.path
47+
.segments
48+
.iter()
49+
.map(|segment| &segment.ident);
50+
51+
if path_idents.eq(path) {
52+
if let syn::Expr::Lit(syn::ExprLit {
53+
lit: Lit::Str(lit), ..
54+
}) = &name_value.value
55+
{
56+
return Some(lit);
57+
}
58+
}
59+
}
60+
61+
None
62+
}

crates/ty/docs/configuration.md

Lines changed: 149 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty/src/args.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,17 @@ impl CheckCommand {
205205
src: Some(SrcOptions {
206206
respect_ignore_files,
207207
exclude: self.exclude.map(|excludes| {
208-
excludes
209-
.iter()
210-
.map(|exclude| RelativeExcludePattern::cli(exclude))
211-
.collect()
208+
RangedValue::cli(
209+
excludes
210+
.iter()
211+
.map(|exclude| RelativeExcludePattern::cli(exclude))
212+
.collect(),
213+
)
212214
}),
213215
..SrcOptions::default()
214216
}),
215217
rules,
218+
..Options::default()
216219
};
217220
// Merge with options passed in via --config
218221
options.combine(self.config.into_options().unwrap_or_default())

0 commit comments

Comments
 (0)