diff options
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/utils')
4 files changed, 94 insertions, 61 deletions
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c0726868f..4003fff27 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -6,7 +6,9 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ + ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -140,7 +142,7 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) { check_node(cx, hir_id, |v| { - v.expr(&v.bind("expr", &hir.body(body_id).value)); + v.expr(&v.bind("expr", hir.body(body_id).value)); }); } } @@ -276,7 +278,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match lit.value.node { LitKind::Bool(val) => kind!("Bool({val:?})"), LitKind::Char(c) => kind!("Char({c:?})"), - LitKind::Err(val) => kind!("Err({val})"), + LitKind::Err => kind!("Err"), LitKind::Byte(b) => kind!("Byte({b})"), LitKind::Int(i, suffix) => { let int_ty = match suffix { @@ -402,10 +404,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(func); self.slice(args, |e| self.expr(e)); }, - ExprKind::MethodCall(method_name, args, _) => { - bind!(self, method_name, args); - kind!("MethodCall({method_name}, {args}, _)"); + ExprKind::MethodCall(method_name, receiver, args, _) => { + bind!(self, method_name, receiver, args); + kind!("MethodCall({method_name}, {receiver}, {args}, _)"); self.ident(field!(method_name.ident)); + self.expr(receiver); self.slice(args, |e| self.expr(e)); }, ExprKind::Tup(elements) => { @@ -595,7 +598,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } fn body(&self, body_id: &Binding<hir::BodyId>) { - let expr = &self.cx.tcx.hir().body(body_id.value).value; + let expr = self.cx.tcx.hir().body(body_id.value).value; bind!(self, expr); out!("let {expr} = &cx.tcx.hir().body({body_id}).value;"); self.expr(expr); @@ -609,10 +612,16 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), - PatKind::Binding(anno, .., name, sub) => { + PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); - kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})"); + let ann = match ann { + BindingAnnotation::NONE => "NONE", + BindingAnnotation::REF => "REF", + BindingAnnotation::MUT => "MUT", + BindingAnnotation::REF_MUT => "REF_MUT", + }; + kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); self.ident(name); sub.if_some(|p| self.pat(p)); }, diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 6e033b3be..a8500beb2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "MinGW", "CamelCase", ]; -const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. #[derive(Clone, Debug, Deserialize)] @@ -68,6 +68,7 @@ pub enum DisallowedType { pub struct TryConf { pub conf: Conf, pub errors: Vec<Box<dyn Error>>, + pub warnings: Vec<Box<dyn Error>>, } impl TryConf { @@ -75,6 +76,7 @@ impl TryConf { Self { conf: Conf::default(), errors: vec![Box::new(error)], + warnings: vec![], } } } @@ -90,14 +92,14 @@ impl fmt::Display for ConfError { impl Error for ConfError {} -fn conf_error(s: String) -> Box<dyn Error> { - Box::new(ConfError(s)) +fn conf_error(s: impl Into<String>) -> Box<dyn Error> { + Box::new(ConfError(s.into())) } macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal)])? + $(#[conf_deprecated($dep:literal, $new_conf:ident)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration @@ -137,17 +139,29 @@ macro_rules! define_Conf { fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> { let mut errors = Vec::new(); + let mut warnings = Vec::new(); $(let mut $name = None;)* // could get `Field` here directly, but get `str` first for diagnostics while let Some(name) = map.next_key::<&str>()? { match Field::deserialize(name.into_deserializer())? { $(Field::$name => { - $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? + $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? match map.next_value() { Err(e) => errors.push(conf_error(e.to_string())), Ok(value) => match $name { Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))), - None => $name = Some(value), + None => { + $name = Some(value); + // $new_conf is the same as one of the defined `$name`s, so + // this variable is defined in line 2 of this function. + $(match $new_conf { + Some(_) => errors.push(conf_error(concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ))), + None => $new_conf = $name.clone(), + })? + }, } } })* @@ -156,7 +170,7 @@ macro_rules! define_Conf { } } let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors }) + Ok(TryConf { conf, errors, warnings }) } } @@ -194,7 +208,7 @@ define_Conf! { /// Lint: Arithmetic. /// /// Suppress checking of the passed type names. - (arithmetic_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), + (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. @@ -203,12 +217,11 @@ define_Conf! { /// /// The minimum rust version that the project supports (msrv: Option<String> = None), - /// Lint: BLACKLISTED_NAME. + /// DEPRECATED LINT: BLACKLISTED_NAME. /// - /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. - (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()), + /// Use the Disallowed Names lint instead + #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] + (blacklisted_names: Vec<String> = Vec::new()), /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have @@ -216,8 +229,14 @@ define_Conf! { /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")] - (cyclomatic_complexity_threshold: Option<u64> = None), + #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] + (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_NAMES. + /// + /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value + /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// default configuration of Clippy. By default any configuration will replace the default value. + (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -331,7 +350,7 @@ define_Conf! { /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()), + (allowed_scripts: Vec<String> = vec!["Latin".to_string()]), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. @@ -360,6 +379,10 @@ define_Conf! { /// /// Whether `dbg!` should be allowed in test functions (allow_dbg_in_tests: bool = false), + /// Lint: RESULT_LARGE_ERR + /// + /// The maximum size of the `Err`-variant in a `Result` returned from a function + (large_error_threshold: u64 = 128), } /// Search for the configuration file. @@ -420,7 +443,7 @@ pub fn read(path: &Path) -> TryConf { match toml::from_str::<TryConf>(&content) { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); - extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); conf }, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index b30965329..17d9a0418 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -496,14 +496,16 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, }; let body_id = cx.tcx.hir().body_owned_by( - impl_item_refs - .iter() - .find(|iiref| iiref.ident.as_str() == "get_lints") - .expect("LintPass needs to implement get_lints") - .id - .hir_id(), + cx.tcx.hir().local_def_id( + impl_item_refs + .iter() + .find(|iiref| iiref.ident.as_str() == "get_lints") + .expect("LintPass needs to implement get_lints") + .id + .hir_id(), + ), ); - collector.visit_expr(&cx.tcx.hir().body(body_id).value); + collector.visit_expr(cx.tcx.hir().body(body_id).value); } } } @@ -569,7 +571,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' item.span, "this item has an invalid `clippy::version` attribute", None, - "please use a valid sematic version, see `doc/adding_lints.md`", + "please use a valid semantic version, see `doc/adding_lints.md`", ); } } else { @@ -591,8 +593,8 @@ fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Opt attrs.iter().find_map(|attr| { if_chain! { // Identify attribute - if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind; - if let [tool_name, attr_name] = &attr_kind.path.segments[..]; + if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind; + if let [tool_name, attr_name] = &attr_kind.item.path.segments[..]; if tool_name.ident.name == sym::clippy; if attr_name.ident.name == sym::version; if let Some(version) = attr.value_str(); @@ -651,7 +653,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { } if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(fn_name.as_str()); let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); @@ -683,9 +685,8 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); if_chain! { if let ["expn_data", "outer_expn"] = method_names.as_slice(); - let args = arg_lists[1]; - if args.len() == 1; - let self_arg = &args[0]; + let (self_arg, args)= arg_lists[1]; + if args.is_empty(); let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { @@ -732,30 +733,30 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if and_then_args.len() == 5; if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind; let body = cx.tcx.hir().body(body); - let only_expr = peel_blocks_with_stmt(&body.value); - if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind; - if let ExprKind::Path(..) = span_call_args[0].kind; + let only_expr = peel_blocks_with_stmt(body.value); + if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind; + if let ExprKind::Path(..) = recv.kind; then { let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).deny_side_effects(); match ps.ident.as_str() { - "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { + "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); }, - "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { - let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); }, - "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { - let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); }, "help" => { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); } "note" => { - let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); } _ => (), @@ -796,9 +797,9 @@ fn span_suggestion_snippets<'a, 'hir>( cx: &LateContext<'_>, span_call_args: &'hir [Expr<'hir>], ) -> SpanSuggestionSnippets<'a> { - let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); - let sugg_snippet = snippet(cx, span_call_args[3].span, ".."); - let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable"); + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); + let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); SpanSuggestionSnippets { help: help_snippet, @@ -952,7 +953,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) { if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind { let body = cx.tcx.hir().body(body_id); - return path_to_matched_type(cx, &body.value); + return path_to_matched_type(cx, body.value); } } }, @@ -1044,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { if el_ty.is_str(); let body = cx.tcx.hir().body(body_id); let typeck_results = cx.tcx.typeck_body(body_id); - if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value); + if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value); let path: Vec<&str> = path.iter().map(|x| { if let Constant::Str(s) = x { s.as_str() @@ -1175,7 +1176,7 @@ impl InterningDefinedSymbol { }; if_chain! { // is a method call - if let ExprKind::MethodCall(_, [item], _) = call.kind; + if let ExprKind::MethodCall(_, item, [], _) = call.kind; if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id); let ty = cx.typeck_results().expr_ty(item); // ...on either an Ident or a Symbol diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92934c16d..342f627e3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -619,7 +619,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { // item validation if is_lint_ref_type(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction @@ -644,7 +644,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { if is_deprecated_lint(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint @@ -797,7 +797,7 @@ fn get_lint_group_and_level_or_lint( let result = cx.lint_store.check_lint_name( lint_name, Some(sym::clippy), - &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(), + &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), ); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { if let Some(group) = get_lint_group(cx, lint_lst[0]) { @@ -1145,8 +1145,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { self.add_single_span_suggestion(); } }, - ExprKind::MethodCall(path, arg, _arg_span) => { - let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0])); + ExprKind::MethodCall(path, recv, _, _arg_span) => { + let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv)); if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) { let called_method = path.ident.name.as_str().to_string(); for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS { |