Don't lint various match lints when expanded by a proc-macro

This commit is contained in:
Jason Newcomb 2022-04-08 16:51:40 -04:00
parent a63308be0a
commit 63f6a79bf8
5 changed files with 77 additions and 8 deletions

View file

@ -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)

View file

@ -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>(

View 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]);
}
}
}

View file

@ -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 {

View file

@ -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