aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics.rs
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 /crates/hir_ty/src/diagnostics.rs
parent6940cfed1e24a67e816e69e1093e04c0eb73e070 (diff)
internal: move diagnostics infra to hir
Diffstat (limited to 'crates/hir_ty/src/diagnostics.rs')
-rw-r--r--crates/hir_ty/src/diagnostics.rs156
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;
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}