mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Move more ImmediateLocation::TypeAnnotation into PathKind::Type
This commit is contained in:
parent
6e07b17f69
commit
6b246292ca
4 changed files with 142 additions and 122 deletions
|
@ -18,7 +18,7 @@ pub(crate) fn complete_field_list(acc: &mut Completions, ctx: &CompletionContext
|
||||||
is_absolute_path: false,
|
is_absolute_path: false,
|
||||||
qualifier: None,
|
qualifier: None,
|
||||||
parent: None,
|
parent: None,
|
||||||
kind: PathKind::Type { in_tuple_struct: true },
|
kind: PathKind::Type { in_tuple_struct: true, ascription: None },
|
||||||
has_type_args: false,
|
has_type_args: false,
|
||||||
..
|
..
|
||||||
})),
|
})),
|
||||||
|
|
|
@ -5,8 +5,8 @@ use ide_db::FxHashSet;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{PathCompletionCtx, PathKind, PathQualifierCtx},
|
context::{PathCompletionCtx, PathKind, PathQualifierCtx, TypeAscriptionTarget},
|
||||||
patterns::{ImmediateLocation, TypeAnnotation},
|
patterns::ImmediateLocation,
|
||||||
render::render_type_inference,
|
render::render_type_inference,
|
||||||
CompletionContext, Completions,
|
CompletionContext, Completions,
|
||||||
};
|
};
|
||||||
|
@ -189,14 +189,22 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn complete_inferred_type(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
pub(crate) fn complete_inferred_type(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
||||||
use TypeAnnotation::*;
|
let pat = match dbg!(ctx.path_context()) {
|
||||||
let pat = match &ctx.completion_location {
|
Some(
|
||||||
Some(ImmediateLocation::TypeAnnotation(t)) => t,
|
ctx @ PathCompletionCtx {
|
||||||
|
kind: PathKind::Type { ascription: Some(ascription), .. },
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) if ctx.is_trivial_path() => ascription,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let x = match pat {
|
let x = match pat {
|
||||||
Let(pat) | FnParam(pat) => ctx.sema.type_of_pat(pat.as_ref()?),
|
TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
|
||||||
Const(exp) | RetType(exp) => ctx.sema.type_of_expr(exp.as_ref()?),
|
ctx.sema.type_of_pat(pat.as_ref()?)
|
||||||
|
}
|
||||||
|
TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => {
|
||||||
|
ctx.sema.type_of_expr(exp.as_ref()?)
|
||||||
|
}
|
||||||
}?
|
}?
|
||||||
.adjusted();
|
.adjusted();
|
||||||
let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?;
|
let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?;
|
||||||
|
|
|
@ -43,44 +43,7 @@ pub(crate) enum Visible {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
/// Existing qualifiers for the thing we are currently completing.
|
||||||
pub(super) enum PathKind {
|
|
||||||
Expr {
|
|
||||||
in_block_expr: bool,
|
|
||||||
in_loop_body: bool,
|
|
||||||
after_if_expr: bool,
|
|
||||||
ref_expr_parent: Option<ast::RefExpr>,
|
|
||||||
is_func_update: Option<ast::RecordExpr>,
|
|
||||||
},
|
|
||||||
Type {
|
|
||||||
in_tuple_struct: bool,
|
|
||||||
},
|
|
||||||
Attr {
|
|
||||||
kind: AttrKind,
|
|
||||||
annotated_item_kind: Option<SyntaxKind>,
|
|
||||||
},
|
|
||||||
Derive,
|
|
||||||
/// Path in item position, that is inside an (Assoc)ItemList
|
|
||||||
Item {
|
|
||||||
kind: ItemListKind,
|
|
||||||
},
|
|
||||||
Pat,
|
|
||||||
Vis {
|
|
||||||
has_in_token: bool,
|
|
||||||
},
|
|
||||||
Use,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub(super) enum ItemListKind {
|
|
||||||
SourceFile,
|
|
||||||
Module,
|
|
||||||
Impl,
|
|
||||||
TraitImpl,
|
|
||||||
Trait,
|
|
||||||
ExternBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(super) struct QualifierCtx {
|
pub(super) struct QualifierCtx {
|
||||||
pub(super) unsafe_tok: Option<SyntaxToken>,
|
pub(super) unsafe_tok: Option<SyntaxToken>,
|
||||||
|
@ -93,6 +56,7 @@ impl QualifierCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the path we are currently completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct PathCompletionCtx {
|
pub(crate) struct PathCompletionCtx {
|
||||||
/// If this is a call with () already there (or {} in case of record patterns)
|
/// If this is a call with () already there (or {} in case of record patterns)
|
||||||
|
@ -127,6 +91,58 @@ impl PathCompletionCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of path we are completing right now.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub(super) enum PathKind {
|
||||||
|
Expr {
|
||||||
|
in_block_expr: bool,
|
||||||
|
in_loop_body: bool,
|
||||||
|
after_if_expr: bool,
|
||||||
|
ref_expr_parent: Option<ast::RefExpr>,
|
||||||
|
is_func_update: Option<ast::RecordExpr>,
|
||||||
|
},
|
||||||
|
Type {
|
||||||
|
in_tuple_struct: bool,
|
||||||
|
/// Whether this type path is a type ascription or not
|
||||||
|
/// Original file ast node
|
||||||
|
ascription: Option<TypeAscriptionTarget>,
|
||||||
|
},
|
||||||
|
Attr {
|
||||||
|
kind: AttrKind,
|
||||||
|
annotated_item_kind: Option<SyntaxKind>,
|
||||||
|
},
|
||||||
|
Derive,
|
||||||
|
/// Path in item position, that is inside an (Assoc)ItemList
|
||||||
|
Item {
|
||||||
|
kind: ItemListKind,
|
||||||
|
},
|
||||||
|
Pat,
|
||||||
|
Vis {
|
||||||
|
has_in_token: bool,
|
||||||
|
},
|
||||||
|
Use,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub(crate) enum TypeAscriptionTarget {
|
||||||
|
Let(Option<ast::Pat>),
|
||||||
|
FnParam(Option<ast::Pat>),
|
||||||
|
RetType(Option<ast::Expr>),
|
||||||
|
Const(Option<ast::Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of item list a [`PathKind::Item`] belongs to.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub(super) enum ItemListKind {
|
||||||
|
SourceFile,
|
||||||
|
Module,
|
||||||
|
Impl,
|
||||||
|
TraitImpl,
|
||||||
|
Trait,
|
||||||
|
ExternBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The path qualifier state of the path we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct PathQualifierCtx {
|
pub(crate) struct PathQualifierCtx {
|
||||||
pub(crate) path: ast::Path,
|
pub(crate) path: ast::Path,
|
||||||
|
@ -139,6 +155,7 @@ pub(crate) struct PathQualifierCtx {
|
||||||
pub(crate) is_infer_qualifier: bool,
|
pub(crate) is_infer_qualifier: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the pattern we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct PatternContext {
|
pub(super) struct PatternContext {
|
||||||
pub(super) refutability: PatternRefutability,
|
pub(super) refutability: PatternRefutability,
|
||||||
|
@ -151,12 +168,14 @@ pub(super) struct PatternContext {
|
||||||
pub(super) record_pat: Option<ast::RecordPat>,
|
pub(super) record_pat: Option<ast::RecordPat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the lifetime we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct LifetimeContext {
|
pub(super) struct LifetimeContext {
|
||||||
pub(super) lifetime: Option<ast::Lifetime>,
|
pub(super) lifetime: Option<ast::Lifetime>,
|
||||||
pub(super) kind: LifetimeKind,
|
pub(super) kind: LifetimeKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of lifetime we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum LifetimeKind {
|
pub(super) enum LifetimeKind {
|
||||||
LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
|
LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
|
||||||
|
@ -165,6 +184,7 @@ pub(super) enum LifetimeKind {
|
||||||
LabelDef,
|
LabelDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the name we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct NameContext {
|
pub(super) struct NameContext {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -172,6 +192,7 @@ pub(super) struct NameContext {
|
||||||
pub(super) kind: NameKind,
|
pub(super) kind: NameKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of the name we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(super) enum NameKind {
|
pub(super) enum NameKind {
|
||||||
|
@ -196,6 +217,7 @@ pub(super) enum NameKind {
|
||||||
Variant,
|
Variant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the NameRef we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct NameRefContext {
|
pub(super) struct NameRefContext {
|
||||||
/// NameRef syntax in the original file
|
/// NameRef syntax in the original file
|
||||||
|
@ -203,6 +225,7 @@ pub(super) struct NameRefContext {
|
||||||
pub(super) kind: Option<NameRefKind>,
|
pub(super) kind: Option<NameRefKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of the NameRef we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum NameRefKind {
|
pub(super) enum NameRefKind {
|
||||||
Path(PathCompletionCtx),
|
Path(PathCompletionCtx),
|
||||||
|
@ -213,21 +236,26 @@ pub(super) enum NameRefKind {
|
||||||
RecordExpr(ast::RecordExpr),
|
RecordExpr(ast::RecordExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The identifier we are currently completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum IdentContext {
|
pub(super) enum IdentContext {
|
||||||
Name(NameContext),
|
Name(NameContext),
|
||||||
NameRef(NameRefContext),
|
NameRef(NameRefContext),
|
||||||
Lifetime(LifetimeContext),
|
Lifetime(LifetimeContext),
|
||||||
/// Original token, fake token
|
/// The string the cursor is currently inside
|
||||||
String {
|
String {
|
||||||
|
/// original token
|
||||||
original: ast::String,
|
original: ast::String,
|
||||||
|
/// fake token
|
||||||
expanded: Option<ast::String>,
|
expanded: Option<ast::String>,
|
||||||
},
|
},
|
||||||
|
/// Set if we are currently completing in an unexpanded attribute, this usually implies a builtin attribute like `allow($0)`
|
||||||
UnexpandedAttrTT {
|
UnexpandedAttrTT {
|
||||||
fake_attribute_under_caret: Option<ast::Attr>,
|
fake_attribute_under_caret: Option<ast::Attr>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about the field or method access we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct DotAccess {
|
pub(super) struct DotAccess {
|
||||||
pub(super) receiver: Option<ast::Expr>,
|
pub(super) receiver: Option<ast::Expr>,
|
||||||
|
@ -1161,13 +1189,65 @@ impl<'a> CompletionContext<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let fetch_ascription = |it: Option<SyntaxNode>| {
|
||||||
|
let parent = it?;
|
||||||
|
match_ast! {
|
||||||
|
match parent {
|
||||||
|
ast::Const(it) => {
|
||||||
|
let name = find_in_original_file(it.name(), original_file)?;
|
||||||
|
let original = ast::Const::cast(name.syntax().parent()?)?;
|
||||||
|
Some(TypeAscriptionTarget::Const(original.body()))
|
||||||
|
},
|
||||||
|
ast::RetType(it) => {
|
||||||
|
if it.thin_arrow_token().is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let parent = match ast::Fn::cast(parent.parent()?) {
|
||||||
|
Some(x) => x.param_list(),
|
||||||
|
None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let parent = find_in_original_file(parent, original_file)?.syntax().parent()?;
|
||||||
|
Some(TypeAscriptionTarget::RetType(match_ast! {
|
||||||
|
match parent {
|
||||||
|
ast::ClosureExpr(it) => {
|
||||||
|
it.body()
|
||||||
|
},
|
||||||
|
ast::Fn(it) => {
|
||||||
|
it.body().map(ast::Expr::BlockExpr)
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
ast::Param(it) => {
|
||||||
|
if it.colon_token().is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(TypeAscriptionTarget::FnParam(find_in_original_file(it.pat(), original_file)))
|
||||||
|
},
|
||||||
|
ast::LetStmt(it) => {
|
||||||
|
if it.colon_token().is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(TypeAscriptionTarget::Let(find_in_original_file(it.pat(), original_file)))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Infer the path kind
|
// Infer the path kind
|
||||||
let kind = path.syntax().parent().and_then(|it| {
|
let kind = path.syntax().parent().and_then(|it| {
|
||||||
match_ast! {
|
match_ast! {
|
||||||
match it {
|
match it {
|
||||||
ast::PathType(it) => Some(PathKind::Type {
|
ast::PathType(it) => {
|
||||||
in_tuple_struct: it.syntax().parent().map_or(false, |it| ast::TupleField::can_cast(it.kind()))
|
let ascription = fetch_ascription(it.syntax().parent());
|
||||||
}),
|
Some(PathKind::Type {
|
||||||
|
in_tuple_struct: it.syntax().parent().map_or(false, |it| ast::TupleField::can_cast(it.kind())),
|
||||||
|
ascription,
|
||||||
|
})
|
||||||
|
},
|
||||||
ast::PathExpr(it) => {
|
ast::PathExpr(it) => {
|
||||||
if let Some(p) = it.syntax().parent() {
|
if let Some(p) = it.syntax().parent() {
|
||||||
if ast::ExprStmt::can_cast(p.kind()) {
|
if ast::ExprStmt::can_cast(p.kind()) {
|
||||||
|
@ -1212,7 +1292,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
let parent = it.syntax().parent();
|
let parent = it.syntax().parent();
|
||||||
match parent.as_ref().map(|it| it.kind()) {
|
match parent.as_ref().map(|it| it.kind()) {
|
||||||
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
|
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
|
||||||
Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type { in_tuple_struct: false }),
|
Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type { in_tuple_struct: false, ascription: None }),
|
||||||
Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
|
Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
|
||||||
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
|
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
|
||||||
Some(it) => match_ast! {
|
Some(it) => match_ast! {
|
||||||
|
|
|
@ -7,23 +7,15 @@
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasLoopBody, HasName},
|
ast::{self, HasLoopBody},
|
||||||
match_ast, AstNode, SyntaxElement,
|
match_ast, AstNode, SyntaxElement,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize,
|
SyntaxNode, SyntaxToken, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::tests::check_pattern_is_applicable;
|
use crate::tests::check_pattern_is_applicable;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub(crate) enum TypeAnnotation {
|
|
||||||
Let(Option<ast::Pat>),
|
|
||||||
FnParam(Option<ast::Pat>),
|
|
||||||
RetType(Option<ast::Expr>),
|
|
||||||
Const(Option<ast::Expr>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Direct parent "thing" of what we are currently completing.
|
/// Direct parent "thing" of what we are currently completing.
|
||||||
///
|
///
|
||||||
/// This may contain nodes of the fake file as well as the original, comments on the variants specify
|
/// This may contain nodes of the fake file as well as the original, comments on the variants specify
|
||||||
|
@ -31,8 +23,6 @@ pub(crate) enum TypeAnnotation {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum ImmediateLocation {
|
pub(crate) enum ImmediateLocation {
|
||||||
TypeBound,
|
TypeBound,
|
||||||
/// Original file ast node
|
|
||||||
TypeAnnotation(TypeAnnotation),
|
|
||||||
// Only set from a type arg
|
// Only set from a type arg
|
||||||
/// Original file ast node
|
/// Original file ast node
|
||||||
GenericArgList(ast::GenericArgList),
|
GenericArgList(ast::GenericArgList),
|
||||||
|
@ -84,62 +74,9 @@ pub(crate) fn determine_location(
|
||||||
ast::GenericArgList(_) => sema
|
ast::GenericArgList(_) => sema
|
||||||
.find_node_at_offset_with_macros(original_file, offset)
|
.find_node_at_offset_with_macros(original_file, offset)
|
||||||
.map(ImmediateLocation::GenericArgList)?,
|
.map(ImmediateLocation::GenericArgList)?,
|
||||||
ast::Const(it) => {
|
|
||||||
if !it.ty().map_or(false, |x| x.syntax().text_range().contains(offset)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let name = find_in_original_file(it.name(), original_file)?;
|
|
||||||
let original = ast::Const::cast(name.syntax().parent()?)?;
|
|
||||||
ImmediateLocation::TypeAnnotation(TypeAnnotation::Const(original.body()))
|
|
||||||
},
|
|
||||||
ast::RetType(it) => {
|
|
||||||
if it.thin_arrow_token().is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if !it.ty().map_or(false, |x| x.syntax().text_range().contains(offset)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let parent = match ast::Fn::cast(parent.parent()?) {
|
|
||||||
Some(x) => x.param_list(),
|
|
||||||
None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
|
|
||||||
};
|
|
||||||
let parent = find_in_original_file(parent, original_file)?.syntax().parent()?;
|
|
||||||
ImmediateLocation::TypeAnnotation(TypeAnnotation::RetType(match_ast! {
|
|
||||||
match parent {
|
|
||||||
ast::ClosureExpr(it) => {
|
|
||||||
it.body()
|
|
||||||
},
|
|
||||||
ast::Fn(it) => {
|
|
||||||
it.body().map(ast::Expr::BlockExpr)
|
|
||||||
},
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
ast::Param(it) => {
|
|
||||||
if it.colon_token().is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if !it.ty().map_or(false, |x| x.syntax().text_range().contains(offset)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
ImmediateLocation::TypeAnnotation(TypeAnnotation::FnParam(find_in_original_file(it.pat(), original_file)))
|
|
||||||
},
|
|
||||||
ast::LetStmt(it) => {
|
|
||||||
if it.colon_token().is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if !it.ty().map_or(false, |x| x.syntax().text_range().contains(offset)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
ImmediateLocation::TypeAnnotation(TypeAnnotation::Let(find_in_original_file(it.pat(), original_file)))
|
|
||||||
},
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fn find_in_original_file<N: AstNode>(x: Option<N>, original_file: &SyntaxNode) -> Option<N> {
|
|
||||||
x.map(|e| e.syntax().text_range()).and_then(|r| find_node_with_range(original_file, r))
|
|
||||||
}
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,11 +101,6 @@ fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode {
|
||||||
name_ref.syntax().clone()
|
name_ref.syntax().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
|
|
||||||
let range = syntax.text_range().intersect(range)?;
|
|
||||||
syntax.covering_element(range).ancestors().find_map(N::cast)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
|
pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
|
||||||
element.into_token().and_then(previous_non_trivia_token)
|
element.into_token().and_then(previous_non_trivia_token)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue