mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Merge #11481
11481: Display parameter names when hovering over a function pointer r=Veykril a=Vannevelj Implements #11474 The idea is pretty straightforward: previously we constructed the hover based on just the parameter types, now we pass in the parameter names as well. I went for a quick-hit approach here but I expect someone will be able to point me to a better way of resolving the identifier. I haven't figured out yet how to actually run my rust-analyzer locally so I can see it in action but the unit test indicates it should work. Co-authored-by: Jeroen Vannevel <jer_vannevel@outlook.com>
This commit is contained in:
commit
24255e5b3d
5 changed files with 105 additions and 24 deletions
|
@ -493,14 +493,14 @@ impl<'a> Printer<'a> {
|
||||||
w!(self, "]");
|
w!(self, "]");
|
||||||
}
|
}
|
||||||
TypeRef::Fn(args_and_ret, varargs) => {
|
TypeRef::Fn(args_and_ret, varargs) => {
|
||||||
let (ret, args) =
|
let ((_, return_type), args) =
|
||||||
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
|
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
|
||||||
w!(self, "fn(");
|
w!(self, "fn(");
|
||||||
for (i, arg) in args.iter().enumerate() {
|
for (i, (_, typeref)) in args.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
w!(self, ", ");
|
w!(self, ", ");
|
||||||
}
|
}
|
||||||
self.print_type_ref(arg);
|
self.print_type_ref(&typeref);
|
||||||
}
|
}
|
||||||
if *varargs {
|
if *varargs {
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
|
@ -509,7 +509,7 @@ impl<'a> Printer<'a> {
|
||||||
w!(self, "...");
|
w!(self, "...");
|
||||||
}
|
}
|
||||||
w!(self, ") -> ");
|
w!(self, ") -> ");
|
||||||
self.print_type_ref(ret);
|
self.print_type_ref(&return_type);
|
||||||
}
|
}
|
||||||
TypeRef::Macro(_ast_id) => {
|
TypeRef::Macro(_ast_id) => {
|
||||||
w!(self, "<macro>");
|
w!(self, "<macro>");
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
//! HIR for references to types. Paths in these are not yet resolved. They can
|
//! HIR for references to types. Paths in these are not yet resolved. They can
|
||||||
//! be directly created from an ast::TypeRef, without further queries.
|
//! be directly created from an ast::TypeRef, without further queries.
|
||||||
|
|
||||||
use hir_expand::{name::Name, AstId, InFile};
|
use hir_expand::{
|
||||||
|
name::{AsName, Name},
|
||||||
|
AstId, InFile,
|
||||||
|
};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use syntax::ast;
|
use syntax::ast::{self, HasName};
|
||||||
|
|
||||||
use crate::{body::LowerCtx, intern::Interned, path::Path};
|
use crate::{body::LowerCtx, intern::Interned, path::Path};
|
||||||
|
|
||||||
|
@ -89,7 +92,7 @@ pub enum TypeRef {
|
||||||
Array(Box<TypeRef>, ConstScalar),
|
Array(Box<TypeRef>, ConstScalar),
|
||||||
Slice(Box<TypeRef>),
|
Slice(Box<TypeRef>),
|
||||||
/// A fn pointer. Last element of the vector is the return type.
|
/// A fn pointer. Last element of the vector is the return type.
|
||||||
Fn(Vec<TypeRef>, bool /*varargs*/),
|
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
|
||||||
// For
|
// For
|
||||||
ImplTrait(Vec<Interned<TypeBound>>),
|
ImplTrait(Vec<Interned<TypeBound>>),
|
||||||
DynTrait(Vec<Interned<TypeBound>>),
|
DynTrait(Vec<Interned<TypeBound>>),
|
||||||
|
@ -188,11 +191,22 @@ impl TypeRef {
|
||||||
is_varargs = param.dotdotdot_token().is_some();
|
is_varargs = param.dotdotdot_token().is_some();
|
||||||
}
|
}
|
||||||
|
|
||||||
pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(ctx, it)).collect()
|
pl.params()
|
||||||
|
.map(|it| {
|
||||||
|
let type_ref = TypeRef::from_ast_opt(ctx, it.ty());
|
||||||
|
let name = match it.pat() {
|
||||||
|
Some(ast::Pat::IdentPat(it)) => Some(
|
||||||
|
it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),
|
||||||
|
),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
(name, type_ref)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
params.push(ret_ty);
|
params.push((None, ret_ty));
|
||||||
TypeRef::Fn(params, is_varargs)
|
TypeRef::Fn(params, is_varargs)
|
||||||
}
|
}
|
||||||
// for types are close enough for our purposes to the inner type for now...
|
// for types are close enough for our purposes to the inner type for now...
|
||||||
|
@ -230,9 +244,10 @@ impl TypeRef {
|
||||||
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
|
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
|
||||||
f(type_ref);
|
f(type_ref);
|
||||||
match type_ref {
|
match type_ref {
|
||||||
TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
|
TypeRef::Fn(params, _) => {
|
||||||
types.iter().for_each(|t| go(t, f))
|
params.iter().for_each(|(_, param_type)| go(¶m_type, f))
|
||||||
}
|
}
|
||||||
|
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
|
||||||
TypeRef::RawPtr(type_ref, _)
|
TypeRef::RawPtr(type_ref, _)
|
||||||
| TypeRef::Reference(type_ref, ..)
|
| TypeRef::Reference(type_ref, ..)
|
||||||
| TypeRef::Array(type_ref, _)
|
| TypeRef::Array(type_ref, _)
|
||||||
|
|
|
@ -1094,20 +1094,32 @@ impl HirDisplay for TypeRef {
|
||||||
inner.hir_fmt(f)?;
|
inner.hir_fmt(f)?;
|
||||||
write!(f, "]")?;
|
write!(f, "]")?;
|
||||||
}
|
}
|
||||||
TypeRef::Fn(tys, is_varargs) => {
|
TypeRef::Fn(parameters, is_varargs) => {
|
||||||
// FIXME: Function pointer qualifiers.
|
// FIXME: Function pointer qualifiers.
|
||||||
write!(f, "fn(")?;
|
write!(f, "fn(")?;
|
||||||
f.write_joined(&tys[..tys.len() - 1], ", ")?;
|
if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
|
||||||
|
for index in 0..function_parameters.len() {
|
||||||
|
let (param_name, param_type) = &function_parameters[index];
|
||||||
|
if let Some(name) = param_name {
|
||||||
|
write!(f, "{}: ", name)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_type.hir_fmt(f)?;
|
||||||
|
|
||||||
|
if index != function_parameters.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
if *is_varargs {
|
if *is_varargs {
|
||||||
write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
|
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
|
||||||
}
|
}
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
let ret_ty = tys.last().unwrap();
|
match &return_type {
|
||||||
match ret_ty {
|
|
||||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||||
_ => {
|
_ => {
|
||||||
write!(f, " -> ")?;
|
write!(f, " -> ")?;
|
||||||
ret_ty.hir_fmt(f)?;
|
return_type.hir_fmt(f)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
TypeRef::Placeholder => TyKind::Error.intern(Interner),
|
TypeRef::Placeholder => TyKind::Error.intern(Interner),
|
||||||
TypeRef::Fn(params, is_varargs) => {
|
TypeRef::Fn(params, is_varargs) => {
|
||||||
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||||
Substitution::from_iter(Interner, params.iter().map(|tr| ctx.lower_ty(tr)))
|
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
|
||||||
});
|
});
|
||||||
TyKind::Function(FnPointer {
|
TyKind::Function(FnPointer {
|
||||||
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
|
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
|
||||||
|
|
|
@ -1310,6 +1310,60 @@ fn test_hover_function_show_qualifiers() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_function_show_types() {
|
||||||
|
check(
|
||||||
|
r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#,
|
||||||
|
expect![[r#"
|
||||||
|
*foo*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn foo(a: i32, b: i32) -> i32
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_function_pointer_show_identifiers() {
|
||||||
|
check(
|
||||||
|
r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#,
|
||||||
|
expect![[r#"
|
||||||
|
*foo*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
type foo = fn(a: i32, b: i32) -> i32
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_function_pointer_no_identifier() {
|
||||||
|
check(
|
||||||
|
r#"type foo$0 = fn(i32, _: i32) -> i32;"#,
|
||||||
|
expect![[r#"
|
||||||
|
*foo*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
type foo = fn(i32, i32) -> i32
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hover_trait_show_qualifiers() {
|
fn test_hover_trait_show_qualifiers() {
|
||||||
check_actions(
|
check_actions(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue