Skip to content

Commit 8798c66

Browse files
committed
Auto merge of rust-lang#10736 - NotAPenguin0:master, r=Alexendoo
initial clippy::ref_pattern implementation This implements a new lint that discourages the use of the `ref` keyword as outlined in rust-lang#9010. I think there are still some things to improve about this lint, but I need some feedback before I can implement those. - [x] ~~Maybe it's desirable that a quick fix is listed too, instead of a generic `avoid using the ref keyword` lint.~~ - [x] `let ref x = y` already has a lint (`clippy::toplevel_ref_arg`). This implementation will report this too, so you get two lints for the same issue, which is not great. I don't really know a way around this though. - [X] The dogfood test is currently failing locally, though I ran `cargo clippy -- -D clippy::all -D clippy::pedantic` and got no output, so I'm not sure why this is. Any help with these would be greatly appreciated. fixes rust-lang#9010 changelog: [`ref_pattern`]: newly added lint
2 parents 3aab0dd + 56e8e1a commit 8798c66

File tree

7 files changed

+104
-1
lines changed

7 files changed

+104
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4978,6 +4978,7 @@ Released 2018-09-13
49784978
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
49794979
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
49804980
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
4981+
[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
49814982
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
49824983
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
49834984
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
539539
crate::redundant_slicing::REDUNDANT_SLICING_INFO,
540540
crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
541541
crate::ref_option_ref::REF_OPTION_REF_INFO,
542+
crate::ref_patterns::REF_PATTERNS_INFO,
542543
crate::reference::DEREF_ADDROF_INFO,
543544
crate::regex::INVALID_REGEX_INFO,
544545
crate::regex::TRIVIAL_REGEX_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ mod redundant_pub_crate;
266266
mod redundant_slicing;
267267
mod redundant_static_lifetimes;
268268
mod ref_option_ref;
269+
mod ref_patterns;
269270
mod reference;
270271
mod regex;
271272
mod return_self_not_must_use;
@@ -971,6 +972,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
971972
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
972973
store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
973974
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
975+
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
974976
store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
975977
// add lints here, do not remove this comment, it's used in `new_lint`
976978
}

clippy_lints/src/misc.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ use rustc_span::source_map::{ExpnKind, Span};
1616

1717
use clippy_utils::sugg::Sugg;
1818
use clippy_utils::{
19-
get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
19+
get_parent_expr, in_constant, is_integer_literal, is_lint_allowed, is_no_std_crate, iter_input_pats,
20+
last_path_segment, SpanlessEq,
2021
};
2122

23+
use crate::ref_patterns::REF_PATTERNS;
24+
2225
declare_clippy_lint! {
2326
/// ### What it does
2427
/// Checks for function arguments and let bindings denoted as
@@ -162,6 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
162165
return;
163166
}
164167
for arg in iter_input_pats(decl, body) {
168+
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
169+
if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) {
170+
return;
171+
}
165172
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
166173
span_lint(
167174
cx,
@@ -180,6 +187,8 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
180187
if let StmtKind::Local(local) = stmt.kind;
181188
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
182189
if let Some(init) = local.init;
190+
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
191+
if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id);
183192
then {
184193
let ctxt = local.span.ctxt();
185194
let mut app = Applicability::MachineApplicable;

clippy_lints/src/ref_patterns.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_ast::ast::{BindingAnnotation, Pat, PatKind};
3+
use rustc_lint::{EarlyContext, EarlyLintPass};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
6+
declare_clippy_lint! {
7+
/// ### What it does
8+
/// Checks for usages of the `ref` keyword.
9+
/// ### Why is this bad?
10+
/// The `ref` keyword can be confusing for people unfamiliar with it, and often
11+
/// it is more concise to use `&` instead.
12+
/// ### Example
13+
/// ```rust
14+
/// let opt = Some(5);
15+
/// if let Some(ref foo) = opt {}
16+
/// ```
17+
/// Use instead:
18+
/// ```rust
19+
/// let opt = Some(5);
20+
/// if let Some(foo) = &opt {}
21+
/// ```
22+
#[clippy::version = "1.71.0"]
23+
pub REF_PATTERNS,
24+
restriction,
25+
"use of a ref pattern, e.g. Some(ref value)"
26+
}
27+
declare_lint_pass!(RefPatterns => [REF_PATTERNS]);
28+
29+
impl EarlyLintPass for RefPatterns {
30+
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
31+
if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind
32+
&& !pat.span.from_expansion()
33+
{
34+
span_lint_and_help(
35+
cx,
36+
REF_PATTERNS,
37+
pat.span,
38+
"usage of ref pattern",
39+
None,
40+
"consider using `&` for clarity instead",
41+
);
42+
}
43+
}
44+
}

tests/ui/ref_patterns.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![allow(unused)]
2+
#![warn(clippy::ref_patterns)]
3+
4+
fn use_in_pattern() {
5+
let opt = Some(5);
6+
match opt {
7+
None => {},
8+
Some(ref opt) => {},
9+
}
10+
}
11+
12+
fn use_in_binding() {
13+
let x = 5;
14+
let ref y = x;
15+
}
16+
17+
fn use_in_parameter(ref x: i32) {}
18+
19+
fn main() {}

tests/ui/ref_patterns.stderr

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: usage of ref pattern
2+
--> $DIR/ref_patterns.rs:8:14
3+
|
4+
LL | Some(ref opt) => {},
5+
| ^^^^^^^
6+
|
7+
= help: consider using `&` for clarity instead
8+
= note: `-D clippy::ref-patterns` implied by `-D warnings`
9+
10+
error: usage of ref pattern
11+
--> $DIR/ref_patterns.rs:14:9
12+
|
13+
LL | let ref y = x;
14+
| ^^^^^
15+
|
16+
= help: consider using `&` for clarity instead
17+
18+
error: usage of ref pattern
19+
--> $DIR/ref_patterns.rs:17:21
20+
|
21+
LL | fn use_in_parameter(ref x: i32) {}
22+
| ^^^^^
23+
|
24+
= help: consider using `&` for clarity instead
25+
26+
error: aborting due to 3 previous errors
27+

0 commit comments

Comments
 (0)