]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/lint/builtin.rs
rollup merge of #21800: brson/unused_features
[rust.git] / src / librustc / lint / builtin.rs
index 34ed5b0cd57a7d73078e008c40dd5d5d1bc66015..1722261f4f2e8d5f4ced8405794b537bc0a7b55a 100644 (file)
@@ -46,7 +46,7 @@
 use syntax::{abi, ast, ast_map};
 use syntax::ast_util::is_shift_binop;
 use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::{self, Span, DUMMY_SP};
+use syntax::codemap::{self, Span};
 use syntax::parse::token;
 use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
 use syntax::ast_util;
@@ -254,7 +254,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
                         let lit_val: f64 = match lit.node {
                             ast::LitFloat(ref v, _) |
                             ast::LitFloatUnsuffixed(ref v) => {
-                                match v.parse() {
+                                match v.parse().ok() {
                                     Some(f) => f,
                                     None => return
                                 }
@@ -493,7 +493,7 @@ fn check_foreign_fn(cx: &Context, decl: &ast::FnDecl) {
 impl BoxPointers {
     fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'a, 'tcx>,
                                  span: Span, ty: Ty<'tcx>) {
-        let mut n_uniq = 0i;
+        let mut n_uniq = 0us;
         ty::fold_ty(cx.tcx, ty, |t| {
             match t.sty {
                 ty::ty_uniq(_) => {
@@ -592,7 +592,15 @@ fn check_item(&mut self, cx: &Context, item: &ast::Item) {
             return
         }
         let did = match item.node {
-            ast::ItemImpl(..) => {
+            ast::ItemImpl(_, _, _, ref t_ref_opt, _, _) => {
+                // Deriving the Copy trait does not cause a warning
+                if let &Some(ref trait_ref) = t_ref_opt {
+                    let def_id = ty::trait_ref_to_def_id(cx.tcx, trait_ref);
+                    if Some(def_id) == cx.tcx.lang_items.copy_trait() {
+                        return
+                    }
+                }
+
                 match ty::node_id_to_type(cx.tcx, item.id).sty {
                     ty::ty_enum(did, _) => did,
                     ty::ty_struct(did, _) => did,
@@ -662,9 +670,6 @@ fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
             // FIXME: #14407 these are only looked at on-demand so we can't
             // guarantee they'll have already been checked
             "deprecated",
-            "experimental",
-            "frozen",
-            "locked",
             "must_use",
             "stable",
             "unstable",
@@ -673,6 +678,7 @@ fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
             // FIXME: #19470 this shouldn't be needed forever
             "old_orphan_check",
             "old_impl_check",
+            "rustc_paren_sugar", // FIXME: #18101 temporary unboxed closure hack
         ];
 
         static CRATE_ATTRS: &'static [&'static str] = &[
@@ -940,6 +946,34 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
 pub struct NonSnakeCase;
 
 impl NonSnakeCase {
+    fn to_snake_case(mut str: &str) -> String {
+        let mut words = vec![];
+        // Preserve leading underscores
+        str = str.trim_left_matches(|&mut: c: char| {
+            if c == '_' {
+                words.push(String::new());
+                true
+            } else { false }
+        });
+        for s in str.split('_') {
+            let mut last_upper = false;
+            let mut buf = String::new();
+            if s.is_empty() { continue; }
+            for ch in s.chars() {
+                if !buf.is_empty() && buf != "'"
+                                   && ch.is_uppercase()
+                                   && !last_upper {
+                    words.push(buf);
+                    buf = String::new();
+                }
+                last_upper = ch.is_uppercase();
+                buf.push(ch.to_lowercase());
+            }
+            words.push(buf);
+        }
+        words.connect("_")
+    }
+
     fn check_snake_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
         fn is_snake_case(ident: ast::Ident) -> bool {
             let ident = token::get_ident(ident);
@@ -950,41 +984,28 @@ fn is_snake_case(ident: ast::Ident) -> bool {
             let mut allow_underscore = true;
             ident.chars().all(|c| {
                 allow_underscore = match c {
-                    c if c.is_lowercase() || c.is_numeric() => true,
-                    '_' if allow_underscore => false,
+                    '_' if !allow_underscore => return false,
+                    '_' => false,
+                    c if !c.is_uppercase() => true,
                     _ => return false,
                 };
                 true
             })
         }
 
-        fn to_snake_case(str: &str) -> String {
-            let mut words = vec![];
-            for s in str.split('_') {
-                let mut last_upper = false;
-                let mut buf = String::new();
-                if s.is_empty() { continue; }
-                for ch in s.chars() {
-                    if !buf.is_empty() && buf != "'"
-                                       && ch.is_uppercase()
-                                       && !last_upper {
-                        words.push(buf);
-                        buf = String::new();
-                    }
-                    last_upper = ch.is_uppercase();
-                    buf.push(ch.to_lowercase());
-                }
-                words.push(buf);
-            }
-            words.connect("_")
-        }
-
         let s = token::get_ident(ident);
 
         if !is_snake_case(ident) {
-            cx.span_lint(NON_SNAKE_CASE, span,
-                &format!("{} `{}` should have a snake case name such as `{}`",
-                        sort, s, to_snake_case(s.get()))[]);
+            let sc = NonSnakeCase::to_snake_case(s.get());
+            if sc != s.get() {
+                cx.span_lint(NON_SNAKE_CASE, span,
+                    &*format!("{} `{}` should have a snake case name such as `{}`",
+                            sort, s, sc));
+            } else {
+                cx.span_lint(NON_SNAKE_CASE, span,
+                    &*format!("{} `{}` should have a snake case name",
+                            sort, s));
+            }
         }
     }
 }
@@ -1052,6 +1073,26 @@ fn check_struct_def(&mut self, cx: &Context, s: &ast::StructDef,
 #[derive(Copy)]
 pub struct NonUpperCaseGlobals;
 
+impl NonUpperCaseGlobals {
+    fn check_upper_case(cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
+        let s = token::get_ident(ident);
+
+        if s.get().chars().any(|c| c.is_lowercase()) {
+            let uc: String = NonSnakeCase::to_snake_case(s.get()).chars()
+                                           .map(|c| c.to_uppercase()).collect();
+            if uc != s.get() {
+                cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
+                    format!("{} `{}` should have an upper case name such as `{}`",
+                            sort, s, uc).as_slice());
+            } else {
+                cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
+                    format!("{} `{}` should have an upper case name",
+                            sort, s).as_slice());
+            }
+        }
+    }
+}
+
 impl LintPass for NonUpperCaseGlobals {
     fn get_lints(&self) -> LintArray {
         lint_array!(NON_UPPER_CASE_GLOBALS)
@@ -1060,19 +1101,11 @@ fn get_lints(&self) -> LintArray {
     fn check_item(&mut self, cx: &Context, it: &ast::Item) {
         match it.node {
             // only check static constants
-            ast::ItemStatic(_, ast::MutImmutable, _) |
+            ast::ItemStatic(_, ast::MutImmutable, _) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "static constant", it.ident, it.span);
+            }
             ast::ItemConst(..) => {
-                let s = token::get_ident(it.ident);
-                // check for lowercase letters rather than non-uppercase
-                // ones (some scripts don't have a concept of
-                // upper/lowercase)
-                if s.get().chars().any(|c| c.is_lowercase()) {
-                    cx.span_lint(NON_UPPER_CASE_GLOBALS, it.span,
-                        &format!("static constant `{}` should have an uppercase name \
-                                 such as `{}`",
-                                s.get(), &s.get().chars().map(|c| c.to_uppercase())
-                                .collect::<String>()[])[]);
-                }
+                NonUpperCaseGlobals::check_upper_case(cx, "constant", it.ident, it.span);
             }
             _ => {}
         }
@@ -1082,14 +1115,8 @@ fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
         // Lint for constants that look like binding identifiers (#7526)
         match (&p.node, cx.tcx.def_map.borrow().get(&p.id)) {
             (&ast::PatIdent(_, ref path1, _), Some(&def::DefConst(..))) => {
-                let s = token::get_ident(path1.node);
-                if s.get().chars().any(|c| c.is_lowercase()) {
-                    cx.span_lint(NON_UPPER_CASE_GLOBALS, path1.span,
-                        &format!("static constant in pattern `{}` should have an uppercase \
-                                 name such as `{}`",
-                                s.get(), &s.get().chars().map(|c| c.to_uppercase())
-                                    .collect::<String>()[])[]);
-                }
+                NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
+                                                      path1.node, p.span);
             }
             _ => {}
         }
@@ -1166,6 +1193,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
                 ast::MatchSource::Normal => (head, "`match` head expression", true),
                 ast::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true),
                 ast::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true),
+                ast::MatchSource::ForLoopDesugar => (head, "`for` head expression", true),
             },
             ast::ExprRet(Some(ref value)) => (value, "`return` value", false),
             ast::ExprAssign(_, ref value) => (value, "assigned value", false),
@@ -1696,37 +1724,16 @@ fn check_item(&mut self, cx: &Context, item: &ast::Item) {
     "detects use of #[deprecated] items"
 }
 
-declare_lint! {
-    UNSTABLE,
-    Warn,
-    "detects use of #[unstable] items (incl. items with no stability attribute)"
-}
-
-/// Checks for use of items with `#[deprecated]`, `#[unstable]` and
-/// `#[unstable]` attributes, or no stability attribute.
+/// Checks for use of items with `#[deprecated]` attributes
 #[derive(Copy)]
-pub struct Stability { this_crate_staged: bool }
+pub struct Stability;
 
 impl Stability {
-    pub fn new() -> Stability { Stability { this_crate_staged: false } }
-
-    fn lint(&self, cx: &Context, id: ast::DefId, span: Span) {
-
-        let ref stability = stability::lookup(cx.tcx, id);
-        let cross_crate = !ast_util::is_local(id);
-        let staged = (!cross_crate && self.this_crate_staged)
-            || (cross_crate && stability::is_staged_api(cx.tcx, id));
-
-        if !staged { return }
+    fn lint(&self, cx: &Context, _id: ast::DefId, span: Span, stability: &Option<attr::Stability>) {
 
-        // stability attributes are promises made across crates; only
-        // check DEPRECATED for crate-local usage.
+        // deprecated attributes apply in-crate and cross-crate
         let (lint, label) = match *stability {
-            // no stability attributes == Unstable
-            None if cross_crate => (UNSTABLE, "unmarked"),
-            Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate =>
-                (UNSTABLE, "unstable"),
-            Some(attr::Stability { level: attr::Deprecated, .. }) =>
+            Some(attr::Stability { deprecated_since: Some(_), .. }) =>
                 (DEPRECATED, "deprecated"),
             _ => return
         };
@@ -1736,7 +1743,7 @@ fn lint(&self, cx: &Context, id: ast::DefId, span: Span) {
         fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>,
                   lint: &'static Lint, label: &'static str) {
             let msg = match *stability {
-                Some(attr::Stability { text: Some(ref s), .. }) => {
+                Some(attr::Stability { reason: Some(ref s), .. }) => {
                     format!("use of {} item: {}", label, *s)
                 }
                 _ => format!("use of {} item", label)
@@ -1745,111 +1752,21 @@ fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>,
             cx.span_lint(lint, span, &msg[]);
         }
     }
-
-
-    fn is_internal(&self, cx: &Context, span: Span) -> bool {
-        cx.tcx.sess.codemap().span_is_internal(span)
-    }
-
 }
 
 impl LintPass for Stability {
     fn get_lints(&self) -> LintArray {
-        lint_array!(DEPRECATED, UNSTABLE)
-    }
-
-    fn check_crate(&mut self, _: &Context, c: &ast::Crate) {
-        // Just mark the #[staged_api] attribute used, though nothing else is done
-        // with it during this pass over the source.
-        for attr in c.attrs.iter() {
-            if attr.name().get() == "staged_api" {
-                match attr.node.value.node {
-                    ast::MetaWord(_) => {
-                        attr::mark_used(attr);
-                        self.this_crate_staged = true;
-                    }
-                    _ => (/*pass*/)
-                }
-            }
-        }
-    }
-
-    fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
-        if self.is_internal(cx, e.span) { return; }
-
-        let mut span = e.span;
-
-        let id = match e.node {
-            ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
-                match cx.tcx.def_map.borrow().get(&e.id) {
-                    Some(&def) => def.def_id(),
-                    None => return
-                }
-            }
-            ast::ExprMethodCall(i, _, _) => {
-                span = i.span;
-                let method_call = ty::MethodCall::expr(e.id);
-                match cx.tcx.method_map.borrow().get(&method_call) {
-                    Some(method) => {
-                        match method.origin {
-                            ty::MethodStatic(def_id) => {
-                                def_id
-                            }
-                            ty::MethodStaticClosure(def_id) => {
-                                def_id
-                            }
-                            ty::MethodTypeParam(ty::MethodParam {
-                                ref trait_ref,
-                                method_num: index,
-                                ..
-                            }) |
-                            ty::MethodTraitObject(ty::MethodObject {
-                                ref trait_ref,
-                                method_num: index,
-                                ..
-                            }) => {
-                                ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id()
-                            }
-                        }
-                    }
-                    None => return
-                }
-            }
-            _ => return
-        };
-
-        self.lint(cx, id, span);
+        lint_array!(DEPRECATED)
     }
 
     fn check_item(&mut self, cx: &Context, item: &ast::Item) {
-        if self.is_internal(cx, item.span) { return }
-
-        match item.node {
-            ast::ItemExternCrate(_) => {
-                // compiler-generated `extern crate` items have a dummy span.
-                if item.span == DUMMY_SP { return }
+        stability::check_item(cx.tcx, item,
+                              &mut |id, sp, stab| self.lint(cx, id, sp, stab));
+    }
 
-                let cnum = match cx.tcx.sess.cstore.find_extern_mod_stmt_cnum(item.id) {
-                    Some(cnum) => cnum,
-                    None => return,
-                };
-                let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
-                self.lint(cx, id, item.span);
-            }
-            ast::ItemTrait(_, _, ref supertraits, _) => {
-                for t in supertraits.iter() {
-                    if let ast::TraitTyParamBound(ref t, _) = *t {
-                        let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref);
-                        self.lint(cx, id, t.trait_ref.path.span);
-                    }
-                }
-            }
-            ast::ItemImpl(_, _, _, Some(ref t), _, _) => {
-                let id = ty::trait_ref_to_def_id(cx.tcx, t);
-                self.lint(cx, id, t.path.span);
-            }
-            _ => (/* pass */)
-        }
+    fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
+        stability::check_expr(cx.tcx, e,
+                              &mut |id, sp, stab| self.lint(cx, id, sp, stab));
     }
 }
 
@@ -2096,9 +2013,9 @@ fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
 }
 
 declare_lint! {
-    pub UNKNOWN_FEATURES,
-    Deny,
-    "unknown features found in crate-level #[feature] directives"
+    pub UNUSED_FEATURES,
+    Warn,
+    "unused or unknown features found in crate-level #[feature] directives"
 }
 
 declare_lint! {
@@ -2142,7 +2059,7 @@ fn get_lints(&self) -> LintArray {
             DEAD_CODE,
             UNREACHABLE_CODE,
             WARNINGS,
-            UNKNOWN_FEATURES,
+            UNUSED_FEATURES,
             UNKNOWN_CRATE_TYPES,
             VARIANT_SIZE_DIFFERENCES,
             FAT_PTR_TRANSMUTES
@@ -2150,6 +2067,35 @@ fn get_lints(&self) -> LintArray {
     }
 }
 
+declare_lint! {
+    PRIVATE_NO_MANGLE_FNS,
+    Warn,
+    "functions marked #[no_mangle] should be exported"
+}
+
+#[derive(Copy)]
+pub struct PrivateNoMangleFns;
+
+impl LintPass for PrivateNoMangleFns {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(PRIVATE_NO_MANGLE_FNS)
+    }
+
+    fn check_item(&mut self, cx: &Context, it: &ast::Item) {
+        match it.node {
+            ast::ItemFn(..) => {
+                if attr::contains_name(it.attrs.as_slice(), "no_mangle") &&
+                       !cx.exported_items.contains(&it.id) {
+                    let msg = format!("function {} is marked #[no_mangle], but not exported",
+                                      it.ident);
+                    cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg.as_slice());
+                }
+            },
+            _ => {},
+        }
+    }
+}
+
 /// Forbids using the `#[feature(...)]` attribute
 #[derive(Copy)]
 pub struct UnstableFeatures;