Merge pull request #238 from birkenfeld/to_string_fix
methods: suggest correct replacement for `to_string()` (fixes #232)
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use rustc::lint::*;
|
use rustc::lint::*;
|
||||||
use rustc::middle::ty;
|
use rustc::middle::ty;
|
||||||
|
use std::iter;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use utils::{span_lint, match_type, walk_ptrs_ty};
|
use utils::{snippet, span_lint, match_type, walk_ptrs_ty_depth};
|
||||||
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};
|
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
@@ -24,7 +26,7 @@ impl LintPass for MethodsPass {
|
|||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||||
if let ExprMethodCall(ref ident, _, ref args) = expr.node {
|
if let ExprMethodCall(ref ident, _, ref args) = expr.node {
|
||||||
let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&args[0]));
|
let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0]));
|
||||||
if ident.node.name == "unwrap" {
|
if ident.node.name == "unwrap" {
|
||||||
if match_type(cx, obj_ty, &OPTION_PATH) {
|
if match_type(cx, obj_ty, &OPTION_PATH) {
|
||||||
span_lint(cx, OPTION_UNWRAP_USED, expr.span,
|
span_lint(cx, OPTION_UNWRAP_USED, expr.span,
|
||||||
@@ -39,7 +41,15 @@ impl LintPass for MethodsPass {
|
|||||||
}
|
}
|
||||||
else if ident.node.name == "to_string" {
|
else if ident.node.name == "to_string" {
|
||||||
if obj_ty.sty == ty::TyStr {
|
if obj_ty.sty == ty::TyStr {
|
||||||
span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster");
|
let mut arg_str = snippet(cx, args[0].span, "_");
|
||||||
|
if ptr_depth > 1 {
|
||||||
|
arg_str = Cow::Owned(format!(
|
||||||
|
"({}{})",
|
||||||
|
iter::repeat('*').take(ptr_depth - 1).collect::<String>(),
|
||||||
|
arg_str));
|
||||||
|
}
|
||||||
|
span_lint(cx, STR_TO_STRING, expr.span, &format!(
|
||||||
|
"`{}.to_owned()` is faster", arg_str));
|
||||||
} else if match_type(cx, obj_ty, &STRING_PATH) {
|
} else if match_type(cx, obj_ty, &STRING_PATH) {
|
||||||
span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \
|
span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \
|
||||||
`clone()` to make a copy");
|
`clone()` to make a copy");
|
||||||
|
|||||||
11
src/utils.rs
11
src/utils.rs
@@ -158,6 +158,17 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// return the base type for references and raw pointers, and count reference depth
|
||||||
|
pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) {
|
||||||
|
fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) {
|
||||||
|
match ty.sty {
|
||||||
|
ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1),
|
||||||
|
_ => (ty, depth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner(ty, 0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Produce a nested chain of if-lets and ifs from the patterns:
|
/// Produce a nested chain of if-lets and ifs from the patterns:
|
||||||
///
|
///
|
||||||
/// if_let_chain! {
|
/// if_let_chain! {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ fn main() {
|
|||||||
let res: Result<i32, ()> = Ok(0);
|
let res: Result<i32, ()> = Ok(0);
|
||||||
let _ = res.unwrap(); //~ERROR used unwrap() on a Result
|
let _ = res.unwrap(); //~ERROR used unwrap() on a Result
|
||||||
|
|
||||||
let string = "str".to_string(); //~ERROR `str.to_owned()` is faster
|
let _ = "str".to_string(); //~ERROR `"str".to_owned()` is faster
|
||||||
|
|
||||||
|
let v = &"str";
|
||||||
|
let string = v.to_string(); //~ERROR `(*v).to_owned()` is faster
|
||||||
let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op
|
let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user