about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-01-14 10:08:27 +0000
committerGitHub <noreply@github.com>2022-01-14 10:08:27 +0000
commitfc331fe831820b33cb710575c90aa209833ca5c7 (patch)
tree74fdfc18bd4a5fdf17339ea63fb3286203c69577
parentb4c31481a554d0132003228ba319bd9476fe85ae (diff)
parentf1cb5ed9b036ea0bfe70fa331ec90032bc6f4c76 (diff)
downloadrust-fc331fe831820b33cb710575c90aa209833ca5c7.tar.gz
rust-fc331fe831820b33cb710575c90aa209833ca5c7.zip
Merge #11282
11282: fix: Properly cache files in Semantics when ascending macros r=Veykril a=Veykril

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11280
bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/hir/src/has_source.rs3
-rw-r--r--crates/hir/src/semantics.rs27
-rw-r--r--crates/hir_expand/src/lib.rs5
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs8
-rw-r--r--crates/ide_completion/src/render/macro_.rs14
5 files changed, 32 insertions, 25 deletions
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index a3f4a655132..8669b00ca1a 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -16,6 +16,9 @@ use crate::{
 
 pub trait HasSource {
     type Ast;
+    /// Fetches the definition's source node.
+    /// Using [`crate::Semantics::source`] is preferred when working with [`crate::Semantics`],
+    /// as that caches the parsed file in the semantics' cache.
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
 }
 
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 444fb4ea54c..9596e818185 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2,7 +2,7 @@
 
 mod source_to_def;
 
-use std::{cell::RefCell, fmt};
+use std::{cell::RefCell, fmt, iter};
 
 use base_db::{FileId, FileRange};
 use either::Either;
@@ -443,8 +443,7 @@ impl<'db> SemanticsImpl<'db> {
     fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
         let sa = self.analyze_no_infer(macro_call.syntax());
         let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
-        let node = self.db.parse_or_expand(file_id)?;
-        self.cache(node.clone(), file_id);
+        let node = self.parse_or_expand(file_id)?;
         Some(node)
     }
 
@@ -452,8 +451,7 @@ impl<'db> SemanticsImpl<'db> {
         let src = self.find_file(item.syntax()).with_value(item.clone());
         let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
         let file_id = macro_call_id.as_file();
-        let node = self.db.parse_or_expand(file_id)?;
-        self.cache(node.clone(), file_id);
+        let node = self.parse_or_expand(file_id)?;
         Some(node)
     }
 
@@ -750,10 +748,9 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
-        let root = self.db.parse_or_expand(src.file_id).unwrap();
-        let node = src.value.to_node(&root);
-        self.cache(root, src.file_id);
-        src.with_value(&node).original_file_range(self.db.upcast())
+        let root = self.parse_or_expand(src.file_id).unwrap();
+        let node = src.map(|it| it.to_node(&root));
+        node.as_ref().original_file_range(self.db.upcast())
     }
 
     fn token_ancestors_with_macros(
@@ -768,7 +765,17 @@ impl<'db> SemanticsImpl<'db> {
         node: SyntaxNode,
     ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
         let node = self.find_file(&node);
-        node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
+        let db = self.db.upcast();
+        iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| {
+            match value.parent() {
+                Some(parent) => Some(InFile::new(file_id, parent)),
+                None => {
+                    self.cache(value.clone(), file_id);
+                    file_id.call_node(db)
+                }
+            }
+        })
+        .map(|it| it.value)
     }
 
     fn ancestors_at_offset_with_macros(
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 5e49d3f6af7..b455fd59172 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -636,10 +636,7 @@ impl<'a> InFile<&'a SyntaxNode> {
     ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
         iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
             Some(parent) => Some(node.with_value(parent)),
-            None => {
-                let parent_node = node.file_id.call_node(db)?;
-                Some(parent_node)
-            }
+            None => node.file_id.call_node(db),
         })
     }
 
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index 46da7cfa372..b214c5c154a 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -31,7 +31,7 @@
 //! }
 //! ```
 
-use hir::{self, HasAttrs, HasSource};
+use hir::{self, HasAttrs};
 use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind};
 use syntax::{
     ast::{self, edit_in_place::AttrsOwnerEdit},
@@ -151,7 +151,7 @@ fn add_function_impl(
 
     let range = replacement_range(ctx, fn_def_node);
 
-    if let Some(source) = func.source(ctx.db) {
+    if let Some(source) = ctx.sema.source(func) {
         let assoc_item = ast::AssocItem::Fn(source.value);
         if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
             let transformed_fn = match transformed_item {
@@ -189,7 +189,7 @@ fn get_transformed_assoc_item(
         target_scope,
         source_scope,
         trait_,
-        impl_def.source(ctx.db)?.value,
+        ctx.sema.source(impl_def)?.value,
     );
 
     transform.apply(assoc_item.syntax());
@@ -227,7 +227,7 @@ fn add_const_impl(
     let const_name = const_.name(ctx.db).map(|n| n.to_smol_str());
 
     if let Some(const_name) = const_name {
-        if let Some(source) = const_.source(ctx.db) {
+        if let Some(source) = ctx.sema.source(const_) {
             let assoc_item = ast::AssocItem::Const(source.value);
             if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
                 let transformed_const = match transformed_item {
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 5386cbcb273..8d6a6349534 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -1,8 +1,8 @@
 //! Renderer for macro invocations.
 
 use either::Either;
-use hir::{db::HirDatabase, Documentation, HasSource};
-use ide_db::SymbolKind;
+use hir::{Documentation, HasSource, InFile, Semantics};
+use ide_db::{RootDatabase, SymbolKind};
 use syntax::{
     display::{fn_as_proc_macro_label, macro_label},
     SmolStr,
@@ -30,8 +30,6 @@ fn render(
     macro_: hir::MacroDef,
     import_to_add: Option<ImportEdit>,
 ) -> CompletionItem {
-    let db = completion.db;
-
     let source_range = if completion.is_immediately_after_macro_bang() {
         cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
         completion.token.parent().map_or_else(|| ctx.source_range(), |it| it.text_range())
@@ -54,7 +52,7 @@ fn render(
         label(&ctx, needs_bang, bra, ket, &name),
     );
     item.set_deprecated(ctx.is_deprecated(macro_))
-        .set_detail(detail(db, macro_))
+        .set_detail(detail(&completion.sema, macro_))
         .set_documentation(docs);
 
     if let Some(import_to_add) = import_to_add {
@@ -104,9 +102,11 @@ fn banged_name(name: &str) -> SmolStr {
     SmolStr::from_iter([name, "!"])
 }
 
-fn detail(db: &dyn HirDatabase, macro_: hir::MacroDef) -> Option<String> {
+fn detail(sema: &Semantics<RootDatabase>, macro_: hir::MacroDef) -> Option<String> {
     // FIXME: This is parsing the file!
-    let detail = match macro_.source(db)?.value {
+    let InFile { file_id, value } = macro_.source(sema.db)?;
+    let _ = sema.parse_or_expand(file_id);
+    let detail = match value {
         Either::Left(node) => macro_label(&node),
         Either::Right(node) => fn_as_proc_macro_label(&node),
     };