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: #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),
}
}
+declare_lint! {
+ MISSING_DEBUG_IMPLEMENTATIONS,
+ Allow,
+ "detects missing implementations of fmt::Debug"
+}
+
+pub struct MissingDebugImplementations {
+ impling_types: Option<NodeSet>,
+}
+
+impl MissingDebugImplementations {
+ pub fn new() -> MissingDebugImplementations {
+ MissingDebugImplementations {
+ impling_types: None,
+ }
+ }
+}
+
+impl LintPass for MissingDebugImplementations {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(MISSING_DEBUG_IMPLEMENTATIONS)
+ }
+
+ fn check_item(&mut self, cx: &Context, item: &ast::Item) {
+ if !cx.exported_items.contains(&item.id) {
+ return;
+ }
+
+ match item.node {
+ ast::ItemStruct(..) | ast::ItemEnum(..) => {},
+ _ => return,
+ }
+
+ let debug = match cx.tcx.lang_items.debug_trait() {
+ Some(debug) => debug,
+ None => return,
+ };
+
+ if self.impling_types.is_none() {
+ let impls = cx.tcx.trait_impls.borrow();
+ let impls = match impls.get(&debug) {
+ Some(impls) => {
+ impls.borrow().iter()
+ .filter(|d| d.krate == ast::LOCAL_CRATE)
+ .filter_map(|d| ty::ty_to_def_id(ty::node_id_to_type(cx.tcx, d.node)))
+ .map(|d| d.node)
+ .collect()
+ }
+ None => NodeSet(),
+ };
+ self.impling_types = Some(impls);
+ debug!("{:?}", self.impling_types);
+ }
+
+ if !self.impling_types.as_ref().unwrap().contains(&item.id) {
+ cx.span_lint(MISSING_DEBUG_IMPLEMENTATIONS,
+ item.span,
+ "type does not implement `fmt::Debug`; consider adding #[derive(Debug)] \
+ or a manual implementation")
+ }
+ }
+}
+
declare_lint! {
DEPRECATED,
Warn,
ty::MethodTraitObject(_) => return false,
// This `did` refers directly to the method definition.
- ty::MethodStatic(did) | ty::MethodStaticUnboxedClosure(did) => did,
+ ty::MethodStatic(did) | ty::MethodStaticClosure(did) => did,
// MethodTypeParam are methods from traits:
declare_lint! {
pub UNUSED_FEATURES,
- Deny,
+ Warn,
"unused or unknown features found in crate-level #[feature] directives"
}
}
}
+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;