From 604c68d47ca50845cdb934a2f853dce1a9eb8c63 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 1 Jul 2015 02:00:23 +0900 Subject: [PATCH] Add a lint for unused type parameters --- src/libcore/lib.rs | 1 + src/librustc/lint/builtin.rs | 7 +++ src/librustc_lint/lib.rs | 3 +- src/librustc_resolve/lib.rs | 54 +++++++++++++++---- src/libstd/io/error.rs | 1 + src/libstd/thread/mod.rs | 1 + src/test/compile-fail/lint-dead-code-1.rs | 1 + .../lint-unused-type-parameters.rs | 42 +++++++++++++++ .../compile-fail/object-safety-phantom-fn.rs | 1 + 9 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/lint-unused-type-parameters.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 030d2a33f8f65..68d0cf6b925bd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,6 +63,7 @@ #![feature(no_std)] #![no_std] #![allow(raw_pointer_derive)] +#![allow(unused_type_parameters)] #![deny(missing_docs)] #![feature(intrinsics)] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 495044f945949..c23cba5501d4a 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -22,6 +22,12 @@ declare_lint! { "imports that are never used" } +declare_lint! { + pub UNUSED_TYPE_PARAMETERS, + Warn, + "type parameters that are never used" +} + declare_lint! { pub UNUSED_EXTERN_CRATES, Allow, @@ -120,6 +126,7 @@ impl LintPass for HardwiredLints { fn get_lints(&self) -> LintArray { lint_array!( UNUSED_IMPORTS, + UNUSED_TYPE_PARAMETERS, UNUSED_EXTERN_CRATES, UNUSED_QUALIFICATIONS, UNKNOWN_LINTS, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c680906dd135b..236b80b5f1f48 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -123,7 +123,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); add_lint_group!(sess, "unused", - UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, + UNUSED_IMPORTS, UNUSED_TYPE_PARAMETERS, + UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5d10b0d9a57b8..a2b828d818e41 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -91,6 +91,7 @@ use syntax::visit::{self, Visitor}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cell::{Cell, RefCell}; +use std::default::Default; use std::fmt; use std::mem::replace; use std::rc::{Rc, Weak}; @@ -363,15 +364,35 @@ enum BareIdentifierPatternResolution { struct Rib { bindings: HashMap, kind: RibKind, + sources: HashMap, + used_names: RefCell>, } impl Rib { fn new(kind: RibKind) -> Rib { Rib { bindings: HashMap::new(), - kind: kind + kind: kind, + sources: Default::default(), + used_names: Default::default(), } } + + fn insert(&mut self, name: Name, def: DefLike) { + self.bindings.insert(name, def); + } + + fn insert_with_source(&mut self, name: Name, id: NodeId, span: Span, def: DefLike) { + self.bindings.insert(name, def); + self.sources.insert(name, (id, span)); + } + + fn get(&self, name: Name) -> Option { + self.bindings.get(&name).map(|def| { + self.used_names.borrow_mut().insert(name); + def.clone() + }) + } } /// The link from a module up to its nearest parent node. @@ -1749,7 +1770,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // FIXME #4950: Try caching? for (i, rib) in ribs.iter().enumerate().rev() { - if let Some(def_like) = rib.bindings.get(&name).cloned() { + if let Some(def_like) = rib.get(name) { return self.upvarify(&ribs[i + 1..], def_like, span); } } @@ -1770,7 +1791,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return None } } - let result = rib.bindings.get(&name).cloned(); + let result = rib.get(name); if result.is_some() { return result } @@ -1919,7 +1940,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { match type_parameters { HasTypeParameters(generics, space, rib_kind) => { - let mut function_type_rib = Rib::new(rib_kind); + let mut type_rib = Rib::new(rib_kind); let mut seen_bindings = HashSet::new(); for (index, type_parameter) in generics.ty_params.iter().enumerate() { let name = type_parameter.ident.name; @@ -1936,13 +1957,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { seen_bindings.insert(name); // plain insert (no renaming) - function_type_rib.bindings.insert(name, + type_rib.insert_with_source(name, type_parameter.id, type_parameter.span, DlDef(DefTyParam(space, index as u32, local_def(type_parameter.id), name))); } - self.type_ribs.push(function_type_rib); + self.type_ribs.push(type_rib); } NoTypeParameters => { @@ -1953,7 +1974,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { f(self); match type_parameters { - HasTypeParameters(..) => { self.type_ribs.pop(); } + HasTypeParameters(..) => { + { + let type_rib = self.type_ribs.last().unwrap(); + for (&name, &(id, span)) in &type_rib.sources { + if !type_rib.used_names.borrow().contains(&name) { + self.session.add_lint(lint::builtin::UNUSED_TYPE_PARAMETERS, + id, span, + "unused type parameter".to_string()); + } + } + } + + self.type_ribs.pop(); + } NoTypeParameters => { } } } @@ -2099,7 +2133,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // plain insert (no renaming, types are not currently hygienic....) let name = special_names::type_self; - self_type_rib.bindings.insert(name, DlDef(self_def)); + self_type_rib.insert(name, DlDef(self_def)); self.type_ribs.push(self_type_rib); f(self); self.type_ribs.pop(); @@ -2474,7 +2508,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !bindings_list.contains_key(&renamed) { let this = &mut *self; let last_rib = this.value_ribs.last_mut().unwrap(); - last_rib.bindings.insert(renamed, DlDef(def)); + last_rib.insert(renamed, DlDef(def)); bindings_list.insert(renamed, pat_id); } else if mode == ArgumentIrrefutableMode && bindings_list.contains_key(&renamed) { @@ -3409,7 +3443,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { let rib = this.label_ribs.last_mut().unwrap(); let renamed = mtwt::resolve(label); - rib.bindings.insert(renamed, def_like); + rib.insert(renamed, def_like); } visit::walk_expr(this, expr); diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index a66789bf2873d..61e5b2169961e 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -280,6 +280,7 @@ impl error::Error for Error { } } +#[allow(unused_type_parameters)] fn _assert_error_is_sync_send() { fn _is_sync_send() {} _is_sync_send::(); diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index dbb7d3233bc39..edc9e295cc04d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -753,6 +753,7 @@ impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { } } +#[allow(unused_type_parameters)] fn _assert_sync_and_send() { fn _assert_both() {} _assert_both::>(); diff --git a/src/test/compile-fail/lint-dead-code-1.rs b/src/test/compile-fail/lint-dead-code-1.rs index e91e6efd1cbf0..8fdfb1e14e41f 100644 --- a/src/test/compile-fail/lint-dead-code-1.rs +++ b/src/test/compile-fail/lint-dead-code-1.rs @@ -81,6 +81,7 @@ enum used_enum { bar3 //~ ERROR variant is never used } +#[allow(unused_type_parameters)] fn f() {} pub fn pub_fn() { diff --git a/src/test/compile-fail/lint-unused-type-parameters.rs b/src/test/compile-fail/lint-unused-type-parameters.rs new file mode 100644 index 0000000000000..ca84e50f9c52a --- /dev/null +++ b/src/test/compile-fail/lint-unused-type-parameters.rs @@ -0,0 +1,42 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(unused_type_parameters)] + +pub fn f() {} //~ ERROR unused type parameter + +pub struct S; +impl S { + pub fn m() {} //~ ERROR unused type parameter +} + +trait Trait { + fn m() {} //~ ERROR unused type parameter +} + +// Now test allow attributes + +pub mod allow { + #[allow(unused_type_parameters)] + pub fn f() {} + + pub struct S; + impl S { + #[allow(unused_type_parameters)] + pub fn m() {} + } + + trait Trait { + #[allow(unused_type_parameters)] + fn m() {} + } +} + +fn main() {} diff --git a/src/test/compile-fail/object-safety-phantom-fn.rs b/src/test/compile-fail/object-safety-phantom-fn.rs index 518c45ac9dff6..c80d2863b0ff3 100644 --- a/src/test/compile-fail/object-safety-phantom-fn.rs +++ b/src/test/compile-fail/object-safety-phantom-fn.rs @@ -12,6 +12,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] trait Baz { }