diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 52 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs | 38 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 6 |
3 files changed, 88 insertions, 8 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index d1c51849a..3a95f1b82 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -19,7 +19,7 @@ use hir_expand::{ | |||
19 | }; | 19 | }; |
20 | use syntax::{ | 20 | use syntax::{ |
21 | ast::{self, NameOwner}, | 21 | ast::{self, NameOwner}, |
22 | AstPtr, | 22 | AstNode, AstPtr, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | use crate::{ | 25 | use crate::{ |
@@ -259,6 +259,21 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
259 | if let Some(expr) = source_ptr.value.as_ref().left() { | 259 | if let Some(expr) = source_ptr.value.as_ref().left() { |
260 | let root = source_ptr.file_syntax(db.upcast()); | 260 | let root = source_ptr.file_syntax(db.upcast()); |
261 | if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { | 261 | if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { |
262 | let parent = match ident_pat.syntax().parent() { | ||
263 | Some(parent) => parent, | ||
264 | None => continue, | ||
265 | }; | ||
266 | |||
267 | // We have to check that it's either `let var = ...` or `Variant(_) @ var` statement, | ||
268 | // because e.g. match arms are patterns as well. | ||
269 | // In other words, we check that it's a named variable binding. | ||
270 | if !ast::LetStmt::cast(parent.clone()).is_some() | ||
271 | && !ast::IdentPat::cast(parent).is_some() | ||
272 | { | ||
273 | // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. | ||
274 | continue; | ||
275 | } | ||
276 | |||
262 | let diagnostic = IncorrectCase { | 277 | let diagnostic = IncorrectCase { |
263 | file: source_ptr.file_id, | 278 | file: source_ptr.file_id, |
264 | ident_type: "Variable".to_string(), | 279 | ident_type: "Variable".to_string(), |
@@ -663,7 +678,7 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | |||
663 | r#" | 678 | r#" |
664 | fn foo() { | 679 | fn foo() { |
665 | let SOME_VALUE = 10; | 680 | let SOME_VALUE = 10; |
666 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have a snake_case name, e.g. `some_value` | 681 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` |
667 | let AnotherValue = 20; | 682 | let AnotherValue = 20; |
668 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` | 683 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` |
669 | } | 684 | } |
@@ -761,4 +776,37 @@ impl someStruct { | |||
761 | "#, | 776 | "#, |
762 | ); | 777 | ); |
763 | } | 778 | } |
779 | |||
780 | #[test] | ||
781 | fn no_diagnostic_for_enum_varinats() { | ||
782 | check_diagnostics( | ||
783 | r#" | ||
784 | enum Option { Some, None } | ||
785 | |||
786 | fn main() { | ||
787 | match Option::None { | ||
788 | None => (), | ||
789 | Some => (), | ||
790 | } | ||
791 | } | ||
792 | "#, | ||
793 | ); | ||
794 | } | ||
795 | |||
796 | #[test] | ||
797 | fn non_let_bind() { | ||
798 | check_diagnostics( | ||
799 | r#" | ||
800 | enum Option { Some, None } | ||
801 | |||
802 | fn main() { | ||
803 | match Option::None { | ||
804 | None @ SOME_VAR => (), | ||
805 | // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` | ||
806 | Some => (), | ||
807 | } | ||
808 | } | ||
809 | "#, | ||
810 | ); | ||
811 | } | ||
764 | } | 812 | } |
diff --git a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs index e3826909b..8f70c5e84 100644 --- a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs +++ b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | //! Functions for string case manipulation, such as detecting the identifier case, | ||
2 | //! and converting it into appropriate form. | ||
3 | |||
1 | #[derive(Debug)] | 4 | #[derive(Debug)] |
2 | enum DetectedCase { | 5 | enum DetectedCase { |
3 | LowerCamelCase, | 6 | LowerCamelCase, |
@@ -44,6 +47,8 @@ fn detect_case(ident: &str) -> DetectedCase { | |||
44 | } | 47 | } |
45 | } | 48 | } |
46 | 49 | ||
50 | /// Converts an identifier to an UpperCamelCase form. | ||
51 | /// Returns `None` if the string is already is UpperCamelCase. | ||
47 | pub fn to_camel_case(ident: &str) -> Option<String> { | 52 | pub fn to_camel_case(ident: &str) -> Option<String> { |
48 | let detected_case = detect_case(ident); | 53 | let detected_case = detect_case(ident); |
49 | 54 | ||
@@ -87,9 +92,17 @@ pub fn to_camel_case(ident: &str) -> Option<String> { | |||
87 | } | 92 | } |
88 | } | 93 | } |
89 | 94 | ||
90 | Some(output) | 95 | if output == ident { |
96 | // While we didn't detect the correct case at the beginning, there | ||
97 | // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE. | ||
98 | None | ||
99 | } else { | ||
100 | Some(output) | ||
101 | } | ||
91 | } | 102 | } |
92 | 103 | ||
104 | /// Converts an identifier to a lower_snake_case form. | ||
105 | /// Returns `None` if the string is already is lower_snake_case. | ||
93 | pub fn to_lower_snake_case(ident: &str) -> Option<String> { | 106 | pub fn to_lower_snake_case(ident: &str) -> Option<String> { |
94 | // First, assume that it's UPPER_SNAKE_CASE. | 107 | // First, assume that it's UPPER_SNAKE_CASE. |
95 | match detect_case(ident) { | 108 | match detect_case(ident) { |
@@ -102,9 +115,18 @@ pub fn to_lower_snake_case(ident: &str) -> Option<String> { | |||
102 | 115 | ||
103 | // Otherwise, assume that it's CamelCase. | 116 | // Otherwise, assume that it's CamelCase. |
104 | let lower_snake_case = stdx::to_lower_snake_case(ident); | 117 | let lower_snake_case = stdx::to_lower_snake_case(ident); |
105 | Some(lower_snake_case) | 118 | |
119 | if lower_snake_case == ident { | ||
120 | // While we didn't detect the correct case at the beginning, there | ||
121 | // may be special cases: e.g. `a` is both valid camelCase and snake_case. | ||
122 | None | ||
123 | } else { | ||
124 | Some(lower_snake_case) | ||
125 | } | ||
106 | } | 126 | } |
107 | 127 | ||
128 | /// Converts an identifier to an UPPER_SNAKE_CASE form. | ||
129 | /// Returns `None` if the string is already is UPPER_SNAKE_CASE. | ||
108 | pub fn to_upper_snake_case(ident: &str) -> Option<String> { | 130 | pub fn to_upper_snake_case(ident: &str) -> Option<String> { |
109 | match detect_case(ident) { | 131 | match detect_case(ident) { |
110 | DetectedCase::UpperSnakeCase => return None, | 132 | DetectedCase::UpperSnakeCase => return None, |
@@ -117,7 +139,14 @@ pub fn to_upper_snake_case(ident: &str) -> Option<String> { | |||
117 | // Normalize the string from whatever form it's in currently, and then just make it uppercase. | 139 | // Normalize the string from whatever form it's in currently, and then just make it uppercase. |
118 | let upper_snake_case = | 140 | let upper_snake_case = |
119 | stdx::to_lower_snake_case(ident).chars().map(|c| c.to_ascii_uppercase()).collect(); | 141 | stdx::to_lower_snake_case(ident).chars().map(|c| c.to_ascii_uppercase()).collect(); |
120 | Some(upper_snake_case) | 142 | |
143 | if upper_snake_case == ident { | ||
144 | // While we didn't detect the correct case at the beginning, there | ||
145 | // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE. | ||
146 | None | ||
147 | } else { | ||
148 | Some(upper_snake_case) | ||
149 | } | ||
121 | } | 150 | } |
122 | 151 | ||
123 | #[cfg(test)] | 152 | #[cfg(test)] |
@@ -139,6 +168,7 @@ mod tests { | |||
139 | check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]); | 168 | check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]); |
140 | check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); | 169 | check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); |
141 | check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]); | 170 | check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]); |
171 | check(to_lower_snake_case, "a", expect![[""]]); | ||
142 | } | 172 | } |
143 | 173 | ||
144 | #[test] | 174 | #[test] |
@@ -151,6 +181,7 @@ mod tests { | |||
151 | check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]); | 181 | check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]); |
152 | check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]); | 182 | check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]); |
153 | check(to_camel_case, "name", expect![["Name"]]); | 183 | check(to_camel_case, "name", expect![["Name"]]); |
184 | check(to_camel_case, "A", expect![[""]]); | ||
154 | } | 185 | } |
155 | 186 | ||
156 | #[test] | 187 | #[test] |
@@ -160,5 +191,6 @@ mod tests { | |||
160 | check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]); | 191 | check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]); |
161 | check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]); | 192 | check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]); |
162 | check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]); | 193 | check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]); |
194 | check(to_upper_snake_case, "A", expect![[""]]); | ||
163 | } | 195 | } |
164 | } | 196 | } |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index 61ffbf5d1..21a121aad 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -190,13 +190,13 @@ struct Ty { | |||
190 | a: u8, | 190 | a: u8, |
191 | } | 191 | } |
192 | 192 | ||
193 | static mut static_mut: Ty = Ty { a: 0 }; | 193 | static mut STATIC_MUT: Ty = Ty { a: 0 }; |
194 | 194 | ||
195 | fn main() { | 195 | fn main() { |
196 | let x = static_mut.a; | 196 | let x = STATIC_MUT.a; |
197 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | 197 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block |
198 | unsafe { | 198 | unsafe { |
199 | let x = static_mut.a; | 199 | let x = STATIC_MUT.a; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | "#, | 202 | "#, |