diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index d67ffa9de21..257a323edf1 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -1,7 +1,7 @@
 use std::sync::Arc;
 
 use ra_syntax::{
-    ast::{self, ModuleItemOwner, NameOwner},
+    ast::{self, ModuleItemOwner, NameOwner, AstNode},
     SmolStr,
 };
 use relative_path::RelativePathBuf;
@@ -12,6 +12,7 @@ use crate::{
     descriptors::DescriptorDatabase,
     input::{SourceRoot, SourceRootId},
     Cancelable, FileId, FileResolverImp,
+    syntax_ptr::SyntaxPtr,
 };
 
 use super::{
@@ -20,8 +21,18 @@ use super::{
 };
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug)]
-pub(crate) struct Submodule {
-    name: SmolStr,
+pub(crate) enum Submodule {
+    Declaration(SmolStr),
+    Definition(SmolStr, SyntaxPtr),
+}
+
+impl Submodule {
+    fn name(&self) -> &SmolStr {
+        match self {
+            Submodule::Declaration(name) => name,
+            Submodule::Definition(name, _) => name,
+        }
+    }
 }
 
 pub(crate) fn submodules(
@@ -29,20 +40,29 @@ pub(crate) fn submodules(
     source: ModuleSource,
 ) -> Cancelable<Arc<Vec<Submodule>>> {
     db::check_canceled(db)?;
+    let file_id = source.file_id();
     let submodules = match source.resolve(db) {
-        ModuleSourceNode::Root(it) => collect_submodules(it.ast()),
+        ModuleSourceNode::Root(it) => collect_submodules(file_id, it.ast()),
         ModuleSourceNode::Inline(it) => it
             .ast()
             .item_list()
-            .map(collect_submodules)
+            .map(|it| collect_submodules(file_id, it))
             .unwrap_or_else(Vec::new),
     };
     return Ok(Arc::new(submodules));
 
-    fn collect_submodules<'a>(root: impl ast::ModuleItemOwner<'a>) -> Vec<Submodule> {
+    fn collect_submodules<'a>(
+        file_id: FileId,
+        root: impl ast::ModuleItemOwner<'a>,
+    ) -> Vec<Submodule> {
         modules(root)
-            .filter(|(_, m)| m.has_semi())
-            .map(|(name, _)| Submodule { name })
+            .map(|(name, m)| {
+                if m.has_semi() {
+                    Submodule::Declaration(name)
+                } else {
+                    Submodule::Definition(name, SyntaxPtr::new(file_id, m.syntax()))
+                }
+            })
             .collect()
     }
 }
@@ -135,25 +155,40 @@ fn build_subtree(
         children: Vec::new(),
     });
     for sub in db.submodules(ModuleSource::File(file_id))?.iter() {
-        let name = sub.name.clone();
-        let (points_to, problem) = resolve_submodule(file_id, &name, &source_root.file_resolver);
         let link = tree.push_link(LinkData {
-            name,
+            name: sub.name().clone(),
             owner: id,
             points_to: Vec::new(),
             problem: None,
         });
 
-        let points_to = points_to
-            .into_iter()
-            .map(|file_id| match roots.remove(&file_id) {
-                Some(module_id) => {
-                    tree.module_mut(module_id).parent = Some(link);
-                    Ok(module_id)
-                }
-                None => build_subtree(db, source_root, tree, visited, roots, Some(link), file_id),
-            })
-            .collect::<Cancelable<Vec<_>>>()?;
+        let (points_to, problem) = match sub {
+            Submodule::Declaration(name) => {
+                let (points_to, problem) =
+                    resolve_submodule(file_id, &name, &source_root.file_resolver);
+                let points_to = points_to
+                    .into_iter()
+                    .map(|file_id| match roots.remove(&file_id) {
+                        Some(module_id) => {
+                            tree.module_mut(module_id).parent = Some(link);
+                            Ok(module_id)
+                        }
+                        None => build_subtree(
+                            db,
+                            source_root,
+                            tree,
+                            visited,
+                            roots,
+                            Some(link),
+                            file_id,
+                        ),
+                    })
+                    .collect::<Cancelable<Vec<_>>>()?;
+                (points_to, problem)
+            }
+            Submodule::Definition(..) => continue,
+        };
+
         tree.link_mut(link).points_to = points_to;
         tree.link_mut(link).problem = problem;
     }
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 13bab0087f9..8464b0618a0 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -164,6 +164,13 @@ impl ModuleSource {
         }
     }
 
+    fn file_id(self) -> FileId {
+        match self {
+            ModuleSource::File(f) => f,
+            ModuleSource::Inline(ptr) => ptr.file_id(),
+        }
+    }
+
     fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode {
         match self {
             ModuleSource::File(file_id) => {
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs
index 4db1529c2c4..4afb1fc9303 100644
--- a/crates/ra_analysis/src/syntax_ptr.rs
+++ b/crates/ra_analysis/src/syntax_ptr.rs
@@ -22,6 +22,10 @@ impl SyntaxPtr {
         let local = LocalSyntaxPtr::new(node);
         SyntaxPtr { file_id, local }
     }
+
+    pub(crate) fn file_id(self) -> FileId {
+        self.file_id
+    }
 }
 
 /// A pionter to a syntax node inside a file.