Migrate write.rs to a late pass

This commit is contained in:
Alex Macleod 2022-08-30 12:20:49 +00:00
parent 32fa80dda5
commit 6fc6d87fd0
39 changed files with 597 additions and 1351 deletions

View file

@ -71,12 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
let value = arg.param.value;
if_chain! {
if format_args.format_string.parts == [kw::Empty];
if arg.format.is_default();
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
ty::Str => true,
_ => false,
};
if !arg.format.has_string_formatting();
then {
let is_new_string = match value.kind {
ExprKind::Binary(..) => true,

View file

@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
then {
for arg in &format_args.args {
if arg.format.has_string_formatting() {
if !arg.format.is_default() {
continue;
}
if is_aliased(&format_args, arg.param.value.hir_id) {

View file

@ -352,7 +352,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(useless_conversion::USELESS_CONVERSION),
LintId::of(vec::USELESS_VEC),
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
LintId::of(write::PRINTLN_EMPTY_STRING),
LintId::of(write::PRINT_LITERAL),
LintId::of(write::PRINT_WITH_NEWLINE),

View file

@ -595,7 +595,6 @@ store.register_lints(&[
vec_init_then_push::VEC_INIT_THEN_PUSH,
wildcard_imports::ENUM_GLOB_USE,
wildcard_imports::WILDCARD_IMPORTS,
write::POSITIONAL_NAMED_FORMAT_PARAMETERS,
write::PRINTLN_EMPTY_STRING,
write::PRINT_LITERAL,
write::PRINT_STDERR,

View file

@ -36,5 +36,4 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
LintId::of(unused_peekable::UNUSED_PEEKABLE),
LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
])

View file

@ -40,7 +40,6 @@ extern crate rustc_lint;
extern crate rustc_middle;
extern crate rustc_mir_dataflow;
extern crate rustc_parse;
extern crate rustc_parse_format;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
@ -425,7 +424,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
})
});
store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
}
@ -879,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
ignore_publish: cargo_ignore_publish,
})
});
store.register_late_pass(|| Box::new(write::Write::default()));
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));

View file

@ -36,6 +36,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::invalid_ref", "invalid_value"),
("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
("clippy::panic_params", "non_fmt_panics"),
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
("clippy::unknown_clippy_lints", "unknown_lints"),
("clippy::unused_label", "unused_labels"),

View file

@ -476,7 +476,7 @@ pub fn format_error(error: Box<dyn Error>) -> String {
let mut msg = String::from(prefix);
for row in 0..rows {
write!(msg, "\n").unwrap();
writeln!(msg).unwrap();
for (column, column_width) in column_widths.iter().copied().enumerate() {
let index = column * rows + row;
let field = fields.get(index).copied().unwrap_or_default();

View file

@ -1,20 +1,12 @@
use std::borrow::Cow;
use std::iter;
use std::ops::{Deref, Range};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_lexer::unescape::{self, EscapeError};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_parse::parser;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall};
use clippy_utils::source::snippet_opt;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@ -74,13 +66,7 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
/// * Only catches `print!` and `println!` calls.
/// * The lint level is unaffected by crate attributes. The level can still
/// be set for functions, modules and other items. To change the level for
/// the entire crate, please use command line flags. More information and a
/// configuration example can be found in [clippy#6610].
///
/// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
/// Only catches `print!` and `println!` calls.
///
/// ### Example
/// ```rust
@ -102,13 +88,7 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
/// * Only catches `eprint!` and `eprintln!` calls.
/// * The lint level is unaffected by crate attributes. The level can still
/// be set for functions, modules and other items. To change the level for
/// the entire crate, please use command line flags. More information and a
/// configuration example can be found in [clippy#6610].
///
/// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
/// Only catches `eprint!` and `eprintln!` calls.
///
/// ### Example
/// ```rust
@ -149,10 +129,6 @@ declare_clippy_lint! {
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// ### Known problems
/// Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// ### Example
/// ```rust
/// println!("{}", "foo");
@ -234,10 +210,6 @@ declare_clippy_lint! {
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// ### Known problems
/// Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// ### Example
/// ```rust
/// # use std::fmt::Write;
@ -257,28 +229,6 @@ declare_clippy_lint! {
"writing a literal with a format string"
}
declare_clippy_lint! {
/// ### What it does
/// This lint warns when a named parameter in a format string is used as a positional one.
///
/// ### Why is this bad?
/// It may be confused for an assignment and obfuscates which parameter is being used.
///
/// ### Example
/// ```rust
/// println!("{}", x = 10);
/// ```
///
/// Use instead:
/// ```rust
/// println!("{x}", x = 10);
/// ```
#[clippy::version = "1.63.0"]
pub POSITIONAL_NAMED_FORMAT_PARAMETERS,
suspicious,
"named parameter in a format string is used positionally"
}
#[derive(Default)]
pub struct Write {
in_debug_impl: bool,
@ -294,537 +244,308 @@ impl_lint_pass!(Write => [
WRITE_WITH_NEWLINE,
WRITELN_EMPTY_STRING,
WRITE_LITERAL,
POSITIONAL_NAMED_FORMAT_PARAMETERS,
]);
impl EarlyLintPass for Write {
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
if let ItemKind::Impl(box Impl {
of_trait: Some(trait_ref),
..
}) = &item.kind
{
let trait_name = trait_ref
.path
.segments
.iter()
.last()
.expect("path has at least one segment")
.ident
.name;
if trait_name == sym::Debug {
impl<'tcx> LateLintPass<'tcx> for Write {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if is_debug_impl(cx, item) {
self.in_debug_impl = true;
}
}
}
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if is_debug_impl(cx, item) {
self.in_debug_impl = false;
}
}
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
fn is_build_script(cx: &EarlyContext<'_>) -> bool {
// Cargo sets the crate name for build scripts to `build_script_build`
cx.sess()
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return };
let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return };
let is_build_script = cx
.sess()
.opts
.crate_name
.as_ref()
.map_or(false, |crate_name| crate_name == "build_script_build")
}
.map_or(false, |crate_name| crate_name == "build_script_build");
if mac.path == sym!(print) {
if !is_build_script(cx) {
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
}
self.lint_print_with_newline(cx, mac);
} else if mac.path == sym!(println) {
if !is_build_script(cx) {
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
}
self.lint_println_empty_string(cx, mac);
} else if mac.path == sym!(eprint) {
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`");
self.lint_print_with_newline(cx, mac);
} else if mac.path == sym!(eprintln) {
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
self.lint_println_empty_string(cx, mac);
} else if mac.path == sym!(write) {
if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) {
if check_newlines(&fmt_str) {
let (nl_span, only_nl) = newline_span(&fmt_str);
let nl_span = match (dest, only_nl) {
// Special case of `write!(buf, "\n")`: Mark everything from the end of
// `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
(Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()),
_ => nl_span,
};
span_lint_and_then(
cx,
WRITE_WITH_NEWLINE,
mac.span(),
"using `write!()` with a format string that ends in a single newline",
|err| {
err.multipart_suggestion(
"use `writeln!()` instead",
vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())],
Applicability::MachineApplicable,
);
},
);
}
}
} else if mac.path == sym!(writeln) {
if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
if fmt_str.symbol == kw::Empty {
let mut applicability = Applicability::MachineApplicable;
let suggestion = if let Some(e) = expr {
snippet_with_applicability(cx, e.span, "v", &mut applicability)
} else {
applicability = Applicability::HasPlaceholders;
Cow::Borrowed("v")
};
span_lint_and_sugg(
cx,
WRITELN_EMPTY_STRING,
mac.span(),
format!("using `writeln!({}, \"\")`", suggestion).as_str(),
"replace it with",
format!("writeln!({})", suggestion),
applicability,
);
}
}
}
}
}
/// Given a format string that ends in a newline and its span, calculates the span of the
/// newline, or the format string itself if the format string consists solely of a newline.
/// Return this and a boolean indicating whether it only consisted of a newline.
fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
let sp = fmtstr.span;
let contents = fmtstr.symbol.as_str();
if contents == r"\n" {
return (sp, true);
}
let newline_sp_hi = sp.hi()
- match fmtstr.style {
StrStyle::Cooked => BytePos(1),
StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
};
let newline_sp_len = if contents.ends_with('\n') {
BytePos(1)
} else if contents.ends_with(r"\n") {
BytePos(2)
} else {
panic!("expected format string to contain a newline");
};
(sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false)
}
/// Stores a list of replacement spans for each argument, but only if all the replacements used an
/// empty format string.
#[derive(Default)]
struct SimpleFormatArgs {
unnamed: Vec<Vec<Span>>,
complex_unnamed: Vec<Vec<Span>>,
named: Vec<(Symbol, Vec<Span>)>,
}
impl SimpleFormatArgs {
fn get_unnamed(&self) -> impl Iterator<Item = &[Span]> {
self.unnamed.iter().map(|x| match x.as_slice() {
// Ignore the dummy span added from out of order format arguments.
[DUMMY_SP] => &[],
x => x,
})
}
fn get_complex_unnamed(&self) -> impl Iterator<Item = &[Span]> {
self.complex_unnamed.iter().map(Vec::as_slice)
}
fn get_named(&self, n: &Path) -> &[Span] {
self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice())
}
fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
use rustc_parse_format::{
AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec,
};
const SIMPLE: FormatSpec<'_> = FormatSpec {
fill: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
precision_span: None,
width: CountImplied,
width_span: None,
ty: "",
ty_span: None,
};
match arg.position {
ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
if self.unnamed.len() <= n {
// Use a dummy span to mark all unseen arguments.
self.unnamed.resize_with(n, || vec![DUMMY_SP]);
if arg.format == SIMPLE {
self.unnamed.push(vec![span]);
} else {
self.unnamed.push(Vec::new());
}
} else {
let args = &mut self.unnamed[n];
match (args.as_mut_slice(), arg.format == SIMPLE) {
// A non-empty format string has been seen already.
([], _) => (),
// Replace the dummy span, if it exists.
([dummy @ DUMMY_SP], true) => *dummy = span,
([_, ..], true) => args.push(span),
([_, ..], false) => *args = Vec::new(),
}
match diag_name {
sym::print_macro | sym::println_macro => {
if !is_build_script {
span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`"));
}
},
ArgumentNamed(n) => {
let n = Symbol::intern(n);
if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
match x.1.as_slice() {
// A non-empty format string has been seen already.
[] => (),
[_, ..] if arg.format == SIMPLE => x.1.push(span),
[_, ..] => x.1 = Vec::new(),
}
} else if arg.format == SIMPLE {
self.named.push((n, vec![span]));
} else {
self.named.push((n, Vec::new()));
}
sym::eprint_macro | sym::eprintln_macro => {
span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`"));
},
};
sym::write_macro | sym::writeln_macro => {},
_ => return,
}
fn push_to_complex(&mut self, span: Span, position: usize) {
if self.complex_unnamed.len() <= position {
self.complex_unnamed.resize_with(position, Vec::new);
self.complex_unnamed.push(vec![span]);
} else {
let args: &mut Vec<Span> = &mut self.complex_unnamed[position];
args.push(span);
}
let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return };
// ignore `writeln!(w)` and `write!(v, some_macro!())`
if format_args.format_string.span.from_expansion() {
return;
}
fn push_complex(
&mut self,
cx: &EarlyContext<'_>,
arg: rustc_parse_format::Argument<'_>,
str_lit_span: Span,
fmt_span: Span,
) {
use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar};
let snippet = snippet_opt(cx, fmt_span);
let end = snippet
.as_ref()
.and_then(|s| s.find(':'))
.or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize));
if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) {
let span = fmt_span.from_inner(InnerSpan::new(1, end));
self.push_to_complex(span, n);
};
if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
// We need to do this hack as precision spans should be converted from .* to .foo$
let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() {
0
} else {
1
};
let span = str_lit_span.from_inner(InnerSpan {
start: span.start + 1,
end: span.end - hack,
});
self.push_to_complex(span, n);
};
if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) {
let span = str_lit_span.from_inner(InnerSpan {
start: span.start,
end: span.end - 1,
});
self.push_to_complex(span, n);
};
}
match diag_name {
sym::print_macro | sym::eprint_macro | sym::write_macro => {
check_newline(cx, &format_args, &macro_call, name);
},
sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
check_empty_string(cx, &format_args, &macro_call, name);
},
_ => {},
}
impl Write {
/// Parses a format string into a collection of spans for each argument. This only keeps track
/// of empty format arguments. Will also lint usages of debug format strings outside of debug
/// impls.
fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<SimpleFormatArgs> {
use rustc_parse_format::{ParseMode, Parser, Piece};
check_literal(cx, &format_args, name);
let str_sym = str_lit.symbol_unescaped.as_str();
let style = match str_lit.style {
StrStyle::Cooked => None,
StrStyle::Raw(n) => Some(n as usize),
};
let mut parser = Parser::new(str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format);
let mut args = SimpleFormatArgs::default();
while let Some(arg) = parser.next() {
let arg = match arg {
Piece::String(_) => continue,
Piece::NextArgument(arg) => arg,
};
let span = parser
.arg_places
.last()
.map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
if !self.in_debug_impl && arg.format.ty == "?" {
// FIXME: modify rustc's fmt string parser to give us the current span
span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
if !self.in_debug_impl {
for arg in &format_args.args {
if arg.format.r#trait == sym::Debug {
span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting");
}
args.push(arg, span);
args.push_complex(cx, arg, str_lit.span, span);
}
parser.errors.is_empty().then_some(args)
}
/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
/// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
/// the contents of the string, whether it's a raw string, and the span of the literal in the
/// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
/// `format_str` should be written to.
///
/// Example:
///
/// Calling this function on
/// ```rust
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// # let something = "something";
/// writeln!(buf, "string to write: {}", something);
/// ```
/// will return
/// ```rust,ignore
/// (Some("string to write: {}"), Some(buf))
/// ```
fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
let expr = if is_write {
match parser
.parse_expr()
.map(rustc_ast::ptr::P::into_inner)
.map_err(DiagnosticBuilder::cancel)
}
}
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
{
// write!(e, ...)
Ok(p) if parser.eat(&token::Comma) => Some(p),
// write!(e) or error
e => return (None, e.ok()),
}
cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
} else {
None
};
let fmtstr = match parser.parse_str_lit() {
Ok(fmtstr) => fmtstr,
Err(_) => return (None, expr),
};
let args = match self.parse_fmt_string(cx, &fmtstr) {
Some(args) => args,
None => return (Some(fmtstr), expr),
};
let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
let mut unnamed_args = args.get_unnamed();
let mut complex_unnamed_args = args.get_complex_unnamed();
loop {
if !parser.eat(&token::Comma) {
return (Some(fmtstr), expr);
false
}
}
let comma_span = parser.prev_token.span;
let token_expr = if let Ok(expr) = parser.parse_expr().map_err(DiagnosticBuilder::cancel) {
expr
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
let format_string_parts = &format_args.format_string.parts;
let mut format_string_span = format_args.format_string.span;
let Some(last) = format_string_parts.last() else { return };
let count_vertical_whitespace = || {
format_string_parts
.iter()
.flat_map(|part| part.as_str().chars())
.filter(|ch| matches!(ch, '\r' | '\n'))
.count()
};
if last.as_str().ends_with('\n')
// ignore format strings with other internal vertical whitespace
&& count_vertical_whitespace() == 1
// ignore trailing arguments: `print!("Issue\n{}", 1265);`
&& format_string_parts.len() > format_args.args.len()
{
let lint = if name == "write" {
format_string_span = expand_past_previous_comma(cx, format_string_span);
WRITE_WITH_NEWLINE
} else {
return (Some(fmtstr), None);
};
let complex_unnamed_arg = complex_unnamed_args.next();
let (fmt_spans, lit) = match &token_expr.kind {
ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit),
ExprKind::Assign(lhs, rhs, _) => {
if let Some(span) = complex_unnamed_arg {
for x in span {
Self::report_positional_named_param(cx, *x, lhs, rhs);
}
}
match (&lhs.kind, &rhs.kind) {
(ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
_ => continue,
}
},
_ => {
unnamed_args.next();
continue;
},
PRINT_WITH_NEWLINE
};
let replacement: String = match lit.token_lit.kind {
LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::StrRaw(_)
| LitKind::Str
| LitKind::ByteStrRaw(_)
| LitKind::ByteStr
| LitKind::Integer
| LitKind::Float
| LitKind::Err => continue,
LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() {
"\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"",
"\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue,
"\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\",
"\\'" => "'",
"{" => "{{",
"}" => "}}",
x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue,
x => x,
}
.into(),
LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(),
};
if !fmt_spans.is_empty() {
span_lint_and_then(
cx,
lint,
token_expr.span,
"literal with an empty format string",
macro_call.span,
&format!("using `{name}!()` with a format string that ends in a single newline"),
|diag| {
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return };
if format_string_parts.len() == 1 && last.as_str() == "\n" {
// print!("\n"), write!(f, "\n")
diag.multipart_suggestion(
"try this",
iter::once((comma_span.to(token_expr.span), String::new()))
.chain(fmt_spans.iter().copied().zip(iter::repeat(replacement)))
.collect(),
&format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
Applicability::MachineApplicable,
);
} else if format_snippet.ends_with("\\n\"") {
// print!("...\n"), write!(f, "...\n")
let hi = format_string_span.hi();
let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
diag.multipart_suggestion(
&format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
Applicability::MachineApplicable,
);
}
},
);
}
}
}
fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P<Expr>, _rhs: &P<Expr>) {
if let ExprKind::Path(_, _p) = &lhs.kind {
let mut applicability = Applicability::MachineApplicable;
let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability);
// We need to do this hack as precision spans should be converted from .* to .foo$
let hack = snippet(cx, span, "").contains('*');
fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
if let [part] = &format_args.format_string.parts[..]
&& let mut span = format_args.format_string.span
&& part.as_str() == "\n"
{
let lint = if name == "writeln" {
span = expand_past_previous_comma(cx, span);
span_lint_and_sugg(
cx,
POSITIONAL_NAMED_FORMAT_PARAMETERS,
span,
&format!("named parameter {} is used as a positional parameter", name),
"replace it with",
if hack {
format!("{}$", name)
WRITELN_EMPTY_STRING
} else {
format!("{}", name)
},
applicability,
);
PRINTLN_EMPTY_STRING
};
}
fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
if fmt_str.symbol == kw::Empty {
let name = mac.path.segments[0].ident.name;
span_lint_and_sugg(
cx,
PRINTLN_EMPTY_STRING,
mac.span(),
&format!("using `{}!(\"\")`", name),
"replace it with",
format!("{}!()", name),
Applicability::MachineApplicable,
);
}
}
}
fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
if check_newlines(&fmt_str) {
let name = mac.path.segments[0].ident.name;
let suggested = format!("{}ln", name);
span_lint_and_then(
cx,
PRINT_WITH_NEWLINE,
mac.span(),
&format!("using `{}!()` with a format string that ends in a single newline", name),
|err| {
err.multipart_suggestion(
&format!("use `{}!` instead", suggested),
vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())],
lint,
macro_call.span,
&format!("empty string literal in `{name}!`"),
|diag| {
diag.span_suggestion(
span,
"remove the empty string",
String::new(),
Applicability::MachineApplicable,
);
},
);
}
}
}
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) {
let mut counts = HirIdMap::<usize>::default();
for param in format_args.params() {
*counts.entry(param.value.hir_id).or_default() += 1;
}
/// Checks if the format string contains a single newline that terminates it.
///
/// Literal and escaped newlines are both checked (only literal for raw strings).
fn check_newlines(fmtstr: &StrLit) -> bool {
let mut has_internal_newline = false;
let mut last_was_cr = false;
let mut should_lint = false;
for arg in &format_args.args {
let value = arg.param.value;
let contents = fmtstr.symbol.as_str();
let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
let c = match c {
Ok(c) => c,
Err(e) if !e.is_fatal() => return,
Err(e) => panic!("{:?}", e),
if counts[&value.hir_id] == 1
&& arg.format.is_default()
&& let ExprKind::Lit(lit) = &value.kind
&& !value.span.from_expansion()
&& let Some(value_string) = snippet_opt(cx, value.span)
{
let (replacement, replace_raw) = match lit.node {
LitKind::Str(..) => extract_str_literal(&value_string),
LitKind::Char(ch) => (
match ch {
'"' => "\\\"",
'\'' => "'",
_ => &value_string[1..value_string.len() - 1],
}
.to_string(),
false,
),
LitKind::Bool(b) => (b.to_string(), false),
_ => continue,
};
if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
should_lint = true;
let lint = if name.starts_with("write") {
WRITE_LITERAL
} else {
last_was_cr = c == '\r';
if c == '\n' {
has_internal_newline = true;
}
}
PRINT_LITERAL
};
match fmtstr.style {
StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
let format_string_is_raw = format_args.format_string.style.is_some();
let replacement = match (format_string_is_raw, replace_raw) {
(false, false) => Some(replacement),
(false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
(true, false) => match conservative_unescape(&replacement) {
Ok(unescaped) => Some(unescaped),
Err(UnescapeErr::Lint) => None,
Err(UnescapeErr::Ignore) => continue,
},
(true, true) => {
if replacement.contains(['#', '"']) {
None
} else {
Some(replacement)
}
},
};
span_lint_and_then(
cx,
lint,
value.span,
"literal with an empty format string",
|diag| {
if let Some(replacement) = replacement {
// `format!("{}", "a")`, `format!("{named}", named = "b")
// ~~~~~ ~~~~~~~~~~~~~
let value_span = expand_past_previous_comma(cx, value.span);
let replacement = replacement.replace('{', "{{").replace('}', "}}");
diag.multipart_suggestion(
"try this",
vec![(arg.span, replacement), (value_span, String::new())],
Applicability::MachineApplicable,
);
}
},
);
}
}
}
should_lint
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
///
/// `r#"a"#` -> (`a`, true)
///
/// `"b"` -> (`b`, false)
fn extract_str_literal(literal: &str) -> (String, bool) {
let (literal, raw) = match literal.strip_prefix('r') {
Some(stripped) => (stripped.trim_matches('#'), true),
None => (literal, false),
};
(literal[1..literal.len() - 1].to_string(), raw)
}
enum UnescapeErr {
/// Should still be linted, can be manually resolved by author, e.g.
///
/// ```ignore
/// print!(r"{}", '"');
/// ```
Lint,
/// Should not be linted, e.g.
///
/// ```ignore
/// print!(r"{}", '\r');
/// ```
Ignore,
}
/// Unescape a normal string into a raw string
fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
let mut unescaped = String::with_capacity(literal.len());
let mut chars = literal.chars();
let mut err = false;
while let Some(ch) = chars.next() {
match ch {
'#' => err = true,
'\\' => match chars.next() {
Some('\\') => unescaped.push('\\'),
Some('"') => err = true,
_ => return Err(UnescapeErr::Ignore),
},
_ => unescaped.push(ch),
}
}
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
}
// Expand from `writeln!(o, "")` to `writeln!(o, "")`
// ^^ ^^^^
fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
extended.with_lo(extended.lo() - BytePos(1))
}

View file

@ -711,9 +711,14 @@ impl<'tcx> FormatSpec<'tcx> {
})
}
/// Returns true if this format spec would change the contents of a string when formatted
pub fn has_string_formatting(&self) -> bool {
self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied()
/// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`,
/// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}`
pub fn is_default(&self) -> bool {
self.r#trait == sym::Display
&& self.width.is_implied()
&& self.precision.is_implied()
&& self.align == Alignment::AlignUnknown
&& self.flags == 0
}
}

View file

@ -391,7 +391,6 @@ docs! {
"partialeq_to_none",
"path_buf_push_overwrite",
"pattern_type_mismatch",
"positional_named_format_parameters",
"possible_missing_comma",
"precedence",
"print_in_format_impl",

View file

@ -1,15 +0,0 @@
### What it does
This lint warns when a named parameter in a format string is used as a positional one.
### Why is this bad?
It may be confused for an assignment and obfuscates which parameter is being used.
### Example
```
println!("{}", x = 10);
```
Use instead:
```
println!("{x}", x = 10);
```

View file

@ -6,10 +6,6 @@ Using literals as `println!` args is inefficient
(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
(i.e., just put the literal in the format string)
### Known problems
Will also warn with macro calls as arguments that expand to literals
-- e.g., `println!("{}", env!("FOO"))`.
### Example
```
println!("{}", "foo");

View file

@ -7,13 +7,7 @@ People often print on *stderr* while debugging an
application and might forget to remove those prints afterward.
### Known problems
* Only catches `eprint!` and `eprintln!` calls.
* The lint level is unaffected by crate attributes. The level can still
be set for functions, modules and other items. To change the level for
the entire crate, please use command line flags. More information and a
configuration example can be found in [clippy#6610].
[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
Only catches `eprint!` and `eprintln!` calls.
### Example
```

View file

@ -7,13 +7,7 @@ People often print on *stdout* while debugging an
application and might forget to remove those prints afterward.
### Known problems
* Only catches `print!` and `println!` calls.
* The lint level is unaffected by crate attributes. The level can still
be set for functions, modules and other items. To change the level for
the entire crate, please use command line flags. More information and a
configuration example can be found in [clippy#6610].
[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
Only catches `print!` and `println!` calls.
### Example
```

View file

@ -6,10 +6,6 @@ Using literals as `writeln!` args is inefficient
(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
(i.e., just put the literal in the format string)
### Known problems
Will also warn with macro calls as arguments that expand to literals
-- e.g., `writeln!(buf, "{}", env!("FOO"))`.
### Example
```
writeln!(buf, "{}", "foo");

View file

@ -45,5 +45,13 @@ fn main() {
eprint!("\r\n");
eprint!("foo\r\n");
eprint!("\\r\n"); //~ ERROR
eprint!("foo\rbar\n") // ~ ERROR
eprint!("foo\rbar\n");
// Ignore expanded format strings
macro_rules! newline {
() => {
"\n"
};
}
eprint!(newline!());
}

View file

@ -83,7 +83,7 @@ LL | | );
help: use `eprintln!` instead
|
LL ~ eprintln!(
LL ~ ""
LL ~
|
error: using `eprint!()` with a format string that ends in a single newline
@ -98,7 +98,7 @@ LL | | );
help: use `eprintln!` instead
|
LL ~ eprintln!(
LL ~ r""
LL ~
|
error: using `eprint!()` with a format string that ends in a single newline
@ -113,17 +113,5 @@ LL - eprint!("/r/n"); //~ ERROR
LL + eprintln!("/r"); //~ ERROR
|
error: using `eprint!()` with a format string that ends in a single newline
--> $DIR/eprint_with_newline.rs:48:5
|
LL | eprint!("foo/rbar/n") // ~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^
|
help: use `eprintln!` instead
|
LL - eprint!("foo/rbar/n") // ~ ERROR
LL + eprintln!("foo/rbar") // ~ ERROR
|
error: aborting due to 10 previous errors
error: aborting due to 9 previous errors

View file

@ -28,8 +28,6 @@ fn main() {
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
format!("{:width$}", "foo", width = 8);
"foo".to_string(); // Warn when the format makes no difference.
"foo".to_string(); // Warn when the format makes no difference.
format!("foo {}", "bar");
format!("{} bar", "foo");
@ -38,8 +36,6 @@ fn main() {
format!("{:?}", arg); // Don't warn about debug.
format!("{:8}", arg);
format!("{:width$}", arg, width = 8);
arg.to_string(); // Warn when the format makes no difference.
arg.to_string(); // Warn when the format makes no difference.
format!("foo {}", arg);
format!("{} bar", arg);

View file

@ -30,8 +30,6 @@ fn main() {
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
format!("{:width$}", "foo", width = 8);
format!("{:+}", "foo"); // Warn when the format makes no difference.
format!("{:<}", "foo"); // Warn when the format makes no difference.
format!("foo {}", "bar");
format!("{} bar", "foo");
@ -40,8 +38,6 @@ fn main() {
format!("{:?}", arg); // Don't warn about debug.
format!("{:8}", arg);
format!("{:width$}", arg, width = 8);
format!("{:+}", arg); // Warn when the format makes no difference.
format!("{:<}", arg); // Warn when the format makes no difference.
format!("foo {}", arg);
format!("{} bar", arg);

View file

@ -46,82 +46,58 @@ LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
--> $DIR/format.rs:33:5
|
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
--> $DIR/format.rs:34:5
|
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
--> $DIR/format.rs:39:5
--> $DIR/format.rs:37:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:43:5
|
LL | format!("{:+}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:44:5
|
LL | format!("{:<}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:71:5
--> $DIR/format.rs:67:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:73:5
--> $DIR/format.rs:69:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
--> $DIR/format.rs:77:18
--> $DIR/format.rs:73:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
--> $DIR/format.rs:81:22
--> $DIR/format.rs:77:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
error: useless use of `format!`
--> $DIR/format.rs:87:13
--> $DIR/format.rs:83:13
|
LL | let _ = format!("{x}");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:89:13
--> $DIR/format.rs:85:13
|
LL | let _ = format!("{y}", y = x);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:93:13
--> $DIR/format.rs:89:13
|
LL | let _ = format!("{abc}");
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
error: useless use of `format!`
--> $DIR/format.rs:95:13
--> $DIR/format.rs:91:13
|
LL | let _ = format!("{xx}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
error: aborting due to 19 previous errors
error: aborting due to 15 previous errors

View file

@ -1,56 +0,0 @@
// run-rustfix
#![allow(unused_must_use)]
#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
#![warn(clippy::positional_named_format_parameters)]
use std::io::Write;
fn main() {
let mut v = Vec::new();
let hello = "Hello";
println!("{hello:.foo$}", foo = 2);
writeln!(v, "{hello:.foo$}", foo = 2);
// Warnings
println!("{zero} {one:?}", zero = 0, one = 1);
println!("This is a test {zero} {one:?}", zero = 0, one = 1);
println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
println!("Hello {one:zero$}!", zero = 5, one = 1);
println!("Hello {zero:one$}!", zero = 4, one = 1);
println!("Hello {zero:0one$}!", zero = 4, one = 1);
println!("Hello is {one:.zero$}", zero = 5, one = 0.01);
println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01);
println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
println!("Hello {world} {world}!", world = 5);
writeln!(v, "{zero} {one:?}", zero = 0, one = 1);
writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1);
writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1);
writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1);
writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1);
writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01);
writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01);
writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01);
writeln!(v, "Hello {world} {world}!", world = 0);
// Tests from other files
println!("{w:w$}", w = 1);
println!("{p:.p$}", p = 1);
println!("{v}", v = 1);
println!("{v:v$}", v = 1);
println!("{v:v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{v:v$.v$}", v = 1);
println!("{w:w$}", w = 1);
println!("{p:.p$}", p = 1);
println!("{:p$.w$}", 1, w = 1, p = 1);
}

View file

@ -1,56 +0,0 @@
// run-rustfix
#![allow(unused_must_use)]
#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
#![warn(clippy::positional_named_format_parameters)]
use std::io::Write;
fn main() {
let mut v = Vec::new();
let hello = "Hello";
println!("{hello:.foo$}", foo = 2);
writeln!(v, "{hello:.foo$}", foo = 2);
// Warnings
println!("{} {1:?}", zero = 0, one = 1);
println!("This is a test { } {000001:?}", zero = 0, one = 1);
println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
println!("Hello {1:0$}!", zero = 5, one = 1);
println!("Hello {0:1$}!", zero = 4, one = 1);
println!("Hello {0:01$}!", zero = 4, one = 1);
println!("Hello is {1:.*}", zero = 5, one = 0.01);
println!("Hello is {:<6.*}", zero = 5, one = 0.01);
println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
println!("Hello {world} {}!", world = 5);
writeln!(v, "{} {1:?}", zero = 0, one = 1);
writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
writeln!(v, "Hello {world} {}!", world = 0);
// Tests from other files
println!("{:w$}", w = 1);
println!("{:.p$}", p = 1);
println!("{}", v = 1);
println!("{:0$}", v = 1);
println!("{0:0$}", v = 1);
println!("{:0$.0$}", v = 1);
println!("{0:0$.0$}", v = 1);
println!("{0:0$.v$}", v = 1);
println!("{0:v$.0$}", v = 1);
println!("{v:0$.0$}", v = 1);
println!("{v:v$.0$}", v = 1);
println!("{v:0$.v$}", v = 1);
println!("{:w$}", w = 1);
println!("{:.p$}", p = 1);
println!("{:p$.w$}", 1, w = 1, p = 1);
}

View file

@ -1,418 +0,0 @@
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:16:16
|
LL | println!("{} {1:?}", zero = 0, one = 1);
| ^ help: replace it with: `zero`
|
= note: `-D clippy::positional-named-format-parameters` implied by `-D warnings`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:16:19
|
LL | println!("{} {1:?}", zero = 0, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:17:31
|
LL | println!("This is a test { } {000001:?}", zero = 0, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:17:35
|
LL | println!("This is a test { } {000001:?}", zero = 0, one = 1);
| ^^^^^^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:18:32
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:18:22
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `one`
error: named parameter two is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:18:29
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `two`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:19:24
|
LL | println!("Hello {1:0$}!", zero = 5, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:19:22
|
LL | println!("Hello {1:0$}!", zero = 5, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:20:22
|
LL | println!("Hello {0:1$}!", zero = 4, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:20:24
|
LL | println!("Hello {0:1$}!", zero = 4, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:21:22
|
LL | println!("Hello {0:01$}!", zero = 4, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:21:25
|
LL | println!("Hello {0:01$}!", zero = 4, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:22:28
|
LL | println!("Hello is {1:.*}", zero = 5, one = 0.01);
| ^ help: replace it with: `zero$`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:22:25
|
LL | println!("Hello is {1:.*}", zero = 5, one = 0.01);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:23:29
|
LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01);
| ^ help: replace it with: `zero$`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:23:25
|
LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:24:16
|
LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:24:28
|
LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
| ^ help: replace it with: `one$`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:25:32
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:25:22
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `one`
error: named parameter two is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:25:29
|
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `two`
error: named parameter world is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:26:30
|
LL | println!("Hello {world} {}!", world = 5);
| ^ help: replace it with: `world`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:28:19
|
LL | writeln!(v, "{} {1:?}", zero = 0, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:28:22
|
LL | writeln!(v, "{} {1:?}", zero = 0, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:29:34
|
LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:29:38
|
LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
| ^^^^^^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:30:35
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:30:25
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `one`
error: named parameter two is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:30:32
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
| ^ help: replace it with: `two`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:31:27
|
LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:31:25
|
LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:32:25
|
LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:32:27
|
LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:33:25
|
LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:33:28
|
LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:34:31
|
LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
| ^ help: replace it with: `zero$`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:34:28
|
LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:35:32
|
LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
| ^ help: replace it with: `zero$`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:35:28
|
LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
| ^ help: replace it with: `one`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:36:19
|
LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:36:31
|
LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
| ^ help: replace it with: `one$`
error: named parameter zero is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:37:35
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
| ^ help: replace it with: `zero`
error: named parameter one is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:37:25
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
| ^ help: replace it with: `one`
error: named parameter two is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:37:32
|
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
| ^ help: replace it with: `two`
error: named parameter world is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:38:33
|
LL | writeln!(v, "Hello {world} {}!", world = 0);
| ^ help: replace it with: `world`
error: named parameter w is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:41:16
|
LL | println!("{:w$}", w = 1);
| ^ help: replace it with: `w`
error: named parameter p is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:42:16
|
LL | println!("{:.p$}", p = 1);
| ^ help: replace it with: `p`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:43:16
|
LL | println!("{}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:44:16
|
LL | println!("{:0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:44:17
|
LL | println!("{:0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:45:16
|
LL | println!("{0:0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:45:18
|
LL | println!("{0:0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:46:16
|
LL | println!("{:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:46:20
|
LL | println!("{:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:46:17
|
LL | println!("{:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:47:16
|
LL | println!("{0:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:47:21
|
LL | println!("{0:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:47:18
|
LL | println!("{0:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:48:16
|
LL | println!("{0:0$.v$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:48:18
|
LL | println!("{0:0$.v$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:49:16
|
LL | println!("{0:v$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:49:21
|
LL | println!("{0:v$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:50:21
|
LL | println!("{v:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:50:18
|
LL | println!("{v:0$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:51:21
|
LL | println!("{v:v$.0$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter v is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:52:18
|
LL | println!("{v:0$.v$}", v = 1);
| ^ help: replace it with: `v`
error: named parameter w is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:53:16
|
LL | println!("{:w$}", w = 1);
| ^ help: replace it with: `w`
error: named parameter p is used as a positional parameter
--> $DIR/positional_named_format_parameters.rs:54:16
|
LL | println!("{:.p$}", p = 1);
| ^ help: replace it with: `p`
error: aborting due to 69 previous errors

View file

@ -20,11 +20,13 @@ fn main() {
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
println!("10 / 4 is {}", 2.5);
println!("2 + 1 = {}", 3);
println!("From expansion {}", stringify!(not a string literal));
// these should throw warnings
print!("Hello {}", "world");
println!("Hello {} {}", world, "world");
println!("Hello {}", "world");
println!("{} {:.4}", "a literal", 5);
// positional args don't change the fact
// that we're using a literal -- this should

View file

@ -1,5 +1,5 @@
error: literal with an empty format string
--> $DIR/print_literal.rs:25:24
--> $DIR/print_literal.rs:26:24
|
LL | print!("Hello {}", "world");
| ^^^^^^^
@ -12,7 +12,7 @@ LL + print!("Hello world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:26:36
--> $DIR/print_literal.rs:27:36
|
LL | println!("Hello {} {}", world, "world");
| ^^^^^^^
@ -24,7 +24,7 @@ LL + println!("Hello {} world", world);
|
error: literal with an empty format string
--> $DIR/print_literal.rs:27:26
--> $DIR/print_literal.rs:28:26
|
LL | println!("Hello {}", "world");
| ^^^^^^^
@ -36,7 +36,19 @@ LL + println!("Hello world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:32:25
--> $DIR/print_literal.rs:29:26
|
LL | println!("{} {:.4}", "a literal", 5);
| ^^^^^^^^^^^
|
help: try this
|
LL - println!("{} {:.4}", "a literal", 5);
LL + println!("a literal {:.4}", 5);
|
error: literal with an empty format string
--> $DIR/print_literal.rs:34:25
|
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
@ -48,7 +60,7 @@ LL + println!("hello {1}", "world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:32:34
--> $DIR/print_literal.rs:34:34
|
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
@ -60,19 +72,7 @@ LL + println!("{0} world", "hello");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:33:25
|
LL | println!("{1} {0}", "hello", "world");
| ^^^^^^^
|
help: try this
|
LL - println!("{1} {0}", "hello", "world");
LL + println!("{1} hello", "world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:33:34
--> $DIR/print_literal.rs:35:34
|
LL | println!("{1} {0}", "hello", "world");
| ^^^^^^^
@ -84,10 +84,22 @@ LL + println!("world {0}", "hello");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:36:29
--> $DIR/print_literal.rs:35:25
|
LL | println!("{1} {0}", "hello", "world");
| ^^^^^^^
|
help: try this
|
LL - println!("{1} {0}", "hello", "world");
LL + println!("{1} hello", "world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:38:35
|
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -96,10 +108,10 @@ LL + println!("hello {bar}", bar = "world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:36:44
--> $DIR/print_literal.rs:38:50
|
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -108,22 +120,10 @@ LL + println!("{foo} world", foo = "hello");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:37:29
--> $DIR/print_literal.rs:39:50
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
|
help: try this
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
LL + println!("{bar} hello", bar = "world");
|
error: literal with an empty format string
--> $DIR/print_literal.rs:37:44
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -131,5 +131,17 @@ LL - println!("{bar} {foo}", foo = "hello", bar = "world");
LL + println!("world {foo}", foo = "hello");
|
error: aborting due to 11 previous errors
error: literal with an empty format string
--> $DIR/print_literal.rs:39:35
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
help: try this
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
LL + println!("{bar} hello", bar = "world");
|
error: aborting due to 12 previous errors

View file

@ -48,5 +48,13 @@ fn main() {
print!("\r\n");
print!("foo\r\n");
print!("\\r\n"); //~ ERROR
print!("foo\rbar\n") // ~ ERROR
print!("foo\rbar\n");
// Ignore expanded format strings
macro_rules! newline {
() => {
"\n"
};
}
print!(newline!());
}

View file

@ -83,7 +83,7 @@ LL | | );
help: use `println!` instead
|
LL ~ println!(
LL ~ ""
LL ~
|
error: using `print!()` with a format string that ends in a single newline
@ -98,7 +98,7 @@ LL | | );
help: use `println!` instead
|
LL ~ println!(
LL ~ r""
LL ~
|
error: using `print!()` with a format string that ends in a single newline
@ -113,17 +113,5 @@ LL - print!("/r/n"); //~ ERROR
LL + println!("/r"); //~ ERROR
|
error: using `print!()` with a format string that ends in a single newline
--> $DIR/print_with_newline.rs:51:5
|
LL | print!("foo/rbar/n") // ~ ERROR
| ^^^^^^^^^^^^^^^^^^^^
|
help: use `println!` instead
|
LL - print!("foo/rbar/n") // ~ ERROR
LL + println!("foo/rbar") // ~ ERROR
|
error: aborting due to 10 previous errors
error: aborting due to 9 previous errors

View file

@ -1,28 +1,36 @@
error: using `println!("")`
error: empty string literal in `println!`
--> $DIR/println_empty_string.rs:6:5
|
LL | println!("");
| ^^^^^^^^^^^^ help: replace it with: `println!()`
| ^^^^^^^^^--^
| |
| help: remove the empty string
|
= note: `-D clippy::println-empty-string` implied by `-D warnings`
error: using `println!("")`
error: empty string literal in `println!`
--> $DIR/println_empty_string.rs:9:14
|
LL | _ => println!(""),
| ^^^^^^^^^^^^ help: replace it with: `println!()`
| ^^^^^^^^^--^
| |
| help: remove the empty string
error: using `eprintln!("")`
error: empty string literal in `eprintln!`
--> $DIR/println_empty_string.rs:13:5
|
LL | eprintln!("");
| ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
| ^^^^^^^^^^--^
| |
| help: remove the empty string
error: using `eprintln!("")`
error: empty string literal in `eprintln!`
--> $DIR/println_empty_string.rs:16:14
|
LL | _ => eprintln!(""),
| ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
| ^^^^^^^^^^--^
| |
| help: remove the empty string
error: aborting due to 4 previous errors

View file

@ -32,6 +32,7 @@
#![allow(invalid_value)]
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
#![allow(named_arguments_used_positionally)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
@ -69,6 +70,7 @@
#![warn(invalid_value)]
#![warn(enum_intrinsics_non_enums)]
#![warn(non_fmt_panics)]
#![warn(named_arguments_used_positionally)]
#![warn(temporary_cstring_as_ptr)]
#![warn(unknown_lints)]
#![warn(unused_labels)]

View file

@ -32,6 +32,7 @@
#![allow(invalid_value)]
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
#![allow(named_arguments_used_positionally)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
@ -69,6 +70,7 @@
#![warn(clippy::invalid_ref)]
#![warn(clippy::mem_discriminant_non_enum)]
#![warn(clippy::panic_params)]
#![warn(clippy::positional_named_format_parameters)]
#![warn(clippy::temporary_cstring_as_ptr)]
#![warn(clippy::unknown_clippy_lints)]
#![warn(clippy::unused_label)]

View file

@ -1,5 +1,5 @@
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
--> $DIR/rename.rs:38:9
--> $DIR/rename.rs:39:9
|
LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
@ -7,220 +7,226 @@ LL | #![warn(clippy::blacklisted_name)]
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:39:9
--> $DIR/rename.rs:40:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:40:9
--> $DIR/rename.rs:41:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
--> $DIR/rename.rs:41:9
--> $DIR/rename.rs:42:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
--> $DIR/rename.rs:42:9
--> $DIR/rename.rs:43:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
--> $DIR/rename.rs:43:9
--> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
--> $DIR/rename.rs:44:9
--> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
--> $DIR/rename.rs:45:9
--> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
--> $DIR/rename.rs:46:9
--> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
--> $DIR/rename.rs:47:9
--> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
--> $DIR/rename.rs:48:9
--> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
--> $DIR/rename.rs:49:9
--> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
--> $DIR/rename.rs:50:9
--> $DIR/rename.rs:51:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
--> $DIR/rename.rs:51:9
--> $DIR/rename.rs:52:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
--> $DIR/rename.rs:52:9
--> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
--> $DIR/rename.rs:53:9
--> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:54:9
--> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:55:9
--> $DIR/rename.rs:56:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:56:9
--> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:57:9
--> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
--> $DIR/rename.rs:58:9
--> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:59:9
--> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:60:9
--> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:61:9
--> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
--> $DIR/rename.rs:62:9
--> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
--> $DIR/rename.rs:63:9
--> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
--> $DIR/rename.rs:64:9
--> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
--> $DIR/rename.rs:65:9
--> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/rename.rs:66:9
--> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/rename.rs:67:9
--> $DIR/rename.rs:68:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> $DIR/rename.rs:68:9
--> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> $DIR/rename.rs:69:9
--> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
--> $DIR/rename.rs:70:9
--> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/rename.rs:71:9
--> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
--> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/rename.rs:72:9
--> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/rename.rs:73:9
--> $DIR/rename.rs:75:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/rename.rs:74:9
--> $DIR/rename.rs:76:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: aborting due to 37 previous errors
error: aborting due to 38 previous errors

View file

@ -25,11 +25,13 @@ fn main() {
writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
writeln!(v, "10 / 4 is {}", 2.5);
writeln!(v, "2 + 1 = {}", 3);
writeln!(v, "From expansion {}", stringify!(not a string literal));
// these should throw warnings
write!(v, "Hello {}", "world");
writeln!(v, "Hello {} {}", world, "world");
writeln!(v, "Hello {}", "world");
writeln!(v, "{} {:.4}", "a literal", 5);
// positional args don't change the fact
// that we're using a literal -- this should

View file

@ -1,5 +1,5 @@
error: literal with an empty format string
--> $DIR/write_literal.rs:30:27
--> $DIR/write_literal.rs:31:27
|
LL | write!(v, "Hello {}", "world");
| ^^^^^^^
@ -12,7 +12,7 @@ LL + write!(v, "Hello world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:31:39
--> $DIR/write_literal.rs:32:39
|
LL | writeln!(v, "Hello {} {}", world, "world");
| ^^^^^^^
@ -24,7 +24,7 @@ LL + writeln!(v, "Hello {} world", world);
|
error: literal with an empty format string
--> $DIR/write_literal.rs:32:29
--> $DIR/write_literal.rs:33:29
|
LL | writeln!(v, "Hello {}", "world");
| ^^^^^^^
@ -36,7 +36,19 @@ LL + writeln!(v, "Hello world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:37:28
--> $DIR/write_literal.rs:34:29
|
LL | writeln!(v, "{} {:.4}", "a literal", 5);
| ^^^^^^^^^^^
|
help: try this
|
LL - writeln!(v, "{} {:.4}", "a literal", 5);
LL + writeln!(v, "a literal {:.4}", 5);
|
error: literal with an empty format string
--> $DIR/write_literal.rs:39:28
|
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
@ -48,7 +60,7 @@ LL + writeln!(v, "hello {1}", "world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:37:37
--> $DIR/write_literal.rs:39:37
|
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
@ -60,19 +72,7 @@ LL + writeln!(v, "{0} world", "hello");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:38:28
|
LL | writeln!(v, "{1} {0}", "hello", "world");
| ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{1} {0}", "hello", "world");
LL + writeln!(v, "{1} hello", "world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:38:37
--> $DIR/write_literal.rs:40:37
|
LL | writeln!(v, "{1} {0}", "hello", "world");
| ^^^^^^^
@ -84,10 +84,22 @@ LL + writeln!(v, "world {0}", "hello");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:41:32
--> $DIR/write_literal.rs:40:28
|
LL | writeln!(v, "{1} {0}", "hello", "world");
| ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{1} {0}", "hello", "world");
LL + writeln!(v, "{1} hello", "world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:43:38
|
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -96,10 +108,10 @@ LL + writeln!(v, "hello {bar}", bar = "world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:41:47
--> $DIR/write_literal.rs:43:53
|
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -108,22 +120,10 @@ LL + writeln!(v, "{foo} world", foo = "hello");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:42:32
--> $DIR/write_literal.rs:44:53
|
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
|
help: try this
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
LL + writeln!(v, "{bar} hello", bar = "world");
|
error: literal with an empty format string
--> $DIR/write_literal.rs:42:47
|
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^^^^^^^
| ^^^^^^^
|
help: try this
|
@ -131,5 +131,17 @@ LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
LL + writeln!(v, "world {foo}", foo = "hello");
|
error: aborting due to 11 previous errors
error: literal with an empty format string
--> $DIR/write_literal.rs:44:38
|
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
LL + writeln!(v, "{bar} hello", bar = "world");
|
error: aborting due to 12 previous errors

View file

@ -10,7 +10,7 @@ fn main() {
writeln!(v, r"{}", r"{hello}");
writeln!(v, "{}", '\'');
writeln!(v, "{}", '"');
writeln!(v, r"{}", '"'); // don't lint
writeln!(v, r"{}", '"');
writeln!(v, r"{}", '\'');
writeln!(
v,
@ -24,4 +24,11 @@ fn main() {
{} \\ {}",
"1", "2", "3",
);
writeln!(v, "{}", "\\");
writeln!(v, r"{}", "\\");
writeln!(v, r#"{}"#, "\\");
writeln!(v, "{}", r"\");
writeln!(v, "{}", "\r");
writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
writeln!(v, r"{}", "\r"); // should not lint
}

View file

@ -47,6 +47,12 @@ LL - writeln!(v, "{}", '"');
LL + writeln!(v, "/"");
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:13:24
|
LL | writeln!(v, r"{}", '"');
| ^^^
error: literal with an empty format string
--> $DIR/write_literal_2.rs:14:24
|
@ -108,5 +114,77 @@ LL ~ {} / 3",
LL ~ "1", "2",
|
error: aborting due to 9 previous errors
error: literal with an empty format string
--> $DIR/write_literal_2.rs:27:23
|
LL | writeln!(v, "{}", "/");
| ^^^^
|
help: try this
|
LL - writeln!(v, "{}", "/");
LL + writeln!(v, "/");
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:28:24
|
LL | writeln!(v, r"{}", "/");
| ^^^^
|
help: try this
|
LL - writeln!(v, r"{}", "/");
LL + writeln!(v, r"/");
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:29:26
|
LL | writeln!(v, r#"{}"#, "/");
| ^^^^
|
help: try this
|
LL - writeln!(v, r#"{}"#, "/");
LL + writeln!(v, r#"/"#);
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:30:23
|
LL | writeln!(v, "{}", r"/");
| ^^^^
|
help: try this
|
LL - writeln!(v, "{}", r"/");
LL + writeln!(v, "/");
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:31:23
|
LL | writeln!(v, "{}", "/r");
| ^^^^
|
help: try this
|
LL - writeln!(v, "{}", "/r");
LL + writeln!(v, "/r");
|
error: literal with an empty format string
--> $DIR/write_literal_2.rs:32:28
|
LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
| ^^^
error: literal with an empty format string
--> $DIR/write_literal_2.rs:32:33
|
LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
| ^^^
error: aborting due to 17 previous errors

View file

@ -56,4 +56,12 @@ fn main() {
write!(v, "foo\r\n");
write!(v, "\\r\n"); //~ ERROR
write!(v, "foo\rbar\n");
// Ignore expanded format strings
macro_rules! newline {
() => {
"\n"
};
}
write!(v, newline!());
}

View file

@ -5,7 +5,7 @@ LL | write!(v, "Hello/n");
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::write-with-newline` implied by `-D warnings`
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "Hello/n");
LL + writeln!(v, "Hello");
@ -17,7 +17,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "Hello {}/n", "world");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "Hello {}/n", "world");
LL + writeln!(v, "Hello {}", "world");
@ -29,7 +29,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "Hello {} {}/n", "world", "#2");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "Hello {} {}/n", "world", "#2");
LL + writeln!(v, "Hello {} {}", "world", "#2");
@ -41,7 +41,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "{}/n", 1265);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "{}/n", 1265);
LL + writeln!(v, "{}", 1265);
@ -53,7 +53,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "/n");
| ^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "/n");
LL + writeln!(v);
@ -65,7 +65,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "//n"); // should fail
| ^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "//n"); // should fail
LL + writeln!(v, "/"); // should fail
@ -81,11 +81,10 @@ LL | | "
LL | | );
| |_____^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL ~ writeln!(
LL | v,
LL ~ ""
LL ~ v
|
error: using `write!()` with a format string that ends in a single newline
@ -98,11 +97,10 @@ LL | | "
LL | | );
| |_____^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL ~ writeln!(
LL | v,
LL ~ r""
LL ~ v
|
error: using `write!()` with a format string that ends in a single newline
@ -111,23 +109,11 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "/r/n"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
help: use `writeln!` instead
|
LL - write!(v, "/r/n"); //~ ERROR
LL + writeln!(v, "/r"); //~ ERROR
|
error: using `write!()` with a format string that ends in a single newline
--> $DIR/write_with_newline.rs:58:5
|
LL | write!(v, "foo/rbar/n");
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `writeln!()` instead
|
LL - write!(v, "foo/rbar/n");
LL + writeln!(v, "foo/rbar");
|
error: aborting due to 10 previous errors
error: aborting due to 9 previous errors

View file

@ -1,16 +1,20 @@
error: using `writeln!(v, "")`
error: empty string literal in `writeln!`
--> $DIR/writeln_empty_string.rs:11:5
|
LL | writeln!(v, "");
| ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)`
| ^^^^^^^^^^----^
| |
| help: remove the empty string
|
= note: `-D clippy::writeln-empty-string` implied by `-D warnings`
error: using `writeln!(suggestion, "")`
error: empty string literal in `writeln!`
--> $DIR/writeln_empty_string.rs:14:5
|
LL | writeln!(suggestion, "");
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)`
| ^^^^^^^^^^^^^^^^^^^----^
| |
| help: remove the empty string
error: aborting due to 2 previous errors