mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-02 02:46:06 +00:00
utils: add match_type() helper function
which saves one level of matching when checking for type paths
This commit is contained in:
parent
a437936d49
commit
8a10440641
@ -2,7 +2,7 @@ use syntax::ast::*;
|
||||
use rustc::lint::*;
|
||||
use rustc::middle::ty;
|
||||
|
||||
use utils::{span_lint, match_def_path, walk_ptrs_ty};
|
||||
use utils::{span_lint, match_type, walk_ptrs_ty};
|
||||
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};
|
||||
|
||||
#[derive(Copy,Clone)]
|
||||
@ -24,31 +24,24 @@ impl LintPass for MethodsPass {
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
if let ExprMethodCall(ref ident, _, ref args) = expr.node {
|
||||
let ref obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty;
|
||||
let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0]));
|
||||
if ident.node.name == "unwrap" {
|
||||
if let ty::TyEnum(did, _) = *obj_ty {
|
||||
if match_def_path(cx, did.did, &OPTION_PATH) {
|
||||
span_lint(cx, OPTION_UNWRAP_USED, expr.span,
|
||||
"used unwrap() on an Option value. If you don't want \
|
||||
to handle the None case gracefully, consider using
|
||||
expect() to provide a better panic message");
|
||||
}
|
||||
else if match_def_path(cx, did.did, &RESULT_PATH) {
|
||||
span_lint(cx, RESULT_UNWRAP_USED, expr.span,
|
||||
"used unwrap() on a Result value. Graceful handling \
|
||||
of Err values is preferred");
|
||||
}
|
||||
if match_type(cx, obj_ty, &OPTION_PATH) {
|
||||
span_lint(cx, OPTION_UNWRAP_USED, expr.span,
|
||||
"used unwrap() on an Option value. If you don't want \
|
||||
to handle the None case gracefully, consider using \
|
||||
expect() to provide a better panic message");
|
||||
} else if match_type(cx, obj_ty, &RESULT_PATH) {
|
||||
span_lint(cx, RESULT_UNWRAP_USED, expr.span,
|
||||
"used unwrap() on a Result value. Graceful handling \
|
||||
of Err values is preferred");
|
||||
}
|
||||
}
|
||||
else if ident.node.name == "to_string" {
|
||||
if let ty::TyStr = *obj_ty {
|
||||
if obj_ty.sty == ty::TyStr {
|
||||
span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster");
|
||||
}
|
||||
else if let ty::TyStruct(did, _) = *obj_ty {
|
||||
if match_def_path(cx, did.did, &STRING_PATH) {
|
||||
span_lint(cx, STRING_TO_STRING, expr.span,
|
||||
"`String.to_string()` is a no-op")
|
||||
}
|
||||
} else if match_type(cx, obj_ty, &STRING_PATH) {
|
||||
span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use rustc::lint::*;
|
||||
use syntax::ast::*;
|
||||
use rustc::middle::ty;
|
||||
|
||||
use utils::{span_lint, match_def_path};
|
||||
use utils::{span_lint, match_type};
|
||||
use utils::{STRING_PATH, VEC_PATH};
|
||||
|
||||
declare_lint! {
|
||||
@ -50,18 +50,15 @@ fn check_fn(cx: &Context, decl: &FnDecl) {
|
||||
}
|
||||
let ref sty = cx.tcx.pat_ty(&*arg.pat).sty;
|
||||
if let &ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = sty {
|
||||
if let ty::TyStruct(did, _) = ty.sty {
|
||||
if match_def_path(cx, did.did, &VEC_PATH) {
|
||||
span_lint(cx, PTR_ARG, arg.ty.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference \
|
||||
and cannot be used with non-Vec-based slices. Consider changing \
|
||||
the type to `&[...]`");
|
||||
}
|
||||
else if match_def_path(cx, did.did, &STRING_PATH) {
|
||||
span_lint(cx, PTR_ARG, arg.ty.span,
|
||||
"writing `&String` instead of `&str` involves a new object \
|
||||
where a slice will do. Consider changing the type to `&str`");
|
||||
}
|
||||
if match_type(cx, ty, &VEC_PATH) {
|
||||
span_lint(cx, PTR_ARG, arg.ty.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference \
|
||||
and cannot be used with non-Vec-based slices. Consider changing \
|
||||
the type to `&[...]`");
|
||||
} else if match_type(cx, ty, &STRING_PATH) {
|
||||
span_lint(cx, PTR_ARG, arg.ty.span,
|
||||
"writing `&String` instead of `&str` involves a new object \
|
||||
where a slice will do. Consider changing the type to `&str`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use rustc::lint::{Context, LintArray, LintPass};
|
||||
use rustc::middle::ty::TypeVariants::TyStruct;
|
||||
use syntax::ast::*;
|
||||
use syntax::codemap::Spanned;
|
||||
use utils::{match_def_path};
|
||||
use utils::match_type;
|
||||
|
||||
declare_lint! {
|
||||
pub RANGE_STEP_BY_ZERO, Warn,
|
||||
@ -34,11 +33,9 @@ impl LintPass for StepByZero {
|
||||
fn is_range(cx: &Context, expr: &Expr) -> bool {
|
||||
// No need for walk_ptrs_ty here because step_by moves self, so it
|
||||
// can't be called on a borrowed range.
|
||||
if let TyStruct(did, _) = cx.tcx.expr_ty(expr).sty {
|
||||
// Note: RangeTo and RangeFull don't have step_by
|
||||
match_def_path(cx, did.did, &["core", "ops", "Range"]) ||
|
||||
match_def_path(cx, did.did, &["core", "ops", "RangeFrom"])
|
||||
} else { false }
|
||||
let ty = cx.tcx.expr_ty(expr);
|
||||
// Note: RangeTo and RangeFull don't have step_by
|
||||
match_type(cx, ty, &["core", "ops", "Range"]) || match_type(cx, ty, &["core", "ops", "RangeFrom"])
|
||||
}
|
||||
|
||||
fn is_lit_zero(expr: &Expr) -> bool {
|
||||
|
@ -4,12 +4,11 @@
|
||||
//! disable the subsumed lint unless it has a higher level
|
||||
|
||||
use rustc::lint::*;
|
||||
use rustc::middle::ty::TypeVariants::TyStruct;
|
||||
use syntax::ast::*;
|
||||
use syntax::codemap::Spanned;
|
||||
|
||||
use eq_op::is_exp_equal;
|
||||
use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr};
|
||||
use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr};
|
||||
use utils::STRING_PATH;
|
||||
|
||||
declare_lint! {
|
||||
@ -62,10 +61,7 @@ impl LintPass for StringAdd {
|
||||
}
|
||||
|
||||
fn is_string(cx: &Context, e: &Expr) -> bool {
|
||||
let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
|
||||
if let TyStruct(did, _) = ty.sty {
|
||||
match_def_path(cx, did.did, &STRING_PATH)
|
||||
} else { false }
|
||||
match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH)
|
||||
}
|
||||
|
||||
fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool {
|
||||
|
27
src/types.rs
27
src/types.rs
@ -5,7 +5,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use rustc::middle::ty;
|
||||
use syntax::codemap::ExpnInfo;
|
||||
|
||||
use utils::{in_macro, match_def_path, snippet, span_lint, span_help_and_lint, in_external_macro};
|
||||
use utils::{in_macro, match_type, snippet, span_lint, span_help_and_lint, in_external_macro};
|
||||
use utils::{LL_PATH, VEC_PATH};
|
||||
|
||||
/// Handles all the linting of funky types
|
||||
@ -26,23 +26,18 @@ impl LintPass for TypePass {
|
||||
fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) {
|
||||
if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
|
||||
if let ty::TyBox(ref inner) = ty.sty {
|
||||
if let ty::TyStruct(did, _) = inner.sty {
|
||||
if match_def_path(cx, did.did, &VEC_PATH) {
|
||||
span_help_and_lint(
|
||||
cx, BOX_VEC, ast_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
|
||||
}
|
||||
if match_type(cx, inner, &VEC_PATH) {
|
||||
span_help_and_lint(
|
||||
cx, BOX_VEC, ast_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
|
||||
}
|
||||
}
|
||||
if let ty::TyStruct(did, _) = ty.sty {
|
||||
if match_def_path(cx, did.did, &LL_PATH) {
|
||||
span_help_and_lint(
|
||||
cx, LINKEDLIST, ast_ty.span,
|
||||
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
|
||||
"a RingBuf might work");
|
||||
return;
|
||||
}
|
||||
else if match_type(cx, ty, &LL_PATH) {
|
||||
span_help_and_lint(
|
||||
cx, LINKEDLIST, ast_ty.span,
|
||||
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
|
||||
"a RingBuf might work");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
src/utils.rs
12
src/utils.rs
@ -44,6 +44,18 @@ pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool {
|
||||
.zip(path.iter()).all(|(nm, p)| nm == p))
|
||||
}
|
||||
|
||||
/// check if type is struct or enum type with given def path
|
||||
pub fn match_type(cx: &Context, ty: ty::Ty, path: &[&str]) -> bool {
|
||||
match ty.sty {
|
||||
ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => {
|
||||
match_def_path(cx, adt.did, path)
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// match a Path against a slice of segment string literals, e.g.
|
||||
/// `match_path(path, &["std", "rt", "begin_unwind"])`
|
||||
pub fn match_path(path: &Path, segments: &[&str]) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user