about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-07-05 12:46:09 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-07-05 12:46:09 +0200
commit976d07e53e2e89b13a440d89dc4d942c87b946aa (patch)
treede9bb0c4a69bd3ce18623247c77b42a519359407
parented44fe52e4a730e4f892cde094fbba8ae8621589 (diff)
downloadrust-976d07e53e2e89b13a440d89dc4d942c87b946aa.tar.gz
rust-976d07e53e2e89b13a440d89dc4d942c87b946aa.zip
fix: Fix unresolved proc macro diagnostics pointing to macro expansions
-rw-r--r--crates/hir-expand/src/lib.rs80
-rw-r--r--crates/ide-assists/src/handlers/generate_function.rs2
-rw-r--r--crates/ide-assists/src/handlers/inline_call.rs2
-rw-r--r--crates/ide-db/src/search.rs6
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs14
5 files changed, 63 insertions, 41 deletions
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 0844e1f6254..8fcfad20095 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -778,36 +778,19 @@ impl<'a> InFile<&'a SyntaxNode> {
     /// For attributes and derives, this will point back to the attribute only.
     /// For the entire item `InFile::use original_file_range_full`.
     pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
-        if let Some(res) = self.original_file_range_opt(db) {
-            return res;
-        }
-
-        // Fall back to whole macro call.
         match self.file_id.0 {
             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
             HirFileIdRepr::MacroFile(mac_file) => {
+                if let Some(res) = self.original_file_range_opt(db) {
+                    return res;
+                }
+                // Fall back to whole macro call.
                 let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
                 loc.kind.original_call_range(db)
             }
         }
     }
 
-    /// Falls back to the macro call range if the node cannot be mapped up fully.
-    pub fn original_file_range_full(self, db: &dyn db::AstDatabase) -> FileRange {
-        if let Some(res) = self.original_file_range_opt(db) {
-            return res;
-        }
-
-        // Fall back to whole macro call.
-        match self.file_id.0 {
-            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
-            HirFileIdRepr::MacroFile(mac_file) => {
-                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
-                loc.kind.original_call_range_with_body(db)
-            }
-        }
-    }
-
     /// Attempts to map the syntax node back up its macro calls.
     pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
         match ascend_node_border_tokens(db, self) {
@@ -834,6 +817,49 @@ impl InFile<SyntaxToken> {
         let expansion = self.file_id.expansion_info(db)?;
         expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
     }
+
+    /// Falls back to the macro call range if the node cannot be mapped up fully.
+    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
+        match self.file_id.0 {
+            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
+            HirFileIdRepr::MacroFile(mac_file) => {
+                if let Some(res) = self.original_file_range_opt(db) {
+                    return res;
+                }
+                // Fall back to whole macro call.
+                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
+                loc.kind.original_call_range(db)
+            }
+        }
+    }
+
+    /// Attempts to map the syntax node back up its macro calls.
+    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
+        match self.file_id.0 {
+            HirFileIdRepr::FileId(file_id) => {
+                Some(FileRange { file_id, range: self.value.text_range() })
+            }
+            HirFileIdRepr::MacroFile(_) => {
+                let expansion = self.file_id.expansion_info(db)?;
+                let InFile { file_id, value } = ascend_call_token(db, &expansion, self)?;
+                let original_file = file_id.original_file(db);
+                if file_id != original_file.into() {
+                    return None;
+                }
+                Some(FileRange { file_id: original_file, range: value.text_range() })
+            }
+        }
+    }
+
+    pub fn ancestors_with_macros(
+        self,
+        db: &dyn db::AstDatabase,
+    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
+        self.value.parent().into_iter().flat_map({
+            let file_id = self.file_id;
+            move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
+        })
+    }
 }
 
 fn ascend_node_border_tokens(
@@ -867,18 +893,6 @@ fn ascend_call_token(
     None
 }
 
-impl InFile<SyntaxToken> {
-    pub fn ancestors_with_macros(
-        self,
-        db: &dyn db::AstDatabase,
-    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
-        self.value.parent().into_iter().flat_map({
-            let file_id = self.file_id;
-            move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
-        })
-    }
-}
-
 impl<N: AstNode> InFile<N> {
     pub fn descendants<T: AstNode>(self) -> impl Iterator<Item = InFile<T>> {
         self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs
index c8650979e95..061a4813447 100644
--- a/crates/ide-assists/src/handlers/generate_function.rs
+++ b/crates/ide-assists/src/handlers/generate_function.rs
@@ -176,7 +176,7 @@ fn get_adt_source(
     adt: &hir::Adt,
     fn_name: &str,
 ) -> Option<(Option<ast::Impl>, FileId)> {
-    let range = adt.source(ctx.sema.db)?.syntax().original_file_range_full(ctx.sema.db);
+    let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
     let file = ctx.sema.parse(range.file_id);
     let adt_source =
         ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index ab614b0ace9..c857adf876e 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -198,7 +198,7 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
     let fn_body = fn_source.value.body()?;
     let param_list = fn_source.value.param_list()?;
 
-    let FileRange { file_id, range } = fn_source.syntax().original_file_range_full(ctx.sema.db);
+    let FileRange { file_id, range } = fn_source.syntax().original_file_range(ctx.sema.db);
     if file_id == ctx.file_id() && range.contains(ctx.offset()) {
         cov_mark::hit!(inline_call_recursive);
         return None;
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index e6bd46347d9..4a11fb73cd6 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -239,14 +239,14 @@ impl Definition {
                 DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
             };
             return match def {
-                Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)),
+                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
                 None => SearchScope::single_file(file_id),
             };
         }
 
         if let Definition::SelfType(impl_) = self {
             return match impl_.source(db).map(|src| src.syntax().cloned()) {
-                Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)),
+                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
                 None => SearchScope::single_file(file_id),
             };
         }
@@ -262,7 +262,7 @@ impl Definition {
                 hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()),
             };
             return match def {
-                Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)),
+                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
                 None => SearchScope::single_file(file_id),
             };
         }
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
index fde3901a730..760f51f9049 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
@@ -1,4 +1,5 @@
 use hir::db::DefDatabase;
+use syntax::NodeOrToken;
 
 use crate::{Diagnostic, DiagnosticsContext, Severity};
 
@@ -18,9 +19,16 @@ pub(crate) fn unresolved_proc_macro(
     proc_attr_macros_enabled: bool,
 ) -> Diagnostic {
     // Use more accurate position if available.
-    let display_range = d
-        .precise_location
-        .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range);
+    let display_range = (|| {
+        let precise_location = d.precise_location?;
+        let root = ctx.sema.parse_or_expand(d.node.file_id)?;
+        match root.covering_element(precise_location) {
+            NodeOrToken::Node(it) => Some(ctx.sema.original_range(&it)),
+            NodeOrToken::Token(it) => d.node.with_value(it).original_file_range_opt(ctx.sema.db),
+        }
+    })()
+    .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()))
+    .range;
 
     let config_enabled = match d.kind {
         hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled,