use std::ops::Range;
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
-use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, MacCall, StrLit, StrStyle};
+use if_chain::if_chain;
+use rustc_ast::ast::{
+ Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle,
+};
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::Applicability;
/// ```rust
/// # use std::fmt::Write;
/// # let mut buf = String::new();
- ///
/// // Bad
/// writeln!(buf, "");
///
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// # let name = "World";
- ///
/// // Bad
/// write!(buf, "Hello {}!\n", name);
///
/// ```rust
/// # use std::fmt::Write;
/// # let mut buf = String::new();
- ///
/// // Bad
/// writeln!(buf, "{}", "foo");
///
impl EarlyLintPass for Write {
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Impl {
+ if let ItemKind::Impl(box ImplKind {
of_trait: Some(trait_ref),
..
- } = &item.kind
+ }) = &item.kind
{
let trait_name = trait_ref
.path
/// (Some("string to write: {}"), Some(buf))
/// ```
#[allow(clippy::too_many_lines)]
- fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
+ fn check_tts<'a>(
+ &self,
+ cx: &EarlyContext<'a>,
+ tts: TokenStream,
+ is_write: bool,
+ ) -> (Option<StrLit>, Option<Expr>) {
use rustc_parse_format::{
- AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser,
- Piece,
+ AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied,
+ FormatSpec, ParseMode, Parser, Piece,
};
let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
if let Piece::NextArgument(arg) = piece {
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, parser.prev_token.span, "use of `Debug`-based formatting");
+ span_lint(
+ cx,
+ USE_DEBUG,
+ parser.prev_token.span,
+ "use of `Debug`-based formatting",
+ );
}
args.push(arg);
}
return (Some(fmtstr), None);
};
match &token_expr.kind {
- ExprKind::Lit(_) => {
+ ExprKind::Lit(lit)
+ if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) =>
+ {
let mut all_simple = true;
let mut seen = false;
for arg in &args {
all_simple &= arg.format == SIMPLE;
seen = true;
}
- },
- ArgumentNamed(_) => {},
+ }
+ ArgumentNamed(_) => {}
}
}
if all_simple && seen {
span_lint(cx, lint, token_expr.span, "literal with an empty format string");
}
idx += 1;
- },
+ }
ExprKind::Assign(lhs, rhs, _) => {
- if let ExprKind::Lit(_) = rhs.kind {
- if let ExprKind::Path(_, p) = &lhs.kind {
+ if_chain! {
+ if let ExprKind::Lit(ref lit) = rhs.kind;
+ if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..));
+ if let ExprKind::Path(_, p) = &lhs.kind;
+ then {
let mut all_simple = true;
let mut seen = false;
for arg in &args {
}
}
}
- },
+ }
_ => idx += 1,
}
}
cx,
PRINT_WITH_NEWLINE,
mac.span(),
- &format!("using `{}!()` with a format string that ends in a single newline", name),
+ &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), String::new())],
+ vec![
+ (mac.path.span, suggested),
+ (newline_span(&fmt_str), String::new()),
+ ],
Applicability::MachineApplicable,
);
},