-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New lint: drop_for_static
#16464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
New lint: drop_for_static
#16464
Changes from 10 commits
8637edf
f77a330
01996a9
5c62dbc
1945c32
3e96514
5bfaf00
029b157
a7b3a92
ffa231c
c921392
20733e7
ed91723
19dcecb
addcd58
2489ce9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| use clippy_utils::diagnostics::span_lint; | ||
| use clippy_utils::ty::has_drop; | ||
| use rustc_hir::intravisit::{Visitor, walk_path}; | ||
| use rustc_hir::{HirId, Item, ItemKind, Path}; | ||
| use rustc_lint::{LateContext, LateLintPass}; | ||
| use rustc_middle::hir::nested_filter; | ||
| use rustc_session::declare_lint_pass; | ||
|
|
||
| declare_clippy_lint! { | ||
| /// ### What it does | ||
| /// Checks for `static` variables whose types implement `Drop`. | ||
| /// | ||
| /// ### Why restrict this? | ||
| /// Rust does not call `Drop::drop` for `static` variables at the end of a program's | ||
| /// execution. If a type relies on its `Drop` implementation to release resources | ||
| /// (like closing files, releasing locks, or deleting temporary files), these | ||
| /// actions will never occur for a `static` instance, potentially leading to | ||
| /// resource leaks or inconsistent state. | ||
| /// | ||
| /// ### Example | ||
| /// ```rust | ||
| /// struct Logger; | ||
| /// | ||
| /// impl Drop for Logger { | ||
| /// fn drop(&mut self) { | ||
| /// println!("Closing log file..."); | ||
| /// } | ||
| /// } | ||
| /// | ||
| /// static GLOBAL_LOGGER: Logger = Logger; | ||
| /// ``` | ||
| /// | ||
| /// ### Known problems | ||
| /// If the type is intended to exist for the lifetime of the program and the | ||
| /// resource is automatically reclaimed by the operating system (like memory), | ||
| /// this lint may be noisy. However, it still serves as a useful reminder that | ||
| /// the `drop` logic will not execute. | ||
| #[clippy::version = "1.93.0"] | ||
| pub DROP_FOR_STATIC, | ||
| nursery, | ||
| "static items with a type that implements 'Drop'" | ||
| } | ||
| declare_lint_pass!(DropForStatic => [DROP_FOR_STATIC]); | ||
|
|
||
| impl LateLintPass<'_> for DropForStatic { | ||
| fn check_item<'a>(&mut self, cx: &LateContext<'a>, item: &'a Item<'a>) { | ||
| if let ItemKind::Static(_, ident, _, _) = item.kind { | ||
| let mut visitor = DropForStaticVisitor::new(cx); | ||
| visitor.visit_item(item); | ||
| if visitor.drop_for_static_found { | ||
| span_lint(cx, DROP_FOR_STATIC, ident.span, "static items with drop implementation"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct DropForStaticVisitor<'a, 'tcx> { | ||
| cx: &'a LateContext<'tcx>, | ||
| drop_for_static_found: bool, | ||
| } | ||
| impl<'a, 'tcx> DropForStaticVisitor<'a, 'tcx> { | ||
| fn new(cx: &'a LateContext<'tcx>) -> Self { | ||
| Self { | ||
| cx, | ||
| drop_for_static_found: false, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<'tcx> Visitor<'tcx> for DropForStaticVisitor<'_, 'tcx> { | ||
| type NestedFilter = nested_filter::All; | ||
|
|
||
| fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { | ||
| if let Some(def_id) = path.res.opt_def_id() { | ||
| let ty = self.cx.tcx.type_of(def_id).instantiate_identity(); | ||
| if has_drop(self.cx, ty) { | ||
| self.drop_for_static_found = true; | ||
|
||
| } else { | ||
| walk_path(self, path); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { | ||
| self.cx.tcx | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| #![warn(clippy::drop_for_static)] | ||
| #![allow(unused)] | ||
|
|
||
| struct FooWithDrop; | ||
| struct FooWithoutDrop; | ||
|
|
||
| impl Drop for FooWithDrop { | ||
| fn drop(&mut self) {} | ||
| } | ||
|
|
||
| static A1: FooWithDrop = FooWithDrop; | ||
| //~^ drop_for_static | ||
| static A2: FooWithoutDrop = FooWithoutDrop; | ||
|
|
||
| static A3: &FooWithDrop = &FooWithDrop; | ||
| //~^ drop_for_static | ||
| static A4: &FooWithoutDrop = &FooWithoutDrop; | ||
|
|
||
| static A5: (FooWithoutDrop, FooWithDrop) = (FooWithoutDrop, FooWithDrop); | ||
| //~^ drop_for_static | ||
| static A6: (FooWithoutDrop, FooWithoutDrop) = (FooWithoutDrop, FooWithoutDrop); | ||
|
|
||
| static A7: [FooWithDrop; 1] = [FooWithDrop]; | ||
| //~^ drop_for_static | ||
| static A8: [FooWithoutDrop; 1] = [FooWithoutDrop]; | ||
|
|
||
| static A9: &[FooWithDrop] = &[FooWithDrop]; | ||
| //~^ drop_for_static | ||
| static A10: &[FooWithoutDrop] = &[FooWithoutDrop]; | ||
|
|
||
| // ---------------------- | ||
| // nested types scenarios | ||
| // ---------------------- | ||
|
|
||
| struct Nested<T1, T2 = ()>(T1, T2); | ||
| static B1: Nested<FooWithDrop> = Nested(FooWithDrop, ()); | ||
| //~^ drop_for_static | ||
| static B2: Nested<FooWithoutDrop> = Nested(FooWithoutDrop, ()); | ||
|
|
||
| static B3: Nested<FooWithoutDrop, Nested<FooWithDrop>> = Nested(FooWithoutDrop, Nested(FooWithDrop, ())); | ||
| //~^ drop_for_static | ||
| static B4: Nested<FooWithoutDrop, Nested<FooWithoutDrop>> = Nested(FooWithoutDrop, Nested(FooWithoutDrop, ())); | ||
|
|
||
| static B5: Nested<&FooWithDrop> = Nested(&FooWithDrop, ()); | ||
| //~^ drop_for_static | ||
| static B6: Nested<&FooWithoutDrop> = Nested(&FooWithoutDrop, ()); | ||
|
|
||
| static B7: Nested<(FooWithoutDrop, FooWithDrop)> = Nested((FooWithoutDrop, FooWithDrop), ()); | ||
| //~^ drop_for_static | ||
| static B8: Nested<(FooWithoutDrop, FooWithoutDrop)> = Nested((FooWithoutDrop, FooWithoutDrop), ()); | ||
|
|
||
| static B9: Nested<[FooWithDrop; 1]> = Nested([FooWithDrop], ()); | ||
| //~^ drop_for_static | ||
| static B10: Nested<[FooWithoutDrop; 1]> = Nested([FooWithoutDrop], ()); | ||
|
|
||
| static B11: Nested<&[FooWithDrop]> = Nested(&[FooWithDrop], ()); | ||
| //~^ drop_for_static | ||
| static B12: Nested<&[FooWithoutDrop]> = Nested(&[FooWithoutDrop], ()); | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:11:8 | ||
| | | ||
| LL | static A1: FooWithDrop = FooWithDrop; | ||
| | ^^ | ||
| | | ||
| = note: `-D clippy::drop-for-static` implied by `-D warnings` | ||
| = help: to override `-D warnings` add `#[allow(clippy::drop_for_static)]` | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:15:8 | ||
| | | ||
| LL | static A3: &FooWithDrop = &FooWithDrop; | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:19:8 | ||
| | | ||
| LL | static A5: (FooWithoutDrop, FooWithDrop) = (FooWithoutDrop, FooWithDrop); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:23:8 | ||
| | | ||
| LL | static A7: [FooWithDrop; 1] = [FooWithDrop]; | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:27:8 | ||
| | | ||
| LL | static A9: &[FooWithDrop] = &[FooWithDrop]; | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:36:8 | ||
| | | ||
| LL | static B1: Nested<FooWithDrop> = Nested(FooWithDrop, ()); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:40:8 | ||
| | | ||
| LL | static B3: Nested<FooWithoutDrop, Nested<FooWithDrop>> = Nested(FooWithoutDrop, Nested(FooWithDrop, ())); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:44:8 | ||
| | | ||
| LL | static B5: Nested<&FooWithDrop> = Nested(&FooWithDrop, ()); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:48:8 | ||
| | | ||
| LL | static B7: Nested<(FooWithoutDrop, FooWithDrop)> = Nested((FooWithoutDrop, FooWithDrop), ()); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:52:8 | ||
| | | ||
| LL | static B9: Nested<[FooWithDrop; 1]> = Nested([FooWithDrop], ()); | ||
| | ^^ | ||
|
|
||
| error: static items with drop implementation | ||
| --> tests/ui/drop_for_static.rs:56:8 | ||
| | | ||
| LL | static B11: Nested<&[FooWithDrop]> = Nested(&[FooWithDrop], ()); | ||
| | ^^^ | ||
|
|
||
| error: aborting due to 11 previous errors | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.