diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-09-17 14:00:25 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-09-17 14:00:25 +0100 |
commit | 933fc1eb1837a902def314d400c0f3a6dd2c1283 (patch) | |
tree | 95325c5d387fbbf13ac1caca9717e7ab0f3cdede /crates/hir_def/src/nameres.rs | |
parent | af92bdb8270f238fbb8af8c749bf6e9fc6a06710 (diff) | |
parent | 0dca7acf0fb65545f0c46f0c604bb15400aa6d91 (diff) |
Merge #6016
6016: Emit diagnostics for unresolved imports and extern crates r=jonas-schievink a=jonas-schievink
AFAIK, we don't have any major bugs in name resolution that would cause a lot of false positives here (except procedural attribute macro support and some rare issues around `#[path]` on module files), so these are *not* marked as experimental diagnostics right now.
I noticed that diagnostics in a file sometimes don't get displayed after opening, but require some edit to be performed. This seems like a preexisting issue though.
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r-- | crates/hir_def/src/nameres.rs | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index bf302172d..5e4d73c1f 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -288,31 +288,70 @@ pub enum ModuleSource { | |||
288 | 288 | ||
289 | mod diagnostics { | 289 | mod diagnostics { |
290 | use hir_expand::diagnostics::DiagnosticSink; | 290 | use hir_expand::diagnostics::DiagnosticSink; |
291 | use hir_expand::hygiene::Hygiene; | ||
292 | use hir_expand::InFile; | ||
291 | use syntax::{ast, AstPtr}; | 293 | use syntax::{ast, AstPtr}; |
292 | 294 | ||
293 | use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId}; | 295 | use crate::path::ModPath; |
296 | use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; | ||
294 | 297 | ||
295 | #[derive(Debug, PartialEq, Eq)] | 298 | #[derive(Debug, PartialEq, Eq)] |
296 | pub(super) enum DefDiagnostic { | 299 | enum DiagnosticKind { |
297 | UnresolvedModule { | 300 | UnresolvedModule { declaration: AstId<ast::Module>, candidate: String }, |
298 | module: LocalModuleId, | 301 | |
299 | declaration: AstId<ast::Module>, | 302 | UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, |
300 | candidate: String, | 303 | |
301 | }, | 304 | UnresolvedImport { ast: AstId<ast::Use>, index: usize }, |
305 | } | ||
306 | |||
307 | #[derive(Debug, PartialEq, Eq)] | ||
308 | pub(super) struct DefDiagnostic { | ||
309 | in_module: LocalModuleId, | ||
310 | kind: DiagnosticKind, | ||
302 | } | 311 | } |
303 | 312 | ||
304 | impl DefDiagnostic { | 313 | impl DefDiagnostic { |
314 | pub(super) fn unresolved_module( | ||
315 | container: LocalModuleId, | ||
316 | declaration: AstId<ast::Module>, | ||
317 | candidate: String, | ||
318 | ) -> Self { | ||
319 | Self { | ||
320 | in_module: container, | ||
321 | kind: DiagnosticKind::UnresolvedModule { declaration, candidate }, | ||
322 | } | ||
323 | } | ||
324 | |||
325 | pub(super) fn unresolved_extern_crate( | ||
326 | container: LocalModuleId, | ||
327 | declaration: AstId<ast::ExternCrate>, | ||
328 | ) -> Self { | ||
329 | Self { | ||
330 | in_module: container, | ||
331 | kind: DiagnosticKind::UnresolvedExternCrate { ast: declaration }, | ||
332 | } | ||
333 | } | ||
334 | |||
335 | pub(super) fn unresolved_import( | ||
336 | container: LocalModuleId, | ||
337 | ast: AstId<ast::Use>, | ||
338 | index: usize, | ||
339 | ) -> Self { | ||
340 | Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } } | ||
341 | } | ||
342 | |||
305 | pub(super) fn add_to( | 343 | pub(super) fn add_to( |
306 | &self, | 344 | &self, |
307 | db: &dyn DefDatabase, | 345 | db: &dyn DefDatabase, |
308 | target_module: LocalModuleId, | 346 | target_module: LocalModuleId, |
309 | sink: &mut DiagnosticSink, | 347 | sink: &mut DiagnosticSink, |
310 | ) { | 348 | ) { |
311 | match self { | 349 | if self.in_module != target_module { |
312 | DefDiagnostic::UnresolvedModule { module, declaration, candidate } => { | 350 | return; |
313 | if *module != target_module { | 351 | } |
314 | return; | 352 | |
315 | } | 353 | match &self.kind { |
354 | DiagnosticKind::UnresolvedModule { declaration, candidate } => { | ||
316 | let decl = declaration.to_node(db.upcast()); | 355 | let decl = declaration.to_node(db.upcast()); |
317 | sink.push(UnresolvedModule { | 356 | sink.push(UnresolvedModule { |
318 | file: declaration.file_id, | 357 | file: declaration.file_id, |
@@ -320,6 +359,36 @@ mod diagnostics { | |||
320 | candidate: candidate.clone(), | 359 | candidate: candidate.clone(), |
321 | }) | 360 | }) |
322 | } | 361 | } |
362 | |||
363 | DiagnosticKind::UnresolvedExternCrate { ast } => { | ||
364 | let item = ast.to_node(db.upcast()); | ||
365 | sink.push(UnresolvedExternCrate { | ||
366 | file: ast.file_id, | ||
367 | item: AstPtr::new(&item), | ||
368 | }); | ||
369 | } | ||
370 | |||
371 | DiagnosticKind::UnresolvedImport { ast, index } => { | ||
372 | let use_item = ast.to_node(db.upcast()); | ||
373 | let hygiene = Hygiene::new(db.upcast(), ast.file_id); | ||
374 | let mut cur = 0; | ||
375 | let mut tree = None; | ||
376 | ModPath::expand_use_item( | ||
377 | InFile::new(ast.file_id, use_item), | ||
378 | &hygiene, | ||
379 | |_mod_path, use_tree, _is_glob, _alias| { | ||
380 | if cur == *index { | ||
381 | tree = Some(use_tree.clone()); | ||
382 | } | ||
383 | |||
384 | cur += 1; | ||
385 | }, | ||
386 | ); | ||
387 | |||
388 | if let Some(tree) = tree { | ||
389 | sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) }); | ||
390 | } | ||
391 | } | ||
323 | } | 392 | } |
324 | } | 393 | } |
325 | } | 394 | } |