-// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
use crate::utils::paths;
use crate::utils::{
in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet,
};
use if_chain::if_chain;
use rustc::hir::*;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::ast::LitKind;
+use syntax::source_map::Span;
/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
fn get_lints(&self) -> LintArray {
lint_array![USELESS_FORMAT]
}
+
+ fn name(&self) -> &'static str {
+ "UselessFormat"
+ }
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
ExprKind::Call(ref fun, ref args) => {
if_chain! {
if let ExprKind::Path(ref qpath) = fun.node;
- if args.len() == 3;
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
- if match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1FORMATTED);
+ let new_v1 = match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1);
+ let new_v1_fmt = match_def_path(
+ cx.tcx,
+ fun_def_id,
+ &paths::FMT_ARGUMENTS_NEWV1FORMATTED
+ );
+ if new_v1 || new_v1_fmt;
if check_single_piece(&args[0]);
if let Some(format_arg) = get_single_string_arg(cx, &args[1]);
- if check_unformatted(&args[2]);
+ if new_v1 || check_unformatted(&args[2]);
if let ExprKind::AddrOf(_, ref format_arg) = format_arg.node;
then {
let (message, sugg) = if_chain! {
}
};
- span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
- db.span_suggestion_with_applicability(
- expr.span,
- message,
- sugg,
- Applicability::MachineApplicable,
- );
- });
+ span_useless_format(cx, span, message, sugg);
}
}
},
if let ExprKind::Tup(ref tup) = matchee.node {
if tup.is_empty() {
let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
- span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
- db.span_suggestion_with_applicability(
- span,
- "consider using .to_string()",
- sugg,
- Applicability::MachineApplicable, // snippet
- );
- });
+ span_useless_format(cx, span, "consider using .to_string()", sugg);
}
}
},
}
}
+fn span_useless_format<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, span: Span, help: &str, mut sugg: String) {
+ let to_replace = span.source_callsite();
+
+ // The callsite span contains the statement semicolon for some reason.
+ let snippet = snippet(cx, to_replace, "..");
+ if snippet.ends_with(';') {
+ sugg.push(';');
+ }
+
+ span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
+ db.span_suggestion(
+ to_replace,
+ help,
+ sugg,
+ Applicability::MachineApplicable, // snippet
+ );
+ });
+}
+
/// Checks if the expressions matches `&[""]`
fn check_single_piece(expr: &Expr) -> bool {
if_chain! {