diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index f13814527cdfd..74a389d353c97 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -937,6 +937,34 @@ declare_lint! { 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); @@ -947,41 +975,28 @@ impl NonSnakeCase { 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)); + } } } } @@ -1049,6 +1064,26 @@ declare_lint! { #[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) @@ -1057,19 +1092,11 @@ impl LintPass for NonUpperCaseGlobals { 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::()[])[]); - } + NonUpperCaseGlobals::check_upper_case(cx, "constant", it.ident, it.span); } _ => {} } @@ -1079,14 +1106,8 @@ impl LintPass for NonUpperCaseGlobals { // 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::()[])[]); - } + NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", + path1.node, p.span); } _ => {} } diff --git a/src/test/compile-fail/issue-17718-const-naming.rs b/src/test/compile-fail/issue-17718-const-naming.rs index 15f66493f8842..06719e2756b19 100644 --- a/src/test/compile-fail/issue-17718-const-naming.rs +++ b/src/test/compile-fail/issue-17718-const-naming.rs @@ -11,7 +11,7 @@ #[deny(warnings)] const foo: isize = 3; -//~^ ERROR: should have an uppercase name such as +//~^ ERROR: should have an upper case name such as //~^^ ERROR: constant item is never used fn main() {} diff --git a/src/test/compile-fail/lint-group-style.rs b/src/test/compile-fail/lint-group-style.rs index 24d16bcaafc1a..59ab5be1572a3 100644 --- a/src/test/compile-fail/lint-group-style.rs +++ b/src/test/compile-fail/lint-group-style.rs @@ -24,7 +24,7 @@ mod test { mod bad { fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name - static bad: isize = 1; //~ ERROR static constant `bad` should have an uppercase name + static bad: isize = 1; //~ ERROR static constant `bad` should have an upper case name } mod warn { diff --git a/src/test/compile-fail/lint-non-uppercase-statics.rs b/src/test/compile-fail/lint-non-uppercase-statics.rs index 10475f967d716..e1fbc73bbed15 100644 --- a/src/test/compile-fail/lint-non-uppercase-statics.rs +++ b/src/test/compile-fail/lint-non-uppercase-statics.rs @@ -11,6 +11,6 @@ #![forbid(non_upper_case_globals)] #![allow(dead_code)] -static foo: isize = 1; //~ ERROR static constant `foo` should have an uppercase name such as `FOO` +static foo: isize = 1; //~ ERROR static constant `foo` should have an upper case name such as `FOO` fn main() { } diff --git a/src/test/compile-fail/match-static-const-lc.rs b/src/test/compile-fail/match-static-const-lc.rs index 345c4aa69a720..04b234d8db7f1 100644 --- a/src/test/compile-fail/match-static-const-lc.rs +++ b/src/test/compile-fail/match-static-const-lc.rs @@ -19,7 +19,7 @@ pub const a : isize = 97; fn f() { let r = match (0,0) { (0, a) => 0, - //~^ ERROR static constant in pattern `a` should have an uppercase name such as `A` + //~^ ERROR constant in pattern `a` should have an upper case name such as `A` (x, y) => 1 + x + y, }; assert!(r == 1); @@ -34,7 +34,7 @@ fn g() { use self::m::aha; let r = match (0,0) { (0, aha) => 0, - //~^ ERROR static constant in pattern `aha` should have an uppercase name such as `AHA` + //~^ ERROR constant in pattern `aha` should have an upper case name such as `AHA` (x, y) => 1 + x + y, }; assert!(r == 1); @@ -48,7 +48,7 @@ fn h() { use self::n::OKAY as not_okay; let r = match (0,0) { (0, not_okay) => 0, -//~^ ERROR static constant in pattern `not_okay` should have an uppercase name such as `NOT_OKAY` +//~^ ERROR constant in pattern `not_okay` should have an upper case name such as `NOT_OKAY` (x, y) => 1 + x + y, }; assert!(r == 1); diff --git a/src/test/run-pass/snake-case-no-lowercase-equivalent.rs b/src/test/run-pass/snake-case-no-lowercase-equivalent.rs new file mode 100644 index 0000000000000..2220761a02666 --- /dev/null +++ b/src/test/run-pass/snake-case-no-lowercase-equivalent.rs @@ -0,0 +1,17 @@ +// Copyright 2014 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. + +#![feature(non_ascii_idents)] +#![deny(non_snake_case)] + +// This name is neither upper nor lower case +fn 你好() {} + +fn main() {}