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>
This commit is contained in:
bors[bot] 2021-01-03 08:56:17 +00:00 committed by GitHub
commit 520b8a5a4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 237 additions and 223 deletions

View file

@ -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))?); 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 // 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) => { ast::StructKind::Tuple(field_list) => {
let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
make::tuple_struct_pat(path, pats).into() make::tuple_struct_pat(path, pats).into()

View file

@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
let parent_name = parent.name(ctx.db()); let parent_name = parent.name(ctx.db());
let target_module = parent.module(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 { let (offset, current_visibility, target) = match in_file_source.value {
hir::FieldSource::Named(it) => { hir::FieldSource::Named(it) => {
let s = it.syntax(); let s = it.syntax();
@ -145,53 +146,53 @@ fn target_data_for_def(
fn offset_target_and_file_id<S, Ast>( fn offset_target_and_file_id<S, Ast>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
x: S, x: S,
) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)>
where where
S: HasSource<Ast = Ast>, S: HasSource<Ast = Ast>,
Ast: AstNode + ast::VisibilityOwner, Ast: AstNode + ast::VisibilityOwner,
{ {
let source = x.source(db); let source = x.source(db)?;
let in_file_syntax = source.syntax(); let in_file_syntax = source.syntax();
let file_id = in_file_syntax.file_id; let file_id = in_file_syntax.file_id;
let syntax = in_file_syntax.value; let syntax = in_file_syntax.value;
let current_visibility = source.value.visibility(); let current_visibility = source.value.visibility();
( Some((
vis_offset(syntax), vis_offset(syntax),
current_visibility, current_visibility,
syntax.text_range(), syntax.text_range(),
file_id.original_file(db.upcast()), file_id.original_file(db.upcast()),
) ))
} }
let target_name; let target_name;
let (offset, current_visibility, target, target_file) = match def { let (offset, current_visibility, target, target_file) = match def {
hir::ModuleDef::Function(f) => { hir::ModuleDef::Function(f) => {
target_name = Some(f.name(db)); target_name = Some(f.name(db));
offset_target_and_file_id(db, f) offset_target_and_file_id(db, f)?
} }
hir::ModuleDef::Adt(adt) => { hir::ModuleDef::Adt(adt) => {
target_name = Some(adt.name(db)); target_name = Some(adt.name(db));
match adt { match adt {
hir::Adt::Struct(s) => offset_target_and_file_id(db, s), hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?,
hir::Adt::Union(u) => offset_target_and_file_id(db, u), hir::Adt::Union(u) => offset_target_and_file_id(db, u)?,
hir::Adt::Enum(e) => offset_target_and_file_id(db, e), hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?,
} }
} }
hir::ModuleDef::Const(c) => { hir::ModuleDef::Const(c) => {
target_name = c.name(db); target_name = c.name(db);
offset_target_and_file_id(db, c) offset_target_and_file_id(db, c)?
} }
hir::ModuleDef::Static(s) => { hir::ModuleDef::Static(s) => {
target_name = s.name(db); target_name = s.name(db);
offset_target_and_file_id(db, s) offset_target_and_file_id(db, s)?
} }
hir::ModuleDef::Trait(t) => { hir::ModuleDef::Trait(t) => {
target_name = Some(t.name(db)); target_name = Some(t.name(db));
offset_target_and_file_id(db, t) offset_target_and_file_id(db, t)?
} }
hir::ModuleDef::TypeAlias(t) => { hir::ModuleDef::TypeAlias(t) => {
target_name = Some(t.name(db)); target_name = Some(t.name(db));
offset_target_and_file_id(db, t) offset_target_and_file_id(db, t)?
} }
hir::ModuleDef::Module(m) => { hir::ModuleDef::Module(m) => {
target_name = m.name(db); target_name = m.name(db);

View file

@ -98,10 +98,14 @@ pub fn filter_assoc_items(
items items
.iter() .iter()
.map(|i| match i { // Note: This throws away items with no source.
hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), .filter_map(|i| {
hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), let item = match i {
hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), 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(has_def_name)
.filter(|it| match it { .filter(|it| match it {

View file

@ -106,8 +106,9 @@ impl Completions {
func: hir::Function, func: hir::Function,
local_name: Option<String>, local_name: Option<String>,
) { ) {
let item = render_fn(RenderContext::new(ctx), None, local_name, func); if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
self.add(item) self.add(item)
}
} }
pub(crate) fn add_variant_pat( pub(crate) fn add_variant_pat(

View file

@ -156,19 +156,21 @@ fn add_function_impl(
}; };
let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
let function_decl = function_declaration(&func.source(ctx.db).value); if let Some(src) = func.source(ctx.db) {
match ctx.config.snippet_cap { let function_decl = function_declaration(&src.value);
Some(cap) => { match ctx.config.snippet_cap {
let snippet = format!("{} {{\n $0\n}}", function_decl); Some(cap) => {
builder.snippet_edit(cap, TextEdit::replace(range, snippet)) let snippet = format!("{} {{\n $0\n}}", function_decl);
} builder.snippet_edit(cap, TextEdit::replace(range, snippet))
None => { }
let header = format!("{} {{", function_decl); None => {
builder.text_edit(TextEdit::replace(range, header)) 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( 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()); let const_name = const_.name(ctx.db).map(|n| n.to_string());
if let Some(const_name) = const_name { if let Some(const_name) = const_name {
let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); 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()); let range =
TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
.text_edit(TextEdit::replace(range, snippet)) .text_edit(TextEdit::replace(range, snippet))
.lookup_by(const_name) .lookup_by(const_name)
.kind(CompletionItemKind::Const) .kind(CompletionItemKind::Const)
.set_documentation(const_.docs(ctx.db)) .set_documentation(const_.docs(ctx.db))
.add_to(acc); .add_to(acc);
}
} }
} }

View file

@ -157,8 +157,7 @@ impl<'a> Render<'a> {
let kind = match resolution { let kind = match resolution {
ScopeDef::ModuleDef(Function(func)) => { ScopeDef::ModuleDef(Function(func)) => {
let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); return render_fn(self.ctx, import_to_add, Some(local_name), *func);
return Some(item);
} }
ScopeDef::ModuleDef(Variant(_)) ScopeDef::ModuleDef(Variant(_))
if self.ctx.completion.is_pat_binding_or_const if self.ctx.completion.is_pat_binding_or_const

View file

@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>(
ctx: RenderContext<'a>, ctx: RenderContext<'a>,
const_: hir::Const, const_: hir::Const,
) -> Option<CompletionItem> { ) -> Option<CompletionItem> {
ConstRender::new(ctx, const_).render() ConstRender::new(ctx, const_)?.render()
} }
#[derive(Debug)] #[derive(Debug)]
@ -26,9 +26,9 @@ struct ConstRender<'a> {
} }
impl<'a> ConstRender<'a> { impl<'a> ConstRender<'a> {
fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> {
let ast_node = const_.source(ctx.db()).value; let ast_node = const_.source(ctx.db())?.value;
ConstRender { ctx, const_, ast_node } Some(ConstRender { ctx, const_, ast_node })
} }
fn render(self) -> Option<CompletionItem> { fn render(self) -> Option<CompletionItem> {

View file

@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>(
import_to_add: Option<ImportEdit>, import_to_add: Option<ImportEdit>,
local_name: Option<String>, local_name: Option<String>,
fn_: hir::Function, fn_: hir::Function,
) -> CompletionItem { ) -> Option<CompletionItem> {
let _p = profile::span("render_fn"); 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)] #[derive(Debug)]
@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> {
ctx: RenderContext<'a>, ctx: RenderContext<'a>,
local_name: Option<String>, local_name: Option<String>,
fn_: hir::Function, fn_: hir::Function,
) -> FunctionRender<'a> { ) -> Option<FunctionRender<'a>> {
let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); 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 { fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {

View file

@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> {
} }
fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 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 = let mut builder =
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
.kind(CompletionItemKind::Macro) .kind(CompletionItemKind::Macro)
.set_documentation(self.docs.clone()) .set_documentation(self.docs.clone())
.set_deprecated(self.ctx.is_deprecated(self.macro_)) .set_deprecated(self.ctx.is_deprecated(self.macro_))
.add_import(import_to_add) .add_import(import_to_add)
.detail(self.detail()); .set_detail(self.detail());
let needs_bang = self.needs_bang(); let needs_bang = self.needs_bang();
builder = match self.ctx.snippet_cap() { builder = match self.ctx.snippet_cap() {
@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> {
format!("{}!", self.name) format!("{}!", self.name)
} }
fn detail(&self) -> String { fn detail(&self) -> Option<String> {
let ast_node = self.macro_.source(self.ctx.db()).value; let ast_node = self.macro_.source(self.ctx.db())?.value;
macro_label(&ast_node) Some(macro_label(&ast_node))
} }
} }

View file

@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>(
ctx: RenderContext<'a>, ctx: RenderContext<'a>,
type_alias: hir::TypeAlias, type_alias: hir::TypeAlias,
) -> Option<CompletionItem> { ) -> Option<CompletionItem> {
TypeAliasRender::new(ctx, type_alias).render() TypeAliasRender::new(ctx, type_alias)?.render()
} }
#[derive(Debug)] #[derive(Debug)]
@ -26,9 +26,9 @@ struct TypeAliasRender<'a> {
} }
impl<'a> TypeAliasRender<'a> { impl<'a> TypeAliasRender<'a> {
fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
let ast_node = type_alias.source(ctx.db()).value; let ast_node = type_alias.source(ctx.db())?.value;
TypeAliasRender { ctx, type_alias, ast_node } Some(TypeAliasRender { ctx, type_alias, ast_node })
} }
fn render(self) -> Option<CompletionItem> { fn render(self) -> Option<CompletionItem> {

View file

@ -983,13 +983,7 @@ impl MacroDef {
/// XXX: this parses the file /// XXX: this parses the file
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
// FIXME: Currently proc-macro do not have ast-node, self.source(db)?.value.name().map(|it| it.as_name())
// 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())
} }
/// Indicate it is a proc-macro /// 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>> { 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 item = src.file_id.is_builtin_derive(db.upcast())?;
let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);

View file

@ -16,7 +16,7 @@ use crate::{
pub trait HasSource { pub trait HasSource {
type Ast; 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: /// NB: Module is !HasSource, because it has two source nodes at the same time:
@ -46,105 +46,104 @@ impl Module {
impl HasSource for Field { impl HasSource for Field {
type Ast = FieldSource; 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 var = VariantId::from(self.parent);
let src = var.child_source(db.upcast()); 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::Left(it) => FieldSource::Pos(it),
Either::Right(it) => FieldSource::Named(it), Either::Right(it) => FieldSource::Named(it),
}) });
Some(field_source)
} }
} }
impl HasSource for Struct { impl HasSource for Struct {
type Ast = ast::Struct; type Ast = ast::Struct;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Union { impl HasSource for Union {
type Ast = ast::Union; type Ast = ast::Union;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Enum { impl HasSource for Enum {
type Ast = ast::Enum; type Ast = ast::Enum;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Variant { impl HasSource for Variant {
type Ast = ast::Variant; type Ast = ast::Variant;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
} }
} }
impl HasSource for Function { impl HasSource for Function {
type Ast = ast::Fn; type Ast = ast::Fn;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Const { impl HasSource for Const {
type Ast = ast::Const; type Ast = ast::Const;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Static { impl HasSource for Static {
type Ast = ast::Static; type Ast = ast::Static;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for Trait { impl HasSource for Trait {
type Ast = ast::Trait; type Ast = ast::Trait;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for TypeAlias { impl HasSource for TypeAlias {
type Ast = ast::TypeAlias; type Ast = ast::TypeAlias;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for MacroDef { impl HasSource for MacroDef {
type Ast = ast::Macro; type Ast = ast::Macro;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
InFile { let ast_id = self.id.ast_id?;
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
}
} }
} }
impl HasSource for Impl { impl HasSource for Impl {
type Ast = ast::Impl; type Ast = ast::Impl;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
self.id.lookup(db.upcast()).source(db.upcast()) Some(self.id.lookup(db.upcast()).source(db.upcast()))
} }
} }
impl HasSource for TypeParam { impl HasSource for TypeParam {
type Ast = Either<ast::Trait, ast::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()); 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 { impl HasSource for LifetimeParam {
type Ast = ast::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()); 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 { impl HasSource for ConstParam {
type Ast = ast::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()); 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()))
} }
} }

View file

@ -8,7 +8,7 @@ use ide_db::RootDatabase;
use syntax::{ast, match_ast, AstNode, TextRange}; use syntax::{ast, match_ast, AstNode, TextRange};
use crate::{ use crate::{
display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
match node { match node {
ast::Fn(it) => { ast::Fn(it) => {
let def = sema.to_def(&it)?; let def = sema.to_def(&it)?;
Some(def.to_nav(sema.db)) def.try_to_nav(sema.db)
}, },
_ => None, _ => None,
} }
@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
match callable.kind() { match callable.kind() {
hir::CallableKind::Function(it) => { hir::CallableKind::Function(it) => {
let fn_def: hir::Function = it.into(); let fn_def: hir::Function = it.into();
let nav = fn_def.to_nav(db); let nav = fn_def.try_to_nav(db)?;
Some(nav) Some(nav)
} }
_ => None, _ => None,
@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
} }
FnCallNode::MethodCallExpr(expr) => { FnCallNode::MethodCallExpr(expr) => {
let function = sema.resolve_method_call(&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())) Some((func_target, name_ref.syntax().text_range()))

View file

@ -156,20 +156,23 @@ fn missing_record_expr_field_fix(
let record_fields = match VariantDef::from(def_id) { let record_fields = match VariantDef::from(def_id) {
VariantDef::Struct(s) => { VariantDef::Struct(s) => {
module = s.module(sema.db); 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; def_file_id = source.file_id;
let fields = source.value.field_list()?; let fields = source.value.field_list()?;
record_field_list(fields)? record_field_list(fields)?
} }
VariantDef::Union(u) => { VariantDef::Union(u) => {
module = u.module(sema.db); 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; def_file_id = source.file_id;
source.value.record_field_list()? source.value.record_field_list()?
} }
VariantDef::Variant(e) => { VariantDef::Variant(e) => {
module = e.module(sema.db); 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; def_file_id = source.file_id;
let fields = source.value.field_list()?; let fields = source.value.field_list()?;
record_field_list(fields)? record_field_list(fields)?

View file

@ -210,41 +210,32 @@ impl ToNav for FileSymbol {
impl TryToNav for Definition { impl TryToNav for Definition {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
match self { match self {
Definition::Macro(it) => { Definition::Macro(it) => it.try_to_nav(db),
// FIXME: Currently proc-macro do not have ast-node, Definition::Field(it) => it.try_to_nav(db),
// 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::ModuleDef(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::Local(it) => Some(it.to_nav(db)),
Definition::TypeParam(it) => Some(it.to_nav(db)), Definition::TypeParam(it) => it.try_to_nav(db),
Definition::LifetimeParam(it) => Some(it.to_nav(db)), Definition::LifetimeParam(it) => it.try_to_nav(db),
Definition::Label(it) => Some(it.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 { impl TryToNav for hir::ModuleDef {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let res = match self { match self {
hir::ModuleDef::Module(it) => it.to_nav(db), hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
hir::ModuleDef::Function(it) => it.to_nav(db), hir::ModuleDef::Function(it) => it.try_to_nav(db),
hir::ModuleDef::Adt(it) => it.to_nav(db), hir::ModuleDef::Adt(it) => it.try_to_nav(db),
hir::ModuleDef::Variant(it) => it.to_nav(db), hir::ModuleDef::Variant(it) => it.try_to_nav(db),
hir::ModuleDef::Const(it) => it.to_nav(db), hir::ModuleDef::Const(it) => it.try_to_nav(db),
hir::ModuleDef::Static(it) => it.to_nav(db), hir::ModuleDef::Static(it) => it.try_to_nav(db),
hir::ModuleDef::Trait(it) => it.to_nav(db), hir::ModuleDef::Trait(it) => it.try_to_nav(db),
hir::ModuleDef::TypeAlias(it) => it.to_nav(db), hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
hir::ModuleDef::BuiltinType(_) => return None, hir::ModuleDef::BuiltinType(_) => None,
}; }
Some(res)
} }
} }
@ -279,13 +270,13 @@ impl ToNavFromAst for hir::Trait {
const KIND: SymbolKind = SymbolKind::Trait; const KIND: SymbolKind = SymbolKind::Trait;
} }
impl<D> ToNav for D impl<D> TryToNav for D
where where
D: HasSource + ToNavFromAst + Copy + HasAttrs, D: HasSource + ToNavFromAst + Copy + HasAttrs,
D::Ast: ast::NameOwner + ShortLabel, D::Ast: ast::NameOwner + ShortLabel,
{ {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
let mut res = NavigationTarget::from_named( let mut res = NavigationTarget::from_named(
db, db,
src.as_ref().map(|it| it as &dyn ast::NameOwner), src.as_ref().map(|it| it as &dyn ast::NameOwner),
@ -293,7 +284,7 @@ where
); );
res.docs = self.docs(db); res.docs = self.docs(db);
res.description = src.value.short_label(); res.description = src.value.short_label();
res Some(res)
} }
} }
@ -312,9 +303,9 @@ impl ToNav for hir::Module {
} }
} }
impl ToNav for hir::Impl { impl TryToNav for hir::Impl {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
let derive_attr = self.is_builtin_derive(db); let derive_attr = self.is_builtin_derive(db);
let frange = if let Some(item) = &derive_attr { let frange = if let Some(item) = &derive_attr {
item.syntax().original_file_range(db) 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) 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, frange.file_id,
"impl".into(), "impl".into(),
focus_range, focus_range,
frange.range, frange.range,
SymbolKind::Impl, SymbolKind::Impl,
) ))
} }
} }
impl ToNav for hir::Field { impl TryToNav for hir::Field {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
match &src.value { let field_source = match &src.value {
FieldSource::Named(it) => { FieldSource::Named(it) => {
let mut res = let mut res =
NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
@ -359,13 +350,14 @@ impl ToNav for hir::Field {
SymbolKind::Field, SymbolKind::Field,
) )
} }
} };
Some(field_source)
} }
} }
impl ToNav for hir::MacroDef { impl TryToNav for hir::MacroDef {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
log::debug!("nav target {:#?}", src.value.syntax()); log::debug!("nav target {:#?}", src.value.syntax());
let mut res = NavigationTarget::from_named( let mut res = NavigationTarget::from_named(
db, db,
@ -373,26 +365,26 @@ impl ToNav for hir::MacroDef {
SymbolKind::Macro, SymbolKind::Macro,
); );
res.docs = self.docs(db); res.docs = self.docs(db);
res Some(res)
} }
} }
impl ToNav for hir::Adt { impl TryToNav for hir::Adt {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
match self { match self {
hir::Adt::Struct(it) => it.to_nav(db), hir::Adt::Struct(it) => it.try_to_nav(db),
hir::Adt::Union(it) => it.to_nav(db), hir::Adt::Union(it) => it.try_to_nav(db),
hir::Adt::Enum(it) => it.to_nav(db), hir::Adt::Enum(it) => it.try_to_nav(db),
} }
} }
} }
impl ToNav for hir::AssocItem { impl TryToNav for hir::AssocItem {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
match self { match self {
AssocItem::Function(it) => it.to_nav(db), AssocItem::Function(it) => it.try_to_nav(db),
AssocItem::Const(it) => it.to_nav(db), AssocItem::Const(it) => it.try_to_nav(db),
AssocItem::TypeAlias(it) => it.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 { impl TryToNav for hir::TypeParam {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
let full_range = match &src.value { let full_range = match &src.value {
Either::Left(it) => it.syntax().text_range(), Either::Left(it) => it.syntax().text_range(),
Either::Right(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::Left(_) => None,
Either::Right(it) => it.name().map(|it| it.syntax().text_range()), Either::Right(it) => it.name().map(|it| it.syntax().text_range()),
}; };
NavigationTarget { Some(NavigationTarget {
file_id: src.file_id.original_file(db), file_id: src.file_id.original_file(db),
name: self.name(db).to_string().into(), name: self.name(db).to_string().into(),
kind: Some(SymbolKind::TypeParam), kind: Some(SymbolKind::TypeParam),
@ -466,15 +458,15 @@ impl ToNav for hir::TypeParam {
container_name: None, container_name: None,
description: None, description: None,
docs: None, docs: None,
} })
} }
} }
impl ToNav for hir::LifetimeParam { impl TryToNav for hir::LifetimeParam {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
let full_range = src.value.syntax().text_range(); let full_range = src.value.syntax().text_range();
NavigationTarget { Some(NavigationTarget {
file_id: src.file_id.original_file(db), file_id: src.file_id.original_file(db),
name: self.name(db).to_string().into(), name: self.name(db).to_string().into(),
kind: Some(SymbolKind::LifetimeParam), kind: Some(SymbolKind::LifetimeParam),
@ -483,15 +475,15 @@ impl ToNav for hir::LifetimeParam {
container_name: None, container_name: None,
description: None, description: None,
docs: None, docs: None,
} })
} }
} }
impl ToNav for hir::ConstParam { impl TryToNav for hir::ConstParam {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let src = self.source(db); let src = self.source(db)?;
let full_range = src.value.syntax().text_range(); let full_range = src.value.syntax().text_range();
NavigationTarget { Some(NavigationTarget {
file_id: src.file_id.original_file(db), file_id: src.file_id.original_file(db),
name: self.name(db).to_string().into(), name: self.name(db).to_string().into(),
kind: Some(SymbolKind::ConstParam), kind: Some(SymbolKind::ConstParam),
@ -500,7 +492,7 @@ impl ToNav for hir::ConstParam {
container_name: None, container_name: None,
description: None, description: None,
docs: None, docs: None,
} })
} }
} }

View file

@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics};
use ide_db::RootDatabase; use ide_db::RootDatabase;
use syntax::{algo::find_node_at_offset, ast, AstNode}; 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 // Feature: Go to Implementation
// //
@ -55,7 +55,7 @@ fn impls_for_def(
impls impls
.into_iter() .into_iter()
.filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) .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(), .collect(),
) )
} }
@ -69,7 +69,7 @@ fn impls_for_trait(
let impls = Impl::for_trait(sema.db, krate, tr); 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)] #[cfg(test)]

View file

@ -1,7 +1,7 @@
use ide_db::RootDatabase; use ide_db::RootDatabase;
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 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 // 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 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])) Some(RangeInfo::new(node.text_range(), vec![nav]))
} }

View file

@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset,
use test_utils::mark; use test_utils::mark;
use crate::{ use crate::{
display::{macro_label, ShortLabel, ToNav, TryToNav}, display::{macro_label, ShortLabel, TryToNav},
doc_links::{remove_links, rewrite_links}, doc_links::{remove_links, rewrite_links},
markdown_remove::remove_markdown, markdown_remove::remove_markdown,
markup::Markup, markup::Markup,
@ -183,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
match def { match def {
Definition::ModuleDef(it) => match it { Definition::ModuleDef(it) => match it {
ModuleDef::Adt(Adt::Struct(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.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.to_nav(db))), ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
_ => None, _ => None,
}, },
_ => None, _ => None,
@ -206,7 +206,8 @@ fn runnable_action(
_ => None, _ => None,
}, },
ModuleDef::Function(it) => { ModuleDef::Function(it) => {
let src = it.source(sema.db); #[allow(deprecated)]
let src = it.source(sema.db)?;
if src.file_id != file_id.into() { if src.file_id != file_id.into() {
mark::hit!(hover_macro_generated_struct_fn_doc_comment); mark::hit!(hover_macro_generated_struct_fn_doc_comment);
mark::hit!(hover_macro_generated_struct_fn_doc_attr); 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); let mod_path = definition_mod_path(db, &def);
return match def { return match def {
Definition::Macro(it) => { Definition::Macro(it) => {
// FIXME: Currently proc-macro do not have ast-node, let label = macro_label(&it.source(db)?.value);
// 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);
from_def_source_labeled(db, it, Some(label), mod_path) from_def_source_labeled(db, it, Some(label), mod_path)
} }
Definition::Field(def) => { Definition::Field(def) => {
let src = def.source(db).value; #[allow(deprecated)]
let src = def.source(db)?.value;
if let FieldSource::Named(it) = src { if let FieldSource::Named(it) = src {
from_def_source_labeled(db, def, it.short_label(), mod_path) from_def_source_labeled(db, def, it.short_label(), mod_path)
} else { } else {
@ -385,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
D: HasSource<Ast = A> + HasAttrs + Copy, D: HasSource<Ast = A> + HasAttrs + Copy,
A: ShortLabel, 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) from_def_source_labeled(db, def, short_label, mod_path)
} }

View file

@ -121,31 +121,56 @@ impl Definition {
if let Definition::Local(var) = self { if let Definition::Local(var) = self {
let range = match var.parent(db) { let range = match var.parent(db) {
DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), DefWithBody::Function(f) => {
DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), f.source(db).and_then(|src| Some(src.value.syntax().text_range()))
DefWithBody::Static(s) => s.source(db).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(); let mut res = FxHashMap::default();
res.insert(file_id, Some(range)); res.insert(file_id, range);
return SearchScope::new(res); return SearchScope::new(res);
} }
if let Definition::LifetimeParam(param) = self { if let Definition::LifetimeParam(param) = self {
#[allow(deprecated)]
let range = match param.parent(db) { 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::GenericDef::Adt(it) => match it {
hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), hir::Adt::Struct(it) => {
hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
hir::Adt::Enum(it) => it.source(db).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::Trait(it) => {
hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), it.source(db).and_then(|src| Some(src.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::TypeAlias(it) => {
hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), 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(); let mut res = FxHashMap::default();
res.insert(file_id, Some(range)); res.insert(file_id, range);
return SearchScope::new(res); return SearchScope::new(res);
} }

View file

@ -161,11 +161,12 @@ impl AnalysisStatsCmd {
} }
let mut msg = format!("processing: {}", full_name); let mut msg = format!("processing: {}", full_name);
if verbosity.is_verbose() { if verbosity.is_verbose() {
let src = f.source(db); if let Some(src) = f.source(db) {
let original_file = src.file_id.original_file(db); let original_file = src.file_id.original_file(db);
let path = vfs.file_path(original_file); let path = vfs.file_path(original_file);
let syntax_range = src.value.syntax().text_range(); let syntax_range = src.value.syntax().text_range();
format_to!(msg, " ({} {:?})", path, syntax_range); format_to!(msg, " ({} {:?})", path, syntax_range);
}
} }
if verbosity.is_spammy() { if verbosity.is_spammy() {
bar.println(msg.to_string()); bar.println(msg.to_string());