diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index ec56dfa6ac6..79152a57c4e 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -196,9 +196,8 @@ where
     N: AstNode,
     DEF: AstItemDef<N>,
 {
-    let module_src =
-        crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax());
-    let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?;
+    let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
+    let module = Module::from_definition(db, Source::new(src.file_id, module_src))?;
     let ctx = LocationCtx::new(db, module.id, src.file_id);
     Some(DEF::from_ast(ctx, &src.ast))
 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 662d3f8808c..f08827ed3d0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -56,7 +56,7 @@ fn try_get_resolver_for_node(
             },
             _ => {
                 if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF {
-                    Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db))
+                    Some(def_with_body_from_child_node(db, Source::new(file_id.into(), node))?.resolver(db))
                 } else {
                     // FIXME add missing cases
                     None
@@ -68,14 +68,13 @@ fn try_get_resolver_for_node(
 
 fn def_with_body_from_child_node(
     db: &impl HirDatabase,
-    file_id: FileId,
-    node: &SyntaxNode,
+    child: Source<&SyntaxNode>,
 ) -> Option<DefWithBody> {
-    let src = crate::ModuleSource::from_child_node(db, file_id, node);
-    let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?;
-    let ctx = LocationCtx::new(db, module.id, file_id.into());
+    let module_source = crate::ModuleSource::from_child_node(db, child);
+    let module = Module::from_definition(db, Source::new(child.file_id, module_source))?;
+    let ctx = LocationCtx::new(db, module.id, child.file_id);
 
-    node.ancestors().find_map(|node| {
+    child.ast.ancestors().find_map(|node| {
         match_ast! {
             match node {
                 ast::FnDef(def)  => { Some(Function {id: ctx.to_def(&def) }.into()) },
@@ -142,7 +141,7 @@ impl SourceAnalyzer {
         node: &SyntaxNode,
         offset: Option<TextUnit>,
     ) -> SourceAnalyzer {
-        let def_with_body = def_with_body_from_child_node(db, file_id, node);
+        let def_with_body = def_with_body_from_child_node(db, Source::new(file_id.into(), node));
         if let Some(def) = def_with_body {
             let source_map = def.body_source_map(db);
             let scopes = def.expr_scopes(db);
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 0a59c4ad772..a240a10b826 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -78,14 +78,13 @@ impl ModuleSource {
         }
     }
 
-    pub fn from_child_node(
-        db: &impl db::DefDatabase2,
-        file_id: FileId,
-        child: &SyntaxNode,
-    ) -> ModuleSource {
-        if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
+    pub fn from_child_node(db: &impl db::DefDatabase2, child: Source<&SyntaxNode>) -> ModuleSource {
+        if let Some(m) =
+            child.ast.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
+        {
             ModuleSource::Module(m)
         } else {
+            let file_id = child.file_id.original_file(db);
             let source_file = db.parse(file_id).tree();
             ModuleSource::SourceFile(source_file)
         }
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 930789b0fe2..437d73e94df 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -230,6 +230,10 @@ pub struct Source<T> {
 }
 
 impl<T> Source<T> {
+    pub fn new(file_id: HirFileId, ast: T) -> Source<T> {
+        Source { file_id, ast }
+    }
+
     pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
         Source { file_id: self.file_id, ast: f(self.ast) }
     }
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs
index 00690e44962..b5e35e29f2b 100644
--- a/crates/ra_ide_api/src/references/classify.rs
+++ b/crates/ra_ide_api/src/references/classify.rs
@@ -144,8 +144,8 @@ pub(crate) fn classify_name_ref(
         }
     }
 
-    let ast = ModuleSource::from_child_node(db, file_id, &parent);
     let file_id = file_id.into();
+    let ast = ModuleSource::from_child_node(db, Source::new(file_id, &parent));
     // FIXME: find correct container and visibility for each case
     let container = Module::from_definition(db, Source { file_id, ast })?;
     let visibility = None;
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 366ac804860..8039a5164eb 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -1,5 +1,6 @@
 //! FIXME: write short doc here
 
+use hir::Source;
 use itertools::Itertools;
 use ra_db::SourceDatabase;
 use ra_syntax::{
@@ -65,9 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
         return None;
     }
     let range = module.syntax().text_range();
-    let src = hir::ModuleSource::from_child_node(db, file_id, &module.syntax());
-    let module =
-        hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), ast: src })?;
+    let src = hir::ModuleSource::from_child_node(db, Source::new(file_id.into(), &module.syntax()));
+    let module = hir::Module::from_definition(db, Source::new(file_id.into(), src))?;
 
     let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
     Some(Runnable { range, kind: RunnableKind::TestMod { path } })