diff options
author | Aleksey Kladov <[email protected]> | 2021-06-12 20:05:23 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-12 20:05:23 +0100 |
commit | 7731714578d4ae6eb7a54ead2e51ae032e9a700a (patch) | |
tree | f8dc2d68cfc72c1fcb839ec85093fb49f479663d /crates/hir_ty/src/diagnostics.rs | |
parent | 6940cfed1e24a67e816e69e1093e04c0eb73e070 (diff) |
internal: move diagnostics infra to hir
Diffstat (limited to 'crates/hir_ty/src/diagnostics.rs')
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 156 |
1 files changed, 7 insertions, 149 deletions
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; | |||
4 | mod unsafe_check; | 4 | mod unsafe_check; |
5 | mod decl_check; | 5 | mod decl_check; |
6 | 6 | ||
7 | use std::{any::Any, fmt}; | 7 | use std::fmt; |
8 | 8 | ||
9 | use base_db::CrateId; | 9 | use base_db::CrateId; |
10 | use hir_def::ModuleDefId; | 10 | use hir_def::ModuleDefId; |
11 | use hir_expand::{HirFileId, InFile}; | 11 | use hir_expand::HirFileId; |
12 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 12 | use syntax::{ast, AstPtr}; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::db::HirDatabase; |
15 | db::HirDatabase, | ||
16 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, | ||
17 | }; | ||
18 | 15 | ||
19 | pub use crate::diagnostics::{ | 16 | pub 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 | |||
103 | impl 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)] | ||
132 | mod 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 | ||
219 | mod permissions; | ||
220 | |||
221 | use permissions::jwt; | ||
222 | |||
223 | fn 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 | ||
229 | pub mod jwt { | ||
230 | pub struct Claims {} | ||
231 | } | ||
232 | |||
233 | //- /jwt/lib.rs crate:jwt | ||
234 | pub struct Claims { | ||
235 | field: u8, | ||
236 | } | ||
237 | "#, | ||
238 | ); | ||
239 | } | ||
240 | } | ||