diff --git a/rust/rubydex/src/diagnostic.rs b/rust/rubydex/src/diagnostic.rs index 208b4a994..3f9cbe566 100644 --- a/rust/rubydex/src/diagnostic.rs +++ b/rust/rubydex/src/diagnostic.rs @@ -1,4 +1,4 @@ -use crate::{model::ids::UriId, offset::Offset}; +use crate::{model::ids::{DiagnosticId, UriId}, offset::Offset}; #[derive(Debug)] pub struct Diagnostic { @@ -26,6 +26,11 @@ impl Diagnostic { Self::new(diagnostics.code(), uri_id, offset, message, diagnostics.severity()) } + #[must_use] + pub fn id(&self) -> DiagnosticId { + DiagnosticId::from(&format!("{}{}{}{}", *self.uri_id, self.offset.start(), self.code, self.message)) + } + #[must_use] pub fn code(&self) -> u16 { self.code diff --git a/rust/rubydex/src/model/document.rs b/rust/rubydex/src/model/document.rs index cf8505744..aeb578ec4 100644 --- a/rust/rubydex/src/model/document.rs +++ b/rust/rubydex/src/model/document.rs @@ -1,4 +1,4 @@ -use crate::model::ids::{DefinitionId, ReferenceId}; +use crate::model::ids::{DefinitionId, DiagnosticId, ReferenceId}; // Represents a document currently loaded into memory. Identified by its unique URI, it holds the edges to all // definitions and references discovered in it @@ -8,6 +8,7 @@ pub struct Document { definition_ids: Vec, method_reference_ids: Vec, constant_reference_ids: Vec, + diagnostic_ids: Vec, } impl Document { @@ -18,6 +19,7 @@ impl Document { definition_ids: Vec::new(), method_reference_ids: Vec::new(), constant_reference_ids: Vec::new(), + diagnostic_ids: Vec::new(), } } @@ -57,6 +59,15 @@ impl Document { pub fn add_constant_reference(&mut self, reference_id: ReferenceId) { self.constant_reference_ids.push(reference_id); } + + #[must_use] + pub fn diagnostic_ids(&self) -> &[DiagnosticId] { + &self.diagnostic_ids + } + + pub fn add_diagnostic_id(&mut self, diagnostic_id: DiagnosticId) { + self.diagnostic_ids.push(diagnostic_id); + } } #[cfg(test)] diff --git a/rust/rubydex/src/model/graph.rs b/rust/rubydex/src/model/graph.rs index 4fcebd2be..f78280574 100644 --- a/rust/rubydex/src/model/graph.rs +++ b/rust/rubydex/src/model/graph.rs @@ -7,7 +7,7 @@ use crate::model::declaration::Declaration; use crate::model::definitions::Definition; use crate::model::document::Document; use crate::model::identity_maps::IdentityHashMap; -use crate::model::ids::{DeclarationId, DefinitionId, NameId, ReferenceId, StringId, UriId}; +use crate::model::ids::{DeclarationId, DefinitionId, DiagnosticId, NameId, ReferenceId, StringId, UriId}; use crate::model::name::{NameRef, ResolvedName}; // use crate::model::integrity::IntegrityChecker; use crate::model::references::{ConstantReference, MethodRef}; @@ -38,8 +38,7 @@ pub struct Graph { constant_references: IdentityHashMap, // Map of method references that still need to be resolved method_references: IdentityHashMap, - - diagnostics: Vec, + diagnostics: IdentityHashMap, } impl Graph { @@ -54,7 +53,7 @@ impl Graph { names: IdentityHashMap::default(), constant_references: IdentityHashMap::default(), method_references: IdentityHashMap::default(), - diagnostics: Vec::new(), + diagnostics: IdentityHashMap::default(), } } @@ -162,8 +161,8 @@ impl Graph { } #[must_use] - pub fn diagnostics(&self) -> &Vec { - &self.diagnostics + pub fn diagnostics(&self) -> Vec<&Diagnostic> { + self.diagnostics.values().collect() } /// # Panics @@ -266,16 +265,20 @@ impl Graph { /// Merges everything in `other` into this Graph. This method is meant to merge all graph representations from /// different threads, but not meant to handle updates to the existing global representation pub fn extend(&mut self, local_graph: LocalGraph) { - let (uri_id, document, definitions, strings, names, constant_references, method_references, diagnostics) = + let (uri_id, mut document, definitions, strings, names, constant_references, method_references, diagnostics) = local_graph.into_parts(); + for diagnostic in diagnostics { + document.add_diagnostic_id(diagnostic.id()); + self.diagnostics.insert(diagnostic.id(), diagnostic); + } + self.documents.insert(uri_id, document); self.definitions.extend(definitions); self.strings.extend(strings); self.names.extend(names); self.constant_references.extend(constant_references); self.method_references.extend(method_references); - self.diagnostics.extend(diagnostics); } /// Updates the global representation with the information contained in `other`, handling deletions, insertions and @@ -296,6 +299,10 @@ impl Graph { return; }; + for diagnostic_id in document.diagnostic_ids() { + self.diagnostics.remove(diagnostic_id); + } + let mut write_lock = self.declarations.write().unwrap(); // TODO: Remove method references from method declarations once method inference is implemented @@ -616,6 +623,21 @@ mod tests { context.graph().assert_integrity(); } + #[test] + fn updating_index_with_deleted_diagnostics() { + let mut context = GraphTest::new(); + + context.index_uri("file:///foo.rb", "class Foo"); + assert!(!context.graph().diagnostics().is_empty()); + let document = context.graph().documents().get(&UriId::from("file:///foo.rb")).unwrap(); + assert!(!document.diagnostic_ids().is_empty()); + + context.index_uri("file:///foo.rb", "class Foo; end"); + assert!(context.graph().diagnostics().is_empty()); + let document = context.graph().documents().get(&UriId::from("file:///foo.rb")).unwrap(); + assert!(document.diagnostic_ids().is_empty()); + } + #[test] fn updating_index_with_new_definitions() { let mut context = GraphTest::new(); diff --git a/rust/rubydex/src/model/ids.rs b/rust/rubydex/src/model/ids.rs index 032a32865..290ef14fc 100644 --- a/rust/rubydex/src/model/ids.rs +++ b/rust/rubydex/src/model/ids.rs @@ -30,3 +30,8 @@ pub type ReferenceId = Id; pub struct NameMarker; /// `NameId` represents an ID for any constant name that we find as part of a reference or definition pub type NameId = Id; + +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub struct DiagnosticMarker; +/// `DiagnosticId` represents the ID of a diagnostic found in a specific file +pub type DiagnosticId = Id;