diff --git a/.vscode/settings.json b/.vscode/settings.json index 11ad9c6..4d3b473 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,10 +26,13 @@ "callsite", "catthehacker", "ctxt", + "desugared", "dylint", + "krate", "qpath", "rustsec", "rustup", + "typeck", "usize" ] } \ No newline at end of file diff --git a/rules/indexing_usage/src/lib.rs b/rules/indexing_usage/src/lib.rs index 1936252..ac50efc 100644 --- a/rules/indexing_usage/src/lib.rs +++ b/rules/indexing_usage/src/lib.rs @@ -149,7 +149,7 @@ mod tests { #[test] fn ui() { Test::src_base(env!("CARGO_PKG_NAME"), "ui") - .rustc_flags(["-Z", "ui-testing"]) + .rustc_flags(["--edition=2024", "-Z", "ui-testing"]) .run(); } } diff --git a/rules/missing_type/src/lib.rs b/rules/missing_type/src/lib.rs index 14140b1..531d8e5 100644 --- a/rules/missing_type/src/lib.rs +++ b/rules/missing_type/src/lib.rs @@ -55,6 +55,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingType { if matches!(local.pat.kind, PatKind::Wild) { return; } + // Skip if the let statement is from a macro expansion, as it may not + // be possible to determine the type annotation in that case. + // Ignore anything coming from macro expansion (async_trait, derives, + // etc.) + if local.span.from_expansion() { + return; + } + + // Ignore desugared constructs (async lowering, ?, for loops, etc.) + if local.span.desugaring_kind().is_some() { + return; + } // Check if the let statement has an explicit type annotation. If not, // emit a warning. @@ -84,12 +96,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingType { context: &LateContext<'tcx>, expression: &'tcx Expr<'tcx>, ) { + if expression.span.from_expansion() { + return; + } + // Only check closure expressions. let ExprKind::Closure(closure): &ExprKind<'tcx> = &expression.kind else { return; }; + // Skip if the expression is from a macro expansion, as it may not be + // possible to determine the type annotation in that case. + if matches!(closure.kind, rustc_hir::ClosureKind::Coroutine(_)) { + return; + } + // Get the body of the closure to access its parameters. let body: &Body<'_> = context.tcx.hir_body(closure.body); @@ -154,7 +176,7 @@ mod tests { #[test] fn ui() { Test::src_base(env!("CARGO_PKG_NAME"), "ui") - .rustc_flags(["-Z", "ui-testing"]) + .rustc_flags(["--edition=2024", "-Z", "ui-testing"]) .run(); } } diff --git a/rules/missing_type/ui/main.rs b/rules/missing_type/ui/main.rs index fd7b57c..7f61ec7 100644 --- a/rules/missing_type/ui/main.rs +++ b/rules/missing_type/ui/main.rs @@ -29,3 +29,19 @@ fn main() { // Closure with `_` pattern (should not trigger). let ignore: fn(i32) -> i32 = |_| 0; } + +/// Asynchronous function example to demonstrate that the `missing_type` lint +/// does not trigger for async functions, as they may have implicit return +/// types and parameters that are not explicitly annotated. This function takes +/// an `i32` parameter and returns a future that resolves to an `i32`. The lint +/// should not emit a warning for this function, as it is common for async +/// functions to have implicit return types and parameters without explicit +/// type annotations, especially when using async/await syntax. +async fn async_example(x: i32) -> i32 { + x + 1 +} + +async fn async_with_let() -> i32 { + let value: i32 = 10; + value +} diff --git a/rules/panic_usage/src/lib.rs b/rules/panic_usage/src/lib.rs index 0d7829c..367941a 100644 --- a/rules/panic_usage/src/lib.rs +++ b/rules/panic_usage/src/lib.rs @@ -12,6 +12,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext, LintStore}; use rustc_middle::ty::TyCtxt; use rustc_session::{Session, declare_lint, declare_lint_pass}; +use rustc_span::sym; declare_lint! { pub SECURITY_PANIC_USAGE, @@ -21,26 +22,6 @@ declare_lint! { declare_lint_pass!(SecurityPanicUsage => [SECURITY_PANIC_USAGE]); -/// Enum representing the different kinds of panic-related constructs that can -/// be detected by the `SECURITY_PANIC_USAGE` lint, such as calls to `unwrap` -/// and `expect` methods, as well as calls to panic-related functions in the -/// standard library. -#[derive(Debug, Clone, Copy)] -enum PanicKind { - Unwrap, - Expect, -} - -impl PanicKind { - fn from_method(name: &str) -> Option { - match name { - "unwrap" => Some(Self::Unwrap), - "expect" => Some(Self::Expect), - _ => None, - } - } -} - /// Enum representing the different panic backends that can be detected by the /// `SECURITY_PANIC_USAGE` lint, such as the `panicking` module, the /// `panic_fmt` function, the `panic_display` function, the `assert_failed` @@ -87,20 +68,29 @@ impl<'tcx> LateLintPass<'tcx> for SecurityPanicUsage { expression: &'tcx Expr<'tcx>, ) { // Detect direct calls to `unwrap` and `expect` methods. - if let ExprKind::MethodCall(segment, _, _, _) = &expression.kind - && let Some(kind) = - PanicKind::from_method(segment.ident.name.as_str()) + // This checks for method calls where the method name is `unwrap` or + // `expect`, and the method is defined in the local crate (to avoid + // false positives from external crates). + if let ExprKind::MethodCall(_, _, _, _) = &expression.kind + && let Some(def_id) = context + .typeck_results() + .type_dependent_def_id(expression.hir_id) { - context.span_lint( - SECURITY_PANIC_USAGE, - expression.span, - |diagnostic: &mut Diag<'_, ()>| { - diagnostic.primary_message(format!( - "Call to panic backend `{kind:?}` detected." - )); - }, - ); - return; + if context.tcx.is_diagnostic_item(sym::unwrap, def_id) + || context.tcx.is_diagnostic_item(sym::option_unwrap, def_id) + || context.tcx.is_diagnostic_item(sym::except, def_id) + || context.tcx.is_diagnostic_item(sym::option_expect, def_id) + { + context.span_lint( + SECURITY_PANIC_USAGE, + expression.span, + |diagnostic: &mut Diag<'_, ()>| { + diagnostic.primary_message( + "Call to panic backend `unwrap/expect` detected.", + ); + }, + ); + } } // Detect calls to panic-related functions in the standard library. @@ -162,7 +152,7 @@ mod tests { #[test] fn ui() { Test::src_base(env!("CARGO_PKG_NAME"), "ui") - .rustc_flags(["-Z", "ui-testing"]) + .rustc_flags(["--edition=2024", "-Z", "ui-testing"]) .run(); } } diff --git a/rules/panic_usage/ui/main.stderr b/rules/panic_usage/ui/main.stderr index ff079cb..5675c85 100644 --- a/rules/panic_usage/ui/main.stderr +++ b/rules/panic_usage/ui/main.stderr @@ -1,4 +1,4 @@ -warning: Call to panic backend `Unwrap` detected. +warning: Call to panic backend `unwrap/expect` detected. --> $DIR/main.rs:10:5 | LL | x.unwrap(); // Should trigger. @@ -10,13 +10,13 @@ note: the lint level is defined here LL | #![warn(security_panic_usage)] | ^^^^^^^^^^^^^^^^^^^^ -warning: Call to panic backend `Expect` detected. +warning: Call to panic backend `unwrap/expect` detected. --> $DIR/main.rs:11:5 | LL | x.expect(""); // should trigger. | ^^^^^^^^^^^^ -warning: Call to panic backend `BeginPanic` detected. +warning: Call to panic backend `PanicFmt` detected. --> $DIR/main.rs:13:5 | LL | panic!(""); // Should trigger. diff --git a/rules/unsafe_usage/src/lib.rs b/rules/unsafe_usage/src/lib.rs index 345dabc..f91d6e4 100644 --- a/rules/unsafe_usage/src/lib.rs +++ b/rules/unsafe_usage/src/lib.rs @@ -159,7 +159,7 @@ mod tests { #[test] fn ui() { Test::src_base(env!("CARGO_PKG_NAME"), "ui") - .rustc_flags(["-Z", "ui-testing"]) + .rustc_flags(["--edition=2024", "-Z", "ui-testing"]) .run(); } }