mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Merge pull request #18466 from ChayimFriedman2/proper-lint-severity
Properly handle different defaults for severity of lints
This commit is contained in:
commit
b707b5a117
15 changed files with 6630 additions and 1438 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -389,6 +389,10 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "edition"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
@ -1266,6 +1270,7 @@ name = "parser"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"drop_bomb",
|
"drop_bomb",
|
||||||
|
"edition",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"limit",
|
"limit",
|
||||||
"ra-ap-rustc_lexer",
|
"ra-ap-rustc_lexer",
|
||||||
|
@ -2662,6 +2667,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"directories",
|
"directories",
|
||||||
|
"edition",
|
||||||
"either",
|
"either",
|
||||||
"flate2",
|
"flate2",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
|
|
@ -83,6 +83,7 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" }
|
||||||
tt = { path = "./crates/tt", version = "0.0.0" }
|
tt = { path = "./crates/tt", version = "0.0.0" }
|
||||||
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
||||||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||||
|
edition = { path = "./crates/edition", version = "0.0.0" }
|
||||||
|
|
||||||
ra-ap-rustc_lexer = { version = "0.85", default-features = false }
|
ra-ap-rustc_lexer = { version = "0.85", default-features = false }
|
||||||
ra-ap-rustc_parse_format = { version = "0.85", default-features = false }
|
ra-ap-rustc_parse_format = { version = "0.85", default-features = false }
|
||||||
|
|
13
crates/edition/Cargo.toml
Normal file
13
crates/edition/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "edition"
|
||||||
|
version = "0.0.0"
|
||||||
|
rust-version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
|
@ -1,6 +1,5 @@
|
||||||
//! The edition of the Rust language used in a crate.
|
//! The edition of the Rust language used in a crate.
|
||||||
// Ideally this would be defined in the span crate, but the dependency chain is all over the place
|
// This should live in a separate crate because we use it in both actual code and codegen.
|
||||||
// wrt to span, parser and syntax.
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
@ -11,7 +11,7 @@ pub(super) fn complete_lint(
|
||||||
existing_lints: &[ast::Path],
|
existing_lints: &[ast::Path],
|
||||||
lints_completions: &[Lint],
|
lints_completions: &[Lint],
|
||||||
) {
|
) {
|
||||||
for &Lint { label, description } in lints_completions {
|
for &Lint { label, description, .. } in lints_completions {
|
||||||
let (qual, name) = {
|
let (qual, name) = {
|
||||||
// FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead?
|
// FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead?
|
||||||
let mut parts = label.split("::");
|
let mut parts = label.split("::");
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -327,3 +327,11 @@ impl<'a> Ranker<'a> {
|
||||||
| ((no_tt_parent as usize) << 3)
|
| ((no_tt_parent as usize) << 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Severity {
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
WeakWarning,
|
||||||
|
Allow,
|
||||||
|
}
|
||||||
|
|
|
@ -586,14 +586,47 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unsafe_op_in_unsafe_fn_allowed_by_default() {
|
fn unsafe_op_in_unsafe_fn_allowed_by_default_in_edition_2021() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
r#"
|
r#"
|
||||||
|
//- /lib.rs crate:foo edition:2021
|
||||||
unsafe fn foo(p: *mut i32) {
|
unsafe fn foo(p: *mut i32) {
|
||||||
*p = 123;
|
*p = 123;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
);
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:foo edition:2021
|
||||||
|
#![deny(warnings)]
|
||||||
|
unsafe fn foo(p: *mut i32) {
|
||||||
|
*p = 123;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsafe_op_in_unsafe_fn_warn_by_default_in_edition_2024() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:foo edition:2024
|
||||||
|
unsafe fn foo(p: *mut i32) {
|
||||||
|
*p = 123;
|
||||||
|
//^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:foo edition:2024
|
||||||
|
#![deny(warnings)]
|
||||||
|
unsafe fn foo(p: *mut i32) {
|
||||||
|
*p = 123;
|
||||||
|
//^^💡 error: dereference of raw pointer is unsafe and requires an unsafe function or block
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -84,12 +84,12 @@ use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFi
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
|
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
|
||||||
base_db::SourceDatabase,
|
base_db::SourceDatabase,
|
||||||
generated::lints::{LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS},
|
generated::lints::{Lint, LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, DEFAULT_LINT_GROUPS},
|
||||||
imports::insert_use::InsertUseConfig,
|
imports::insert_use::InsertUseConfig,
|
||||||
label::Label,
|
label::Label,
|
||||||
source_change::SourceChange,
|
source_change::SourceChange,
|
||||||
syntax_helpers::node_ext::parse_tt_as_comma_sep_paths,
|
syntax_helpers::node_ext::parse_tt_as_comma_sep_paths,
|
||||||
EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, SnippetCap,
|
EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -210,14 +210,6 @@ impl Diagnostic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Severity {
|
|
||||||
Error,
|
|
||||||
Warning,
|
|
||||||
WeakWarning,
|
|
||||||
Allow,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ExprFillDefaultMode {
|
pub enum ExprFillDefaultMode {
|
||||||
Todo,
|
Todo,
|
||||||
|
@ -568,26 +560,35 @@ fn handle_diag_from_macros(
|
||||||
|
|
||||||
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
|
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
|
||||||
|
|
||||||
static RUSTC_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
|
struct BuiltLint {
|
||||||
LazyLock::new(|| build_group_dict(DEFAULT_LINT_GROUPS, &["warnings", "__RA_EVERY_LINT"], ""));
|
lint: &'static Lint,
|
||||||
|
groups: Vec<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
static CLIPPY_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
|
static RUSTC_LINTS: LazyLock<FxHashMap<&str, BuiltLint>> =
|
||||||
LazyLock::new(|| build_group_dict(CLIPPY_LINT_GROUPS, &["__RA_EVERY_LINT"], "clippy::"));
|
LazyLock::new(|| build_lints_map(DEFAULT_LINTS, DEFAULT_LINT_GROUPS, ""));
|
||||||
|
|
||||||
|
static CLIPPY_LINTS: LazyLock<FxHashMap<&str, BuiltLint>> = LazyLock::new(|| {
|
||||||
|
build_lints_map(ide_db::generated::lints::CLIPPY_LINTS, CLIPPY_LINT_GROUPS, "clippy::")
|
||||||
|
});
|
||||||
|
|
||||||
// FIXME: Autogenerate this instead of enumerating by hand.
|
// FIXME: Autogenerate this instead of enumerating by hand.
|
||||||
static LINTS_TO_REPORT_IN_EXTERNAL_MACROS: LazyLock<FxHashSet<&str>> =
|
static LINTS_TO_REPORT_IN_EXTERNAL_MACROS: LazyLock<FxHashSet<&str>> =
|
||||||
LazyLock::new(|| FxHashSet::from_iter([]));
|
LazyLock::new(|| FxHashSet::from_iter([]));
|
||||||
|
|
||||||
fn build_group_dict(
|
fn build_lints_map(
|
||||||
|
lints: &'static [Lint],
|
||||||
lint_group: &'static [LintGroup],
|
lint_group: &'static [LintGroup],
|
||||||
all_groups: &'static [&'static str],
|
|
||||||
prefix: &'static str,
|
prefix: &'static str,
|
||||||
) -> FxHashMap<&'static str, Vec<&'static str>> {
|
) -> FxHashMap<&'static str, BuiltLint> {
|
||||||
let mut map_with_prefixes: FxHashMap<&str, Vec<&str>> = FxHashMap::default();
|
let mut map_with_prefixes: FxHashMap<_, _> = lints
|
||||||
|
.iter()
|
||||||
|
.map(|lint| (lint.label, BuiltLint { lint, groups: vec![lint.label, "__RA_EVERY_LINT"] }))
|
||||||
|
.collect();
|
||||||
for g in lint_group {
|
for g in lint_group {
|
||||||
let mut add_children = |label: &'static str| {
|
let mut add_children = |label: &'static str| {
|
||||||
for child in g.children {
|
for child in g.children {
|
||||||
map_with_prefixes.entry(child).or_default().push(label);
|
map_with_prefixes.get_mut(child).unwrap().groups.push(label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
add_children(g.lint.label);
|
add_children(g.lint.label);
|
||||||
|
@ -597,18 +598,9 @@ fn build_group_dict(
|
||||||
add_children("bad_style");
|
add_children("bad_style");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (lint, groups) in map_with_prefixes.iter_mut() {
|
|
||||||
groups.push(lint);
|
|
||||||
groups.extend_from_slice(all_groups);
|
|
||||||
}
|
|
||||||
map_with_prefixes.into_iter().map(|(k, v)| (k.strip_prefix(prefix).unwrap(), v)).collect()
|
map_with_prefixes.into_iter().map(|(k, v)| (k.strip_prefix(prefix).unwrap(), v)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Thd default severity for lints that are not warn by default.
|
|
||||||
// FIXME: Autogenerate this instead of write manually.
|
|
||||||
static LINTS_DEFAULT_SEVERITY: LazyLock<FxHashMap<&str, Severity>> =
|
|
||||||
LazyLock::new(|| FxHashMap::from_iter([("unsafe_op_in_unsafe_fn", Severity::Allow)]));
|
|
||||||
|
|
||||||
fn handle_lints(
|
fn handle_lints(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
|
cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
|
||||||
|
@ -618,10 +610,12 @@ fn handle_lints(
|
||||||
) {
|
) {
|
||||||
for (node, diag) in diagnostics {
|
for (node, diag) in diagnostics {
|
||||||
let lint = match diag.code {
|
let lint = match diag.code {
|
||||||
DiagnosticCode::RustcLint(lint) | DiagnosticCode::Clippy(lint) => lint,
|
DiagnosticCode::RustcLint(lint) => RUSTC_LINTS[lint].lint,
|
||||||
|
DiagnosticCode::Clippy(lint) => CLIPPY_LINTS[lint].lint,
|
||||||
_ => panic!("non-lint passed to `handle_lints()`"),
|
_ => panic!("non-lint passed to `handle_lints()`"),
|
||||||
};
|
};
|
||||||
if let Some(&default_severity) = LINTS_DEFAULT_SEVERITY.get(lint) {
|
let default_severity = default_lint_severity(lint, edition);
|
||||||
|
if !(default_severity == Severity::Allow && diag.severity == Severity::WeakWarning) {
|
||||||
diag.severity = default_severity;
|
diag.severity = default_severity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,6 +633,16 @@ fn handle_lints(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_lint_severity(lint: &Lint, edition: Edition) -> Severity {
|
||||||
|
if lint.deny_since.is_some_and(|e| edition >= e) {
|
||||||
|
Severity::Error
|
||||||
|
} else if lint.warn_since.is_some_and(|e| edition >= e) {
|
||||||
|
Severity::Warning
|
||||||
|
} else {
|
||||||
|
lint.default_severity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_outline_mod_lint_severity(
|
fn find_outline_mod_lint_severity(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
node: &InFile<SyntaxNode>,
|
node: &InFile<SyntaxNode>,
|
||||||
|
@ -654,14 +658,14 @@ fn find_outline_mod_lint_severity(
|
||||||
let mod_def = sema.to_module_def(&mod_node)?;
|
let mod_def = sema.to_module_def(&mod_node)?;
|
||||||
let module_source_file = sema.module_definition_node(mod_def);
|
let module_source_file = sema.module_definition_node(mod_def);
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
let lint_groups = lint_groups(&diag.code);
|
let lint_groups = lint_groups(&diag.code, edition);
|
||||||
lint_attrs(
|
lint_attrs(
|
||||||
sema,
|
sema,
|
||||||
ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"),
|
ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"),
|
||||||
edition,
|
edition,
|
||||||
)
|
)
|
||||||
.for_each(|(lint, severity)| {
|
.for_each(|(lint, severity)| {
|
||||||
if lint_groups.contains(&&*lint) {
|
if lint_groups.contains(&lint) {
|
||||||
result = Some(severity);
|
result = Some(severity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -737,9 +741,9 @@ fn fill_lint_attrs(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let all_matching_groups = lint_groups(&diag.code)
|
let all_matching_groups = lint_groups(&diag.code, edition)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|lint_group| cached.get(&**lint_group));
|
.filter_map(|lint_group| cached.get(lint_group));
|
||||||
let cached_severity =
|
let cached_severity =
|
||||||
all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity);
|
all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity);
|
||||||
|
|
||||||
|
@ -751,7 +755,7 @@ fn fill_lint_attrs(
|
||||||
// Insert this node's descendants' attributes into any outline descendant, but not including this node.
|
// Insert this node's descendants' attributes into any outline descendant, but not including this node.
|
||||||
// This must come before inserting this node's own attributes to preserve order.
|
// This must come before inserting this node's own attributes to preserve order.
|
||||||
collected_lint_attrs.drain().for_each(|(lint, severity)| {
|
collected_lint_attrs.drain().for_each(|(lint, severity)| {
|
||||||
if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) {
|
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
|
||||||
diag_severity = Some(severity.severity);
|
diag_severity = Some(severity.severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,7 +778,7 @@ fn fill_lint_attrs(
|
||||||
if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
|
if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
|
||||||
// Insert this node's attributes into any outline descendant, including this node.
|
// Insert this node's attributes into any outline descendant, including this node.
|
||||||
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
|
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
|
||||||
if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) {
|
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
|
||||||
diag_severity = Some(severity);
|
diag_severity = Some(severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,7 +808,7 @@ fn fill_lint_attrs(
|
||||||
return diag_severity;
|
return diag_severity;
|
||||||
} else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
|
} else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
|
||||||
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
|
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
|
||||||
if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) {
|
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
|
||||||
diag_severity = Some(severity);
|
diag_severity = Some(severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,16 +909,37 @@ fn cfg_attr_lint_attrs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_groups(lint: &DiagnosticCode) -> &'static [&'static str] {
|
#[derive(Debug)]
|
||||||
match lint {
|
struct LintGroups {
|
||||||
|
groups: &'static [&'static str],
|
||||||
|
inside_warnings: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LintGroups {
|
||||||
|
fn contains(&self, group: &str) -> bool {
|
||||||
|
self.groups.contains(&group) || (self.inside_warnings && group == "warnings")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> impl Iterator<Item = &'static str> {
|
||||||
|
self.groups.iter().copied().chain(self.inside_warnings.then_some("warnings"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lint_groups(lint: &DiagnosticCode, edition: Edition) -> LintGroups {
|
||||||
|
let (groups, inside_warnings) = match lint {
|
||||||
DiagnosticCode::RustcLint(name) => {
|
DiagnosticCode::RustcLint(name) => {
|
||||||
RUSTC_LINT_GROUPS_DICT.get(name).map(|it| &**it).unwrap_or_default()
|
let lint = &RUSTC_LINTS[name];
|
||||||
|
let inside_warnings = default_lint_severity(lint.lint, edition) == Severity::Warning;
|
||||||
|
(&lint.groups, inside_warnings)
|
||||||
}
|
}
|
||||||
DiagnosticCode::Clippy(name) => {
|
DiagnosticCode::Clippy(name) => {
|
||||||
CLIPPY_LINT_GROUPS_DICT.get(name).map(|it| &**it).unwrap_or_default()
|
let lint = &CLIPPY_LINTS[name];
|
||||||
|
let inside_warnings = default_lint_severity(lint.lint, edition) == Severity::Warning;
|
||||||
|
(&lint.groups, inside_warnings)
|
||||||
}
|
}
|
||||||
_ => &[],
|
_ => panic!("non-lint passed to `handle_lints()`"),
|
||||||
}
|
};
|
||||||
|
LintGroups { groups, inside_warnings }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
|
fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
|
||||||
|
|
|
@ -6413,7 +6413,7 @@ fn hover_feature() {
|
||||||
by the codegen backend, but not the MIR inliner.
|
by the codegen backend, but not the MIR inliner.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(rustc_attrs)]
|
#![feature(intrinsics)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
|
@ -6423,7 +6423,7 @@ fn hover_feature() {
|
||||||
Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
|
Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(rustc_attrs)]
|
#![feature(intrinsics)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
|
|
|
@ -132,11 +132,9 @@ pub use ide_db::{
|
||||||
search::{ReferenceCategory, SearchScope},
|
search::{ReferenceCategory, SearchScope},
|
||||||
source_change::{FileSystemEdit, SnippetEdit, SourceChange},
|
source_change::{FileSystemEdit, SnippetEdit, SourceChange},
|
||||||
symbol_index::Query,
|
symbol_index::Query,
|
||||||
FileId, FilePosition, FileRange, RootDatabase, SymbolKind,
|
FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
|
||||||
};
|
|
||||||
pub use ide_diagnostics::{
|
|
||||||
Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode, Severity,
|
|
||||||
};
|
};
|
||||||
|
pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode};
|
||||||
pub use ide_ssr::SsrError;
|
pub use ide_ssr::SsrError;
|
||||||
pub use span::Edition;
|
pub use span::Edition;
|
||||||
pub use syntax::{TextRange, TextSize};
|
pub use syntax::{TextRange, TextSize};
|
||||||
|
|
|
@ -18,6 +18,8 @@ ra-ap-rustc_lexer.workspace = true
|
||||||
limit.workspace = true
|
limit.workspace = true
|
||||||
tracing = { workspace = true, optional = true }
|
tracing = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
expect-test = "1.4.0"
|
expect-test = "1.4.0"
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ extern crate ra_ap_rustc_lexer as rustc_lexer;
|
||||||
#[cfg(feature = "in-rust-tree")]
|
#[cfg(feature = "in-rust-tree")]
|
||||||
extern crate rustc_lexer;
|
extern crate rustc_lexer;
|
||||||
|
|
||||||
mod edition;
|
|
||||||
mod event;
|
mod event;
|
||||||
mod grammar;
|
mod grammar;
|
||||||
mod input;
|
mod input;
|
||||||
|
@ -41,8 +40,9 @@ mod tests;
|
||||||
|
|
||||||
pub(crate) use token_set::TokenSet;
|
pub(crate) use token_set::TokenSet;
|
||||||
|
|
||||||
|
pub use edition::Edition;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
edition::Edition,
|
|
||||||
input::Input,
|
input::Input,
|
||||||
lexed_str::LexedStr,
|
lexed_str::LexedStr,
|
||||||
output::{Output, Step},
|
output::{Output, Step},
|
||||||
|
|
|
@ -21,6 +21,7 @@ quote = "1.0.20"
|
||||||
ungrammar = "1.16.1"
|
ungrammar = "1.16.1"
|
||||||
either.workspace = true
|
either.workspace = true
|
||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
# Avoid adding more dependencies to this crate
|
# Avoid adding more dependencies to this crate
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
//! Generates descriptor structures for unstable features from the unstable book
|
//! Generates descriptor structures for unstable features from the unstable book
|
||||||
//! and lints from rustc, rustdoc, and clippy.
|
//! and lints from rustc, rustdoc, and clippy.
|
||||||
use std::{borrow::Cow, fs, path::Path};
|
#![allow(clippy::disallowed_types)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::{hash_map, HashMap},
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use edition::Edition;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use xshell::{cmd, Shell};
|
use xshell::{cmd, Shell};
|
||||||
|
|
||||||
|
@ -36,10 +44,17 @@ pub(crate) fn generate(check: bool) {
|
||||||
|
|
||||||
let mut contents = String::from(
|
let mut contents = String::from(
|
||||||
r"
|
r"
|
||||||
|
use span::Edition;
|
||||||
|
|
||||||
|
use crate::Severity;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Lint {
|
pub struct Lint {
|
||||||
pub label: &'static str,
|
pub label: &'static str,
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
|
pub default_severity: Severity,
|
||||||
|
pub warn_since: Option<Edition>,
|
||||||
|
pub deny_since: Option<Edition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LintGroup {
|
pub struct LintGroup {
|
||||||
|
@ -68,7 +83,7 @@ pub struct LintGroup {
|
||||||
let lints_json = project_root().join("./target/clippy_lints.json");
|
let lints_json = project_root().join("./target/clippy_lints.json");
|
||||||
cmd!(
|
cmd!(
|
||||||
sh,
|
sh,
|
||||||
"curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}"
|
"curl https://rust-lang.github.io/rust-clippy/stable/lints.json --output {lints_json}"
|
||||||
)
|
)
|
||||||
.run()
|
.run()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -85,6 +100,48 @@ pub struct LintGroup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum Severity {
|
||||||
|
Allow,
|
||||||
|
Warn,
|
||||||
|
Deny,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Severity {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Severity::{}",
|
||||||
|
match self {
|
||||||
|
Severity::Allow => "Allow",
|
||||||
|
Severity::Warn => "Warning",
|
||||||
|
Severity::Deny => "Error",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Severity {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"allow" => Ok(Self::Allow),
|
||||||
|
"warn" => Ok(Self::Warn),
|
||||||
|
"deny" => Ok(Self::Deny),
|
||||||
|
_ => Err("invalid severity"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Lint {
|
||||||
|
description: String,
|
||||||
|
default_severity: Severity,
|
||||||
|
warn_since: Option<Edition>,
|
||||||
|
deny_since: Option<Edition>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses the output of `rustdoc -Whelp` and prints `Lint` and `LintGroup` constants into `buf`.
|
/// Parses the output of `rustdoc -Whelp` and prints `Lint` and `LintGroup` constants into `buf`.
|
||||||
///
|
///
|
||||||
/// As of writing, the output of `rustc -Whelp` (not rustdoc) has the following format:
|
/// As of writing, the output of `rustc -Whelp` (not rustdoc) has the following format:
|
||||||
|
@ -108,52 +165,203 @@ pub struct LintGroup {
|
||||||
/// `rustdoc -Whelp` (and any other custom `rustc` driver) adds another two
|
/// `rustdoc -Whelp` (and any other custom `rustc` driver) adds another two
|
||||||
/// tables after the `rustc` ones, with a different title but the same format.
|
/// tables after the `rustc` ones, with a different title but the same format.
|
||||||
fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
||||||
let stdout = cmd!(sh, "rustdoc -Whelp").read().unwrap();
|
fn get_lints_as_text(
|
||||||
let lints_pat = "---- ------- -------\n";
|
stdout: &str,
|
||||||
let lint_groups_pat = "---- ---------\n";
|
) -> (
|
||||||
let lints = find_and_slice(&stdout, lints_pat);
|
impl Iterator<Item = (String, &str, Severity)> + '_,
|
||||||
let lint_groups = find_and_slice(lints, lint_groups_pat);
|
impl Iterator<Item = (String, Lint, impl Iterator<Item = String> + '_)> + '_,
|
||||||
let lints_rustdoc = find_and_slice(lint_groups, lints_pat);
|
impl Iterator<Item = (String, &str, Severity)> + '_,
|
||||||
let lint_groups_rustdoc = find_and_slice(lints_rustdoc, lint_groups_pat);
|
impl Iterator<Item = (String, Lint, impl Iterator<Item = String> + '_)> + '_,
|
||||||
|
) {
|
||||||
|
let lints_pat = "---- ------- -------\n";
|
||||||
|
let lint_groups_pat = "---- ---------\n";
|
||||||
|
let lints = find_and_slice(stdout, lints_pat);
|
||||||
|
let lint_groups = find_and_slice(lints, lint_groups_pat);
|
||||||
|
let lints_rustdoc = find_and_slice(lint_groups, lints_pat);
|
||||||
|
let lint_groups_rustdoc = find_and_slice(lints_rustdoc, lint_groups_pat);
|
||||||
|
|
||||||
|
let lints = lints.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||||
|
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
let (severity, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
(name.trim().replace('-', "_"), description.trim(), severity.parse().unwrap())
|
||||||
|
});
|
||||||
|
let lint_groups = lint_groups.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||||
|
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
let label = name.trim().replace('-', "_");
|
||||||
|
let lint = Lint {
|
||||||
|
description: format!("lint group for: {}", lints.trim()),
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
};
|
||||||
|
let children = lints
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.map(|s| s.trim().trim_matches(',').replace('-', "_"));
|
||||||
|
(label, lint, children)
|
||||||
|
});
|
||||||
|
|
||||||
|
let lints_rustdoc = lints_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||||
|
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
let (severity, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
(name.trim().replace('-', "_"), description.trim(), severity.parse().unwrap())
|
||||||
|
});
|
||||||
|
let lint_groups_rustdoc =
|
||||||
|
lint_groups_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||||
|
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||||
|
let label = name.trim().replace('-', "_");
|
||||||
|
let lint = Lint {
|
||||||
|
description: format!("lint group for: {}", lints.trim()),
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
};
|
||||||
|
let children = lints
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.map(|s| s.trim().trim_matches(',').replace('-', "_"));
|
||||||
|
(label, lint, children)
|
||||||
|
});
|
||||||
|
|
||||||
|
(lints, lint_groups, lints_rustdoc, lint_groups_rustdoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_lints<'a>(
|
||||||
|
edition: Edition,
|
||||||
|
lints_map: &mut HashMap<String, Lint>,
|
||||||
|
lint_groups_map: &mut HashMap<String, (Lint, Vec<String>)>,
|
||||||
|
lints: impl Iterator<Item = (String, &'a str, Severity)>,
|
||||||
|
lint_groups: impl Iterator<Item = (String, Lint, impl Iterator<Item = String>)>,
|
||||||
|
) {
|
||||||
|
for (lint_name, lint_description, lint_severity) in lints {
|
||||||
|
let lint = lints_map.entry(lint_name).or_insert_with(|| Lint {
|
||||||
|
description: lint_description.to_owned(),
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
});
|
||||||
|
if lint_severity == Severity::Warn
|
||||||
|
&& lint.warn_since.is_none()
|
||||||
|
&& lint.default_severity < Severity::Warn
|
||||||
|
{
|
||||||
|
lint.warn_since = Some(edition);
|
||||||
|
}
|
||||||
|
if lint_severity == Severity::Deny
|
||||||
|
&& lint.deny_since.is_none()
|
||||||
|
&& lint.default_severity < Severity::Deny
|
||||||
|
{
|
||||||
|
lint.deny_since = Some(edition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (group_name, lint, children) in lint_groups {
|
||||||
|
match lint_groups_map.entry(group_name) {
|
||||||
|
hash_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert((lint, Vec::from_iter(children)));
|
||||||
|
}
|
||||||
|
hash_map::Entry::Occupied(mut entry) => {
|
||||||
|
// Overwrite, because some groups (such as edition incompatibility) are changed.
|
||||||
|
*entry.get_mut() = (lint, Vec::from_iter(children));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_lints(
|
||||||
|
sh: &Shell,
|
||||||
|
edition: Edition,
|
||||||
|
lints_map: &mut HashMap<String, Lint>,
|
||||||
|
lint_groups_map: &mut HashMap<String, (Lint, Vec<String>)>,
|
||||||
|
lints_rustdoc_map: &mut HashMap<String, Lint>,
|
||||||
|
lint_groups_rustdoc_map: &mut HashMap<String, (Lint, Vec<String>)>,
|
||||||
|
) {
|
||||||
|
let edition_str = edition.to_string();
|
||||||
|
let stdout = cmd!(sh, "rustdoc +nightly -Whelp -Zunstable-options --edition={edition_str}")
|
||||||
|
.read()
|
||||||
|
.unwrap();
|
||||||
|
let (lints, lint_groups, lints_rustdoc, lint_groups_rustdoc) = get_lints_as_text(&stdout);
|
||||||
|
|
||||||
|
insert_lints(edition, lints_map, lint_groups_map, lints, lint_groups);
|
||||||
|
insert_lints(
|
||||||
|
edition,
|
||||||
|
lints_rustdoc_map,
|
||||||
|
lint_groups_rustdoc_map,
|
||||||
|
lints_rustdoc,
|
||||||
|
lint_groups_rustdoc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let basic_lints = cmd!(sh, "rustdoc +nightly -Whelp --edition=2015").read().unwrap();
|
||||||
|
let (lints, lint_groups, lints_rustdoc, lint_groups_rustdoc) = get_lints_as_text(&basic_lints);
|
||||||
|
|
||||||
|
let mut lints = lints
|
||||||
|
.map(|(label, description, severity)| {
|
||||||
|
(
|
||||||
|
label,
|
||||||
|
Lint {
|
||||||
|
description: description.to_owned(),
|
||||||
|
default_severity: severity,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
let mut lint_groups = lint_groups
|
||||||
|
.map(|(label, lint, children)| (label, (lint, Vec::from_iter(children))))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
let mut lints_rustdoc = lints_rustdoc
|
||||||
|
.map(|(label, description, severity)| {
|
||||||
|
(
|
||||||
|
label,
|
||||||
|
Lint {
|
||||||
|
description: description.to_owned(),
|
||||||
|
default_severity: severity,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
let mut lint_groups_rustdoc = lint_groups_rustdoc
|
||||||
|
.map(|(label, lint, children)| (label, (lint, Vec::from_iter(children))))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
for edition in Edition::iter().skip(1) {
|
||||||
|
get_lints(
|
||||||
|
sh,
|
||||||
|
edition,
|
||||||
|
&mut lints,
|
||||||
|
&mut lint_groups,
|
||||||
|
&mut lints_rustdoc,
|
||||||
|
&mut lint_groups_rustdoc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lints = Vec::from_iter(lints);
|
||||||
|
lints.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
let mut lint_groups = Vec::from_iter(lint_groups);
|
||||||
|
lint_groups.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
let mut lints_rustdoc = Vec::from_iter(lints_rustdoc);
|
||||||
|
lints_rustdoc.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
let mut lint_groups_rustdoc = Vec::from_iter(lint_groups_rustdoc);
|
||||||
|
lint_groups_rustdoc.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#);
|
buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#);
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
|
|
||||||
let lints = lints.lines().take_while(|l| !l.is_empty()).map(|line| {
|
for (name, lint) in &lints {
|
||||||
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
push_lint_completion(buf, name, lint);
|
||||||
let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
}
|
||||||
(name.trim(), Cow::Borrowed(description.trim()), vec![])
|
for (name, (group, _)) in &lint_groups {
|
||||||
});
|
push_lint_completion(buf, name, group);
|
||||||
let lint_groups = lint_groups.lines().take_while(|l| !l.is_empty()).map(|line| {
|
|
||||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
|
||||||
(
|
|
||||||
name.trim(),
|
|
||||||
format!("lint group for: {}", lints.trim()).into(),
|
|
||||||
lints
|
|
||||||
.split_ascii_whitespace()
|
|
||||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut lints = lints.chain(lint_groups).collect::<Vec<_>>();
|
|
||||||
lints.sort_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2));
|
|
||||||
|
|
||||||
for (name, description, ..) in &lints {
|
|
||||||
push_lint_completion(buf, &name.replace('-', "_"), description);
|
|
||||||
}
|
}
|
||||||
buf.push_str("];\n\n");
|
buf.push_str("];\n\n");
|
||||||
|
|
||||||
buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#);
|
buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#);
|
||||||
for (name, description, children) in &lints {
|
for (name, (lint, children)) in &lint_groups {
|
||||||
if !children.is_empty() {
|
if name == "warnings" {
|
||||||
// HACK: warnings is emitted with a general description, not with its members
|
continue;
|
||||||
if name == &"warnings" {
|
|
||||||
push_lint_group(buf, name, description, &Vec::new());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
push_lint_group(buf, &name.replace('-', "_"), description, children);
|
|
||||||
}
|
}
|
||||||
|
push_lint_group(buf, name, lint, children);
|
||||||
}
|
}
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
buf.push_str("];\n");
|
buf.push_str("];\n");
|
||||||
|
@ -164,37 +372,17 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
||||||
buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#);
|
buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#);
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
|
|
||||||
let lints_rustdoc = lints_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
for (name, lint) in &lints_rustdoc {
|
||||||
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
push_lint_completion(buf, name, lint);
|
||||||
let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
}
|
||||||
(name.trim(), Cow::Borrowed(description.trim()), vec![])
|
for (name, (group, _)) in &lint_groups_rustdoc {
|
||||||
});
|
push_lint_completion(buf, name, group);
|
||||||
let lint_groups_rustdoc =
|
|
||||||
lint_groups_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
|
||||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
|
||||||
(
|
|
||||||
name.trim(),
|
|
||||||
format!("lint group for: {}", lints.trim()).into(),
|
|
||||||
lints
|
|
||||||
.split_ascii_whitespace()
|
|
||||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut lints_rustdoc = lints_rustdoc.chain(lint_groups_rustdoc).collect::<Vec<_>>();
|
|
||||||
lints_rustdoc.sort_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2));
|
|
||||||
|
|
||||||
for (name, description, ..) in &lints_rustdoc {
|
|
||||||
push_lint_completion(buf, &name.replace('-', "_"), description)
|
|
||||||
}
|
}
|
||||||
buf.push_str("];\n\n");
|
buf.push_str("];\n\n");
|
||||||
|
|
||||||
buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#);
|
buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#);
|
||||||
for (name, description, children) in &lints_rustdoc {
|
for (name, (lint, children)) in &lint_groups_rustdoc {
|
||||||
if !children.is_empty() {
|
push_lint_group(buf, name, lint, children);
|
||||||
push_lint_group(buf, &name.replace('-', "_"), description, children);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
buf.push_str("];\n");
|
buf.push_str("];\n");
|
||||||
|
@ -228,13 +416,19 @@ fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) {
|
||||||
|
|
||||||
buf.push_str(r#"pub const FEATURES: &[Lint] = &["#);
|
buf.push_str(r#"pub const FEATURES: &[Lint] = &["#);
|
||||||
for (feature_ident, doc) in features.into_iter() {
|
for (feature_ident, doc) in features.into_iter() {
|
||||||
push_lint_completion(buf, &feature_ident, &doc)
|
let lint = Lint {
|
||||||
|
description: doc,
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
};
|
||||||
|
push_lint_completion(buf, &feature_ident, &lint);
|
||||||
}
|
}
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
buf.push_str("];\n");
|
buf.push_str("];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Debug, Default)]
|
||||||
struct ClippyLint {
|
struct ClippyLint {
|
||||||
help: String,
|
help: String,
|
||||||
id: String,
|
id: String,
|
||||||
|
@ -295,8 +489,14 @@ fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
for clippy_lint in clippy_lints.into_iter() {
|
for clippy_lint in clippy_lints.into_iter() {
|
||||||
let lint_ident = format!("clippy::{}", clippy_lint.id);
|
let lint_ident = format!("clippy::{}", clippy_lint.id);
|
||||||
let doc = clippy_lint.help;
|
let lint = Lint {
|
||||||
push_lint_completion(buf, &lint_ident, &doc);
|
description: clippy_lint.help,
|
||||||
|
// Allow clippy lints by default, not all users want them.
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
};
|
||||||
|
push_lint_completion(buf, &lint_ident, &lint);
|
||||||
}
|
}
|
||||||
buf.push_str("];\n");
|
buf.push_str("];\n");
|
||||||
|
|
||||||
|
@ -306,33 +506,59 @@ fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
let lint_ident = format!("clippy::{id}");
|
let lint_ident = format!("clippy::{id}");
|
||||||
let description = format!("lint group for: {}", children.join(", "));
|
let description = format!("lint group for: {}", children.join(", "));
|
||||||
push_lint_group(buf, &lint_ident, &description, &children);
|
let lint = Lint {
|
||||||
|
description,
|
||||||
|
default_severity: Severity::Allow,
|
||||||
|
warn_since: None,
|
||||||
|
deny_since: None,
|
||||||
|
};
|
||||||
|
push_lint_group(buf, &lint_ident, &lint, &children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
buf.push_str("];\n");
|
buf.push_str("];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_lint_completion(buf: &mut String, label: &str, description: &str) {
|
fn push_lint_completion(buf: &mut String, name: &str, lint: &Lint) {
|
||||||
format_to!(
|
format_to!(
|
||||||
buf,
|
buf,
|
||||||
r###" Lint {{
|
r###" Lint {{
|
||||||
label: "{}",
|
label: "{}",
|
||||||
description: r##"{}"##,
|
description: r##"{}"##,
|
||||||
}},"###,
|
default_severity: {},
|
||||||
label,
|
warn_since: "###,
|
||||||
description,
|
name,
|
||||||
|
lint.description,
|
||||||
|
lint.default_severity,
|
||||||
|
);
|
||||||
|
match lint.warn_since {
|
||||||
|
Some(edition) => format_to!(buf, "Some(Edition::Edition{edition})"),
|
||||||
|
None => buf.push_str("None"),
|
||||||
|
}
|
||||||
|
format_to!(
|
||||||
|
buf,
|
||||||
|
r###",
|
||||||
|
deny_since: "###
|
||||||
|
);
|
||||||
|
match lint.deny_since {
|
||||||
|
Some(edition) => format_to!(buf, "Some(Edition::Edition{edition})"),
|
||||||
|
None => buf.push_str("None"),
|
||||||
|
}
|
||||||
|
format_to!(
|
||||||
|
buf,
|
||||||
|
r###",
|
||||||
|
}},"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_lint_group(buf: &mut String, label: &str, description: &str, children: &[String]) {
|
fn push_lint_group(buf: &mut String, name: &str, lint: &Lint, children: &[String]) {
|
||||||
buf.push_str(
|
buf.push_str(
|
||||||
r###" LintGroup {
|
r###" LintGroup {
|
||||||
lint:
|
lint:
|
||||||
"###,
|
"###,
|
||||||
);
|
);
|
||||||
|
|
||||||
push_lint_completion(buf, label, description);
|
push_lint_completion(buf, name, lint);
|
||||||
|
|
||||||
let children = format!(
|
let children = format!(
|
||||||
"&[{}]",
|
"&[{}]",
|
||||||
|
|
Loading…
Reference in a new issue