1 use clippy_utils
::diagnostics
::span_lint_and_help
;
2 use clippy_utils
::macros
::root_macro_call_first_node
;
3 use clippy_utils
::visitors
::is_local_used
;
4 use if_chain
::if_chain
;
5 use rustc_hir
::{Body, Impl, ImplItem, ImplItemKind, ItemKind}
;
6 use rustc_lint
::{LateContext, LateLintPass}
;
7 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
8 use std
::ops
::ControlFlow
;
10 declare_clippy_lint
! {
12 /// Checks methods that contain a `self` argument but don't use it
14 /// ### Why is this bad?
15 /// It may be clearer to define the method as an associated function instead
16 /// of an instance method if it doesn't require `self`.
22 /// fn method(&self) {}
34 #[clippy::version = "1.40.0"]
37 "methods that contain a `self` argument but don't use it"
40 pub struct UnusedSelf
{
41 avoid_breaking_exported_api
: bool
,
44 impl_lint_pass
!(UnusedSelf
=> [UNUSED_SELF
]);
47 pub fn new(avoid_breaking_exported_api
: bool
) -> Self {
49 avoid_breaking_exported_api
,
54 impl<'tcx
> LateLintPass
<'tcx
> for UnusedSelf
{
55 fn check_impl_item(&mut self, cx
: &LateContext
<'tcx
>, impl_item
: &ImplItem
<'_
>) {
56 if impl_item
.span
.from_expansion() {
59 let parent
= cx
.tcx
.hir().get_parent_item(impl_item
.hir_id()).def_id
;
60 let parent_item
= cx
.tcx
.hir().expect_item(parent
);
61 let assoc_item
= cx
.tcx
.associated_item(impl_item
.owner_id
);
62 let contains_todo
= |cx
, body
: &'_ Body
<'_
>| -> bool
{
63 clippy_utils
::visitors
::for_each_expr(body
.value
, |e
| {
64 if let Some(macro_call
) = root_macro_call_first_node(cx
, e
) {
65 if cx
.tcx
.item_name(macro_call
.def_id
).as_str() == "todo" {
66 ControlFlow
::Break(())
68 ControlFlow
::Continue(())
71 ControlFlow
::Continue(())
77 if let ItemKind
::Impl(Impl { of_trait: None, .. }
) = parent_item
.kind
;
78 if assoc_item
.fn_has_self_parameter
;
79 if let ImplItemKind
::Fn(.., body_id
) = &impl_item
.kind
;
80 if !cx
.effective_visibilities
.is_exported(impl_item
.owner_id
.def_id
) || !self.avoid_breaking_exported_api
;
81 let body
= cx
.tcx
.hir().body(*body_id
);
82 if let [self_param
, ..] = body
.params
;
83 if !is_local_used(cx
, body
, self_param
.pat
.hir_id
);
84 if !contains_todo(cx
, body
);
90 "unused `self` argument",
92 "consider refactoring to an associated function",