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;
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
}
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(_) => {
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,
// 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",
// 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] = &[
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);
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));
+ }
}
}
}
#[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)
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);
}
_ => {}
}
// 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);
}
_ => {}
}
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),
"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
};
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)
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));
}
}
}
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! {
DEAD_CODE,
UNREACHABLE_CODE,
WARNINGS,
- UNKNOWN_FEATURES,
+ UNUSED_FEATURES,
UNKNOWN_CRATE_TYPES,
VARIANT_SIZE_DIFFERENCES,
FAT_PTR_TRANSMUTES
}
}
+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;