Skip to content

Commit f048f73

Browse files
Add warning about semver compatibility if it's a public function
1 parent 33adfcd commit f048f73

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

clippy_lints/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10581058
let stack_size_threshold = conf.stack_size_threshold;
10591059
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
10601060
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
1061-
store.register_late_pass(|_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut));
1061+
store.register_late_pass(move |_| {
1062+
Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(
1063+
avoid_breaking_exported_api,
1064+
))
1065+
});
10621066
store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls));
10631067
store.register_late_pass(move |_| {
10641068
Box::new(single_call_fn::SingleCallFn {

clippy_lints/src/needless_pass_by_ref_mut.rs

+47-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::needless_pass_by_value::requires_exact_signature;
2-
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::source::snippet;
44
use clippy_utils::{is_from_proc_macro, is_self};
55
use if_chain::if_chain;
@@ -12,7 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt;
1212
use rustc_lint::{LateContext, LateLintPass};
1313
use rustc_middle::mir::FakeReadCause;
1414
use rustc_middle::ty::{self, Ty};
15-
use rustc_session::{declare_lint_pass, declare_tool_lint};
15+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1616
use rustc_span::def_id::LocalDefId;
1717
use rustc_span::symbol::kw;
1818
use rustc_span::Span;
@@ -46,7 +46,21 @@ declare_clippy_lint! {
4646
suspicious,
4747
"using a `&mut` argument when it's not mutated"
4848
}
49-
declare_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]);
49+
50+
#[derive(Copy, Clone)]
51+
pub struct NeedlessPassByRefMut {
52+
avoid_breaking_exported_api: bool,
53+
}
54+
55+
impl NeedlessPassByRefMut {
56+
pub fn new(avoid_breaking_exported_api: bool) -> Self {
57+
Self {
58+
avoid_breaking_exported_api,
59+
}
60+
}
61+
}
62+
63+
impl_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]);
5064

5165
fn should_skip<'tcx>(
5266
cx: &LateContext<'tcx>,
@@ -134,26 +148,45 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
134148
ctx
135149
};
136150

137-
for ((&input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params) {
138-
if should_skip(cx, input, ty, arg) {
139-
continue;
140-
}
141-
151+
let mut it = decl
152+
.inputs
153+
.iter()
154+
.zip(fn_sig.inputs())
155+
.zip(body.params)
156+
.filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
157+
.peekable();
158+
if it.peek().is_none() {
159+
return;
160+
}
161+
let show_semver_warning = self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id);
162+
for ((&input, &_), arg) in it {
142163
// Only take `&mut` arguments.
143164
if_chain! {
144165
if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind;
145166
if !mutably_used_vars.contains(&canonical_id);
146167
if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind;
147168
then {
148-
// If the argument is never used mutably, we emit the error.
149-
span_lint_and_sugg(
169+
// If the argument is never used mutably, we emit the warning.
170+
let sp = input.span;
171+
span_lint_and_then(
150172
cx,
151173
NEEDLESS_PASS_BY_REF_MUT,
152-
input.span,
174+
sp,
153175
"this argument is a mutable reference, but not used mutably",
154-
"consider changing to",
155-
format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_")),
156-
Applicability::Unspecified,
176+
|diag| {
177+
diag.span_suggestion(
178+
sp,
179+
"consider changing to".to_string(),
180+
format!(
181+
"&{}",
182+
snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),
183+
),
184+
Applicability::Unspecified,
185+
);
186+
if show_semver_warning {
187+
diag.warn("changing this function will impact semver compatibility");
188+
}
189+
},
157190
);
158191
}
159192
}

tests/ui/should_impl_trait/method_list_2.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ error: this argument is a mutable reference, but not used mutably
4545
LL | pub fn hash(&self, state: &mut T) {
4646
| ^^^^^^ help: consider changing to: `&T`
4747
|
48+
= warning: changing this function will impact semver compatibility
4849
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
4950

5051
error: method `index` can be confused for the standard trait method `std::ops::Index::index`

0 commit comments

Comments
 (0)