enum glob use and copies left

This commit is contained in:
Oliver Schneider
2016-12-02 17:38:31 +01:00
parent 59b0077565
commit 16aab71688
15 changed files with 117 additions and 109 deletions

View File

@@ -48,6 +48,8 @@ impl EnumGlobUse {
return; // re-exports are fine
}
if let ItemUse(ref path, UseKind::Glob) = item.node {
// FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;`
// extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an `Enum`
if let Def::Enum(_) = path.def {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}

View File

@@ -5,7 +5,7 @@ use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics};
use std::collections::{HashSet, HashMap};
use syntax::codemap::Span;
use utils::{in_external_macro, span_lint};
use utils::{in_external_macro, span_lint, last_path_segment};
/// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
@@ -240,9 +240,8 @@ impl<'v, 't> RefVisitor<'v, 't> {
}
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
if let QPath::Resolved(_, ref path) = *qpath {
let last_path_segment = path.segments.last().map(|s| &s.parameters);
if let Some(&AngleBracketedParameters(ref params)) = last_path_segment {
let last_path_segment = &last_path_segment(qpath).parameters;
if let &AngleBracketedParameters(ref params) = last_path_segment {
if params.lifetimes.is_empty() {
match self.cx.tcx.tables().qpath_def(qpath, ty.id) {
Def::TyAlias(def_id) |
@@ -263,7 +262,6 @@ impl<'v, 't> RefVisitor<'v, 't> {
}
}
}
}
}
impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> {

View File

@@ -16,7 +16,7 @@ use utils::sugg;
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg,
in_external_macro, is_refutable, span_help_and_lint, is_integer_literal,
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty};
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty, last_path_segment};
use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some
@@ -369,8 +369,7 @@ impl LateLintPass for Pass {
if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _),
&ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) {
let iter_expr = &method_args[0];
if let QPath::Resolved(_, ref path) = *qpath {
if let Some(lhs_constructor) = path.segments.last() {
let lhs_constructor = last_path_segment(qpath);
if &*method_name.node.as_str() == "next" &&
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
&*lhs_constructor.name.as_str() == "Some" &&
@@ -391,8 +390,6 @@ impl LateLintPass for Pass {
}
}
}
}
}
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
if let StmtSemi(ref expr, _) = stmt.node {

View File

@@ -3,6 +3,7 @@ use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::middle::const_qualif::ConstQualif;
use rustc::ty;
use rustc::hir::def::Def;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::eval_const_expr_partial;
use std::borrow::Cow;
@@ -10,7 +11,8 @@ use std::fmt;
use syntax::codemap::Span;
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path,
match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet,
span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth,
last_path_segment, single_segment_path, match_def_path};
use utils::paths;
use utils::sugg;
@@ -701,12 +703,8 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
}
if name == "unwrap_or" {
if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = fun.node {
let path: &str = &path.segments
.last()
.expect("A path must have at least one segment")
.name
.as_str();
if let hir::ExprPath(ref qpath) = fun.node {
let path: &str = &*last_path_segment(qpath).name.as_str();
if ["default", "new"].contains(&path) {
let arg_ty = cx.tcx.tables().expr_ty(arg);
@@ -878,7 +876,8 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
let hir::ExprCall(ref fun, ref args) = new.node,
args.len() == 1,
let hir::ExprPath(ref path) = fun.node,
match_path(path, &paths::CSTRING_NEW),
let Def::Method(did) = cx.tcx.tables().qpath_def(path, fun.id),
match_def_path(cx, did, &paths::CSTRING_NEW)
], {
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
"you are getting the inner pointer of a temporary `CString`",
@@ -1188,8 +1187,9 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other:
let Some(args) = method_chain_args(chain, &["chars", "next"]),
let hir::ExprCall(ref fun, ref arg_char) = other.node,
arg_char.len() == 1,
let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = fun.node,
path.segments.len() == 1 && &*path.segments[0].name.as_str() == "Some"
let hir::ExprPath(ref qpath) = fun.node,
let Some(segment) = single_segment_path(qpath),
&*segment.name.as_str() == "Some"
], {
let self_ty = walk_ptrs_ty(cx.tcx.tables().expr_ty_adjusted(&args[0][0]));

View File

@@ -10,7 +10,7 @@ use rustc_const_math::ConstFloat;
use syntax::codemap::{Span, Spanned, ExpnFormat};
use utils::{
get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path,
snippet, span_lint, span_lint_and_then, walk_ptrs_ty
snippet, span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment
};
use utils::sugg::Sugg;
@@ -263,12 +263,7 @@ impl LateLintPass for Pass {
}
let binding = match expr.node {
ExprPath(ref qpath) => {
if let QPath::Resolved(_, ref path) = *qpath {
let binding = path.segments
.last()
.expect("path should always have at least one segment")
.name
.as_str();
let binding = last_path_segment(qpath).name.as_str();
if binding.starts_with('_') &&
!binding.starts_with("__") &&
&*binding != "_result" && // FIXME: #944
@@ -279,9 +274,6 @@ impl LateLintPass for Pass {
} else {
None
}
} else {
None
}
}
ExprField(_, spanned) => {
let name = spanned.node.as_str();

View File

@@ -75,17 +75,13 @@ impl LateLintPass for StepByZero {
// .iter() and .len() called on same Path
let ExprPath(QPath::Resolved(_, ref iter_path)) = iter_args[0].node,
let ExprPath(QPath::Resolved(_, ref len_path)) = len_args[0].node,
iter_path == len_path
iter_path.segments == len_path.segments
], {
let Path { segments: ref iter_path, .. } = **iter_path;
let Path { segments: ref len_path, .. } = **len_path;
if iter_path == len_path {
span_lint(cx,
RANGE_ZIP_WITH_LEN,
expr.span,
&format!("It is more idiomatic to use {}.iter().enumerate()",
snippet(cx, iter_args[0].span, "_")));
}
}}
}
}

View File

@@ -2,7 +2,7 @@ use rustc::lint::*;
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
use rustc::ty;
use rustc::hir::*;
use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet};
use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet, last_path_segment};
use utils::sugg;
/// **What it does:** Checks for transmutes that can't ever be correct on any
@@ -191,9 +191,8 @@ impl LateLintPass for Transmute {
/// the type's `ToString` implementation. In weird cases it could lead to types with invalid `'_`
/// lifetime, but it should be rare.
fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: ty::Ty) -> String {
let seg = last_path_segment(path);
if_let_chain!{[
let QPath::Resolved(_, ref path) = *path,
let Some(seg) = path.segments.last(),
let PathParameters::AngleBracketedParameters(ref ang) = seg.parameters,
let Some(to_ty) = ang.types.get(1),
let TyRptr(_, ref to_ty) = to_ty.node,

View File

@@ -7,7 +7,7 @@ use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::codemap::Span;
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet,
span_help_and_lint, span_lint, opt_def_id};
span_help_and_lint, span_lint, opt_def_id, last_path_segment};
use utils::paths;
/// Handles all the linting of funky types
@@ -78,9 +78,8 @@ impl LateLintPass for TypePass {
let def = cx.tcx.tables().qpath_def(qpath, ast_ty.id);
if let Some(def_id) = opt_def_id(def) {
if def_id == cx.tcx.lang_items.owned_box().unwrap() {
let last = last_path_segment(qpath);
if_let_chain! {[
let QPath::Resolved(_, ref path) = *qpath,
let Some(ref last) = path.segments.last(),
let PathParameters::AngleBracketedParameters(ref ag) = last.parameters,
let Some(ref vec) = ag.types.get(0),
let TyPath(ref qpath) = vec.node,

View File

@@ -163,7 +163,7 @@ pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e
// `vec![elem; size]` case
Some(VecArgs::Repeat(&args[0], &args[1]))
}
else if match_path(path, &["into_vec"]) && args.len() == 1 {
else if match_def_path(cx, fun_def.def_id(), &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
if_let_chain!{[
let hir::ExprBox(ref boxed) = args[0].node,

View File

@@ -3,7 +3,7 @@ use rustc::lint::*;
use rustc::hir::*;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use syntax::ast::Name;
use syntax::ast::{Name, NodeId};
use syntax::ptr::P;
use utils::differing_macro_contexts;
@@ -457,13 +457,13 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
ExprPath(ref qpath) => {
let c: fn(_) -> _ = ExprPath;
c.hash(&mut self.s);
self.hash_qpath(qpath);
self.hash_qpath(qpath, e.id);
}
ExprStruct(ref path, ref fields, ref expr) => {
let c: fn(_, _, _) -> _ = ExprStruct;
c.hash(&mut self.s);
self.hash_qpath(path);
self.hash_qpath(path, e.id);
for f in fields {
self.hash_name(&f.name.node);
@@ -528,21 +528,8 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
n.as_str().hash(&mut self.s);
}
pub fn hash_qpath(&mut self, p: &QPath) {
match *p {
QPath::Resolved(ref _ty, ref path) => {
let c: fn(_, _) -> _ = QPath::Resolved;
c.hash(&mut self.s);
// self.hash_ty(ty); FIXME
self.hash_path(path);
},
QPath::TypeRelative(ref _ty, ref seg) => {
let c: fn(_, _) -> _ = QPath::TypeRelative;
c.hash(&mut self.s);
// self.hash_ty(ty); FIXME
self.hash_name(&seg.name);
},
}
pub fn hash_qpath(&mut self, p: &QPath, id: NodeId) {
self.cx.tcx.tables().qpath_def(p, id).hash(&mut self.s);
}
pub fn hash_path(&mut self, p: &Path) {

View File

@@ -95,7 +95,16 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
}
/// Returns true if this `expn_info` was expanded by any macro.
pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some())
cx.sess().codemap().with_expn_info(span.expn_id, |info| match info {
Some(info) => {
match info.callee.format {
// don't treat range expressions desugared to structs as "in_macro"
ExpnFormat::CompilerDesugaring(name) => name != "...",
_ => true,
}
},
None => false,
})
}
/// Returns true if the macro that expanded the crate was outside of the current crate or was a
@@ -150,6 +159,9 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
let mut apb = AbsolutePathBuffer { names: vec![] };
cx.tcx.push_item_path(&mut apb, def_id);
if path == paths::VEC_FROM_ELEM {
println!("{:#?} == {:#?}", apb.names, path);
}
apb.names.len() == path.len() &&
apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b)
@@ -197,6 +209,23 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool
}
}
pub fn last_path_segment(path: &QPath) -> &PathSegment {
match *path {
QPath::Resolved(_, ref path) => path.segments
.last()
.expect("A path must have at least one segment"),
QPath::TypeRelative(_, ref seg) => &seg,
}
}
pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> {
match *path {
QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]),
QPath::Resolved(..) => None,
QPath::TypeRelative(_, ref seg) => Some(&seg),
}
}
/// Match a `Path` against a slice of segment string literals.
///
/// # Examples
@@ -204,10 +233,16 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool
/// match_path(path, &["std", "rt", "begin_unwind"])
/// ```
pub fn match_path(path: &QPath, segments: &[&str]) -> bool {
if let QPath::Resolved(_, ref path) = *path {
match_path_old(path, segments)
} else {
false
match *path {
QPath::Resolved(_, ref path) => match_path_old(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node {
TyPath(ref inner_path) => {
segments.len() > 0 &&
match_path(inner_path, &segments[..(segments.len() - 1)]) &&
segment.name == segments[segments.len() - 1]
},
_ => false,
},
}
}

View File

@@ -12,7 +12,7 @@ pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"];
pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"];
pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"];
pub const CSTRING_NEW: [&'static str; 5] = ["std", "ffi", "c_str", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Display", "fmt"];
@@ -64,6 +64,7 @@ pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&'static str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&'static str; 4] = ["core", "result", "Result", "Ok"];
pub const SERDE_DE_VISITOR: [&'static str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&'static str; 4] = ["collections", "slice", "<impl [T]>", "into_vec"];
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];

View File

@@ -9,6 +9,7 @@
#![allow(blacklisted_name)]
#![allow(collapsible_if)]
#![allow(zero_divided_by_zero, eq_op)]
#![allow(path_statements)]
fn bar<T>(_: T) {}
fn foo() -> bool { unimplemented!() }

View File

@@ -10,5 +10,5 @@ pub fn test(_: LinkedList<u8>) { //~ ERROR I see you're using a LinkedList!
}
fn main(){
test(LinkedList::new());
test(LinkedList::new()); //~ ERROR I see you're using a LinkedList!
}

View File

@@ -21,6 +21,7 @@ fn run_mode(dir: &'static str, mode: &'static str) {
fn prepare_env() {
set_var("CLIPPY_DISABLE_WIKI_LINKS", "true");
set_var("RUST_BACKTRACE", "0"); // these are riddicously slow right now
}
#[test]