From b8533413cf082f2d942b78af841e3895db252106 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 Nov 2019 23:11:05 +0300 Subject: Move Source to hir_expand --- crates/ra_hir_expand/src/lib.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir_expand') diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 5a0e5a19c..85c2b22ac 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -13,7 +13,10 @@ pub mod hygiene; use std::hash::{Hash, Hasher}; use ra_db::{salsa, CrateId, FileId}; -use ra_syntax::ast::{self, AstNode}; +use ra_syntax::{ + ast::{self, AstNode}, + SyntaxNode, +}; use crate::ast_id_map::FileAstId; @@ -151,3 +154,18 @@ impl AstId { db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) } } + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Source { + pub file_id: HirFileId, + pub ast: T, +} + +impl Source { + pub fn map U, U>(self, f: F) -> Source { + Source { file_id: self.file_id, ast: f(self.ast) } + } + pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { + db.parse_or_expand(self.file_id).expect("source created from invalid file") + } +} -- cgit v1.2.3 From 13735d91a78ba51fb202cb7dde1dfe25420afe9a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 Nov 2019 23:42:38 +0300 Subject: Move diagnostics to hir_expand --- crates/ra_hir_expand/src/diagnostics.rs | 85 +++++++++++++++++++++++++++++++++ crates/ra_hir_expand/src/lib.rs | 1 + 2 files changed, 86 insertions(+) create mode 100644 crates/ra_hir_expand/src/diagnostics.rs (limited to 'crates/ra_hir_expand') diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs new file mode 100644 index 000000000..201884b95 --- /dev/null +++ b/crates/ra_hir_expand/src/diagnostics.rs @@ -0,0 +1,85 @@ +//! Semantic errors and warnings. +//! +//! The `Diagnostic` trait defines a trait object which can represent any +//! diagnostic. +//! +//! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating +//! a `DiagnosticSink`, you supply a callback which can react to a `dyn +//! Diagnostic` or to any concrete diagnostic (downcasting is sued internally). +//! +//! Because diagnostics store file offsets, it's a bad idea to store them +//! directly in salsa. For this reason, every hir subsytem defines it's own +//! strongly-typed closed set of diagnostics which use hir ids internally, are +//! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a +//! subsystem provides a separate, non-query-based API which can walk all stored +//! values and transform them into instances of `Diagnostic`. + +use std::{any::Any, fmt}; + +use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; + +use crate::{db::AstDatabase, Source}; + +pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { + fn message(&self) -> String; + fn source(&self) -> Source; + fn highlight_range(&self) -> TextRange { + self.source().ast.range() + } + fn as_any(&self) -> &(dyn Any + Send + 'static); +} + +pub trait AstDiagnostic { + type AST; + fn ast(&self, db: &impl AstDatabase) -> Self::AST; +} + +impl dyn Diagnostic { + pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode { + let node = db.parse_or_expand(self.source().file_id).unwrap(); + self.source().ast.to_node(&node) + } + + pub fn downcast_ref(&self) -> Option<&D> { + self.as_any().downcast_ref() + } +} + +pub struct DiagnosticSink<'a> { + callbacks: Vec Result<(), ()> + 'a>>, + default_callback: Box, +} + +impl<'a> DiagnosticSink<'a> { + /// FIXME: split `new` and `on` into a separate builder type + pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { + DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } + } + + pub fn on(mut self, mut cb: F) -> DiagnosticSink<'a> { + let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::() { + Some(d) => { + cb(d); + Ok(()) + } + None => Err(()), + }; + self.callbacks.push(Box::new(cb)); + self + } + + pub fn push(&mut self, d: impl Diagnostic) { + let d: &dyn Diagnostic = &d; + self._push(d); + } + + fn _push(&mut self, d: &dyn Diagnostic) { + for cb in self.callbacks.iter_mut() { + match cb(d) { + Ok(()) => return, + Err(()) => (), + } + } + (self.default_callback)(d) + } +} diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 85c2b22ac..dd07a16b4 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -9,6 +9,7 @@ pub mod ast_id_map; pub mod either; pub mod name; pub mod hygiene; +pub mod diagnostics; use std::hash::{Hash, Hasher}; -- cgit v1.2.3