Slightly refactor inlay hints

This commit is contained in:
Aleksey Kladov 2020-02-29 23:24:50 +01:00
parent 2e0d89401a
commit 584c8d9875
2 changed files with 60 additions and 71 deletions

View file

@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase;
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ use ra_syntax::{
ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
match_ast, SmolStr, SyntaxNode, TextRange, match_ast, SmolStr, TextRange,
}; };
use crate::{FileId, FunctionSignature}; use crate::{FileId, FunctionSignature};
@ -28,50 +28,76 @@ pub(crate) fn inlay_hints(
file_id: FileId, file_id: FileId,
max_inlay_hint_length: Option<usize>, max_inlay_hint_length: Option<usize>,
) -> Vec<InlayHint> { ) -> Vec<InlayHint> {
let _p = profile("inlay_hints");
let sema = Semantics::new(db); let sema = Semantics::new(db);
let file = sema.parse(file_id); let file = sema.parse(file_id);
let mut res = Vec::new(); let mut res = Vec::new();
for node in file.syntax().descendants() { for node in file.syntax().descendants() {
get_inlay_hints(&mut res, &sema, &node, max_inlay_hint_length); match_ast! {
match node {
ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, max_inlay_hint_length, it); },
_ => (),
}
}
} }
res res
} }
fn get_inlay_hints( fn get_param_name_hints(
acc: &mut Vec<InlayHint>, acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
node: &SyntaxNode, expr: ast::Expr,
max_inlay_hint_length: Option<usize>,
) -> Option<()> { ) -> Option<()> {
let _p = profile("get_inlay_hints"); let args = match &expr {
let db = sema.db; ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
match_ast! { ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
match node { _ => return None,
ast::CallExpr(it) => { };
get_param_name_hints(acc, sema, ast::Expr::from(it)); let args_count = args.clone().count();
},
ast::MethodCallExpr(it) => {
get_param_name_hints(acc, sema, ast::Expr::from(it));
},
ast::BindPat(it) => {
let pat = ast::Pat::from(it.clone());
let ty = sema.type_of_pat(&pat)?;
if should_not_display_type_hint(db, &it, &ty) { let fn_signature = get_fn_signature(sema, &expr)?;
let n_params_to_skip =
if fn_signature.has_self_param && fn_signature.parameter_names.len() > args_count {
1
} else {
0
};
let hints = fn_signature
.parameter_names
.iter()
.skip(n_params_to_skip)
.zip(args)
.filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
.map(|(param_name, arg)| InlayHint {
range: arg.syntax().text_range(),
kind: InlayKind::ParameterHint,
label: param_name.into(),
});
acc.extend(hints);
Some(())
}
fn get_bind_pat_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>,
max_inlay_hint_length: Option<usize>,
pat: ast::BindPat,
) -> Option<()> {
let ty = sema.type_of_pat(&pat.clone().into())?;
if should_not_display_type_hint(sema.db, &pat, &ty) {
return None; return None;
} }
acc.push( acc.push(InlayHint {
InlayHint {
range: pat.syntax().text_range(), range: pat.syntax().text_range(),
kind: InlayKind::TypeHint, kind: InlayKind::TypeHint,
label: ty.display_truncated(db, max_inlay_hint_length).to_string().into(), label: ty.display_truncated(sema.db, max_inlay_hint_length).to_string().into(),
} });
);
},
_ => (),
}
};
Some(()) Some(())
} }
@ -120,43 +146,6 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_
false false
} }
fn get_param_name_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>,
expr: ast::Expr,
) -> Option<()> {
let args = match &expr {
ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
_ => return None,
}
.into_iter()
// we need args len to determine whether to skip or not the &self parameter
.collect::<Vec<_>>();
let fn_signature = get_fn_signature(sema, &expr)?;
let n_params_to_skip =
if fn_signature.has_self_param && fn_signature.parameter_names.len() > args.len() {
1
} else {
0
};
let hints = fn_signature
.parameter_names
.iter()
.skip(n_params_to_skip)
.zip(args)
.filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
.map(|(param_name, arg)| InlayHint {
range: arg.syntax().text_range(),
kind: InlayKind::ParameterHint,
label: param_name.into(),
});
acc.extend(hints);
Some(())
}
fn should_show_param_hint( fn should_show_param_hint(
fn_signature: &FunctionSignature, fn_signature: &FunctionSignature,
param_name: &str, param_name: &str,

View file

@ -59,7 +59,7 @@ pub trait AstToken {
} }
/// An iterator over `SyntaxNode` children of a particular AST type. /// An iterator over `SyntaxNode` children of a particular AST type.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct AstChildren<N> { pub struct AstChildren<N> {
inner: SyntaxNodeChildren, inner: SyntaxNodeChildren,
ph: PhantomData<N>, ph: PhantomData<N>,