aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-12 20:05:23 +0100
committerAleksey Kladov <[email protected]>2021-06-12 20:05:23 +0100
commit7731714578d4ae6eb7a54ead2e51ae032e9a700a (patch)
treef8dc2d68cfc72c1fcb839ec85093fb49f479663d
parent6940cfed1e24a67e816e69e1093e04c0eb73e070 (diff)
internal: move diagnostics infra to hir
-rw-r--r--crates/hir/src/diagnostics.rs35
-rw-r--r--crates/hir/src/diagnostics_sink.rs (renamed from crates/hir_ty/src/diagnostics_sink.rs)0
-rw-r--r--crates/hir/src/lib.rs32
-rw-r--r--crates/hir_ty/src/diagnostics.rs156
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs359
-rw-r--r--crates/hir_ty/src/lib.rs1
-rw-r--r--crates/ide/src/diagnostics.rs354
7 files changed, 417 insertions, 520 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 26dbcd86a..8a7c3a4fd 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -11,9 +11,8 @@ use hir_expand::{name::Name, HirFileId, InFile};
11use stdx::format_to; 11use stdx::format_to;
12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
13 13
14pub use hir_ty::{ 14pub use crate::diagnostics_sink::{
15 diagnostics::IncorrectCase, 15 Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
16 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder},
17}; 16};
18 17
19// Diagnostic: unresolved-module 18// Diagnostic: unresolved-module
@@ -578,3 +577,33 @@ impl Diagnostic for InternalBailedOut {
578 self 577 self
579 } 578 }
580} 579}
580
581pub use hir_ty::diagnostics::IncorrectCase;
582
583impl Diagnostic for IncorrectCase {
584 fn code(&self) -> DiagnosticCode {
585 DiagnosticCode("incorrect-ident-case")
586 }
587
588 fn message(&self) -> String {
589 format!(
590 "{} `{}` should have {} name, e.g. `{}`",
591 self.ident_type,
592 self.ident_text,
593 self.expected_case.to_string(),
594 self.suggested_text
595 )
596 }
597
598 fn display_source(&self) -> InFile<SyntaxNodePtr> {
599 InFile::new(self.file, self.ident.clone().into())
600 }
601
602 fn as_any(&self) -> &(dyn Any + Send + 'static) {
603 self
604 }
605
606 fn is_experimental(&self) -> bool {
607 true
608 }
609}
diff --git a/crates/hir_ty/src/diagnostics_sink.rs b/crates/hir/src/diagnostics_sink.rs
index 084fa8b06..084fa8b06 100644
--- a/crates/hir_ty/src/diagnostics_sink.rs
+++ b/crates/hir/src/diagnostics_sink.rs
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index dd5515c2b..2468c0dc6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -27,6 +27,7 @@ mod attrs;
27mod has_source; 27mod has_source;
28 28
29pub mod diagnostics; 29pub mod diagnostics;
30pub mod diagnostics_sink;
30pub mod db; 31pub mod db;
31 32
32mod display; 33mod display;
@@ -35,13 +36,6 @@ use std::{iter, sync::Arc};
35 36
36use arrayvec::ArrayVec; 37use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 38use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount,
40 MissingFields, MissingOkOrSomeInTailExpr, MissingPatFields, MissingUnsafe, NoSuchField,
41 RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnimplementedBuiltinMacro,
42 UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
43 UnresolvedProcMacro,
44};
45use either::Either; 39use either::Either;
46use hir_def::{ 40use hir_def::{
47 adt::{ReprKind, VariantData}, 41 adt::{ReprKind, VariantData},
@@ -64,8 +58,7 @@ use hir_ty::{
64 consteval::ConstExt, 58 consteval::ConstExt,
65 could_unify, 59 could_unify,
66 diagnostics::BodyValidationDiagnostic, 60 diagnostics::BodyValidationDiagnostic,
67 diagnostics_sink::DiagnosticSink, 61 method_resolution::{self, TyFingerprint},
68 method_resolution::{self, def_crates, TyFingerprint},
69 primitive::UintTy, 62 primitive::UintTy,
70 subst_prefix, 63 subst_prefix,
71 traits::FnTrait, 64 traits::FnTrait,
@@ -87,7 +80,14 @@ use tt::{Ident, Leaf, Literal, TokenTree};
87 80
88use crate::{ 81use crate::{
89 db::{DefDatabase, HirDatabase}, 82 db::{DefDatabase, HirDatabase},
90 diagnostics::MissingMatchArms, 83 diagnostics::{
84 BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount,
85 MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, MissingPatFields,
86 MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
87 UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
88 UnresolvedModule, UnresolvedProcMacro,
89 },
90 diagnostics_sink::DiagnosticSink,
91}; 91};
92 92
93pub use crate::{ 93pub use crate::{
@@ -361,7 +361,9 @@ impl ModuleDef {
361 None => return, 361 None => return,
362 }; 362 };
363 363
364 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) 364 for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) {
365 sink.push(diag)
366 }
365 } 367 }
366} 368}
367 369
@@ -1225,7 +1227,9 @@ impl Function {
1225 } 1227 }
1226 } 1228 }
1227 1229
1228 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 1230 for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
1231 sink.push(diag)
1232 }
1229 } 1233 }
1230 1234
1231 /// Whether this function declaration has a definition. 1235 /// Whether this function declaration has a definition.
@@ -1944,7 +1948,7 @@ impl Impl {
1944 } 1948 }
1945 1949
1946 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { 1950 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> {
1947 let def_crates = match def_crates(db, &ty, krate) { 1951 let def_crates = match method_resolution::def_crates(db, &ty, krate) {
1948 Some(def_crates) => def_crates, 1952 Some(def_crates) => def_crates,
1949 None => return Vec::new(), 1953 None => return Vec::new(),
1950 }; 1954 };
@@ -2350,7 +2354,7 @@ impl Type {
2350 krate: Crate, 2354 krate: Crate,
2351 mut callback: impl FnMut(AssocItem) -> Option<T>, 2355 mut callback: impl FnMut(AssocItem) -> Option<T>,
2352 ) -> Option<T> { 2356 ) -> Option<T> {
2353 for krate in def_crates(db, &self.ty, krate.id)? { 2357 for krate in method_resolution::def_crates(db, &self.ty, krate.id)? {
2354 let impls = db.inherent_impls_in_crate(krate); 2358 let impls = db.inherent_impls_in_crate(krate);
2355 2359
2356 for impl_def in impls.for_self_ty(&self.ty) { 2360 for impl_def in impls.for_self_ty(&self.ty) {
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index f3236bc06..407273943 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -4,17 +4,14 @@ mod match_check;
4mod unsafe_check; 4mod unsafe_check;
5mod decl_check; 5mod decl_check;
6 6
7use std::{any::Any, fmt}; 7use std::fmt;
8 8
9use base_db::CrateId; 9use base_db::CrateId;
10use hir_def::ModuleDefId; 10use hir_def::ModuleDefId;
11use hir_expand::{HirFileId, InFile}; 11use hir_expand::HirFileId;
12use syntax::{ast, AstPtr, SyntaxNodePtr}; 12use syntax::{ast, AstPtr};
13 13
14use crate::{ 14use crate::db::HirDatabase;
15 db::HirDatabase,
16 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
17};
18 15
19pub use crate::diagnostics::{ 16pub use crate::diagnostics::{
20 expr::{ 17 expr::{
@@ -27,11 +24,11 @@ pub fn validate_module_item(
27 db: &dyn HirDatabase, 24 db: &dyn HirDatabase,
28 krate: CrateId, 25 krate: CrateId,
29 owner: ModuleDefId, 26 owner: ModuleDefId,
30 sink: &mut DiagnosticSink<'_>, 27) -> Vec<IncorrectCase> {
31) {
32 let _p = profile::span("validate_module_item"); 28 let _p = profile::span("validate_module_item");
33 let mut validator = decl_check::DeclValidator::new(db, krate, sink); 29 let mut validator = decl_check::DeclValidator::new(db, krate);
34 validator.validate_item(owner); 30 validator.validate_item(owner);
31 validator.sink
35} 32}
36 33
37#[derive(Debug)] 34#[derive(Debug)]
@@ -99,142 +96,3 @@ pub struct IncorrectCase {
99 pub ident_text: String, 96 pub ident_text: String,
100 pub suggested_text: String, 97 pub suggested_text: String,
101} 98}
102
103impl Diagnostic for IncorrectCase {
104 fn code(&self) -> DiagnosticCode {
105 DiagnosticCode("incorrect-ident-case")
106 }
107
108 fn message(&self) -> String {
109 format!(
110 "{} `{}` should have {} name, e.g. `{}`",
111 self.ident_type,
112 self.ident_text,
113 self.expected_case.to_string(),
114 self.suggested_text
115 )
116 }
117
118 fn display_source(&self) -> InFile<SyntaxNodePtr> {
119 InFile::new(self.file, self.ident.clone().into())
120 }
121
122 fn as_any(&self) -> &(dyn Any + Send + 'static) {
123 self
124 }
125
126 fn is_experimental(&self) -> bool {
127 true
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
134 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
135 use hir_expand::db::AstDatabase;
136 use rustc_hash::FxHashMap;
137 use syntax::{TextRange, TextSize};
138
139 use crate::{
140 diagnostics::validate_module_item,
141 diagnostics_sink::{Diagnostic, DiagnosticSinkBuilder},
142 test_db::TestDB,
143 };
144
145 impl TestDB {
146 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
147 let crate_graph = self.crate_graph();
148 for krate in crate_graph.iter() {
149 let crate_def_map = self.crate_def_map(krate);
150
151 let mut fns = Vec::new();
152 for (module_id, _) in crate_def_map.modules() {
153 for decl in crate_def_map[module_id].scope.declarations() {
154 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
155 validate_module_item(self, krate, decl, &mut sink);
156
157 if let ModuleDefId::FunctionId(f) = decl {
158 fns.push(f)
159 }
160 }
161
162 for impl_id in crate_def_map[module_id].scope.impls() {
163 let impl_data = self.impl_data(impl_id);
164 for item in impl_data.items.iter() {
165 if let AssocItemId::FunctionId(f) = item {
166 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
167 validate_module_item(
168 self,
169 krate,
170 ModuleDefId::FunctionId(*f),
171 &mut sink,
172 );
173 fns.push(*f)
174 }
175 }
176 }
177 }
178 }
179 }
180 }
181
182 pub(crate) fn check_diagnostics(ra_fixture: &str) {
183 let db = TestDB::with_files(ra_fixture);
184 let annotations = db.extract_annotations();
185
186 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
187 db.diagnostics(|d| {
188 let src = d.display_source();
189 let root = db.parse_or_expand(src.file_id).unwrap();
190 // FIXME: macros...
191 let file_id = src.file_id.original_file(&db);
192 let range = src.value.to_node(&root).text_range();
193 let message = d.message();
194 actual.entry(file_id).or_default().push((range, message));
195 });
196
197 for (file_id, diags) in actual.iter_mut() {
198 diags.sort_by_key(|it| it.0.start());
199 let text = db.file_text(*file_id);
200 // For multiline spans, place them on line start
201 for (range, content) in diags {
202 if text[*range].contains('\n') {
203 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
204 *content = format!("... {}", content);
205 }
206 }
207 }
208
209 assert_eq!(annotations, actual);
210 }
211
212 #[test]
213 fn import_extern_crate_clash_with_inner_item() {
214 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
215
216 check_diagnostics(
217 r#"
218//- /lib.rs crate:lib deps:jwt
219mod permissions;
220
221use permissions::jwt;
222
223fn f() {
224 fn inner() {}
225 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
226}
227
228//- /permissions.rs
229pub mod jwt {
230 pub struct Claims {}
231}
232
233//- /jwt/lib.rs crate:jwt
234pub struct Claims {
235 field: u8,
236}
237 "#,
238 );
239 }
240}
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index cfb5d7320..ca452e879 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -29,7 +29,6 @@ use syntax::{
29use crate::{ 29use crate::{
30 db::HirDatabase, 30 db::HirDatabase,
31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, 31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase},
32 diagnostics_sink::DiagnosticSink,
33}; 32};
34 33
35mod allow { 34mod allow {
@@ -40,10 +39,10 @@ mod allow {
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 39 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
41} 40}
42 41
43pub(super) struct DeclValidator<'a, 'b> { 42pub(super) struct DeclValidator<'a> {
44 db: &'a dyn HirDatabase, 43 db: &'a dyn HirDatabase,
45 krate: CrateId, 44 krate: CrateId,
46 sink: &'a mut DiagnosticSink<'b>, 45 pub(super) sink: Vec<IncorrectCase>,
47} 46}
48 47
49#[derive(Debug)] 48#[derive(Debug)]
@@ -53,13 +52,9 @@ struct Replacement {
53 expected_case: CaseType, 52 expected_case: CaseType,
54} 53}
55 54
56impl<'a, 'b> DeclValidator<'a, 'b> { 55impl<'a> DeclValidator<'a> {
57 pub(super) fn new( 56 pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
58 db: &'a dyn HirDatabase, 57 DeclValidator { db, krate, sink: Vec::new() }
59 krate: CrateId,
60 sink: &'a mut DiagnosticSink<'b>,
61 ) -> DeclValidator<'a, 'b> {
62 DeclValidator { db, krate, sink }
63 } 58 }
64 59
65 pub(super) fn validate_item(&mut self, item: ModuleDefId) { 60 pub(super) fn validate_item(&mut self, item: ModuleDefId) {
@@ -121,7 +116,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
121 fn validate_func(&mut self, func: FunctionId) { 116 fn validate_func(&mut self, func: FunctionId) {
122 let data = self.db.function_data(func); 117 let data = self.db.function_data(func);
123 if data.is_in_extern_block() { 118 if data.is_in_extern_block() {
124 cov_mark::hit!(extern_func_incorrect_case_ignored);
125 return; 119 return;
126 } 120 }
127 121
@@ -131,7 +125,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
131 for (_, block_def_map) in body.blocks(self.db.upcast()) { 125 for (_, block_def_map) in body.blocks(self.db.upcast()) {
132 for (_, module) in block_def_map.modules() { 126 for (_, module) in block_def_map.modules() {
133 for def_id in module.scope.declarations() { 127 for def_id in module.scope.declarations() {
134 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 128 let mut validator = DeclValidator::new(self.db, self.krate);
135 validator.validate_item(def_id); 129 validator.validate_item(def_id);
136 } 130 }
137 } 131 }
@@ -578,7 +572,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
578 fn validate_static(&mut self, static_id: StaticId) { 572 fn validate_static(&mut self, static_id: StaticId) {
579 let data = self.db.static_data(static_id); 573 let data = self.db.static_data(static_id);
580 if data.is_extern { 574 if data.is_extern {
581 cov_mark::hit!(extern_static_incorrect_case_ignored);
582 return; 575 return;
583 } 576 }
584 577
@@ -623,343 +616,3 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
623 self.sink.push(diagnostic); 616 self.sink.push(diagnostic);
624 } 617 }
625} 618}
626
627#[cfg(test)]
628mod tests {
629 use crate::diagnostics::tests::check_diagnostics;
630
631 #[test]
632 fn incorrect_function_name() {
633 check_diagnostics(
634 r#"
635fn NonSnakeCaseName() {}
636// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
637"#,
638 );
639 }
640
641 #[test]
642 fn incorrect_function_params() {
643 check_diagnostics(
644 r#"
645fn foo(SomeParam: u8) {}
646 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
647
648fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
649 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
650"#,
651 );
652 }
653
654 #[test]
655 fn incorrect_variable_names() {
656 check_diagnostics(
657 r#"
658fn foo() {
659 let SOME_VALUE = 10;
660 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
661 let AnotherValue = 20;
662 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
663}
664"#,
665 );
666 }
667
668 #[test]
669 fn incorrect_struct_names() {
670 check_diagnostics(
671 r#"
672struct non_camel_case_name {}
673 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
674
675struct SCREAMING_CASE {}
676 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
677"#,
678 );
679 }
680
681 #[test]
682 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
683 check_diagnostics(
684 r#"
685struct AABB {}
686"#,
687 );
688 }
689
690 #[test]
691 fn incorrect_struct_field() {
692 check_diagnostics(
693 r#"
694struct SomeStruct { SomeField: u8 }
695 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
696"#,
697 );
698 }
699
700 #[test]
701 fn incorrect_enum_names() {
702 check_diagnostics(
703 r#"
704enum some_enum { Val(u8) }
705 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
706
707enum SOME_ENUM
708 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
709"#,
710 );
711 }
712
713 #[test]
714 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
715 check_diagnostics(
716 r#"
717enum AABB {}
718"#,
719 );
720 }
721
722 #[test]
723 fn incorrect_enum_variant_name() {
724 check_diagnostics(
725 r#"
726enum SomeEnum { SOME_VARIANT(u8) }
727 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
728"#,
729 );
730 }
731
732 #[test]
733 fn incorrect_const_name() {
734 check_diagnostics(
735 r#"
736const some_weird_const: u8 = 10;
737 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
738
739fn func() {
740 const someConstInFunc: &str = "hi there";
741 // ^^^^^^^^^^^^^^^ Constant `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
742
743}
744"#,
745 );
746 }
747
748 #[test]
749 fn incorrect_static_name() {
750 check_diagnostics(
751 r#"
752static some_weird_const: u8 = 10;
753 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
754
755fn func() {
756 static someConstInFunc: &str = "hi there";
757 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
758}
759"#,
760 );
761 }
762
763 #[test]
764 fn fn_inside_impl_struct() {
765 check_diagnostics(
766 r#"
767struct someStruct;
768 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
769
770impl someStruct {
771 fn SomeFunc(&self) {
772 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
773 static someConstInFunc: &str = "hi there";
774 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
775 let WHY_VAR_IS_CAPS = 10;
776 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
777 }
778}
779"#,
780 );
781 }
782
783 #[test]
784 fn no_diagnostic_for_enum_varinats() {
785 check_diagnostics(
786 r#"
787enum Option { Some, None }
788
789fn main() {
790 match Option::None {
791 None => (),
792 Some => (),
793 }
794}
795"#,
796 );
797 }
798
799 #[test]
800 fn non_let_bind() {
801 check_diagnostics(
802 r#"
803enum Option { Some, None }
804
805fn main() {
806 match Option::None {
807 SOME_VAR @ None => (),
808 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
809 Some => (),
810 }
811}
812"#,
813 );
814 }
815
816 #[test]
817 fn allow_attributes() {
818 check_diagnostics(
819 r#"
820#[allow(non_snake_case)]
821fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
822 // cov_flags generated output from elsewhere in this file
823 extern "C" {
824 #[no_mangle]
825 static lower_case: u8;
826 }
827
828 let OtherVar = SOME_VAR + 1;
829 OtherVar
830}
831
832#[allow(nonstandard_style)]
833mod CheckNonstandardStyle {
834 fn HiImABadFnName() {}
835}
836
837#[allow(bad_style)]
838mod CheckBadStyle {
839 fn HiImABadFnName() {}
840}
841
842mod F {
843 #![allow(non_snake_case)]
844 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
845}
846
847#[allow(non_snake_case, non_camel_case_types)]
848pub struct some_type {
849 SOME_FIELD: u8,
850 SomeField: u16,
851}
852
853#[allow(non_upper_case_globals)]
854pub const some_const: u8 = 10;
855
856#[allow(non_upper_case_globals)]
857pub static SomeStatic: u8 = 10;
858 "#,
859 );
860 }
861
862 #[test]
863 fn allow_attributes_crate_attr() {
864 check_diagnostics(
865 r#"
866#![allow(non_snake_case)]
867
868mod F {
869 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
870}
871 "#,
872 );
873 }
874
875 #[test]
876 #[ignore]
877 fn bug_trait_inside_fn() {
878 // FIXME:
879 // This is broken, and in fact, should not even be looked at by this
880 // lint in the first place. There's weird stuff going on in the
881 // collection phase.
882 // It's currently being brought in by:
883 // * validate_func on `a` recursing into modules
884 // * then it finds the trait and then the function while iterating
885 // through modules
886 // * then validate_func is called on Dirty
887 // * ... which then proceeds to look at some unknown module taking no
888 // attrs from either the impl or the fn a, and then finally to the root
889 // module
890 //
891 // It should find the attribute on the trait, but it *doesn't even see
892 // the trait* as far as I can tell.
893
894 check_diagnostics(
895 r#"
896trait T { fn a(); }
897struct U {}
898impl T for U {
899 fn a() {
900 // this comes out of bitflags, mostly
901 #[allow(non_snake_case)]
902 trait __BitFlags {
903 const HiImAlsoBad: u8 = 2;
904 #[inline]
905 fn Dirty(&self) -> bool {
906 false
907 }
908 }
909
910 }
911}
912 "#,
913 );
914 }
915
916 #[test]
917 #[ignore]
918 fn bug_traits_arent_checked() {
919 // FIXME: Traits and functions in traits aren't currently checked by
920 // r-a, even though rustc will complain about them.
921 check_diagnostics(
922 r#"
923trait BAD_TRAIT {
924 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
925 fn BAD_FUNCTION();
926 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
927 fn BadFunction();
928 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
929}
930 "#,
931 );
932 }
933
934 #[test]
935 fn ignores_extern_items() {
936 cov_mark::check!(extern_func_incorrect_case_ignored);
937 cov_mark::check!(extern_static_incorrect_case_ignored);
938 check_diagnostics(
939 r#"
940extern {
941 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
942 pub static SomeStatic: u8 = 10;
943}
944 "#,
945 );
946 }
947
948 #[test]
949 fn infinite_loop_inner_items() {
950 check_diagnostics(
951 r#"
952fn qualify() {
953 mod foo {
954 use super::*;
955 }
956}
957 "#,
958 )
959 }
960
961 #[test] // Issue #8809.
962 fn parenthesized_parameter() {
963 check_diagnostics(r#"fn f((O): _) {}"#)
964 }
965}
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 0c6b19653..128cae830 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -21,7 +21,6 @@ mod utils;
21mod walk; 21mod walk;
22pub mod db; 22pub mod db;
23pub mod diagnostics; 23pub mod diagnostics;
24pub mod diagnostics_sink;
25pub mod display; 24pub mod display;
26pub mod method_resolution; 25pub mod method_resolution;
27pub mod primitive; 26pub mod primitive;
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index dffb6fdc8..e34341631 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -1338,6 +1338,35 @@ fn main() {
1338 "#, 1338 "#,
1339 ); 1339 );
1340 } 1340 }
1341
1342 #[test]
1343 fn import_extern_crate_clash_with_inner_item() {
1344 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
1345
1346 check_diagnostics(
1347 r#"
1348//- /lib.rs crate:lib deps:jwt
1349mod permissions;
1350
1351use permissions::jwt;
1352
1353fn f() {
1354 fn inner() {}
1355 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
1356}
1357
1358//- /permissions.rs
1359pub mod jwt {
1360 pub struct Claims {}
1361}
1362
1363//- /jwt/lib.rs crate:jwt
1364pub struct Claims {
1365 field: u8,
1366}
1367 "#,
1368 );
1369 }
1341} 1370}
1342 1371
1343#[cfg(test)] 1372#[cfg(test)]
@@ -2245,3 +2274,328 @@ fn main() {
2245 } 2274 }
2246 } 2275 }
2247} 2276}
2277
2278#[cfg(test)]
2279mod decl_check_tests {
2280 use crate::diagnostics::tests::check_diagnostics;
2281
2282 #[test]
2283 fn incorrect_function_name() {
2284 check_diagnostics(
2285 r#"
2286fn NonSnakeCaseName() {}
2287// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
2288"#,
2289 );
2290 }
2291
2292 #[test]
2293 fn incorrect_function_params() {
2294 check_diagnostics(
2295 r#"
2296fn foo(SomeParam: u8) {}
2297 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
2298
2299fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
2300 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
2301"#,
2302 );
2303 }
2304
2305 #[test]
2306 fn incorrect_variable_names() {
2307 check_diagnostics(
2308 r#"
2309fn foo() {
2310 let SOME_VALUE = 10;
2311 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
2312 let AnotherValue = 20;
2313 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
2314}
2315"#,
2316 );
2317 }
2318
2319 #[test]
2320 fn incorrect_struct_names() {
2321 check_diagnostics(
2322 r#"
2323struct non_camel_case_name {}
2324 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
2325
2326struct SCREAMING_CASE {}
2327 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
2328"#,
2329 );
2330 }
2331
2332 #[test]
2333 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
2334 check_diagnostics(
2335 r#"
2336struct AABB {}
2337"#,
2338 );
2339 }
2340
2341 #[test]
2342 fn incorrect_struct_field() {
2343 check_diagnostics(
2344 r#"
2345struct SomeStruct { SomeField: u8 }
2346 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
2347"#,
2348 );
2349 }
2350
2351 #[test]
2352 fn incorrect_enum_names() {
2353 check_diagnostics(
2354 r#"
2355enum some_enum { Val(u8) }
2356 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
2357
2358enum SOME_ENUM {}
2359 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
2360"#,
2361 );
2362 }
2363
2364 #[test]
2365 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
2366 check_diagnostics(
2367 r#"
2368enum AABB {}
2369"#,
2370 );
2371 }
2372
2373 #[test]
2374 fn incorrect_enum_variant_name() {
2375 check_diagnostics(
2376 r#"
2377enum SomeEnum { SOME_VARIANT(u8) }
2378 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
2379"#,
2380 );
2381 }
2382
2383 #[test]
2384 fn incorrect_const_name() {
2385 check_diagnostics(
2386 r#"
2387const some_weird_const: u8 = 10;
2388 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2389"#,
2390 );
2391 }
2392
2393 #[test]
2394 fn incorrect_static_name() {
2395 check_diagnostics(
2396 r#"
2397static some_weird_const: u8 = 10;
2398 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2399"#,
2400 );
2401 }
2402
2403 #[test]
2404 fn fn_inside_impl_struct() {
2405 check_diagnostics(
2406 r#"
2407struct someStruct;
2408 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
2409
2410impl someStruct {
2411 fn SomeFunc(&self) {
2412 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
2413 let WHY_VAR_IS_CAPS = 10;
2414 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
2415 }
2416}
2417"#,
2418 );
2419 }
2420
2421 #[test]
2422 fn no_diagnostic_for_enum_varinats() {
2423 check_diagnostics(
2424 r#"
2425enum Option { Some, None }
2426
2427fn main() {
2428 match Option::None {
2429 None => (),
2430 Some => (),
2431 }
2432}
2433"#,
2434 );
2435 }
2436
2437 #[test]
2438 fn non_let_bind() {
2439 check_diagnostics(
2440 r#"
2441enum Option { Some, None }
2442
2443fn main() {
2444 match Option::None {
2445 SOME_VAR @ None => (),
2446 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
2447 Some => (),
2448 }
2449}
2450"#,
2451 );
2452 }
2453
2454 #[test]
2455 fn allow_attributes() {
2456 check_diagnostics(
2457 r#"
2458#[allow(non_snake_case)]
2459fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
2460 // cov_flags generated output from elsewhere in this file
2461 extern "C" {
2462 #[no_mangle]
2463 static lower_case: u8;
2464 }
2465
2466 let OtherVar = SOME_VAR + 1;
2467 OtherVar
2468}
2469
2470#[allow(nonstandard_style)]
2471mod CheckNonstandardStyle {
2472 fn HiImABadFnName() {}
2473}
2474
2475#[allow(bad_style)]
2476mod CheckBadStyle {
2477 fn HiImABadFnName() {}
2478}
2479
2480mod F {
2481 #![allow(non_snake_case)]
2482 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
2483}
2484
2485#[allow(non_snake_case, non_camel_case_types)]
2486pub struct some_type {
2487 SOME_FIELD: u8,
2488 SomeField: u16,
2489}
2490
2491#[allow(non_upper_case_globals)]
2492pub const some_const: u8 = 10;
2493
2494#[allow(non_upper_case_globals)]
2495pub static SomeStatic: u8 = 10;
2496 "#,
2497 );
2498 }
2499
2500 #[test]
2501 fn allow_attributes_crate_attr() {
2502 check_diagnostics(
2503 r#"
2504#![allow(non_snake_case)]
2505
2506mod F {
2507 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
2508}
2509 "#,
2510 );
2511 }
2512
2513 #[test]
2514 #[ignore]
2515 fn bug_trait_inside_fn() {
2516 // FIXME:
2517 // This is broken, and in fact, should not even be looked at by this
2518 // lint in the first place. There's weird stuff going on in the
2519 // collection phase.
2520 // It's currently being brought in by:
2521 // * validate_func on `a` recursing into modules
2522 // * then it finds the trait and then the function while iterating
2523 // through modules
2524 // * then validate_func is called on Dirty
2525 // * ... which then proceeds to look at some unknown module taking no
2526 // attrs from either the impl or the fn a, and then finally to the root
2527 // module
2528 //
2529 // It should find the attribute on the trait, but it *doesn't even see
2530 // the trait* as far as I can tell.
2531
2532 check_diagnostics(
2533 r#"
2534trait T { fn a(); }
2535struct U {}
2536impl T for U {
2537 fn a() {
2538 // this comes out of bitflags, mostly
2539 #[allow(non_snake_case)]
2540 trait __BitFlags {
2541 const HiImAlsoBad: u8 = 2;
2542 #[inline]
2543 fn Dirty(&self) -> bool {
2544 false
2545 }
2546 }
2547
2548 }
2549}
2550 "#,
2551 );
2552 }
2553
2554 #[test]
2555 #[ignore]
2556 fn bug_traits_arent_checked() {
2557 // FIXME: Traits and functions in traits aren't currently checked by
2558 // r-a, even though rustc will complain about them.
2559 check_diagnostics(
2560 r#"
2561trait BAD_TRAIT {
2562 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
2563 fn BAD_FUNCTION();
2564 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
2565 fn BadFunction();
2566 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
2567}
2568 "#,
2569 );
2570 }
2571
2572 #[test]
2573 fn ignores_extern_items() {
2574 check_diagnostics(
2575 r#"
2576extern {
2577 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
2578 pub static SomeStatic: u8 = 10;
2579}
2580 "#,
2581 );
2582 }
2583
2584 #[test]
2585 fn infinite_loop_inner_items() {
2586 check_diagnostics(
2587 r#"
2588fn qualify() {
2589 mod foo {
2590 use super::*;
2591 }
2592}
2593 "#,
2594 )
2595 }
2596
2597 #[test] // Issue #8809.
2598 fn parenthesized_parameter() {
2599 check_diagnostics(r#"fn f((O): _) {}"#)
2600 }
2601}