Repository: rust-analyzer/rust-analyzer
Pull request #4111 (2020-04-23 21:27:32)

Record definitions in `extern` blocks
Enables completion of extern functions and statics.

Closes https://github.com/rust-analyzer/rust-analyzer/issues/3711

matklad: :heart_eyes: 

bors r+
matklad: `cargo fmt`
matklad: bors d+
bors[bot]: :v: jonas-schievink can now approve this pull request. To approve and merge a pull request, simply reply with `bors r+`. More detailed instructions are available [here](https://bors.tech/documentation/getting-started/#reviewing-pull-requests).

Patch:
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index afd538e4ac..39b011ad72 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -266,8 +266,8 @@ impl RawItemsCollector {
                 self.add_macro(current_module, it);
                 return;
             }
-            ast::ModuleItem::ExternBlock(_) => {
-                // FIXME: add extern block
+            ast::ModuleItem::ExternBlock(it) => {
+                self.add_extern_block(current_module, it);
                 return;
             }
         };
@@ -278,6 +278,34 @@ impl RawItemsCollector {
         }
     }
 
+    fn add_extern_block(
+        &mut self,
+        current_module: Option<Idx<ModuleData>>,
+        block: ast::ExternBlock,
+    ) {
+        if let Some(items) = block.extern_item_list() {
+            for item in items.extern_items() {
+                let attrs = self.parse_attrs(&item);
+                let visibility =
+                    RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
+                let (kind, name) = match item {
+                    ast::ExternItem::FnDef(it) => {
+                        (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
+                    }
+                    ast::ExternItem::StaticDef(it) => {
+                        (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
+                    }
+                };
+
+                if let Some(name) = name {
+                    let name = name.as_name();
+                    let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
+                    self.push_item(current_module, attrs, RawItemKind::Def(def));
+                }
+            }
+        }
+    }
+
     fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) {
         let name = match module.name() {
             Some(it) => it.as_name(),
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index ecbfffcf42..8d9812d241 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -30,6 +30,10 @@ impl SyntaxNodePtr {
         .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
     }
 
+    // pub fn range(&self) -> TextRange {
+    //     self.range
+    // }
+
     pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
         if !N::can_cast(self.kind) {
             return None;


Test patch:
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 949ca7595f..83120fa365 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -25,7 +25,7 @@ fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
 #[test]
 fn crate_def_map_smoke_test() {
     let map = def_map(
-        "
+        r"
         //- /lib.rs
         mod foo;
         struct S;
@@ -45,6 +45,11 @@ fn crate_def_map_smoke_test() {
         }
 
         enum E { V }
+
+        extern {
+            static EXT: u8;
+            fn ext();
+        }
         ",
     );
     assert_snapshot!(map, @r###"
@@ -61,7 +66,9 @@ fn crate_def_map_smoke_test() {
         ⋮crate::foo::bar
         ⋮Baz: t v
         ⋮E: t
+        ⋮EXT: v
         ⋮U: t v
+        ⋮ext: v
     "###)
 }