-
Notifications
You must be signed in to change notification settings - Fork 15
Remove diagnostics when documents change #441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<ReferenceId, ConstantReference>, | ||
| // Map of method references that still need to be resolved | ||
| method_references: IdentityHashMap<ReferenceId, MethodRef>, | ||
|
|
||
| diagnostics: Vec<Diagnostic>, | ||
| diagnostics: IdentityHashMap<DiagnosticId, Diagnostic>, | ||
| } | ||
|
|
||
| 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<Diagnostic> { | ||
| &self.diagnostics | ||
| pub fn diagnostics(&self) -> Vec<&Diagnostic> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can probably change this one to return the |
||
| 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 { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should register the diagnostics inside of the documents during indexing using the |
||
| 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(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be a problem.
Indexing diagnostics are indeed related to a specific document but resolution may not. They are more "global".
Take this example:
We have a circular dependency diagnostic and both documents participate to the error.
Let's say we put the error in
file1.rb, then you updatefile2.rbto change the code toYou'll have to figure out you need to discard the diagnostic in
file1.rb.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. Maybe we need diagnostics to be a top level node in the graph so that multiple other nodes can have edges to it?
For example, maybe indexing diagnostics get associated with documents and resolution diagnostics with declarations.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks both. I pushed an alternative approach that keeps diagnostics at the top level, but indexed by
DiagnosticIdfor lookup purposes.I used URI/offset/code/message to generate the ID. However, this is not guaranteed to be unique by Prism which we use for parse error diagnostics. In some cases Prism has previously attached identical looking errors at the same location (even though they stem from different issues in the source code). Perhaps that would be considered a Prism bug and we don't care about attaching multiple instances of seemingly identical errors?
Do you think they would be linked to the document as well, or just the declaration? Will there always be a suitable declaration for resolution issues?
Another option would be to have a
DiagnosticGroupIdwhich links together diagnostics for problems that span multiple documents. We could have anIdentityHashMap<DiagnosticGroupID, Vec[DiagnosticId]>index in the graph and eachDiagnosticcould store an optionalgroup_id. In the cyclic references example there would be a separateDiagnosticin bothfile1.rbandfile2.rbboth with the samegroup_id.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we attached the resolution diagnostics to the declarations instead of the graph?
That way when we remove a definition we also reset the declaration diagnostics before running the resolution again?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☝️ that's what I was thinking too
I believe if we make diagnostics a hashmap and allow documents and declarations to associate with them, we can account for indexing and resolution cases.
We can probably make this PR just about indexing ones though and then follow up with the resolution part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
For this one I don't know if it will be enough.
Let's consider this code:
This is a resolution error (we need to have tried to resolve
Footo know it doesn't exist). But we don't really have a Declaration to attach the error? Or maybe it would be inObject?Then if we later add the constant, the diagnostic should disappear:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vinistock and I just discussed that maybe we could attach diagnostics to any of documents, declarations, definitions, and constant references, depending on the type of issue. I am also going to take a look at how ty and Pyre to understand how they do it too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, it would make sense to have diagnostics attached to all possible nodes:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just opened a draft PR here with that alternative approach.