mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
Improve inlay hint resolution reliability
This commit is contained in:
parent
13ac53e73d
commit
5ca5d52697
20 changed files with 282 additions and 216 deletions
|
@ -15,7 +15,7 @@ use span::{Edition, EditionedFileId};
|
||||||
use stdx::never;
|
use stdx::never;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize,
|
match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize, WalkEvent,
|
||||||
};
|
};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
@ -36,6 +36,192 @@ mod implicit_static;
|
||||||
mod param_name;
|
mod param_name;
|
||||||
mod range_exclusive;
|
mod range_exclusive;
|
||||||
|
|
||||||
|
// Feature: Inlay Hints
|
||||||
|
//
|
||||||
|
// rust-analyzer shows additional information inline with the source code.
|
||||||
|
// Editors usually render this using read-only virtual text snippets interspersed with code.
|
||||||
|
//
|
||||||
|
// rust-analyzer by default shows hints for
|
||||||
|
//
|
||||||
|
// * types of local variables
|
||||||
|
// * names of function arguments
|
||||||
|
// * names of const generic parameters
|
||||||
|
// * types of chained expressions
|
||||||
|
//
|
||||||
|
// Optionally, one can enable additional hints for
|
||||||
|
//
|
||||||
|
// * return types of closure expressions
|
||||||
|
// * elided lifetimes
|
||||||
|
// * compiler inserted reborrows
|
||||||
|
// * names of generic type and lifetime parameters
|
||||||
|
//
|
||||||
|
// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
|
||||||
|
// any of the
|
||||||
|
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria]
|
||||||
|
// are met:
|
||||||
|
//
|
||||||
|
// * the parameter name is a suffix of the function's name
|
||||||
|
// * the argument is a qualified constructing or call expression where the qualifier is an ADT
|
||||||
|
// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
|
||||||
|
// of argument with _ splitting it off
|
||||||
|
// * the parameter name starts with `ra_fixture`
|
||||||
|
// * the parameter name is a
|
||||||
|
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name]
|
||||||
|
// in a unary function
|
||||||
|
// * the parameter name is a
|
||||||
|
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character]
|
||||||
|
// in a unary function
|
||||||
|
//
|
||||||
|
// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
|
||||||
|
pub(crate) fn inlay_hints(
|
||||||
|
db: &RootDatabase,
|
||||||
|
file_id: FileId,
|
||||||
|
range_limit: Option<TextRange>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
) -> Vec<InlayHint> {
|
||||||
|
let _p = tracing::info_span!("inlay_hints").entered();
|
||||||
|
let sema = Semantics::new(db);
|
||||||
|
let file_id = sema
|
||||||
|
.attach_first_edition(file_id)
|
||||||
|
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
|
||||||
|
let file = sema.parse(file_id);
|
||||||
|
let file = file.syntax();
|
||||||
|
|
||||||
|
let mut acc = Vec::new();
|
||||||
|
|
||||||
|
let Some(scope) = sema.scope(file) else {
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
let famous_defs = FamousDefs(&sema, scope.krate());
|
||||||
|
|
||||||
|
let parent_impl = &mut None;
|
||||||
|
let hints = |node| hints(&mut acc, parent_impl, &famous_defs, config, file_id, node);
|
||||||
|
match range_limit {
|
||||||
|
// FIXME: This can miss some hints that require the parent of the range to calculate
|
||||||
|
Some(range) => match file.covering_element(range) {
|
||||||
|
NodeOrToken::Token(_) => return acc,
|
||||||
|
NodeOrToken::Node(n) => n
|
||||||
|
.preorder()
|
||||||
|
.filter(|event| matches!(event, WalkEvent::Enter(node) if range.intersect(node.text_range()).is_some()))
|
||||||
|
.for_each(hints),
|
||||||
|
},
|
||||||
|
None => file.preorder().for_each(hints),
|
||||||
|
};
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn inlay_hints_resolve(
|
||||||
|
db: &RootDatabase,
|
||||||
|
file_id: FileId,
|
||||||
|
resolve_range: TextRange,
|
||||||
|
hash: u64,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
hasher: impl Fn(&InlayHint) -> u64,
|
||||||
|
) -> Option<InlayHint> {
|
||||||
|
let _p = tracing::info_span!("inlay_hints_resolve").entered();
|
||||||
|
let sema = Semantics::new(db);
|
||||||
|
let file_id = sema
|
||||||
|
.attach_first_edition(file_id)
|
||||||
|
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
|
||||||
|
let file = sema.parse(file_id);
|
||||||
|
let file = file.syntax();
|
||||||
|
|
||||||
|
let scope = sema.scope(file)?;
|
||||||
|
let famous_defs = FamousDefs(&sema, scope.krate());
|
||||||
|
let mut acc = Vec::new();
|
||||||
|
|
||||||
|
let parent_impl = &mut None;
|
||||||
|
let hints = |node| hints(&mut acc, parent_impl, &famous_defs, config, file_id, node);
|
||||||
|
|
||||||
|
let mut res = file.clone();
|
||||||
|
let res = loop {
|
||||||
|
res = match res.child_or_token_at_range(resolve_range) {
|
||||||
|
Some(NodeOrToken::Node(n)) if n.text_range() == resolve_range => break n,
|
||||||
|
Some(NodeOrToken::Node(n)) => n,
|
||||||
|
_ => break res,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
res.preorder().for_each(hints);
|
||||||
|
acc.into_iter().find(|hint| hasher(hint) == hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hints(
|
||||||
|
hints: &mut Vec<InlayHint>,
|
||||||
|
parent_impl: &mut Option<ast::Impl>,
|
||||||
|
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
file_id: EditionedFileId,
|
||||||
|
node: WalkEvent<SyntaxNode>,
|
||||||
|
) {
|
||||||
|
let node = match node {
|
||||||
|
WalkEvent::Enter(node) => node,
|
||||||
|
WalkEvent::Leave(n) => {
|
||||||
|
if ast::Impl::can_cast(n.kind()) {
|
||||||
|
parent_impl.take();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
closing_brace::hints(hints, sema, config, file_id, node.clone());
|
||||||
|
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
|
||||||
|
generic_param::hints(hints, sema, config, any_has_generic_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
match_ast! {
|
||||||
|
match node {
|
||||||
|
ast::Expr(expr) => {
|
||||||
|
chaining::hints(hints, famous_defs, config, file_id, &expr);
|
||||||
|
adjustment::hints(hints, famous_defs, config, file_id, &expr);
|
||||||
|
match expr {
|
||||||
|
ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)),
|
||||||
|
ast::Expr::MethodCallExpr(it) => {
|
||||||
|
param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it))
|
||||||
|
}
|
||||||
|
ast::Expr::ClosureExpr(it) => {
|
||||||
|
closure_captures::hints(hints, famous_defs, config, file_id, it.clone());
|
||||||
|
closure_ret::hints(hints, famous_defs, config, file_id, it)
|
||||||
|
},
|
||||||
|
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::Pat(it) => {
|
||||||
|
binding_mode::hints(hints, famous_defs, config, file_id, &it);
|
||||||
|
match it {
|
||||||
|
ast::Pat::IdentPat(it) => {
|
||||||
|
bind_pat::hints(hints, famous_defs, config, file_id, &it);
|
||||||
|
}
|
||||||
|
ast::Pat::RangePat(it) => {
|
||||||
|
range_exclusive::hints(hints, famous_defs, config, file_id, it);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Some(())
|
||||||
|
},
|
||||||
|
ast::Item(it) => match it {
|
||||||
|
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
|
||||||
|
ast::Item::Impl(impl_) => {
|
||||||
|
*parent_impl = Some(impl_);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
ast::Item::Fn(it) => {
|
||||||
|
implicit_drop::hints(hints, famous_defs, config, file_id, &it);
|
||||||
|
fn_lifetime_fn::hints(hints, famous_defs, config, file_id, it)
|
||||||
|
},
|
||||||
|
// static type elisions
|
||||||
|
ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)),
|
||||||
|
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
|
||||||
|
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
// FIXME: fn-ptr type, dyn fn type, and trait object type elisions
|
||||||
|
ast::Type(_) => None,
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct InlayHintsConfig {
|
pub struct InlayHintsConfig {
|
||||||
pub render_colons: bool,
|
pub render_colons: bool,
|
||||||
|
@ -162,6 +348,9 @@ pub struct InlayHint {
|
||||||
pub label: InlayHintLabel,
|
pub label: InlayHintLabel,
|
||||||
/// Text edit to apply when "accepting" this inlay hint.
|
/// Text edit to apply when "accepting" this inlay hint.
|
||||||
pub text_edit: Option<TextEdit>,
|
pub text_edit: Option<TextEdit>,
|
||||||
|
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
|
||||||
|
/// hint does not support resolving.
|
||||||
|
pub resolve_parent: Option<TextRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::hash::Hash for InlayHint {
|
impl std::hash::Hash for InlayHint {
|
||||||
|
@ -186,6 +375,7 @@ impl InlayHint {
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,11 +388,12 @@ impl InlayHint {
|
||||||
position: InlayHintPosition::Before,
|
position: InlayHintPosition::Before,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_resolve(&self) -> bool {
|
pub fn needs_resolve(&self) -> Option<TextRange> {
|
||||||
self.text_edit.is_some() || self.label.needs_resolve()
|
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,190 +625,6 @@ fn label_of_ty(
|
||||||
Some(r)
|
Some(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_to_text_edit(
|
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
|
||||||
node_for_hint: &SyntaxNode,
|
|
||||||
ty: &hir::Type,
|
|
||||||
offset_to_insert: TextSize,
|
|
||||||
prefix: String,
|
|
||||||
) -> Option<TextEdit> {
|
|
||||||
let scope = sema.scope(node_for_hint)?;
|
|
||||||
// FIXME: Limit the length and bail out on excess somehow?
|
|
||||||
let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?;
|
|
||||||
|
|
||||||
let mut builder = TextEdit::builder();
|
|
||||||
builder.insert(offset_to_insert, prefix);
|
|
||||||
builder.insert(offset_to_insert, rendered);
|
|
||||||
Some(builder.finish())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feature: Inlay Hints
|
|
||||||
//
|
|
||||||
// rust-analyzer shows additional information inline with the source code.
|
|
||||||
// Editors usually render this using read-only virtual text snippets interspersed with code.
|
|
||||||
//
|
|
||||||
// rust-analyzer by default shows hints for
|
|
||||||
//
|
|
||||||
// * types of local variables
|
|
||||||
// * names of function arguments
|
|
||||||
// * names of const generic parameters
|
|
||||||
// * types of chained expressions
|
|
||||||
//
|
|
||||||
// Optionally, one can enable additional hints for
|
|
||||||
//
|
|
||||||
// * return types of closure expressions
|
|
||||||
// * elided lifetimes
|
|
||||||
// * compiler inserted reborrows
|
|
||||||
// * names of generic type and lifetime parameters
|
|
||||||
//
|
|
||||||
// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
|
|
||||||
// any of the
|
|
||||||
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria]
|
|
||||||
// are met:
|
|
||||||
//
|
|
||||||
// * the parameter name is a suffix of the function's name
|
|
||||||
// * the argument is a qualified constructing or call expression where the qualifier is an ADT
|
|
||||||
// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
|
|
||||||
// of argument with _ splitting it off
|
|
||||||
// * the parameter name starts with `ra_fixture`
|
|
||||||
// * the parameter name is a
|
|
||||||
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name]
|
|
||||||
// in a unary function
|
|
||||||
// * the parameter name is a
|
|
||||||
// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character]
|
|
||||||
// in a unary function
|
|
||||||
//
|
|
||||||
// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
|
|
||||||
pub(crate) fn inlay_hints(
|
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: FileId,
|
|
||||||
range_limit: Option<TextRange>,
|
|
||||||
config: &InlayHintsConfig,
|
|
||||||
) -> Vec<InlayHint> {
|
|
||||||
let _p = tracing::info_span!("inlay_hints").entered();
|
|
||||||
let sema = Semantics::new(db);
|
|
||||||
let file_id = sema
|
|
||||||
.attach_first_edition(file_id)
|
|
||||||
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
|
|
||||||
let file = sema.parse(file_id);
|
|
||||||
let file = file.syntax();
|
|
||||||
|
|
||||||
let mut acc = Vec::new();
|
|
||||||
|
|
||||||
if let Some(scope) = sema.scope(file) {
|
|
||||||
let famous_defs = FamousDefs(&sema, scope.krate());
|
|
||||||
|
|
||||||
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
|
|
||||||
match range_limit {
|
|
||||||
Some(range) => match file.covering_element(range) {
|
|
||||||
NodeOrToken::Token(_) => return acc,
|
|
||||||
NodeOrToken::Node(n) => n
|
|
||||||
.descendants()
|
|
||||||
.filter(|descendant| range.intersect(descendant.text_range()).is_some())
|
|
||||||
.for_each(hints),
|
|
||||||
},
|
|
||||||
None => file.descendants().for_each(hints),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn inlay_hints_resolve(
|
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: FileId,
|
|
||||||
position: TextSize,
|
|
||||||
hash: u64,
|
|
||||||
config: &InlayHintsConfig,
|
|
||||||
hasher: impl Fn(&InlayHint) -> u64,
|
|
||||||
) -> Option<InlayHint> {
|
|
||||||
let _p = tracing::info_span!("inlay_hints_resolve").entered();
|
|
||||||
let sema = Semantics::new(db);
|
|
||||||
let file_id = sema
|
|
||||||
.attach_first_edition(file_id)
|
|
||||||
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
|
|
||||||
let file = sema.parse(file_id);
|
|
||||||
let file = file.syntax();
|
|
||||||
|
|
||||||
let scope = sema.scope(file)?;
|
|
||||||
let famous_defs = FamousDefs(&sema, scope.krate());
|
|
||||||
let mut acc = Vec::new();
|
|
||||||
|
|
||||||
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
|
|
||||||
let token = file.token_at_offset(position).left_biased()?;
|
|
||||||
if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) {
|
|
||||||
parent_block.syntax().descendants().for_each(hints)
|
|
||||||
} else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) {
|
|
||||||
parent_item.syntax().descendants().for_each(hints)
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
acc.into_iter().find(|hint| hasher(hint) == hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hints(
|
|
||||||
hints: &mut Vec<InlayHint>,
|
|
||||||
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
|
||||||
config: &InlayHintsConfig,
|
|
||||||
file_id: EditionedFileId,
|
|
||||||
node: SyntaxNode,
|
|
||||||
) {
|
|
||||||
closing_brace::hints(hints, sema, config, file_id, node.clone());
|
|
||||||
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
|
|
||||||
generic_param::hints(hints, sema, config, any_has_generic_args);
|
|
||||||
}
|
|
||||||
match_ast! {
|
|
||||||
match node {
|
|
||||||
ast::Expr(expr) => {
|
|
||||||
chaining::hints(hints, famous_defs, config, file_id, &expr);
|
|
||||||
adjustment::hints(hints, sema, config, file_id, &expr);
|
|
||||||
match expr {
|
|
||||||
ast::Expr::CallExpr(it) => param_name::hints(hints, sema, config, ast::Expr::from(it)),
|
|
||||||
ast::Expr::MethodCallExpr(it) => {
|
|
||||||
param_name::hints(hints, sema, config, ast::Expr::from(it))
|
|
||||||
}
|
|
||||||
ast::Expr::ClosureExpr(it) => {
|
|
||||||
closure_captures::hints(hints, famous_defs, config, file_id, it.clone());
|
|
||||||
closure_ret::hints(hints, famous_defs, config, file_id, it)
|
|
||||||
},
|
|
||||||
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, config, it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::Pat(it) => {
|
|
||||||
binding_mode::hints(hints, sema, config, &it);
|
|
||||||
match it {
|
|
||||||
ast::Pat::IdentPat(it) => {
|
|
||||||
bind_pat::hints(hints, famous_defs, config, file_id, &it);
|
|
||||||
}
|
|
||||||
ast::Pat::RangePat(it) => {
|
|
||||||
range_exclusive::hints(hints, config, it);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
},
|
|
||||||
ast::Item(it) => match it {
|
|
||||||
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
|
|
||||||
ast::Item::Impl(_) => None,
|
|
||||||
ast::Item::Fn(it) => {
|
|
||||||
implicit_drop::hints(hints, sema, config, file_id, &it);
|
|
||||||
fn_lifetime_fn::hints(hints, config, it)
|
|
||||||
},
|
|
||||||
// static type elisions
|
|
||||||
ast::Item::Static(it) => implicit_static::hints(hints, config, Either::Left(it)),
|
|
||||||
ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
|
|
||||||
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
// FIXME: fn-ptr type, dyn fn type, and trait object type elisions
|
|
||||||
ast::Type(_) => None,
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator.
|
/// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator.
|
||||||
fn hint_iterator(
|
fn hint_iterator(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
@ -653,6 +660,23 @@ fn hint_iterator(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ty_to_text_edit(
|
||||||
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
node_for_hint: &SyntaxNode,
|
||||||
|
ty: &hir::Type,
|
||||||
|
offset_to_insert: TextSize,
|
||||||
|
prefix: String,
|
||||||
|
) -> Option<TextEdit> {
|
||||||
|
let scope = sema.scope(node_for_hint)?;
|
||||||
|
// FIXME: Limit the length and bail out on excess somehow?
|
||||||
|
let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?;
|
||||||
|
|
||||||
|
let mut builder = TextEdit::builder();
|
||||||
|
builder.insert(offset_to_insert, prefix);
|
||||||
|
builder.insert(offset_to_insert, rendered);
|
||||||
|
Some(builder.finish())
|
||||||
|
}
|
||||||
|
|
||||||
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
||||||
matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
|
matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
|
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
|
||||||
Semantics,
|
|
||||||
};
|
};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::famous_defs::FamousDefs;
|
||||||
|
|
||||||
use span::EditionedFileId;
|
use span::EditionedFileId;
|
||||||
use stdx::never;
|
use stdx::never;
|
||||||
|
@ -24,7 +23,7 @@ use crate::{
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
file_id: EditionedFileId,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
|
@ -156,6 +155,7 @@ pub(super) fn hints(
|
||||||
kind: InlayKind::Adjustment,
|
kind: InlayKind::Adjustment,
|
||||||
label,
|
label,
|
||||||
text_edit: None,
|
text_edit: None,
|
||||||
|
resolve_parent: Some(expr.syntax().text_range()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if !postfix && needs_inner_parens {
|
if !postfix && needs_inner_parens {
|
||||||
|
|
|
@ -110,6 +110,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: !render_colons,
|
pad_left: !render_colons,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(pat.syntax().text_range()),
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -2,17 +2,19 @@
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! let /* & */ (/* ref */ x,) = &(0,);
|
//! let /* & */ (/* ref */ x,) = &(0,);
|
||||||
//! ```
|
//! ```
|
||||||
use hir::{Mutability, Semantics};
|
use hir::Mutability;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::famous_defs::FamousDefs;
|
||||||
|
|
||||||
|
use span::EditionedFileId;
|
||||||
use syntax::ast::{self, AstNode};
|
use syntax::ast::{self, AstNode};
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
|
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
pat: &ast::Pat,
|
pat: &ast::Pat,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.binding_mode_hints {
|
if !config.binding_mode_hints {
|
||||||
|
@ -57,6 +59,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::Before,
|
position: InlayHintPosition::Before,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: mut_reference,
|
pad_right: mut_reference,
|
||||||
|
resolve_parent: Some(pat.syntax().text_range()),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
match pat {
|
match pat {
|
||||||
|
@ -75,6 +78,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::Before,
|
position: InlayHintPosition::Before,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: Some(pat.syntax().text_range()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
|
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
|
||||||
|
|
|
@ -67,6 +67,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: true,
|
pad_left: true,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(expr.syntax().text_range()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,13 @@ pub(super) fn hints(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
file_id: EditionedFileId,
|
||||||
mut node: SyntaxNode,
|
original_node: SyntaxNode,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let min_lines = config.closing_brace_hints_min_lines?;
|
let min_lines = config.closing_brace_hints_min_lines?;
|
||||||
|
|
||||||
let name = |it: ast::Name| it.syntax().text_range();
|
let name = |it: ast::Name| it.syntax().text_range();
|
||||||
|
|
||||||
|
let mut node = original_node.clone();
|
||||||
let mut closing_token;
|
let mut closing_token;
|
||||||
let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
||||||
closing_token = item_list.r_curly_token()?;
|
closing_token = item_list.r_curly_token()?;
|
||||||
|
@ -145,6 +146,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: true,
|
pad_left: true,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(original_node.text_range()),
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(closure.syntax().text_range()),
|
||||||
});
|
});
|
||||||
range
|
range
|
||||||
}
|
}
|
||||||
|
@ -52,6 +53,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: None,
|
||||||
});
|
});
|
||||||
let last = captures.len() - 1;
|
let last = captures.len() - 1;
|
||||||
for (idx, capture) in captures.into_iter().enumerate() {
|
for (idx, capture) in captures.into_iter().enumerate() {
|
||||||
|
@ -85,6 +87,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(closure.syntax().text_range()),
|
||||||
});
|
});
|
||||||
|
|
||||||
if idx != last {
|
if idx != last {
|
||||||
|
@ -96,6 +99,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +111,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -72,6 +72,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(closure.syntax().text_range()),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub(super) fn enum_hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
for variant in enum_.variant_list()?.variants() {
|
for variant in enum_.variant_list()?.variants() {
|
||||||
variant_hints(acc, sema, &variant);
|
variant_hints(acc, sema, &enum_, &variant);
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ pub(super) fn enum_hints(
|
||||||
fn variant_hints(
|
fn variant_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
enum_: &ast::Enum,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if variant.expr().is_some() {
|
if variant.expr().is_some() {
|
||||||
|
@ -90,6 +91,7 @@ fn variant_hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: Some(enum_.syntax().text_range()),
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! fn example/* <'0> */(a: &/* '0 */()) {}
|
//! fn example/* <'0> */(a: &/* '0 */()) {}
|
||||||
//! ```
|
//! ```
|
||||||
use ide_db::{syntax_helpers::node_ext::walk_ty, FxHashMap};
|
use ide_db::{famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use span::EditionedFileId;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, HasGenericParams, HasName},
|
ast::{self, AstNode, HasGenericParams, HasName},
|
||||||
SyntaxToken,
|
SyntaxToken,
|
||||||
|
@ -14,7 +15,9 @@ use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeE
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
func: ast::Fn,
|
func: ast::Fn,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
||||||
|
@ -29,6 +32,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_list = func.param_list()?;
|
let param_list = func.param_list()?;
|
||||||
|
@ -195,6 +199,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(None, allocated_lifetimes) => acc.push(InlayHint {
|
(None, allocated_lifetimes) => acc.push(InlayHint {
|
||||||
|
@ -205,6 +210,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
resolve_parent: None,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -92,6 +92,7 @@ pub(crate) fn hints(
|
||||||
kind: InlayKind::GenericParameter,
|
kind: InlayKind::GenericParameter,
|
||||||
label,
|
label,
|
||||||
text_edit: None,
|
text_edit: None,
|
||||||
|
resolve_parent: Some(node.syntax().text_range()),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
use hir::{
|
use hir::{
|
||||||
db::{DefDatabase as _, HirDatabase as _},
|
db::{DefDatabase as _, HirDatabase as _},
|
||||||
mir::{MirSpan, TerminatorKind},
|
mir::{MirSpan, TerminatorKind},
|
||||||
ChalkTyInterner, DefWithBody, Semantics,
|
ChalkTyInterner, DefWithBody,
|
||||||
};
|
};
|
||||||
use ide_db::{FileRange, RootDatabase};
|
use ide_db::{famous_defs::FamousDefs, FileRange};
|
||||||
|
|
||||||
use span::EditionedFileId;
|
use span::EditionedFileId;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -22,16 +22,16 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
file_id: EditionedFileId,
|
||||||
def: &ast::Fn,
|
node: &ast::Fn,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.implicit_drop_hints {
|
if !config.implicit_drop_hints {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let def = sema.to_def(def)?;
|
let def = sema.to_def(node)?;
|
||||||
let def: DefWithBody = def.into();
|
let def: DefWithBody = def.into();
|
||||||
|
|
||||||
let (hir, source_map) = sema.db.body_with_source_map(def.into());
|
let (hir, source_map) = sema.db.body_with_source_map(def.into());
|
||||||
|
@ -121,6 +121,7 @@ pub(super) fn hints(
|
||||||
kind: InlayKind::Drop,
|
kind: InlayKind::Drop,
|
||||||
label,
|
label,
|
||||||
text_edit: None,
|
text_edit: None,
|
||||||
|
resolve_parent: Some(node.syntax().text_range()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
//! static S: &/* 'static */str = "";
|
//! static S: &/* 'static */str = "";
|
||||||
//! ```
|
//! ```
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use ide_db::famous_defs::FamousDefs;
|
||||||
|
use span::EditionedFileId;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
|
@ -12,7 +14,9 @@ use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeE
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
statik_or_const: Either<ast::Static, ast::Const>,
|
statik_or_const: Either<ast::Static, ast::Const>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints != LifetimeElisionHints::Always {
|
if config.lifetime_elision_hints != LifetimeElisionHints::Always {
|
||||||
|
@ -38,6 +42,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{Callable, Semantics};
|
use hir::{Callable, Semantics};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::{famous_defs::FamousDefs, RootDatabase};
|
||||||
|
|
||||||
|
use span::EditionedFileId;
|
||||||
use stdx::to_lower_snake_case;
|
use stdx::to_lower_snake_case;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, HasArgList, HasName, UnaryOp},
|
ast::{self, AstNode, HasArgList, HasName, UnaryOp},
|
||||||
|
@ -19,8 +20,9 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
expr: ast::Expr,
|
expr: ast::Expr,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.parameter_hints {
|
if !config.parameter_hints {
|
||||||
|
@ -60,6 +62,7 @@ pub(super) fn hints(
|
||||||
position: InlayHintPosition::Before,
|
position: InlayHintPosition::Before,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
resolve_parent: Some(expr.syntax().text_range()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
//! for i in 0../* < */10 {}
|
//! for i in 0../* < */10 {}
|
||||||
//! if let ../* < */100 = 50 {}
|
//! if let ../* < */100 = 50 {}
|
||||||
//! ```
|
//! ```
|
||||||
|
use ide_db::famous_defs::FamousDefs;
|
||||||
|
use span::EditionedFileId;
|
||||||
use syntax::{ast, SyntaxToken, T};
|
use syntax::{ast, SyntaxToken, T};
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintsConfig};
|
use crate::{InlayHint, InlayHintsConfig};
|
||||||
|
|
||||||
pub(super) fn hints(
|
pub(super) fn hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
range: impl ast::RangeItem,
|
range: impl ast::RangeItem,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
(config.range_exclusive_hints && range.end().is_some())
|
(config.range_exclusive_hints && range.end().is_some())
|
||||||
|
@ -30,6 +34,7 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint {
|
||||||
kind: crate::InlayKind::RangeExclusive,
|
kind: crate::InlayKind::RangeExclusive,
|
||||||
label: crate::InlayHintLabel::from("<"),
|
label: crate::InlayHintLabel::from("<"),
|
||||||
text_edit: None,
|
text_edit: None,
|
||||||
|
resolve_parent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,12 +439,12 @@ impl Analysis {
|
||||||
&self,
|
&self,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
position: TextSize,
|
resolve_range: TextRange,
|
||||||
hash: u64,
|
hash: u64,
|
||||||
hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe,
|
hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe,
|
||||||
) -> Cancellable<Option<InlayHint>> {
|
) -> Cancellable<Option<InlayHint>> {
|
||||||
self.with_db(|db| {
|
self.with_db(|db| {
|
||||||
inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config, hasher)
|
inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1602,14 +1602,14 @@ pub(crate) fn handle_inlay_hints_resolve(
|
||||||
anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
|
anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
|
||||||
|
|
||||||
let line_index = snap.file_line_index(file_id)?;
|
let line_index = snap.file_line_index(file_id)?;
|
||||||
let hint_position = from_proto::offset(&line_index, original_hint.position)?;
|
let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?;
|
||||||
|
|
||||||
let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
|
let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
|
||||||
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
|
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
|
||||||
let resolve_hints = snap.analysis.inlay_hints_resolve(
|
let resolve_hints = snap.analysis.inlay_hints_resolve(
|
||||||
&forced_resolve_inlay_hints_config,
|
&forced_resolve_inlay_hints_config,
|
||||||
file_id,
|
file_id,
|
||||||
hint_position,
|
range,
|
||||||
hash,
|
hash,
|
||||||
|hint| {
|
|hint| {
|
||||||
std::hash::BuildHasher::hash_one(
|
std::hash::BuildHasher::hash_one(
|
||||||
|
|
|
@ -819,6 +819,7 @@ pub struct InlayHintResolveData {
|
||||||
pub file_id: u32,
|
pub file_id: u32,
|
||||||
// This is a string instead of a u64 as javascript can't represent u64 fully
|
// This is a string instead of a u64 as javascript can't represent u64 fully
|
||||||
pub hash: String,
|
pub hash: String,
|
||||||
|
pub resolve_range: lsp_types::Range,
|
||||||
pub version: Option<i32>,
|
pub version: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -452,10 +452,13 @@ pub(crate) fn inlay_hint(
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
mut inlay_hint: InlayHint,
|
mut inlay_hint: InlayHint,
|
||||||
) -> Cancellable<lsp_types::InlayHint> {
|
) -> Cancellable<lsp_types::InlayHint> {
|
||||||
let resolve_hash = inlay_hint.needs_resolve().then(|| {
|
let resolve_range_and_hash = inlay_hint.needs_resolve().map(|range| {
|
||||||
std::hash::BuildHasher::hash_one(
|
(
|
||||||
&std::hash::BuildHasherDefault::<FxHasher>::default(),
|
range,
|
||||||
&inlay_hint,
|
std::hash::BuildHasher::hash_one(
|
||||||
|
&std::hash::BuildHasherDefault::<FxHasher>::default(),
|
||||||
|
&inlay_hint,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -465,7 +468,7 @@ pub(crate) fn inlay_hint(
|
||||||
.visual_studio_code_version()
|
.visual_studio_code_version()
|
||||||
// https://github.com/microsoft/vscode/issues/193124
|
// https://github.com/microsoft/vscode/issues/193124
|
||||||
.map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
|
.map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
|
||||||
&& resolve_hash.is_some()
|
&& resolve_range_and_hash.is_some()
|
||||||
&& fields_to_resolve.resolve_text_edits
|
&& fields_to_resolve.resolve_text_edits
|
||||||
{
|
{
|
||||||
something_to_resolve |= inlay_hint.text_edit.is_some();
|
something_to_resolve |= inlay_hint.text_edit.is_some();
|
||||||
|
@ -477,16 +480,17 @@ pub(crate) fn inlay_hint(
|
||||||
snap,
|
snap,
|
||||||
fields_to_resolve,
|
fields_to_resolve,
|
||||||
&mut something_to_resolve,
|
&mut something_to_resolve,
|
||||||
resolve_hash.is_some(),
|
resolve_range_and_hash.is_some(),
|
||||||
inlay_hint.label,
|
inlay_hint.label,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let data = match resolve_hash {
|
let data = match resolve_range_and_hash {
|
||||||
Some(hash) if something_to_resolve => Some(
|
Some((resolve_range, hash)) if something_to_resolve => Some(
|
||||||
to_value(lsp_ext::InlayHintResolveData {
|
to_value(lsp_ext::InlayHintResolveData {
|
||||||
file_id: file_id.index(),
|
file_id: file_id.index(),
|
||||||
hash: hash.to_string(),
|
hash: hash.to_string(),
|
||||||
version: snap.file_version(file_id),
|
version: snap.file_version(file_id),
|
||||||
|
resolve_range: range(line_index, resolve_range),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!---
|
<!---
|
||||||
lsp/ext.rs hash: 3429c08745984b3d
|
lsp/ext.rs hash: c6e83d3d08d993de
|
||||||
|
|
||||||
If you need to change the above hash to make the test pass, please check if you
|
If you need to change the above hash to make the test pass, please check if you
|
||||||
need to adjust this doc as well and ping this issue:
|
need to adjust this doc as well and ping this issue:
|
||||||
|
|
Loading…
Reference in a new issue