Don't lint various match lints when expanded by a proc-macro
This commit is contained in:
parent
a63308be0a
commit
63f6a79bf8
@ -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 clippy_utils::{meets_msrv, msrvs};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
|
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
|
||||||
use rustc_lexer::{tokenize, TokenKind};
|
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 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 !contains_cfg_arm(cx, expr, ex, arms) {
|
||||||
if source == MatchSource::Normal {
|
if source == MatchSource::Normal {
|
||||||
if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO)
|
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_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LintContext};
|
use rustc_lint::{LateContext, LintContext};
|
||||||
use rustc_span::hygiene;
|
use rustc_span::hygiene;
|
||||||
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
|
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
|
||||||
use std::borrow::Cow;
|
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`.
|
/// 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.
|
/// Also takes an `Option<String>` which can be put inside the braces.
|
||||||
pub fn expr_block<'a, T: LintContext>(
|
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)]
|
#![warn(clippy::single_match_else)]
|
||||||
#![allow(clippy::needless_return)]
|
#![allow(clippy::needless_return)]
|
||||||
#![allow(clippy::no_effect)]
|
#![allow(clippy::no_effect)]
|
||||||
|
|
||||||
|
extern crate proc_macro_with_span;
|
||||||
|
use proc_macro_with_span::with_span;
|
||||||
|
|
||||||
enum ExprNode {
|
enum ExprNode {
|
||||||
ExprAddrOf,
|
ExprAddrOf,
|
||||||
Butterflies,
|
Butterflies,
|
||||||
@ -11,13 +16,22 @@ enum ExprNode {
|
|||||||
static NODE: ExprNode = ExprNode::Unicorns;
|
static NODE: ExprNode = ExprNode::Unicorns;
|
||||||
|
|
||||||
fn unwrap_addr() -> Option<&'static ExprNode> {
|
fn unwrap_addr() -> Option<&'static ExprNode> {
|
||||||
match ExprNode::Butterflies {
|
let _ = match ExprNode::Butterflies {
|
||||||
ExprNode::ExprAddrOf => Some(&NODE),
|
ExprNode::ExprAddrOf => Some(&NODE),
|
||||||
_ => {
|
_ => {
|
||||||
let x = 5;
|
let x = 5;
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Don't lint
|
||||||
|
with_span!(span match ExprNode::Butterflies {
|
||||||
|
ExprNode::ExprAddrOf => Some(&NODE),
|
||||||
|
_ => {
|
||||||
|
let x = 5;
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! unwrap_addr {
|
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`
|
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 | | ExprNode::ExprAddrOf => Some(&NODE),
|
||||||
LL | | _ => {
|
LL | | _ => {
|
||||||
LL | | let x = 5;
|
LL | | let x = 5;
|
||||||
LL | | None
|
LL | | None
|
||||||
LL | | },
|
LL | | },
|
||||||
LL | | }
|
LL | | };
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::single-match-else` implied by `-D warnings`
|
= note: `-D clippy::single-match-else` implied by `-D warnings`
|
||||||
help: try this
|
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 + let x = 5;
|
||||||
LL + None
|
LL + None
|
||||||
LL + }
|
LL ~ };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
Loading…
x
Reference in New Issue
Block a user