Skip to content

Commit

Permalink
Auto merge of rust-lang#15418 - oxalica:fix/sig-from-macro, r=Veykril
Browse files Browse the repository at this point in the history
Fix signature help of methods from macros

Currently the receiver type is copied from AST instead re-formatting through `HirDisplay`. Macro generated functions seem to have no spaces and their signature help are rendered like `fn foo(&'amutself)` instead of `fn foo(&'a mut self)`.
  • Loading branch information
bors committed Aug 15, 2023
2 parents 2fbe69d + de86444 commit 0fa822d
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 42 deletions.
63 changes: 36 additions & 27 deletions crates/hir/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use hir_def::{
type_ref::{TypeBound, TypeRef},
AdtId, GenericDefId,
};
use hir_expand::name;
use hir_ty::{
display::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
Expand All @@ -19,8 +18,9 @@ use hir_ty::{

use crate::{
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field,
Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct,
Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, SelfParam,
Static, Struct, Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam,
Union, Variant,
};

impl HirDisplay for Function {
Expand Down Expand Up @@ -57,37 +57,21 @@ impl HirDisplay for Function {

f.write_char('(')?;

let write_self_param = |ty: &TypeRef, f: &mut HirFormatter<'_>| match ty {
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
{
f.write_char('&')?;
if let Some(lifetime) = lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
}
if let hir_def::type_ref::Mutability::Mut = mut_ {
f.write_str("mut ")?;
}
f.write_str("self")
}
_ => {
f.write_str("self: ")?;
ty.hir_fmt(f)
}
};

let mut first = true;
let mut skip_self = 0;
if let Some(self_param) = self.self_param(db) {
self_param.hir_fmt(f)?;
first = false;
skip_self = 1;
}

// FIXME: Use resolved `param.ty` once we no longer discard lifetimes
for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)) {
for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) {
let local = param.as_local(db).map(|it| it.name(db));
if !first {
f.write_str(", ")?;
} else {
first = false;
if local == Some(name!(self)) {
write_self_param(type_ref, f)?;
continue;
}
}
match local {
Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?,
Expand Down Expand Up @@ -137,6 +121,31 @@ impl HirDisplay for Function {
}
}

impl HirDisplay for SelfParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let data = f.db.function_data(self.func);
let param = data.params.first().unwrap();
match &**param {
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
{
f.write_char('&')?;
if let Some(lifetime) = lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
}
if let hir_def::type_ref::Mutability::Mut = mut_ {
f.write_str("mut ")?;
}
f.write_str("self")
}
ty => {
f.write_str("self: ")?;
ty.hir_fmt(f)
}
}
}
}

impl HirDisplay for Adt {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match self {
Expand Down
15 changes: 3 additions & 12 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2090,14 +2090,6 @@ impl SelfParam {
.unwrap_or(Access::Owned)
}

pub fn display(self, db: &dyn HirDatabase) -> &'static str {
match self.access(db) {
Access::Shared => "&self",
Access::Exclusive => "&mut self",
Access::Owned => "self",
}
}

pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
let InFile { file_id, value } = Function::from(self.func).source(db)?;
value
Expand Down Expand Up @@ -4406,14 +4398,13 @@ impl Callable {
Other => CallableKind::Other,
}
}
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(ast::SelfParam, Type)> {
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
let func = match self.callee {
Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
_ => return None,
};
let src = func.lookup(db.upcast()).source(db.upcast());
let param_list = src.value.param_list()?;
Some((param_list.self_param()?, self.ty.derived(self.sig.params()[0].clone())))
let func = Function { id: func };
Some((func.self_param(db)?, self.ty.derived(self.sig.params()[0].clone())))
}
pub fn n_params(&self) -> usize {
self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
Expand Down
6 changes: 4 additions & 2 deletions crates/ide-ssr/src/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
placeholder_value.autoref_kind = self
.sema
.resolve_method_call_as_callable(code)
.and_then(|callable| callable.receiver_param(self.sema.db))
.map(|(self_param, _)| self_param.kind())
.and_then(|callable| {
let (self_param, _) = callable.receiver_param(self.sema.db)?;
Some(self_param.source(self.sema.db)?.value.kind())
})
.unwrap_or(ast::SelfParamKind::Owned);
}
}
Expand Down
21 changes: 20 additions & 1 deletion crates/ide/src/signature_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn signature_help_for_call(
res.signature.push('(');
{
if let Some((self_param, _)) = callable.receiver_param(db) {
format_to!(res.signature, "{}", self_param)
format_to!(res.signature, "{}", self_param.display(db))
}
let mut buf = String::new();
for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() {
Expand Down Expand Up @@ -1314,6 +1314,25 @@ id! {
);
}

#[test]
fn fn_signature_for_method_call_defined_in_macro() {
check(
r#"
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
struct S;
id! {
impl S {
fn foo<'a>(&'a mut self) {}
}
}
fn test() { S.foo($0); }
"#,
expect![[r#"
fn foo(&'a mut self)
"#]],
);
}

#[test]
fn call_info_for_lambdas() {
check(
Expand Down

0 comments on commit 0fa822d

Please sign in to comment.