diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index a24c659689139..fea347f3e6de9 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -19,6 +19,7 @@ //! (/libgcc/unwind-c.c as of this writing) #![allow(non_upper_case_globals)] +#![cfg_attr(not(stage0), allow(misleading_constant_patterns))] #![allow(unused)] use dwarf::DwarfReader; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 71efc5654eff3..4f359c9706c7f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -139,6 +139,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NonCamelCaseTypes: NonCamelCaseTypes, NonSnakeCase: NonSnakeCase, NonUpperCaseGlobals: NonUpperCaseGlobals, + MisleadingConstantPatterns: MisleadingConstantPatterns, NonShorthandFieldPatterns: NonShorthandFieldPatterns, UnsafeCode: UnsafeCode, UnusedAllocation: UnusedAllocation, @@ -165,7 +166,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "nonstandard_style", NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, - NON_UPPER_CASE_GLOBALS); + NON_UPPER_CASE_GLOBALS, + MISLEADING_CONSTANT_PATTERNS); add_lint_group!(sess, "unused", diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 40781b0771d89..bfc84673ea2e9 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -16,6 +16,7 @@ use lint::{LintPass, LateLintPass}; use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; +use syntax::errors::Applicability; use syntax_pos::Span; use rustc::hir::{self, GenericParamKind, PatKind}; @@ -340,7 +341,7 @@ pub struct NonUpperCaseGlobals; impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) { - if name.as_str().chars().any(|c| c.is_lowercase()) { + if has_lower_case_chars(&name.as_str()) { let uc = NonSnakeCase::to_snake_case(&name.as_str()).to_uppercase(); if name != &*uc { cx.span_lint(NON_UPPER_CASE_GLOBALS, @@ -399,18 +400,64 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { _ => {} } } +} + +declare_lint! { + pub MISLEADING_CONSTANT_PATTERNS, + Warn, + "constants in patterns should have upper case identifiers" +} +#[derive(Copy, Clone)] +pub struct MisleadingConstantPatterns; + +impl MisleadingConstantPatterns { + fn check_upper_case(cx: &LateContext, name: ast::Name, span: Span) { + if has_lower_case_chars(&name.as_str()) { + let uc = NonSnakeCase::to_snake_case(&name.as_str()).to_uppercase(); + + cx.struct_span_lint( + MISLEADING_CONSTANT_PATTERNS, + span, + &format!("constant pattern `{}` should be upper case", name), + ) + .span_label(span, "looks like a binding") + .span_suggestion_with_applicability( + span, + "convert the pattern to upper case", + uc, + Applicability::MaybeIncorrect, + ) + .emit(); + } + } +} + +impl LintPass for MisleadingConstantPatterns { + fn get_lints(&self) -> LintArray { + lint_array!(MISLEADING_CONSTANT_PATTERNS) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MisleadingConstantPatterns { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { if let Def::Const(..) = path.def { if path.segments.len() == 1 { - NonUpperCaseGlobals::check_upper_case(cx, - "constant in pattern", - path.segments[0].ident.name, - path.span); + MisleadingConstantPatterns::check_upper_case( + cx, + path.segments[0].ident.name, + path.span, + ); } } } } } + +/// Returns whether a string contains any lower case characters. Note that this is different from +/// checking if a string is not fully upper case, since most scripts do not have case distinctions. +fn has_lower_case_chars(s: &str) -> bool { + s.chars().any(char::is_lowercase) +} diff --git a/src/test/run-pass/structs-enums/empty-struct-braces.rs b/src/test/run-pass/structs-enums/empty-struct-braces.rs index aebd1b70c3c7c..8196741669917 100644 --- a/src/test/run-pass/structs-enums/empty-struct-braces.rs +++ b/src/test/run-pass/structs-enums/empty-struct-braces.rs @@ -11,6 +11,7 @@ // run-pass #![allow(unused_variables)] #![allow(non_upper_case_globals)] +#![allow(misleading_constant_patterns)] // Empty struct defined with braces add names into type namespace // Empty struct defined without braces add names into both type and value namespaces diff --git a/src/test/run-pass/binding/match-static-const-rename.rs b/src/test/ui/lint/lint-misleading-constant-patterns.rs similarity index 57% rename from src/test/run-pass/binding/match-static-const-rename.rs rename to src/test/ui/lint/lint-misleading-constant-patterns.rs index 0d75c81b1e6db..260dc960ca82e 100644 --- a/src/test/run-pass/binding/match-static-const-rename.rs +++ b/src/test/ui/lint/lint-misleading-constant-patterns.rs @@ -8,21 +8,58 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// run-pass // Issue #7526: lowercase static constants in patterns look like bindings -// This is similar to compile-fail/match-static-const-lc, except it -// shows the expected usual workaround (choosing a different name for -// the static definition) and also demonstrates that one can work -// around this problem locally by renaming the constant in the `use` -// form to an uppercase identifier that placates the lint. +#![deny(misleading_constant_patterns)] +#![allow(dead_code)] +#[allow(non_upper_case_globals)] +pub const a : isize = 97; -#![deny(non_upper_case_globals)] +fn f() { + let r = match (0,0) { + (0, a) => 0, //~ ERROR should be upper case + //| HELP convert the pattern to upper case + //| SUGGESTION A + (x, y) => 1 + x + y, + }; + assert_eq!(r, 1); +} + +mod m { + #[allow(non_upper_case_globals)] + pub const aha : isize = 7; +} + +fn g() { + use self::m::aha; + let r = match (0,0) { + (0, aha) => 0, //~ ERROR should be upper case + //| HELP convert the pattern to upper case + //| SUGGESTION AHA + (x, y) => 1 + x + y, + }; + assert_eq!(r, 1); +} + +mod n { + pub const OKAY : isize = 8; +} + +fn h() { + use self::n::OKAY as not_okay; + let r = match (0,0) { + (0, not_okay) => 0, //~ ERROR should be upper case + //| HELP convert the pattern to upper case + //| SUGGESTION NOT_OKAY + (x, y) => 1 + x + y, + }; + assert_eq!(r, 1); +} pub const A : isize = 97; -fn f() { +fn i() { let r = match (0,0) { (0, A) => 0, (x, y) => 1 + x + y, @@ -35,12 +72,7 @@ fn f() { assert_eq!(r, 0); } -mod m { - #[allow(non_upper_case_globals)] - pub const aha : isize = 7; -} - -fn g() { +fn j() { use self::m::aha as AHA; let r = match (0,0) { (0, AHA) => 0, @@ -54,7 +86,7 @@ fn g() { assert_eq!(r, 0); } -fn h() { +fn k() { let r = match (0,0) { (0, self::m::aha) => 0, (x, y) => 1 + x + y, @@ -67,8 +99,4 @@ fn h() { assert_eq!(r, 0); } -pub fn main () { - f(); - g(); - h(); -} +fn main() {} diff --git a/src/test/ui/lint/lint-misleading-constant-patterns.stderr b/src/test/ui/lint/lint-misleading-constant-patterns.stderr new file mode 100644 index 0000000000000..7f625c6ab0c13 --- /dev/null +++ b/src/test/ui/lint/lint-misleading-constant-patterns.stderr @@ -0,0 +1,35 @@ +error: constant pattern `a` should be upper case + --> $DIR/lint-misleading-constant-patterns.rs:21:13 + | +LL | (0, a) => 0, //~ ERROR should be upper case + | ^ + | | + | looks like a binding + | help: convert the pattern to upper case: `A` + | +note: lint level defined here + --> $DIR/lint-misleading-constant-patterns.rs:13:9 + | +LL | #![deny(misleading_constant_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern `aha` should be upper case + --> $DIR/lint-misleading-constant-patterns.rs:37:13 + | +LL | (0, aha) => 0, //~ ERROR should be upper case + | ^^^ + | | + | looks like a binding + | help: convert the pattern to upper case: `AHA` + +error: constant pattern `not_okay` should be upper case + --> $DIR/lint-misleading-constant-patterns.rs:52:13 + | +LL | (0, not_okay) => 0, //~ ERROR should be upper case + | ^^^^^^^^ + | | + | looks like a binding + | help: convert the pattern to upper case: `NOT_OKAY` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/match/match-static-const-lc.rs b/src/test/ui/match/match-static-const-lc.rs deleted file mode 100644 index afc858c0c299e..0000000000000 --- a/src/test/ui/match/match-static-const-lc.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2012-2013 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. - -// Issue #7526: lowercase static constants in patterns look like bindings - -#![allow(dead_code)] -#![deny(non_upper_case_globals)] - -#[allow(non_upper_case_globals)] -pub const a : isize = 97; - -fn f() { - let r = match (0,0) { - (0, a) => 0, - //~^ ERROR constant in pattern `a` should have an upper case name such as `A` - (x, y) => 1 + x + y, - }; - assert_eq!(r, 1); -} - -mod m { - #[allow(non_upper_case_globals)] - pub const aha : isize = 7; -} - -fn g() { - use self::m::aha; - let r = match (0,0) { - (0, aha) => 0, - //~^ ERROR constant in pattern `aha` should have an upper case name such as `AHA` - (x, y) => 1 + x + y, - }; - assert_eq!(r, 1); -} - -mod n { - pub const OKAY : isize = 8; -} - -fn h() { - use self::n::OKAY as not_okay; - let r = match (0,0) { - (0, not_okay) => 0, -//~^ ERROR constant in pattern `not_okay` should have an upper case name such as `NOT_OKAY` - (x, y) => 1 + x + y, - }; - assert_eq!(r, 1); -} - -fn main () { - f(); - g(); - h(); -} diff --git a/src/test/ui/match/match-static-const-lc.stderr b/src/test/ui/match/match-static-const-lc.stderr deleted file mode 100644 index 08eb5712875e8..0000000000000 --- a/src/test/ui/match/match-static-const-lc.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: constant in pattern `a` should have an upper case name such as `A` - --> $DIR/match-static-const-lc.rs:21:13 - | -LL | (0, a) => 0, - | ^ - | -note: lint level defined here - --> $DIR/match-static-const-lc.rs:14:9 - | -LL | #![deny(non_upper_case_globals)] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: constant in pattern `aha` should have an upper case name such as `AHA` - --> $DIR/match-static-const-lc.rs:36:13 - | -LL | (0, aha) => 0, - | ^^^ - -error: constant in pattern `not_okay` should have an upper case name such as `NOT_OKAY` - --> $DIR/match-static-const-lc.rs:50:13 - | -LL | (0, not_okay) => 0, - | ^^^^^^^^ - -error: aborting due to 3 previous errors -