-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
use clippy_utils::{ | ||
diagnostics::{span_lint, span_lint_hir_and_then}, | ||
path_res, | ||
ty::implements_trait, | ||
}; | ||
use rustc_hir::{def_id::DefId, Item, ItemKind, Node}; | ||
use rustc_hir_analysis::hir_ty_to_ty; | ||
use rustc_lint::{LateContext, LateLintPass}; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
use rustc_span::sym; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for types named `Error` that implement `Error`. | ||
/// | ||
/// ### Why is this bad? | ||
/// It can become confusing when a codebase has 20 types all named `Error`, requiring either | ||
/// aliasing them in the `use` statement them or qualifying them like `my_module::Error`. This | ||
/// severely hinders readability. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// #[derive(Debug)] | ||
/// pub enum Error { ... } | ||
/// | ||
/// impl std::fmt::Display for Error { ... } | ||
/// | ||
/// impl std::error::Error for Error { ... } | ||
/// ``` | ||
#[clippy::version = "1.72.0"] | ||
pub ERROR_IMPL_ERROR, | ||
restriction, | ||
"types named `Error` that implement `Error`" | ||
} | ||
declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]); | ||
|
||
impl<'tcx> LateLintPass<'tcx> for ErrorImplError { | ||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { | ||
let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else { | ||
return; | ||
}; | ||
|
||
match item.kind { | ||
ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[]) | ||
&& item.ident.name == sym::Error => | ||
{ | ||
span_lint( | ||
cx, | ||
ERROR_IMPL_ERROR, | ||
item.ident.span, | ||
"type alias named `Error` that implements `Error`", | ||
); | ||
}, | ||
ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) | ||
&& error_def_id == trait_def_id | ||
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) | ||
&& let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) | ||
&& let Node::Item(ty_item) = cx.tcx.hir().get(hir_id) | ||
&& ty_item.ident.name == sym::Error => | ||
{ | ||
span_lint_hir_and_then( | ||
cx, | ||
ERROR_IMPL_ERROR, | ||
hir_id, | ||
ty_item.ident.span, | ||
"type named `Error` that implements `Error`", | ||
|diag| { | ||
diag.span_note(item.span, "`Error` was implemented here"); | ||
} | ||
); | ||
} | ||
_ => {}, | ||
} | ||
{} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#![allow(unused)] | ||
#![warn(clippy::error_impl_error)] | ||
#![no_main] | ||
|
||
mod a { | ||
#[derive(Debug)] | ||
struct Error; | ||
|
||
impl std::fmt::Display for Error { | ||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl std::error::Error for Error {} | ||
} | ||
|
||
mod b { | ||
#[derive(Debug)] | ||
enum Error {} | ||
|
||
impl std::fmt::Display for Error { | ||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl std::error::Error for Error {} | ||
} | ||
|
||
mod c { | ||
union Error { | ||
a: u32, | ||
b: u32, | ||
} | ||
|
||
impl std::fmt::Debug for Error { | ||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl std::fmt::Display for Error { | ||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl std::error::Error for Error {} | ||
} | ||
|
||
mod d { | ||
type Error = std::fmt::Error; | ||
} | ||
|
||
mod e { | ||
#[derive(Debug)] | ||
struct MyError; | ||
|
||
impl std::fmt::Display for MyError { | ||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl std::error::Error for MyError {} | ||
} | ||
|
||
mod f { | ||
type MyError = std::fmt::Error; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
error: type named `Error` that implements `Error` | ||
--> $DIR/error_impl_error.rs:7:12 | ||
| | ||
LL | struct Error; | ||
| ^^^^^ | ||
| | ||
note: `Error` was implemented here | ||
--> $DIR/error_impl_error.rs:15:5 | ||
| | ||
LL | impl std::error::Error for Error {} | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
= note: `-D clippy::error-impl-error` implied by `-D warnings` | ||
|
||
error: type named `Error` that implements `Error` | ||
--> $DIR/error_impl_error.rs:20:10 | ||
| | ||
LL | enum Error {} | ||
| ^^^^^ | ||
| | ||
note: `Error` was implemented here | ||
--> $DIR/error_impl_error.rs:28:5 | ||
| | ||
LL | impl std::error::Error for Error {} | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: type named `Error` that implements `Error` | ||
--> $DIR/error_impl_error.rs:32:11 | ||
| | ||
LL | union Error { | ||
| ^^^^^ | ||
| | ||
note: `Error` was implemented here | ||
--> $DIR/error_impl_error.rs:49:5 | ||
| | ||
LL | impl std::error::Error for Error {} | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: type alias named `Error` that implements `Error` | ||
--> $DIR/error_impl_error.rs:53:10 | ||
| | ||
LL | type Error = std::fmt::Error; | ||
| ^^^^^ | ||
|
||
error: aborting due to 4 previous errors | ||
|