Skip to content

Commit f1391de

Browse files
committed
submodules: update clippy from 20da8f4 to 71be6f6
Changes: ```` rustup rust-lang/rust#57428 Remove `to_string()`s from CompilerLintFunctions Fix comment grammar Fix .map(..).unwrap_or_else(..) bad suggestion add suggestions for print/write with newline lint ````
1 parent 73df096 commit f1391de

10 files changed

+254
-101
lines changed

clippy_lints/src/methods/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use syntax::symbol::LocalInternedString;
2020

2121
use crate::utils::paths;
2222
use crate::utils::sugg;
23+
use crate::utils::usage::mutated_variables;
2324
use crate::utils::{
2425
get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
2526
is_ctor_function, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path,
@@ -1880,7 +1881,20 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
18801881
// lint if the caller of `map()` is an `Option`
18811882
let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
18821883
let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
1884+
18831885
if is_option || is_result {
1886+
// Don't make a suggestion that may fail to compile due to mutably borrowing
1887+
// the same variable twice.
1888+
let map_mutated_vars = mutated_variables(&map_args[0], cx);
1889+
let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
1890+
if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
1891+
if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
1892+
return;
1893+
}
1894+
} else {
1895+
return;
1896+
}
1897+
18841898
// lint message
18851899
let msg = if is_option {
18861900
"called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \

clippy_lints/src/utils/hir_utils.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
237237
&& over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
238238
} else if left.parenthesized && right.parenthesized {
239239
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
240-
&& both(&Some(&left.bindings[0].ty), &Some(&right.bindings[0].ty), |l, r| {
240+
&& both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
241241
self.eq_ty(l, r)
242242
})
243243
} else {
@@ -299,7 +299,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
299299
}
300300

301301
fn eq_type_binding(&mut self, left: &TypeBinding, right: &TypeBinding) -> bool {
302-
left.ident.name == right.ident.name && self.eq_ty(&left.ty, &right.ty)
302+
left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
303303
}
304304
}
305305

clippy_lints/src/utils/internal_lints.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,17 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for LintCollector<'a, 'tcx> {
213213

214214
#[derive(Clone, Default)]
215215
pub struct CompilerLintFunctions {
216-
map: FxHashMap<String, String>,
216+
map: FxHashMap<&'static str, &'static str>,
217217
}
218218

219219
impl CompilerLintFunctions {
220220
pub fn new() -> Self {
221221
let mut map = FxHashMap::default();
222-
map.insert("span_lint".to_string(), "utils::span_lint".to_string());
223-
map.insert("struct_span_lint".to_string(), "utils::span_lint".to_string());
224-
map.insert("lint".to_string(), "utils::span_lint".to_string());
225-
map.insert("span_lint_note".to_string(), "utils::span_note_and_lint".to_string());
226-
map.insert("span_lint_help".to_string(), "utils::span_help_and_lint".to_string());
222+
map.insert("span_lint", "utils::span_lint");
223+
map.insert("struct_span_lint", "utils::span_lint");
224+
map.insert("lint", "utils::span_lint");
225+
map.insert("span_lint_note", "utils::span_note_and_lint");
226+
map.insert("span_lint_help", "utils::span_help_and_lint");
227227
Self { map }
228228
}
229229
}
@@ -234,8 +234,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
234234
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
235235
if_chain! {
236236
if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
237-
let fn_name = path.ident.as_str().to_string();
238-
if let Some(sugg) = self.map.get(&fn_name);
237+
let fn_name = path.ident;
238+
if let Some(sugg) = self.map.get(&*fn_name.as_str());
239239
let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
240240
if match_type(cx, ty, &paths::EARLY_CONTEXT)
241241
|| match_type(cx, ty, &paths::LATE_CONTEXT);

clippy_lints/src/write.rs

+110-54
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg};
1+
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
22
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
33
use rustc::{declare_lint_pass, declare_tool_lint};
44
use rustc_errors::Applicability;
55
use std::borrow::Cow;
66
use syntax::ast::*;
77
use syntax::parse::{parser, token};
8-
use syntax::tokenstream::{TokenStream, TokenTree};
9-
use syntax_pos::symbol::Symbol;
8+
use syntax::tokenstream::TokenStream;
9+
use syntax_pos::{symbol::Symbol, BytePos, Span};
1010

1111
declare_clippy_lint! {
1212
/// **What it does:** This lint warns when you use `println!("")` to
@@ -184,8 +184,8 @@ impl EarlyLintPass for Write {
184184
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
185185
if mac.node.path == sym!(println) {
186186
span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
187-
if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
188-
if fmtstr == "" {
187+
if let (Some(fmt_str), _) = check_tts(cx, &mac.node.tts, false) {
188+
if fmt_str.contents.is_empty() {
189189
span_lint_and_sugg(
190190
cx,
191191
PRINTLN_EMPTY_STRING,
@@ -199,35 +199,52 @@ impl EarlyLintPass for Write {
199199
}
200200
} else if mac.node.path == sym!(print) {
201201
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
202-
if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, false) {
203-
if check_newlines(&fmtstr, is_raw) {
204-
span_lint(
202+
if let (Some(fmt_str), _) = check_tts(cx, &mac.node.tts, false) {
203+
if check_newlines(&fmt_str) {
204+
span_lint_and_then(
205205
cx,
206206
PRINT_WITH_NEWLINE,
207207
mac.span,
208-
"using `print!()` with a format string that ends in a \
209-
single newline, consider using `println!()` instead",
208+
"using `print!()` with a format string that ends in a single newline",
209+
|err| {
210+
err.multipart_suggestion(
211+
"use `println!` instead",
212+
vec![
213+
(mac.node.path.span, String::from("println")),
214+
(fmt_str.newline_span(), String::new()),
215+
],
216+
Applicability::MachineApplicable,
217+
);
218+
},
210219
);
211220
}
212221
}
213222
} else if mac.node.path == sym!(write) {
214-
if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, true) {
215-
if check_newlines(&fmtstr, is_raw) {
216-
span_lint(
223+
if let (Some(fmt_str), _) = check_tts(cx, &mac.node.tts, true) {
224+
if check_newlines(&fmt_str) {
225+
span_lint_and_then(
217226
cx,
218227
WRITE_WITH_NEWLINE,
219228
mac.span,
220-
"using `write!()` with a format string that ends in a \
221-
single newline, consider using `writeln!()` instead",
222-
);
229+
"using `write!()` with a format string that ends in a single newline",
230+
|err| {
231+
err.multipart_suggestion(
232+
"use `writeln!()` instead",
233+
vec![
234+
(mac.node.path.span, String::from("writeln")),
235+
(fmt_str.newline_span(), String::new()),
236+
],
237+
Applicability::MachineApplicable,
238+
);
239+
},
240+
)
223241
}
224242
}
225243
} else if mac.node.path == sym!(writeln) {
226-
let check_tts = check_tts(cx, &mac.node.tts, true);
227-
if let Some(fmtstr) = check_tts.0 {
228-
if fmtstr == "" {
244+
if let (Some(fmt_str), expr) = check_tts(cx, &mac.node.tts, true) {
245+
if fmt_str.contents.is_empty() {
229246
let mut applicability = Applicability::MachineApplicable;
230-
let suggestion = check_tts.1.map_or_else(
247+
let suggestion = expr.map_or_else(
231248
move || {
232249
applicability = Applicability::HasPlaceholders;
233250
Cow::Borrowed("v")
@@ -250,10 +267,44 @@ impl EarlyLintPass for Write {
250267
}
251268
}
252269

270+
/// The arguments of a `print[ln]!` or `write[ln]!` invocation.
271+
struct FmtStr {
272+
/// The contents of the format string (inside the quotes).
273+
contents: String,
274+
style: StrStyle,
275+
/// The span of the format string, including quotes, the raw marker, and any raw hashes.
276+
span: Span,
277+
}
278+
279+
impl FmtStr {
280+
/// Given a format string that ends in a newline and its span, calculates the span of the
281+
/// newline.
282+
fn newline_span(&self) -> Span {
283+
let sp = self.span;
284+
285+
let newline_sp_hi = sp.hi()
286+
- match self.style {
287+
StrStyle::Cooked => BytePos(1),
288+
StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
289+
};
290+
291+
let newline_sp_len = if self.contents.ends_with('\n') {
292+
BytePos(1)
293+
} else if self.contents.ends_with(r"\n") {
294+
BytePos(2)
295+
} else {
296+
panic!("expected format string to contain a newline");
297+
};
298+
299+
sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi)
300+
}
301+
}
302+
253303
/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
254-
/// options and a bool. The first part of the tuple is `format_str` of the macros. The second part
255-
/// of the tuple is in the `write[ln]!` case the expression the `format_str` should be written to.
256-
/// The final part is a boolean flag indicating if the string is a raw string.
304+
/// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
305+
/// the contents of the string, whether it's a raw string, and the span of the literal in the
306+
/// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
307+
/// `format_str` should be written to.
257308
///
258309
/// Example:
259310
///
@@ -266,49 +317,36 @@ impl EarlyLintPass for Write {
266317
/// ```
267318
/// will return
268319
/// ```rust,ignore
269-
/// (Some("string to write: {}"), Some(buf), false)
320+
/// (Some("string to write: {}"), Some(buf))
270321
/// ```
271-
fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (Option<String>, Option<Expr>, bool) {
322+
fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (Option<FmtStr>, Option<Expr>) {
272323
use fmt_macros::*;
273324
let tts = tts.clone();
274-
let mut is_raw = false;
275-
if let TokenStream(Some(tokens)) = &tts {
276-
for token in tokens.iter() {
277-
if let (TokenTree::Token(_, token::Token::Literal(lit)), _) = token {
278-
match lit.kind {
279-
token::Str => break,
280-
token::StrRaw(_) => {
281-
is_raw = true;
282-
break;
283-
},
284-
_ => {},
285-
}
286-
}
287-
}
288-
}
325+
289326
let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false, None);
290327
let mut expr: Option<Expr> = None;
291328
if is_write {
292329
expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
293330
Ok(p) => Some(p.into_inner()),
294-
Err(_) => return (None, None, is_raw),
331+
Err(_) => return (None, None),
295332
};
296333
// might be `writeln!(foo)`
297334
if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
298-
return (None, expr, is_raw);
335+
return (None, expr);
299336
}
300337
}
301338

302-
let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
303-
Ok(token) => token.0.to_string(),
304-
Err(_) => return (None, expr, is_raw),
339+
let (fmtstr, fmtstyle) = match parser.parse_str().map_err(|mut err| err.cancel()) {
340+
Ok((fmtstr, fmtstyle)) => (fmtstr.to_string(), fmtstyle),
341+
Err(_) => return (None, expr),
305342
};
343+
let fmtspan = parser.prev_span;
306344
let tmp = fmtstr.clone();
307345
let mut args = vec![];
308346
let mut fmt_parser = Parser::new(&tmp, None, Vec::new(), false);
309347
while let Some(piece) = fmt_parser.next() {
310348
if !fmt_parser.errors.is_empty() {
311-
return (None, expr, is_raw);
349+
return (None, expr);
312350
}
313351
if let Piece::NextArgument(arg) = piece {
314352
if arg.format.ty == "?" {
@@ -330,11 +368,26 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (O
330368
ty: "",
331369
};
332370
if !parser.eat(&token::Comma) {
333-
return (Some(fmtstr), expr, is_raw);
371+
return (
372+
Some(FmtStr {
373+
contents: fmtstr,
374+
style: fmtstyle,
375+
span: fmtspan,
376+
}),
377+
expr,
378+
);
334379
}
335-
let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
336-
Ok(expr) => expr,
337-
Err(_) => return (Some(fmtstr), None, is_raw),
380+
let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) {
381+
expr
382+
} else {
383+
return (
384+
Some(FmtStr {
385+
contents: fmtstr,
386+
style: fmtstyle,
387+
span: fmtspan,
388+
}),
389+
None,
390+
);
338391
};
339392
match &token_expr.node {
340393
ExprKind::Lit(_) => {
@@ -383,12 +436,15 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (O
383436
}
384437
}
385438

386-
// Checks if `s` constains a single newline that terminates it
387-
// Literal and escaped newlines are both checked (only literal for raw strings)
388-
fn check_newlines(s: &str, is_raw: bool) -> bool {
439+
/// Checks if the format string constains a single newline that terminates it.
440+
///
441+
/// Literal and escaped newlines are both checked (only literal for raw strings).
442+
fn check_newlines(fmt_str: &FmtStr) -> bool {
443+
let s = &fmt_str.contents;
444+
389445
if s.ends_with('\n') {
390446
return true;
391-
} else if is_raw {
447+
} else if let StrStyle::Raw(_) = fmt_str.style {
392448
return false;
393449
}
394450

tests/ui/methods.rs

+15
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,21 @@ fn option_methods() {
203203
// Macro case.
204204
// Should not lint.
205205
let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
206+
207+
// Issue #4144
208+
{
209+
let mut frequencies = HashMap::new();
210+
let word = "foo";
211+
212+
frequencies
213+
.get_mut(word)
214+
.map(|count| {
215+
*count += 1;
216+
})
217+
.unwrap_or_else(|| {
218+
frequencies.insert(word.to_owned(), 1);
219+
});
220+
}
206221
}
207222

208223
/// Checks implementation of `FILTER_NEXT` lint.

0 commit comments

Comments
 (0)