Skip to content

Commit 2b21c9e

Browse files
add tostring_impl lint
1 parent e899684 commit 2b21c9e

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5625,6 +5625,7 @@ Released 2018-09-13
56255625
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
56265626
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
56275627
[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
5628+
[`tostring_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#tostring_impl
56285629
[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
56295630
[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
56305631
[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
655655
crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
656656
crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO,
657657
crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
658+
crate::tostring_impl::TOSTRING_IMPL_INFO,
658659
crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
659660
crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
660661
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ mod temporary_assignment;
325325
mod tests_outside_test_module;
326326
mod thread_local_initializer_can_be_made_const;
327327
mod to_digit_is_some;
328+
mod tostring_impl;
328329
mod trailing_empty_array;
329330
mod trait_bounds;
330331
mod transmute;
@@ -1092,6 +1093,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
10921093
store.register_late_pass(move |_| {
10931094
Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv()))
10941095
});
1096+
store.register_late_pass(|_| Box::new(tostring_impl::TostringImpl));
10951097
// add lints here, do not remove this comment, it's used in `new_lint`
10961098
}
10971099

clippy_lints/src/tostring_impl.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_hir::*;
3+
use rustc_lint::{LateContext, LateLintPass};
4+
use rustc_session::declare_lint_pass;
5+
use rustc_span::sym;
6+
7+
declare_clippy_lint! {
8+
/// ### What it does
9+
/// Checks for direct implementations of `ToString`.
10+
/// ### Why is this bad?
11+
/// This trait is automatically implemented for any type which implements the `Display` trait.
12+
/// As such, `ToString` shouldn’t be implemented directly: `Display` should be implemented instead,
13+
/// and you get the `ToString` implementation for free.
14+
/// ### Example
15+
/// ```no_run
16+
/// impl ToString for Point {
17+
/// fn to_string(&self) -> String {
18+
/// format!("({}, {})", self.x, self.y)
19+
/// }
20+
/// }
21+
/// ```
22+
/// Use instead:
23+
/// ```no_run
24+
/// impl fmt::Display for Point {
25+
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
/// write!(f, "({}, {})", self.x, self.y)
27+
/// }
28+
/// }
29+
/// ```
30+
#[clippy::version = "1.77.0"]
31+
pub TOSTRING_IMPL,
32+
style,
33+
"default lint description"
34+
}
35+
36+
declare_lint_pass!(TostringImpl => [TOSTRING_IMPL]);
37+
38+
impl<'tcx> LateLintPass<'tcx> for TostringImpl {
39+
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) {
40+
if let ItemKind::Impl(Impl {
41+
of_trait: Some(trait_ref),
42+
..
43+
}) = it.kind
44+
&& let Some(trait_did) = trait_ref.trait_def_id()
45+
&& cx.tcx.is_diagnostic_item(sym::ToString, trait_did)
46+
{
47+
span_lint_and_help(
48+
cx,
49+
TOSTRING_IMPL,
50+
it.span,
51+
"direct implementation of `ToString`",
52+
None,
53+
"prefer implementing `Display` instead",
54+
);
55+
}
56+
}
57+
}

tests/ui/tostring_impl.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![warn(clippy::tostring_impl)]
2+
3+
use std::fmt::{self, Display};
4+
5+
struct Point {
6+
x: usize,
7+
y: usize,
8+
}
9+
10+
impl ToString for Point {
11+
fn to_string(&self) -> String {
12+
format!("({}, {})", self.x, self.y)
13+
}
14+
}
15+
16+
struct Foo;
17+
18+
impl Display for Foo {
19+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
write!(f, "Foo")
21+
}
22+
}

tests/ui/tostring_impl.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: direct implementation of `ToString`
2+
--> $DIR/tostring_impl.rs:10:1
3+
|
4+
LL | / impl ToString for Point {
5+
LL | | fn to_string(&self) -> String {
6+
LL | | format!("({}, {})", self.x, self.y)
7+
LL | | }
8+
LL | | }
9+
| |_^
10+
|
11+
= help: prefer implementing `Display` instead
12+
= note: `-D clippy::tostring-impl` implied by `-D warnings`
13+
= help: to override `-D warnings` add `#[allow(clippy::tostring_impl)]`
14+
15+
error: aborting due to 1 previous error
16+

0 commit comments

Comments
 (0)