Skip to content

Commit

Permalink
Auto merge of #8667 - Jarcho:proc_macro_check, r=flip1995
Browse files Browse the repository at this point in the history
Don't lint various match lints when expanded by a proc-macro

fixes #4952

As always for proc-macro output this is a hack-job of a fix. It would be really nice if more proc-macro authors would set spans correctly.

changelog: Don't lint various lints on proc-macro output.
  • Loading branch information
bors committed Apr 11, 2022
2 parents 131ff87 + 63f6a79 commit 89ee6aa
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 8 deletions.
5 changes: 4 additions & 1 deletion clippy_lints/src/matches/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions clippy_utils/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down
32 changes: 32 additions & 0 deletions tests/ui/auxiliary/proc_macro_with_span.rs
Original file line number Diff line number Diff line change
@@ -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]);
}
}
}
18 changes: 16 additions & 2 deletions tests/ui/single_match_else.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 {
Expand Down
11 changes: 6 additions & 5 deletions tests/ui/single_match_else.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 89ee6aa

Please sign in to comment.