From 82146737acc74b2483f39f1dd0ae4dfffcfda824 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Wed, 20 Jan 2021 20:05:48 +0100
Subject: Treat BlockExpr as a potential module origin

---
 crates/assists/src/handlers/generate_function.rs | 19 ++++++++++++++-----
 crates/hir_def/src/attr.rs                       |  1 +
 crates/hir_def/src/nameres.rs                    | 12 ++++++++++--
 crates/ide/src/display/navigation_target.rs      |  1 +
 crates/ide/src/display/short_label.rs            |  6 ++++++
 crates/ide/src/hover.rs                          |  1 +
 crates/ide/src/runnables.rs                      |  1 +
 crates/ide_db/src/search.rs                      | 10 ++++++++++
 8 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index 06ac85f67..1805c1dfd 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -158,11 +158,11 @@ impl FunctionBuilder {
                 it.text_range().end()
             }
             GeneratedFunctionTarget::InEmptyItemList(it) => {
-                let indent = IndentLevel::from_node(it.syntax());
+                let indent = IndentLevel::from_node(&it);
                 leading_ws = format!("\n{}", indent + 1);
                 fn_def = fn_def.indent(indent + 1);
                 trailing_ws = format!("\n{}", indent);
-                it.syntax().text_range().start() + TextSize::of('{')
+                it.text_range().start() + TextSize::of('{')
             }
         };
 
@@ -179,14 +179,14 @@ impl FunctionBuilder {
 
 enum GeneratedFunctionTarget {
     BehindItem(SyntaxNode),
-    InEmptyItemList(ast::ItemList),
+    InEmptyItemList(SyntaxNode),
 }
 
 impl GeneratedFunctionTarget {
     fn syntax(&self) -> &SyntaxNode {
         match self {
             GeneratedFunctionTarget::BehindItem(it) => it,
-            GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(),
+            GeneratedFunctionTarget::InEmptyItemList(it) => it,
         }
     }
 }
@@ -323,7 +323,16 @@ fn next_space_for_fn_in_module(
             if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) {
                 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
             } else {
-                GeneratedFunctionTarget::InEmptyItemList(it.item_list()?)
+                GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone())
+            }
+        }
+        hir::ModuleSource::BlockExpr(it) => {
+            if let Some(last_item) =
+                it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
+            {
+                GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
+            } else {
+                GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
             }
         }
     };
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1b09ff816..c72649c41 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -207,6 +207,7 @@ impl Attrs {
                         mod_data.definition_source(db).as_ref().map(|src| match src {
                             ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
                             ModuleSource::Module(module) => module as &dyn AttrsOwner,
+                            ModuleSource::BlockExpr(block) => block as &dyn AttrsOwner,
                         }),
                     ),
                 }
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 23f960ad4..a3200c710 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -109,6 +109,10 @@ pub enum ModuleOrigin {
     Inline {
         definition: AstId<ast::Module>,
     },
+    /// Pseudo-module introduced by a block scope (contains only inner items).
+    BlockExpr {
+        block: AstId<ast::BlockExpr>,
+    },
 }
 
 impl Default for ModuleOrigin {
@@ -122,7 +126,7 @@ impl ModuleOrigin {
         match self {
             ModuleOrigin::File { declaration: module, .. }
             | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
-            ModuleOrigin::CrateRoot { .. } => None,
+            ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
         }
     }
 
@@ -137,7 +141,7 @@ impl ModuleOrigin {
 
     pub fn is_inline(&self) -> bool {
         match self {
-            ModuleOrigin::Inline { .. } => true,
+            ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true,
             ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false,
         }
     }
@@ -155,6 +159,9 @@ impl ModuleOrigin {
                 definition.file_id,
                 ModuleSource::Module(definition.to_node(db.upcast())),
             ),
+            ModuleOrigin::BlockExpr { block } => {
+                InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
+            }
         }
     }
 }
@@ -300,6 +307,7 @@ impl ModuleData {
 pub enum ModuleSource {
     SourceFile(ast::SourceFile),
     Module(ast::Module),
+    BlockExpr(ast::BlockExpr),
 }
 
 mod diagnostics {
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 671aa1373..9c568c90c 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -294,6 +294,7 @@ impl ToNav for hir::Module {
             ModuleSource::Module(node) => {
                 (node.syntax(), node.name().map(|it| it.syntax().text_range()))
             }
+            ModuleSource::BlockExpr(node) => (node.syntax(), None),
         };
         let frange = src.with_value(syntax).original_file_range(db);
         NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module)
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs
index b8e4cc181..7ac050473 100644
--- a/crates/ide/src/display/short_label.rs
+++ b/crates/ide/src/display/short_label.rs
@@ -53,6 +53,12 @@ impl ShortLabel for ast::SourceFile {
     }
 }
 
+impl ShortLabel for ast::BlockExpr {
+    fn short_label(&self) -> Option<String> {
+        None
+    }
+}
+
 impl ShortLabel for ast::TypeAlias {
     fn short_label(&self) -> Option<String> {
         short_label_from_node(self, "type ")
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 44ebdbd35..ec1631486 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -321,6 +321,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
                 match it.definition_source(db).value {
                     ModuleSource::Module(it) => it.short_label(),
                     ModuleSource::SourceFile(it) => it.short_label(),
+                    ModuleSource::BlockExpr(it) => it.short_label(),
                 },
                 mod_path,
             ),
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 47a85dc45..975abf47f 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -131,6 +131,7 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module
             match submodule.definition_source(sema.db).value {
                 hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule),
                 hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules),
+                hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable
             }
         }
     }
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 0ecb13a64..b9ba0aed5 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -228,6 +228,15 @@ impl Definition {
                             // so do nothing.
                         }
                     }
+                    ModuleSource::BlockExpr(b) => {
+                        if is_first {
+                            let range = Some(b.syntax().text_range());
+                            res.insert(file_id, range);
+                        } else {
+                            // We have already added the enclosing file to the search scope,
+                            // so do nothing.
+                        }
+                    }
                     ModuleSource::SourceFile(_) => {
                         res.insert(file_id, None);
                     }
@@ -257,6 +266,7 @@ impl Definition {
         let mut res = FxHashMap::default();
         let range = match module_src.value {
             ModuleSource::Module(m) => Some(m.syntax().text_range()),
+            ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
             ModuleSource::SourceFile(_) => None,
         };
         res.insert(file_id, range);
-- 
cgit v1.2.3