about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-01-03 08:56:17 +0000
committerGitHub <noreply@github.com>2021-01-03 08:56:17 +0000
commit520b8a5a4dde032ba6118efb02801611191acc4e (patch)
tree811cd86e5c9a2803bc3d38f19f4ad86e60be1d18
parent3bf4cec79932de0a49338f6b87dc20f85dc3a509 (diff)
parent40cd6cdf67dcfad89a80ff3a662bec2dfd983d67 (diff)
downloadrust-520b8a5a4dde032ba6118efb02801611191acc4e.tar.gz
rust-520b8a5a4dde032ba6118efb02801611191acc4e.zip
Merge #7115
7115: Migrate HasSource::source to return Option r=matklad a=nick96

I've made a start on fixing #6913 based on the provided work plan, migrating `HasSource::source` to return an `Option`. The simple cases are migrated but there are a few that I'm unsure exactly how they should be handled:

- Logging the processing of functions in `AnalysisStatsCmd::run`: In verbose mode it includes the path to the module containing the function and the syntax range. I've handled this with an if-let but would it be better to blow up here with `expect`? I'm not 100% on the code paths but if we're processing a function definition then the source should exist.

I've handled `source()` in all code paths as `None` being a valid return value but are there some cases where we should just blow up? Also, all I've done is bubble up the returned `None`s, there may be some places where we can recover and still provide something.

Co-authored-by: Nick Spain <nicholas.spain@stileeducation.com>
Co-authored-by: Nick Spain <nicholas.spain96@gmail.com>
-rw-r--r--crates/assists/src/handlers/fill_match_arms.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs27
-rw-r--r--crates/assists/src/utils.rs12
-rw-r--r--crates/completion/src/completions.rs5
-rw-r--r--crates/completion/src/completions/trait_impl.rs47
-rw-r--r--crates/completion/src/render.rs3
-rw-r--r--crates/completion/src/render/const_.rs8
-rw-r--r--crates/completion/src/render/function.rs10
-rw-r--r--crates/completion/src/render/macro_.rs15
-rw-r--r--crates/completion/src/render/type_alias.rs8
-rw-r--r--crates/hir/src/code_model.rs10
-rw-r--r--crates/hir/src/has_source.rs69
-rw-r--r--crates/ide/src/call_hierarchy.rs8
-rw-r--r--crates/ide/src/diagnostics/fixes.rs9
-rw-r--r--crates/ide/src/display/navigation_target.rs130
-rw-r--r--crates/ide/src/goto_implementation.rs6
-rw-r--r--crates/ide/src/goto_type_definition.rs4
-rw-r--r--crates/ide/src/hover.rs27
-rw-r--r--crates/ide_db/src/search.rs53
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs11
20 files changed, 239 insertions, 225 deletions
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs
index cb60a312828..f9a62b9facd 100644
--- a/crates/assists/src/handlers/fill_match_arms.rs
+++ b/crates/assists/src/handlers/fill_match_arms.rs
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio
     let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
 
     // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
-    let pat: ast::Pat = match var.source(db).value.kind() {
+    let pat: ast::Pat = match var.source(db)?.value.kind() {
         ast::StructKind::Tuple(field_list) => {
             let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
             make::tuple_struct_pat(path, pats).into()
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index 8558a8ff01c..de1e8f0bfa6 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
     let parent_name = parent.name(ctx.db());
     let target_module = parent.module(ctx.db());
 
-    let in_file_source = record_field_def.source(ctx.db());
+    #[allow(deprecated)]
+    let in_file_source = record_field_def.source(ctx.db())?;
     let (offset, current_visibility, target) = match in_file_source.value {
         hir::FieldSource::Named(it) => {
             let s = it.syntax();
@@ -145,53 +146,53 @@ fn target_data_for_def(
     fn offset_target_and_file_id<S, Ast>(
         db: &dyn HirDatabase,
         x: S,
-    ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId)
+    ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)>
     where
         S: HasSource<Ast = Ast>,
         Ast: AstNode + ast::VisibilityOwner,
     {
-        let source = x.source(db);
+        let source = x.source(db)?;
         let in_file_syntax = source.syntax();
         let file_id = in_file_syntax.file_id;
         let syntax = in_file_syntax.value;
         let current_visibility = source.value.visibility();
-        (
+        Some((
             vis_offset(syntax),
             current_visibility,
             syntax.text_range(),
             file_id.original_file(db.upcast()),
-        )
+        ))
     }
 
     let target_name;
     let (offset, current_visibility, target, target_file) = match def {
         hir::ModuleDef::Function(f) => {
             target_name = Some(f.name(db));
-            offset_target_and_file_id(db, f)
+            offset_target_and_file_id(db, f)?
         }
         hir::ModuleDef::Adt(adt) => {
             target_name = Some(adt.name(db));
             match adt {
-                hir::Adt::Struct(s) => offset_target_and_file_id(db, s),
-                hir::Adt::Union(u) => offset_target_and_file_id(db, u),
-                hir::Adt::Enum(e) => offset_target_and_file_id(db, e),
+                hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?,
+                hir::Adt::Union(u) => offset_target_and_file_id(db, u)?,
+                hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?,
             }
         }
         hir::ModuleDef::Const(c) => {
             target_name = c.name(db);
-            offset_target_and_file_id(db, c)
+            offset_target_and_file_id(db, c)?
         }
         hir::ModuleDef::Static(s) => {
             target_name = s.name(db);
-            offset_target_and_file_id(db, s)
+            offset_target_and_file_id(db, s)?
         }
         hir::ModuleDef::Trait(t) => {
             target_name = Some(t.name(db));
-            offset_target_and_file_id(db, t)
+            offset_target_and_file_id(db, t)?
         }
         hir::ModuleDef::TypeAlias(t) => {
             target_name = Some(t.name(db));
-            offset_target_and_file_id(db, t)
+            offset_target_and_file_id(db, t)?
         }
         hir::ModuleDef::Module(m) => {
             target_name = m.name(db);
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 5a6125534f8..b055964465a 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -98,10 +98,14 @@ pub fn filter_assoc_items(
 
     items
         .iter()
-        .map(|i| match i {
-            hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value),
-            hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value),
-            hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value),
+        // Note: This throws away items with no source.
+        .filter_map(|i| {
+            let item = match i {
+                hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value),
+                hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value),
+                hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value),
+            };
+            Some(item)
         })
         .filter(has_def_name)
         .filter(|it| match it {
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index d9fe1348552..00c9e76f038 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -106,8 +106,9 @@ impl Completions {
         func: hir::Function,
         local_name: Option<String>,
     ) {
-        let item = render_fn(RenderContext::new(ctx), None, local_name, func);
-        self.add(item)
+        if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
+            self.add(item)
+        }
     }
 
     pub(crate) fn add_variant_pat(
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index c4e0d06698f..54bb897e9b7 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -156,19 +156,21 @@ fn add_function_impl(
     };
     let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
 
-    let function_decl = function_declaration(&func.source(ctx.db).value);
-    match ctx.config.snippet_cap {
-        Some(cap) => {
-            let snippet = format!("{} {{\n    $0\n}}", function_decl);
-            builder.snippet_edit(cap, TextEdit::replace(range, snippet))
-        }
-        None => {
-            let header = format!("{} {{", function_decl);
-            builder.text_edit(TextEdit::replace(range, header))
+    if let Some(src) = func.source(ctx.db) {
+        let function_decl = function_declaration(&src.value);
+        match ctx.config.snippet_cap {
+            Some(cap) => {
+                let snippet = format!("{} {{\n    $0\n}}", function_decl);
+                builder.snippet_edit(cap, TextEdit::replace(range, snippet))
+            }
+            None => {
+                let header = format!("{} {{", function_decl);
+                builder.text_edit(TextEdit::replace(range, header))
+            }
         }
+        .kind(completion_kind)
+        .add_to(acc);
     }
-    .kind(completion_kind)
-    .add_to(acc);
 }
 
 fn add_type_alias_impl(
@@ -200,16 +202,19 @@ fn add_const_impl(
     let const_name = const_.name(ctx.db).map(|n| n.to_string());
 
     if let Some(const_name) = const_name {
-        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);
-
-        let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
-
-        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
-            .text_edit(TextEdit::replace(range, snippet))
-            .lookup_by(const_name)
-            .kind(CompletionItemKind::Const)
-            .set_documentation(const_.docs(ctx.db))
-            .add_to(acc);
+        if let Some(source) = const_.source(ctx.db) {
+            let snippet = make_const_compl_syntax(&source.value);
+
+            let range =
+                TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
+
+            CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
+                .text_edit(TextEdit::replace(range, snippet))
+                .lookup_by(const_name)
+                .kind(CompletionItemKind::Const)
+                .set_documentation(const_.docs(ctx.db))
+                .add_to(acc);
+        }
     }
 }
 
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 1ba7201a138..ac0b2a5139e 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -157,8 +157,7 @@ impl<'a> Render<'a> {
 
         let kind = match resolution {
             ScopeDef::ModuleDef(Function(func)) => {
-                let item = render_fn(self.ctx, import_to_add, Some(local_name), *func);
-                return Some(item);
+                return render_fn(self.ctx, import_to_add, Some(local_name), *func);
             }
             ScopeDef::ModuleDef(Variant(_))
                 if self.ctx.completion.is_pat_binding_or_const
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index 039bdabc051..ce924f30952 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>(
     ctx: RenderContext<'a>,
     const_: hir::Const,
 ) -> Option<CompletionItem> {
-    ConstRender::new(ctx, const_).render()
+    ConstRender::new(ctx, const_)?.render()
 }
 
 #[derive(Debug)]
@@ -26,9 +26,9 @@ struct ConstRender<'a> {
 }
 
 impl<'a> ConstRender<'a> {
-    fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> {
-        let ast_node = const_.source(ctx.db()).value;
-        ConstRender { ctx, const_, ast_node }
+    fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> {
+        let ast_node = const_.source(ctx.db())?.value;
+        Some(ConstRender { ctx, const_, ast_node })
     }
 
     fn render(self) -> Option<CompletionItem> {
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 316e05b529c..081be14f4eb 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>(
     import_to_add: Option<ImportEdit>,
     local_name: Option<String>,
     fn_: hir::Function,
-) -> CompletionItem {
+) -> Option<CompletionItem> {
     let _p = profile::span("render_fn");
-    FunctionRender::new(ctx, local_name, fn_).render(import_to_add)
+    Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
 }
 
 #[derive(Debug)]
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> {
         ctx: RenderContext<'a>,
         local_name: Option<String>,
         fn_: hir::Function,
-    ) -> FunctionRender<'a> {
+    ) -> Option<FunctionRender<'a>> {
         let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
-        let ast_node = fn_.source(ctx.db()).value;
+        let ast_node = fn_.source(ctx.db())?.value;
 
-        FunctionRender { ctx, name, func: fn_, ast_node }
+        Some(FunctionRender { ctx, name, func: fn_, ast_node })
     }
 
     fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index dac79592f7f..6f4f9945c19 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> {
     }
 
     fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
-        // FIXME: Currently proc-macro do not have ast-node,
-        // such that it does not have source
-        // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
-        if self.macro_.is_proc_macro() {
-            return None;
-        }
-
         let mut builder =
             CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
                 .kind(CompletionItemKind::Macro)
                 .set_documentation(self.docs.clone())
                 .set_deprecated(self.ctx.is_deprecated(self.macro_))
                 .add_import(import_to_add)
-                .detail(self.detail());
+                .set_detail(self.detail());
 
         let needs_bang = self.needs_bang();
         builder = match self.ctx.snippet_cap() {
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> {
         format!("{}!", self.name)
     }
 
-    fn detail(&self) -> String {
-        let ast_node = self.macro_.source(self.ctx.db()).value;
-        macro_label(&ast_node)
+    fn detail(&self) -> Option<String> {
+        let ast_node = self.macro_.source(self.ctx.db())?.value;
+        Some(macro_label(&ast_node))
     }
 }
 
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 9605c7fa942..69b445b9c69 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>(
     ctx: RenderContext<'a>,
     type_alias: hir::TypeAlias,
 ) -> Option<CompletionItem> {
-    TypeAliasRender::new(ctx, type_alias).render()
+    TypeAliasRender::new(ctx, type_alias)?.render()
 }
 
 #[derive(Debug)]
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> {
 }
 
 impl<'a> TypeAliasRender<'a> {
-    fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> {
-        let ast_node = type_alias.source(ctx.db()).value;
-        TypeAliasRender { ctx, type_alias, ast_node }
+    fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
+        let ast_node = type_alias.source(ctx.db())?.value;
+        Some(TypeAliasRender { ctx, type_alias, ast_node })
     }
 
     fn render(self) -> Option<CompletionItem> {
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 97b7a8b5f58..3c83231cf1c 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -983,13 +983,7 @@ impl MacroDef {
 
     /// XXX: this parses the file
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
-        // FIXME: Currently proc-macro do not have ast-node,
-        // such that it does not have source
-        // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
-        if self.is_proc_macro() {
-            return None;
-        }
-        self.source(db).value.name().map(|it| it.as_name())
+        self.source(db)?.value.name().map(|it| it.as_name())
     }
 
     /// Indicate it is a proc-macro
@@ -1378,7 +1372,7 @@ impl Impl {
     }
 
     pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
-        let src = self.source(db);
+        let src = self.source(db)?;
         let item = src.file_id.is_builtin_derive(db.upcast())?;
         let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
 
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index dd7c0c57067..7c57d8378cc 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -16,7 +16,7 @@ use crate::{
 
 pub trait HasSource {
     type Ast;
-    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
 }
 
 /// NB: Module is !HasSource, because it has two source nodes at the same time:
@@ -46,105 +46,104 @@ impl Module {
 
 impl HasSource for Field {
     type Ast = FieldSource;
-    fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let var = VariantId::from(self.parent);
         let src = var.child_source(db.upcast());
-        src.map(|it| match it[self.id].clone() {
+        let field_source = src.map(|it| match it[self.id].clone() {
             Either::Left(it) => FieldSource::Pos(it),
             Either::Right(it) => FieldSource::Named(it),
-        })
+        });
+        Some(field_source)
     }
 }
 impl HasSource for Struct {
     type Ast = ast::Struct;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Union {
     type Ast = ast::Union;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Enum {
     type Ast = ast::Enum;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Variant {
     type Ast = ast::Variant;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
-        self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
+        Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
     }
 }
 impl HasSource for Function {
     type Ast = ast::Fn;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Const {
     type Ast = ast::Const;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Static {
     type Ast = ast::Static;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Trait {
     type Ast = ast::Trait;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for TypeAlias {
     type Ast = ast::TypeAlias;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for MacroDef {
     type Ast = ast::Macro;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> {
-        InFile {
-            file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
-            value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
-        }
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        let ast_id = self.id.ast_id?;
+        Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
     }
 }
 impl HasSource for Impl {
     type Ast = ast::Impl;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
-        self.id.lookup(db.upcast()).source(db.upcast())
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 
 impl HasSource for TypeParam {
     type Ast = Either<ast::Trait, ast::TypeParam>;
-    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
-        child_source.map(|it| it[self.id.local_id].clone())
+        Some(child_source.map(|it| it[self.id.local_id].clone()))
     }
 }
 
 impl HasSource for LifetimeParam {
     type Ast = ast::LifetimeParam;
-    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
-        child_source.map(|it| it[self.id.local_id].clone())
+        Some(child_source.map(|it| it[self.id.local_id].clone()))
     }
 }
 
 impl HasSource for ConstParam {
     type Ast = ast::ConstParam;
-    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
-        child_source.map(|it| it[self.id.local_id].clone())
+        Some(child_source.map(|it| it[self.id.local_id].clone()))
     }
 }
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 60e0cd4addf..3c2d39f5dfb 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -8,7 +8,7 @@ use ide_db::RootDatabase;
 use syntax::{ast, match_ast, AstNode, TextRange};
 
 use crate::{
-    display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
+    display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
 };
 
 #[derive(Debug, Clone)]
@@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
                 match node {
                     ast::Fn(it) => {
                         let def = sema.to_def(&it)?;
-                        Some(def.to_nav(sema.db))
+                        def.try_to_nav(sema.db)
                     },
                     _ => None,
                 }
@@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
                     match callable.kind() {
                         hir::CallableKind::Function(it) => {
                             let fn_def: hir::Function = it.into();
-                            let nav = fn_def.to_nav(db);
+                            let nav = fn_def.try_to_nav(db)?;
                             Some(nav)
                         }
                         _ => None,
@@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
                 }
                 FnCallNode::MethodCallExpr(expr) => {
                     let function = sema.resolve_method_call(&expr)?;
-                    Some(function.to_nav(db))
+                    function.try_to_nav(db)
                 }
             } {
                 Some((func_target, name_ref.syntax().text_range()))
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index d79f5c17006..ec0f840e9d7 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -156,20 +156,23 @@ fn missing_record_expr_field_fix(
     let record_fields = match VariantDef::from(def_id) {
         VariantDef::Struct(s) => {
             module = s.module(sema.db);
-            let source = s.source(sema.db);
+            #[allow(deprecated)]
+            let source = s.source(sema.db)?;
             def_file_id = source.file_id;
             let fields = source.value.field_list()?;
             record_field_list(fields)?
         }
         VariantDef::Union(u) => {
             module = u.module(sema.db);
-            let source = u.source(sema.db);
+            #[allow(deprecated)]
+            let source = u.source(sema.db)?;
             def_file_id = source.file_id;
             source.value.record_field_list()?
         }
         VariantDef::Variant(e) => {
             module = e.module(sema.db);
-            let source = e.source(sema.db);
+            #[allow(deprecated)]
+            let source = e.source(sema.db)?;
             def_file_id = source.file_id;
             let fields = source.value.field_list()?;
             record_field_list(fields)?
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index bcde2b6f125..e24c7830176 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -210,41 +210,32 @@ impl ToNav for FileSymbol {
 impl TryToNav for Definition {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         match self {
-            Definition::Macro(it) => {
-                // FIXME: Currently proc-macro do not have ast-node,
-                // such that it does not have source
-                // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
-                if it.is_proc_macro() {
-                    return None;
-                }
-                Some(it.to_nav(db))
-            }
-            Definition::Field(it) => Some(it.to_nav(db)),
+            Definition::Macro(it) => it.try_to_nav(db),
+            Definition::Field(it) => it.try_to_nav(db),
             Definition::ModuleDef(it) => it.try_to_nav(db),
-            Definition::SelfType(it) => Some(it.to_nav(db)),
+            Definition::SelfType(it) => it.try_to_nav(db),
             Definition::Local(it) => Some(it.to_nav(db)),
-            Definition::TypeParam(it) => Some(it.to_nav(db)),
-            Definition::LifetimeParam(it) => Some(it.to_nav(db)),
+            Definition::TypeParam(it) => it.try_to_nav(db),
+            Definition::LifetimeParam(it) => it.try_to_nav(db),
             Definition::Label(it) => Some(it.to_nav(db)),
-            Definition::ConstParam(it) => Some(it.to_nav(db)),
+            Definition::ConstParam(it) => it.try_to_nav(db),
         }
     }
 }
 
 impl TryToNav for hir::ModuleDef {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let res = match self {
-            hir::ModuleDef::Module(it) => it.to_nav(db),
-            hir::ModuleDef::Function(it) => it.to_nav(db),
-            hir::ModuleDef::Adt(it) => it.to_nav(db),
-            hir::ModuleDef::Variant(it) => it.to_nav(db),
-            hir::ModuleDef::Const(it) => it.to_nav(db),
-            hir::ModuleDef::Static(it) => it.to_nav(db),
-            hir::ModuleDef::Trait(it) => it.to_nav(db),
-            hir::ModuleDef::TypeAlias(it) => it.to_nav(db),
-            hir::ModuleDef::BuiltinType(_) => return None,
-        };
-        Some(res)
+        match self {
+            hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
+            hir::ModuleDef::Function(it) => it.try_to_nav(db),
+            hir::ModuleDef::Adt(it) => it.try_to_nav(db),
+            hir::ModuleDef::Variant(it) => it.try_to_nav(db),
+            hir::ModuleDef::Const(it) => it.try_to_nav(db),
+            hir::ModuleDef::Static(it) => it.try_to_nav(db),
+            hir::ModuleDef::Trait(it) => it.try_to_nav(db),
+            hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
+            hir::ModuleDef::BuiltinType(_) => None,
+        }
     }
 }
 
@@ -279,13 +270,13 @@ impl ToNavFromAst for hir::Trait {
     const KIND: SymbolKind = SymbolKind::Trait;
 }
 
-impl<D> ToNav for D
+impl<D> TryToNav for D
 where
     D: HasSource + ToNavFromAst + Copy + HasAttrs,
     D::Ast: ast::NameOwner + ShortLabel,
 {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         let mut res = NavigationTarget::from_named(
             db,
             src.as_ref().map(|it| it as &dyn ast::NameOwner),
@@ -293,7 +284,7 @@ where
         );
         res.docs = self.docs(db);
         res.description = src.value.short_label();
-        res
+        Some(res)
     }
 }
 
@@ -312,9 +303,9 @@ impl ToNav for hir::Module {
     }
 }
 
-impl ToNav for hir::Impl {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::Impl {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         let derive_attr = self.is_builtin_derive(db);
         let frange = if let Some(item) = &derive_attr {
             item.syntax().original_file_range(db)
@@ -327,21 +318,21 @@ impl ToNav for hir::Impl {
             src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
         };
 
-        NavigationTarget::from_syntax(
+        Some(NavigationTarget::from_syntax(
             frange.file_id,
             "impl".into(),
             focus_range,
             frange.range,
             SymbolKind::Impl,
-        )
+        ))
     }
 }
 
-impl ToNav for hir::Field {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::Field {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
 
-        match &src.value {
+        let field_source = match &src.value {
             FieldSource::Named(it) => {
                 let mut res =
                     NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
@@ -359,13 +350,14 @@ impl ToNav for hir::Field {
                     SymbolKind::Field,
                 )
             }
-        }
+        };
+        Some(field_source)
     }
 }
 
-impl ToNav for hir::MacroDef {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::MacroDef {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         log::debug!("nav target {:#?}", src.value.syntax());
         let mut res = NavigationTarget::from_named(
             db,
@@ -373,26 +365,26 @@ impl ToNav for hir::MacroDef {
             SymbolKind::Macro,
         );
         res.docs = self.docs(db);
-        res
+        Some(res)
     }
 }
 
-impl ToNav for hir::Adt {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+impl TryToNav for hir::Adt {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         match self {
-            hir::Adt::Struct(it) => it.to_nav(db),
-            hir::Adt::Union(it) => it.to_nav(db),
-            hir::Adt::Enum(it) => it.to_nav(db),
+            hir::Adt::Struct(it) => it.try_to_nav(db),
+            hir::Adt::Union(it) => it.try_to_nav(db),
+            hir::Adt::Enum(it) => it.try_to_nav(db),
         }
     }
 }
 
-impl ToNav for hir::AssocItem {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+impl TryToNav for hir::AssocItem {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         match self {
-            AssocItem::Function(it) => it.to_nav(db),
-            AssocItem::Const(it) => it.to_nav(db),
-            AssocItem::TypeAlias(it) => it.to_nav(db),
+            AssocItem::Function(it) => it.try_to_nav(db),
+            AssocItem::Const(it) => it.try_to_nav(db),
+            AssocItem::TypeAlias(it) => it.try_to_nav(db),
         }
     }
 }
@@ -446,9 +438,9 @@ impl ToNav for hir::Label {
     }
 }
 
-impl ToNav for hir::TypeParam {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::TypeParam {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         let full_range = match &src.value {
             Either::Left(it) => it.syntax().text_range(),
             Either::Right(it) => it.syntax().text_range(),
@@ -457,7 +449,7 @@ impl ToNav for hir::TypeParam {
             Either::Left(_) => None,
             Either::Right(it) => it.name().map(|it| it.syntax().text_range()),
         };
-        NavigationTarget {
+        Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
             name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::TypeParam),
@@ -466,15 +458,15 @@ impl ToNav for hir::TypeParam {
             container_name: None,
             description: None,
             docs: None,
-        }
+        })
     }
 }
 
-impl ToNav for hir::LifetimeParam {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::LifetimeParam {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         let full_range = src.value.syntax().text_range();
-        NavigationTarget {
+        Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
             name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::LifetimeParam),
@@ -483,15 +475,15 @@ impl ToNav for hir::LifetimeParam {
             container_name: None,
             description: None,
             docs: None,
-        }
+        })
     }
 }
 
-impl ToNav for hir::ConstParam {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
+impl TryToNav for hir::ConstParam {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
         let full_range = src.value.syntax().text_range();
-        NavigationTarget {
+        Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
             name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::ConstParam),
@@ -500,7 +492,7 @@ impl ToNav for hir::ConstParam {
             container_name: None,
             description: None,
             docs: None,
-        }
+        })
     }
 }
 
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 6eac3963925..da9378a97e6 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics};
 use ide_db::RootDatabase;
 use syntax::{algo::find_node_at_offset, ast, AstNode};
 
-use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
+use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
 
 // Feature: Go to Implementation
 //
@@ -55,7 +55,7 @@ fn impls_for_def(
         impls
             .into_iter()
             .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
-            .map(|imp| imp.to_nav(sema.db))
+            .filter_map(|imp| imp.try_to_nav(sema.db))
             .collect(),
     )
 }
@@ -69,7 +69,7 @@ fn impls_for_trait(
 
     let impls = Impl::for_trait(sema.db, krate, tr);
 
-    Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect())
+    Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
 }
 
 #[cfg(test)]
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index aba6bf5dc26..7e84e06bea4 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
 use ide_db::RootDatabase;
 use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
 
-use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
+use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
 
 // Feature: Go to Type Definition
 //
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition(
 
     let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
 
-    let nav = adt_def.to_nav(db);
+    let nav = adt_def.try_to_nav(db)?;
     Some(RangeInfo::new(node.text_range(), vec![nav]))
 }
 
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 98c7bfbe51b..2737c900f4c 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset,
 use test_utils::mark;
 
 use crate::{
-    display::{macro_label, ShortLabel, ToNav, TryToNav},
+    display::{macro_label, ShortLabel, TryToNav},
     doc_links::{remove_links, rewrite_links},
     markdown_remove::remove_markdown,
     markup::Markup,
@@ -183,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
 
     match def {
         Definition::ModuleDef(it) => match it {
-            ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
+            ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
             _ => None,
         },
         _ => None,
@@ -206,7 +206,8 @@ fn runnable_action(
                 _ => None,
             },
             ModuleDef::Function(it) => {
-                let src = it.source(sema.db);
+                #[allow(deprecated)]
+                let src = it.source(sema.db)?;
                 if src.file_id != file_id.into() {
                     mark::hit!(hover_macro_generated_struct_fn_doc_comment);
                     mark::hit!(hover_macro_generated_struct_fn_doc_attr);
@@ -326,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
     let mod_path = definition_mod_path(db, &def);
     return match def {
         Definition::Macro(it) => {
-            // FIXME: Currently proc-macro do not have ast-node,
-            // such that it does not have source
-            // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
-            if it.is_proc_macro() {
-                return None;
-            }
-            let label = macro_label(&it.source(db).value);
+            let label = macro_label(&it.source(db)?.value);
             from_def_source_labeled(db, it, Some(label), mod_path)
         }
         Definition::Field(def) => {
-            let src = def.source(db).value;
+            #[allow(deprecated)]
+            let src = def.source(db)?.value;
             if let FieldSource::Named(it) = src {
                 from_def_source_labeled(db, def, it.short_label(), mod_path)
             } else {
@@ -385,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
         D: HasSource<Ast = A> + HasAttrs + Copy,
         A: ShortLabel,
     {
-        let short_label = def.source(db).value.short_label();
+        #[allow(deprecated)]
+        let short_label = def.source(db)?.value.short_label();
         from_def_source_labeled(db, def, short_label, mod_path)
     }
 
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index ff10f71c358..436c59d2c7b 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -121,31 +121,56 @@ impl Definition {
 
         if let Definition::Local(var) = self {
             let range = match var.parent(db) {
-                DefWithBody::Function(f) => f.source(db).value.syntax().text_range(),
-                DefWithBody::Const(c) => c.source(db).value.syntax().text_range(),
-                DefWithBody::Static(s) => s.source(db).value.syntax().text_range(),
+                DefWithBody::Function(f) => {
+                    f.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                DefWithBody::Const(c) => {
+                    c.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                DefWithBody::Static(s) => {
+                    s.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
             };
             let mut res = FxHashMap::default();
-            res.insert(file_id, Some(range));
+            res.insert(file_id, range);
             return SearchScope::new(res);
         }
 
         if let Definition::LifetimeParam(param) = self {
+            #[allow(deprecated)]
             let range = match param.parent(db) {
-                hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(),
+                hir::GenericDef::Function(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
                 hir::GenericDef::Adt(it) => match it {
-                    hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(),
-                    hir::Adt::Union(it) => it.source(db).value.syntax().text_range(),
-                    hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(),
+                    hir::Adt::Struct(it) => {
+                        it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                    }
+                    hir::Adt::Union(it) => {
+                        it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                    }
+                    hir::Adt::Enum(it) => {
+                        it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                    }
                 },
-                hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(),
-                hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(),
-                hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(),
-                hir::GenericDef::Variant(it) => it.source(db).value.syntax().text_range(),
-                hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(),
+                hir::GenericDef::Trait(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                hir::GenericDef::TypeAlias(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                hir::GenericDef::Impl(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                hir::GenericDef::Variant(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
+                hir::GenericDef::Const(it) => {
+                    it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
+                }
             };
             let mut res = FxHashMap::default();
-            res.insert(file_id, Some(range));
+            res.insert(file_id, range);
             return SearchScope::new(res);
         }
 
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index a23fb7a33a4..9445aec074d 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -161,11 +161,12 @@ impl AnalysisStatsCmd {
             }
             let mut msg = format!("processing: {}", full_name);
             if verbosity.is_verbose() {
-                let src = f.source(db);
-                let original_file = src.file_id.original_file(db);
-                let path = vfs.file_path(original_file);
-                let syntax_range = src.value.syntax().text_range();
-                format_to!(msg, " ({} {:?})", path, syntax_range);
+                if let Some(src) = f.source(db) {
+                    let original_file = src.file_id.original_file(db);
+                    let path = vfs.file_path(original_file);
+                    let syntax_range = src.value.syntax().text_range();
+                    format_to!(msg, " ({} {:?})", path, syntax_range);
+                }
             }
             if verbosity.is_spammy() {
                 bar.println(msg.to_string());