From 038f528f452e35a5d586898c878b3b69fd8ff539 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 19 Apr 2016 16:27:01 -0700 Subject: [PATCH] Added lint for use imports which remove unsafe from name --- src/lib.rs | 3 + src/unsafe_removed_from_name.rs | 90 +++++++++++++++++++ .../compile-fail/unsafe_removed_from_name.rs | 12 +++ 3 files changed, 105 insertions(+) create mode 100644 src/unsafe_removed_from_name.rs create mode 100644 tests/compile-fail/unsafe_removed_from_name.rs diff --git a/src/lib.rs b/src/lib.rs index 6d98cf55f091..eee091e6195f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,6 +109,7 @@ pub mod transmute; pub mod types; pub mod unicode; pub mod unused_label; +pub mod unsafe_removed_from_name; pub mod vec; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -234,6 +235,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents)); reg.register_late_lint_pass(box neg_multiply::NegMultiply); + reg.register_late_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -379,6 +381,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, unused_label::UNUSED_LABEL, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/src/unsafe_removed_from_name.rs b/src/unsafe_removed_from_name.rs new file mode 100644 index 000000000000..86860c67cfee --- /dev/null +++ b/src/unsafe_removed_from_name.rs @@ -0,0 +1,90 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::ast::{Name, NodeId}; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::span_lint; + +/// **What it does:** This lint checks for imports that remove "unsafe" from an item's name +/// +/// **Why is this bad?** Renaming makes it less clear which traits and structures are unsafe. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// use std::cell::{UnsafeCell as TotallySafeCell}; +/// +/// extern crate crossbeam; +/// use crossbeam::{spawn_unsafe as spawn}; +/// ``` +declare_lint! { + pub UNSAFE_REMOVED_FROM_NAME, + Warn, + "unsafe removed from name" +} + +pub struct UnsafeNameRemoval; + +impl LintPass for UnsafeNameRemoval { + fn get_lints(&self) -> LintArray { + lint_array!(UNSAFE_REMOVED_FROM_NAME) + } +} + +impl LateLintPass for UnsafeNameRemoval { + fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { + // only check top level `use` statements + for item in &m.item_ids { + self.lint_item(cx, cx.krate.item(item.id)); + } + } +} + +impl UnsafeNameRemoval { + fn lint_item(&self, cx: &LateContext, item: &Item) { + if let ItemUse(ref item_use) = item.node { + match item_use.node { + ViewPath_::ViewPathSimple(ref name, ref path) => { + unsafe_to_safe_check( + path.segments + .last() + .expect("use paths cannot be empty") + .identifier.name, + *name, + cx, &item.span + ); + }, + ViewPath_::ViewPathList(_, ref path_list_items) => { + for path_list_item in path_list_items.iter() { + let plid = path_list_item.node; + if let (Some(name), Some(rename)) = (plid.name(), plid.rename()) { + unsafe_to_safe_check(name, rename, cx, &item.span); + }; + } + }, + ViewPath_::ViewPathGlob(_) => {} + } + } + } +} + +fn unsafe_to_safe_check(old_name: Name, new_name: Name, cx: &LateContext, span: &Span) { + let old_str = old_name.as_str(); + let new_str = new_name.as_str(); + if contains_unsafe(&old_str) && !contains_unsafe(&new_str) { + span_lint( + cx, + UNSAFE_REMOVED_FROM_NAME, + *span, + &format!( + "removed \"unsafe\" from the name of `{}` in use as `{}`", + old_str, + new_str + )); + } +} + +fn contains_unsafe(name: &InternedString) -> bool { + name.contains("Unsafe") || name.contains("unsafe") +} diff --git a/tests/compile-fail/unsafe_removed_from_name.rs b/tests/compile-fail/unsafe_removed_from_name.rs new file mode 100644 index 000000000000..facdb2c64edb --- /dev/null +++ b/tests/compile-fail/unsafe_removed_from_name.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused_imports)] +#![deny(unsafe_removed_from_name)] + +use std::cell::{UnsafeCell as TotallySafeCell}; +//~^ ERROR removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCell` + +use std::cell::UnsafeCell as TotallySafeCellAgain; +//~^ ERROR removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCellAgain` + +fn main() {}