aboutsummaryrefslogtreecommitdiff
path: root/crates/hir/src/lib.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-05-23 21:31:59 +0100
committerAleksey Kladov <[email protected]>2021-05-25 15:49:59 +0100
commit5c9f31d4c28478b4373e6cf5ec155745c840ee3f (patch)
tree6d105121d271c7532170875feafaadcd7ad500ba /crates/hir/src/lib.rs
parentb7414fa14a85f4acd37b5bdfdc2a4ab97a072bd2 (diff)
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and `DiagnosticSink` infrastructure altogether, and just have a `enum hir::Diagnostic` instead. The problem with `dyn Diagnostic` is that it is defined in the lowest level of the stack (hir_expand), but is used by the highest level (ide). As a first step, we free hir_expand and hir_def from `dyn Diagnostic` and kick the can up to `hir_ty`, as an intermediate state. The plan is then to move DiagnosticSink similarly to the hir crate, and, as final third step, remove its usage from the ide. One currently unsolved problem is testing. You can notice that the test which checks precise diagnostic ranges, unresolved_import_in_use_tree, was moved to the ide layer. Logically, only IDE should have the infra to render a specific range. At the same time, the range is determined with the data produced in hir_def and hir crates, so this layering is rather unfortunate. Working on hir_def shouldn't require compiling `ide` for testing.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs176
1 files changed, 172 insertions, 4 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index cdf65a044..1ecd2391b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,12 +35,18 @@ use std::{iter, sync::Arc};
35 35
36use arrayvec::ArrayVec; 36use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 37use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 InactiveCode, MacroError, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
40 UnresolvedModule, UnresolvedProcMacro,
41};
38use either::Either; 42use either::Either;
39use hir_def::{ 43use hir_def::{
40 adt::{ReprKind, VariantData}, 44 adt::{ReprKind, VariantData},
45 body::BodyDiagnostic,
41 expr::{BindingAnnotation, LabelId, Pat, PatId}, 46 expr::{BindingAnnotation, LabelId, Pat, PatId},
42 item_tree::ItemTreeNode, 47 item_tree::ItemTreeNode,
43 lang_item::LangItemTarget, 48 lang_item::LangItemTarget,
49 nameres,
44 per_ns::PerNs, 50 per_ns::PerNs,
45 resolver::{HasResolver, Resolver}, 51 resolver::{HasResolver, Resolver},
46 src::HasSource as _, 52 src::HasSource as _,
@@ -50,11 +56,12 @@ use hir_def::{
50 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 56 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
51 TypeParamId, UnionId, 57 TypeParamId, UnionId,
52}; 58};
53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 59use hir_expand::{name::name, MacroCallKind, MacroDefKind};
54use hir_ty::{ 60use hir_ty::{
55 autoderef, 61 autoderef,
56 consteval::ConstExt, 62 consteval::ConstExt,
57 could_unify, 63 could_unify,
64 diagnostics_sink::DiagnosticSink,
58 method_resolution::{self, def_crates, TyFingerprint}, 65 method_resolution::{self, def_crates, TyFingerprint},
59 primitive::UintTy, 66 primitive::UintTy,
60 subst_prefix, 67 subst_prefix,
@@ -65,11 +72,12 @@ use hir_ty::{
65 WhereClause, 72 WhereClause,
66}; 73};
67use itertools::Itertools; 74use itertools::Itertools;
75use nameres::diagnostics::DefDiagnosticKind;
68use rustc_hash::FxHashSet; 76use rustc_hash::FxHashSet;
69use stdx::{format_to, impl_from}; 77use stdx::{format_to, impl_from};
70use syntax::{ 78use syntax::{
71 ast::{self, AttrsOwner, NameOwner}, 79 ast::{self, AttrsOwner, NameOwner},
72 AstNode, SmolStr, 80 AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
73}; 81};
74use tt::{Ident, Leaf, Literal, TokenTree}; 82use tt::{Ident, Leaf, Literal, TokenTree};
75 83
@@ -442,7 +450,137 @@ impl Module {
442 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 450 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
443 }); 451 });
444 let def_map = self.id.def_map(db.upcast()); 452 let def_map = self.id.def_map(db.upcast());
445 def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 453 for diag in def_map.diagnostics() {
454 if diag.in_module != self.id.local_id {
455 // FIXME: This is accidentally quadratic.
456 continue;
457 }
458 match &diag.kind {
459 DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
460 let decl = declaration.to_node(db.upcast());
461 sink.push(UnresolvedModule {
462 file: declaration.file_id,
463 decl: AstPtr::new(&decl),
464 candidate: candidate.clone(),
465 })
466 }
467 DefDiagnosticKind::UnresolvedExternCrate { ast } => {
468 let item = ast.to_node(db.upcast());
469 sink.push(UnresolvedExternCrate {
470 file: ast.file_id,
471 item: AstPtr::new(&item),
472 });
473 }
474
475 DefDiagnosticKind::UnresolvedImport { ast, index } => {
476 let use_item = ast.to_node(db.upcast());
477 let hygiene = Hygiene::new(db.upcast(), ast.file_id);
478 let mut cur = 0;
479 let mut tree = None;
480 ModPath::expand_use_item(
481 db.upcast(),
482 InFile::new(ast.file_id, use_item),
483 &hygiene,
484 |_mod_path, use_tree, _is_glob, _alias| {
485 if cur == *index {
486 tree = Some(use_tree.clone());
487 }
488
489 cur += 1;
490 },
491 );
492
493 if let Some(tree) = tree {
494 sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
495 }
496 }
497
498 DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
499 let item = ast.to_node(db.upcast());
500 sink.push(InactiveCode {
501 file: ast.file_id,
502 node: AstPtr::new(&item).into(),
503 cfg: cfg.clone(),
504 opts: opts.clone(),
505 });
506 }
507
508 DefDiagnosticKind::UnresolvedProcMacro { ast } => {
509 let mut precise_location = None;
510 let (file, ast, name) = match ast {
511 MacroCallKind::FnLike { ast_id, .. } => {
512 let node = ast_id.to_node(db.upcast());
513 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
514 }
515 MacroCallKind::Derive { ast_id, derive_name, .. } => {
516 let node = ast_id.to_node(db.upcast());
517
518 // Compute the precise location of the macro name's token in the derive
519 // list.
520 // FIXME: This does not handle paths to the macro, but neither does the
521 // rest of r-a.
522 let derive_attrs =
523 node.attrs().filter_map(|attr| match attr.as_simple_call() {
524 Some((name, args)) if name == "derive" => Some(args),
525 _ => None,
526 });
527 'outer: for attr in derive_attrs {
528 let tokens =
529 attr.syntax().children_with_tokens().filter_map(|elem| {
530 match elem {
531 syntax::NodeOrToken::Node(_) => None,
532 syntax::NodeOrToken::Token(tok) => Some(tok),
533 }
534 });
535 for token in tokens {
536 if token.kind() == SyntaxKind::IDENT
537 && token.text() == derive_name.as_str()
538 {
539 precise_location = Some(token.text_range());
540 break 'outer;
541 }
542 }
543 }
544
545 (
546 ast_id.file_id,
547 SyntaxNodePtr::from(AstPtr::new(&node)),
548 Some(derive_name.clone()),
549 )
550 }
551 };
552 sink.push(UnresolvedProcMacro {
553 file,
554 node: ast,
555 precise_location,
556 macro_name: name,
557 });
558 }
559
560 DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
561 let node = ast.to_node(db.upcast());
562 sink.push(UnresolvedMacroCall {
563 file: ast.file_id,
564 node: AstPtr::new(&node),
565 path: path.clone(),
566 });
567 }
568
569 DefDiagnosticKind::MacroError { ast, message } => {
570 let (file, ast) = match ast {
571 MacroCallKind::FnLike { ast_id, .. } => {
572 let node = ast_id.to_node(db.upcast());
573 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
574 }
575 MacroCallKind::Derive { ast_id, .. } => {
576 let node = ast_id.to_node(db.upcast());
577 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
578 }
579 };
580 sink.push(MacroError { file, node: ast, message: message.clone() });
581 }
582 }
583 }
446 for decl in self.declarations(db) { 584 for decl in self.declarations(db) {
447 match decl { 585 match decl {
448 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 586 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@@ -865,7 +1003,37 @@ impl Function {
865 1003
866 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 1004 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
867 let krate = self.module(db).id.krate(); 1005 let krate = self.module(db).id.krate();
868 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); 1006
1007 let source_map = db.body_with_source_map(self.id.into()).1;
1008 for diag in source_map.diagnostics() {
1009 match diag {
1010 BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode {
1011 file: node.file_id,
1012 node: node.value.clone(),
1013 cfg: cfg.clone(),
1014 opts: opts.clone(),
1015 }),
1016 BodyDiagnostic::MacroError { node, message } => sink.push(MacroError {
1017 file: node.file_id,
1018 node: node.value.clone().into(),
1019 message: message.to_string(),
1020 }),
1021 BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro {
1022 file: node.file_id,
1023 node: node.value.clone().into(),
1024 precise_location: None,
1025 macro_name: None,
1026 }),
1027 BodyDiagnostic::UnresolvedMacroCall { node, path } => {
1028 sink.push(UnresolvedMacroCall {
1029 file: node.file_id,
1030 node: node.value.clone(),
1031 path: path.clone(),
1032 })
1033 }
1034 }
1035 }
1036
869 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 1037 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
870 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 1038 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
871 } 1039 }