Merge pull request #557 from mcarton/cmp_owned
Check types in the CMP_OWNED lint
This commit is contained in:
commit
4293c77198
@ -318,7 +318,7 @@ fn check_unwrap_or_default(
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if implements_trait(cx, arg_ty, default_trait_id) {
|
if implements_trait(cx, arg_ty, default_trait_id, None) {
|
||||||
span_lint(cx, OR_FUN_CALL, span,
|
span_lint(cx, OR_FUN_CALL, span,
|
||||||
&format!("use of `{}` followed by a call to `{}`", name, path))
|
&format!("use of `{}` followed by a call to `{}`", name, path))
|
||||||
.span_suggestion(span, "try this",
|
.span_suggestion(span, "try this",
|
||||||
|
29
src/misc.rs
29
src/misc.rs
@ -11,7 +11,7 @@
|
|||||||
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
|
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
|
||||||
|
|
||||||
use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint};
|
use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint};
|
||||||
use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal};
|
use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal, implements_trait};
|
||||||
|
|
||||||
/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default.
|
/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default.
|
||||||
///
|
///
|
||||||
@ -210,18 +210,18 @@ impl LateLintPass for CmpOwned {
|
|||||||
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
|
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
|
||||||
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
|
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
|
||||||
if is_comparison_binop(cmp.node) {
|
if is_comparison_binop(cmp.node) {
|
||||||
check_to_owned(cx, left, right.span, true, cmp.span);
|
check_to_owned(cx, left, right, true, cmp.span);
|
||||||
check_to_owned(cx, right, left.span, false, cmp.span)
|
check_to_owned(cx, right, left, false, cmp.span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, op: Span) {
|
fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) {
|
||||||
let snip = match expr.node {
|
let (arg_ty, snip) = match expr.node {
|
||||||
ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => {
|
ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => {
|
||||||
if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) {
|
if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) {
|
||||||
snippet(cx, args[0].span, "..")
|
(cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o
|
|||||||
ExprCall(ref path, ref v) if v.len() == 1 => {
|
ExprCall(ref path, ref v) if v.len() == 1 => {
|
||||||
if let ExprPath(None, ref path) = path.node {
|
if let ExprPath(None, ref path) = path.node {
|
||||||
if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) {
|
if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) {
|
||||||
snippet(cx, v[0].span, "..")
|
(cx.tcx.expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -239,6 +239,17 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o
|
|||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let other_ty = cx.tcx.expr_ty(other);
|
||||||
|
let partial_eq_trait_id = match cx.tcx.lang_items.eq_trait() {
|
||||||
|
Some(id) => id,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !implements_trait(cx, arg_ty, partial_eq_trait_id, Some(vec![other_ty])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if left {
|
if left {
|
||||||
span_lint(cx,
|
span_lint(cx,
|
||||||
CMP_OWNED,
|
CMP_OWNED,
|
||||||
@ -247,14 +258,14 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o
|
|||||||
compare without allocation",
|
compare without allocation",
|
||||||
snip,
|
snip,
|
||||||
snippet(cx, op, "=="),
|
snippet(cx, op, "=="),
|
||||||
snippet(cx, other_span, "..")));
|
snippet(cx, other.span, "..")));
|
||||||
} else {
|
} else {
|
||||||
span_lint(cx,
|
span_lint(cx,
|
||||||
CMP_OWNED,
|
CMP_OWNED,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \
|
&format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \
|
||||||
compare without allocation",
|
compare without allocation",
|
||||||
snippet(cx, other_span, ".."),
|
snippet(cx, other.span, ".."),
|
||||||
snippet(cx, op, "=="),
|
snippet(cx, op, "=="),
|
||||||
snip));
|
snip));
|
||||||
}
|
}
|
||||||
|
@ -242,14 +242,14 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> {
|
|||||||
|
|
||||||
/// Check whether a type implements a trait.
|
/// Check whether a type implements a trait.
|
||||||
/// See also `get_trait_def_id`.
|
/// See also `get_trait_def_id`.
|
||||||
pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId) -> bool {
|
pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, ty_params: Option<Vec<ty::Ty<'tcx>>>) -> bool {
|
||||||
cx.tcx.populate_implementations_for_trait_if_necessary(trait_id);
|
cx.tcx.populate_implementations_for_trait_if_necessary(trait_id);
|
||||||
|
|
||||||
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None);
|
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None);
|
||||||
let obligation = traits::predicate_for_trait_def(cx.tcx,
|
let obligation = traits::predicate_for_trait_def(cx.tcx,
|
||||||
traits::ObligationCause::dummy(),
|
traits::ObligationCause::dummy(),
|
||||||
trait_id, 0, ty,
|
trait_id, 0, ty,
|
||||||
vec![]);
|
ty_params.unwrap_or_default());
|
||||||
|
|
||||||
traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
|
traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,6 @@ fn with_to_string(x : &str) {
|
|||||||
// as of 2015-08-14
|
// as of 2015-08-14
|
||||||
|
|
||||||
x != String::from("foo"); //~ERROR this creates an owned instance
|
x != String::from("foo"); //~ERROR this creates an owned instance
|
||||||
|
|
||||||
|
42.to_string() == "42";
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user