mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
Don't lint various match lints when expanded by a proc-macro
This commit is contained in:
parent
a63308be0a
commit
63f6a79bf8
5 changed files with 77 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
|||
use clippy_utils::source::{snippet_opt, walk_span_to_context};
|
||||
use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
|
@ -653,6 +653,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
|||
}
|
||||
|
||||
if let ExprKind::Match(ex, arms, source) = expr.kind {
|
||||
if !span_starts_with(cx, expr.span, "match") {
|
||||
return;
|
||||
}
|
||||
if !contains_cfg_arm(cx, expr, ex, arms) {
|
||||
if source == MatchSource::Normal {
|
||||
if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO)
|
||||
|
|
|
@ -7,9 +7,28 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_span::hygiene;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Checks if the span starts with the given text. This will return false if the span crosses
|
||||
/// multiple files or if source is not available.
|
||||
///
|
||||
/// This is used to check for proc macros giving unhelpful spans to things.
|
||||
pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
|
||||
fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
|
||||
let pos = sm.lookup_byte_offset(span.lo());
|
||||
let Some(ref src) = pos.sf.src else {
|
||||
return false;
|
||||
};
|
||||
let end = span.hi() - pos.sf.start_pos;
|
||||
src.get(pos.pos.0 as usize..end.0 as usize)
|
||||
// Expression spans can include wrapping parenthesis. Remove them first.
|
||||
.map_or(false, |s| s.trim_start_matches('(').starts_with(text))
|
||||
}
|
||||
helper(cx.sess().source_map(), span, text)
|
||||
}
|
||||
|
||||
/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
|
||||
/// Also takes an `Option<String>` which can be put inside the braces.
|
||||
pub fn expr_block<'a, T: LintContext>(
|
||||
|
|
32
tests/ui/auxiliary/proc_macro_with_span.rs
Normal file
32
tests/ui/auxiliary/proc_macro_with_span.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// compile-flags: --emit=link
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{token_stream::IntoIter, Group, Span, TokenStream, TokenTree};
|
||||
|
||||
#[proc_macro]
|
||||
pub fn with_span(input: TokenStream) -> TokenStream {
|
||||
let mut iter = input.into_iter();
|
||||
let span = iter.next().unwrap().span();
|
||||
let mut res = TokenStream::new();
|
||||
write_with_span(span, iter, &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
fn write_with_span(s: Span, input: IntoIter, out: &mut TokenStream) {
|
||||
for mut tt in input {
|
||||
if let TokenTree::Group(g) = tt {
|
||||
let mut stream = TokenStream::new();
|
||||
write_with_span(s, g.stream().into_iter(), &mut stream);
|
||||
let mut group = Group::new(g.delimiter(), stream);
|
||||
group.set_span(s);
|
||||
out.extend([TokenTree::Group(group)]);
|
||||
} else {
|
||||
tt.set_span(s);
|
||||
out.extend([tt]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
// aux-build: proc_macro_with_span.rs
|
||||
|
||||
#![warn(clippy::single_match_else)]
|
||||
#![allow(clippy::needless_return)]
|
||||
#![allow(clippy::no_effect)]
|
||||
|
||||
extern crate proc_macro_with_span;
|
||||
use proc_macro_with_span::with_span;
|
||||
|
||||
enum ExprNode {
|
||||
ExprAddrOf,
|
||||
Butterflies,
|
||||
|
@ -11,13 +16,22 @@ enum ExprNode {
|
|||
static NODE: ExprNode = ExprNode::Unicorns;
|
||||
|
||||
fn unwrap_addr() -> Option<&'static ExprNode> {
|
||||
match ExprNode::Butterflies {
|
||||
let _ = match ExprNode::Butterflies {
|
||||
ExprNode::ExprAddrOf => Some(&NODE),
|
||||
_ => {
|
||||
let x = 5;
|
||||
None
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Don't lint
|
||||
with_span!(span match ExprNode::Butterflies {
|
||||
ExprNode::ExprAddrOf => Some(&NODE),
|
||||
_ => {
|
||||
let x = 5;
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! unwrap_addr {
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match_else.rs:14:5
|
||||
--> $DIR/single_match_else.rs:19:13
|
||||
|
|
||||
LL | / match ExprNode::Butterflies {
|
||||
LL | let _ = match ExprNode::Butterflies {
|
||||
| _____________^
|
||||
LL | | ExprNode::ExprAddrOf => Some(&NODE),
|
||||
LL | | _ => {
|
||||
LL | | let x = 5;
|
||||
LL | | None
|
||||
LL | | },
|
||||
LL | | }
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= note: `-D clippy::single-match-else` implied by `-D warnings`
|
||||
help: try this
|
||||
|
|
||||
LL ~ if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
|
||||
LL ~ let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
|
||||
LL + let x = 5;
|
||||
LL + None
|
||||
LL + }
|
||||
LL ~ };
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
Loading…
Reference in a new issue