From 9e82ad87b9ae43bee6f06308631fbe0fb0a1c847 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:47:20 +0000 Subject: [PATCH] [`let_and_return`]: avoid linting when `#[cfg]` attributes are present --- clippy_lints/src/matches/mod.rs | 32 +++----------------------------- clippy_lints/src/returns.rs | 3 ++- clippy_utils/src/attrs.rs | 32 +++++++++++++++++++++++++++++++- tests/ui/let_and_return.fixed | 7 +++++++ tests/ui/let_and_return.rs | 7 +++++++ 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 50494f4819f44..dd83e32a9430e 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -25,14 +25,13 @@ mod try_err; mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; +use clippy_utils::source::walk_span_to_context; +use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{Span, SpanData, SyntaxContext}; +use rustc_span::{SpanData, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -1196,28 +1195,3 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar Err(()) => true, } } - -/// Checks if the given span contains a `#[cfg(..)]` attribute -fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); - - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; - } - } - false -} diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 8bc24eda46597..e8f9d43810473 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{ - fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, + fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; @@ -232,6 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && !in_external_macro(cx.sess(), initexpr.span) && !in_external_macro(cx.sess(), retexpr.span) && !local.span.from_expansion() + && !span_contains_cfg(cx, stmt.span.between(retexpr.span)) { span_lint_hir_and_then( cx, diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2d0c2cf125364..d2200bcf7103b 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,10 +1,15 @@ use rustc_ast::{ast, attr}; use rustc_errors::Applicability; +use rustc_lexer::TokenKind; +use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::sym; +use rustc_span::{sym, Span}; use std::str::FromStr; +use crate::source::snippet_opt; +use crate::tokenize_with_text; + /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { /// Attribute is deprecated @@ -171,3 +176,28 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { .all_fields() .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive)) } + +/// Checks if the given span contains a `#[cfg(..)]` attribute +pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { + let Some(snip) = snippet_opt(cx, s) else { + // Assume true. This would require either an invalid span, or one which crosses file boundaries. + return true; + }; + let mut iter = tokenize_with_text(&snip); + + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + { + return true; + } + } + false +} diff --git a/tests/ui/let_and_return.fixed b/tests/ui/let_and_return.fixed index b5584fcde8c95..4187019e58944 100644 --- a/tests/ui/let_and_return.fixed +++ b/tests/ui/let_and_return.fixed @@ -203,4 +203,11 @@ fn_in_macro!({ return 1; }); +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + fn main() {} diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs index f13c7c4e2034b..54444957b7d53 100644 --- a/tests/ui/let_and_return.rs +++ b/tests/ui/let_and_return.rs @@ -203,4 +203,11 @@ fn_in_macro!({ return 1; }); +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + fn main() {}