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))?);
// 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()

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 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);

View file

@ -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 {

View file

@ -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(

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 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);
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())
.text_edit(TextEdit::replace(range, snippet))
.lookup_by(const_name)
.kind(CompletionItemKind::Const)
.set_documentation(const_.docs(ctx.db))
.add_to(acc);
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);
}
}
}

View file

@ -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

View file

@ -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> {

View file

@ -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 {

View file

@ -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))
}
}

View file

@ -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> {

View file

@ -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);

View file

@ -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()))
}
}

View file

@ -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()))

View file

@ -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)?

View file

@ -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,
}
})
}
}

View file

@ -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)]

View file

@ -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]))
}

View file

@ -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)
}

View file

@ -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);
}

View file

@ -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());