mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
format function
This commit is contained in:
parent
a207299344
commit
43638fb0c1
@ -109,50 +109,90 @@ pub(super) fn hints(
|
|||||||
}
|
}
|
||||||
has_adjustments = true;
|
has_adjustments = true;
|
||||||
|
|
||||||
// FIXME: Add some nicer tooltips to each of these
|
let (text, coercion, detailed_tooltip) = match kind {
|
||||||
let (text, coercion) = match kind {
|
|
||||||
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
|
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
|
||||||
allow_edit = false;
|
allow_edit = false;
|
||||||
("<never-to-any>", "never to any")
|
(
|
||||||
}
|
"<never-to-any>",
|
||||||
Adjust::Deref(None) => ("*", "dereference"),
|
"never to any",
|
||||||
Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => {
|
"Coerces the never type `!` into any other type. This happens in code paths that never return, like after `panic!()` or `return`.",
|
||||||
("*", "`Deref` dereference")
|
)
|
||||||
}
|
|
||||||
Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => {
|
|
||||||
("*", "`DerefMut` dereference")
|
|
||||||
}
|
|
||||||
Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"),
|
|
||||||
Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"),
|
|
||||||
Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => {
|
|
||||||
("&raw const ", "const pointer borrow")
|
|
||||||
}
|
|
||||||
Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => {
|
|
||||||
("&raw mut ", "mut pointer borrow")
|
|
||||||
}
|
}
|
||||||
|
Adjust::Deref(None) => (
|
||||||
|
"*",
|
||||||
|
"dereference",
|
||||||
|
"Built-in dereference of a reference to access the underlying value. The compiler inserts `*` to get the value from `&T`.",
|
||||||
|
),
|
||||||
|
Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => (
|
||||||
|
"*",
|
||||||
|
"`Deref` dereference",
|
||||||
|
"Dereference via the `Deref` trait. Used for types like `Box<T>` or `Rc<T>` so they act like plain `T`.",
|
||||||
|
),
|
||||||
|
Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => (
|
||||||
|
"*",
|
||||||
|
"`DerefMut` dereference",
|
||||||
|
"Mutable dereference using the `DerefMut` trait. Enables smart pointers to give mutable access to their inner values.",
|
||||||
|
),
|
||||||
|
Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => (
|
||||||
|
"&",
|
||||||
|
"shared borrow",
|
||||||
|
"Inserts `&` to create a shared reference. Lets you use a value without moving or cloning it.",
|
||||||
|
),
|
||||||
|
Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => (
|
||||||
|
"&mut ",
|
||||||
|
"mutable borrow",
|
||||||
|
"Inserts `&mut` to create a unique, mutable reference. Lets you modify a value without taking ownership.",
|
||||||
|
),
|
||||||
|
Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => (
|
||||||
|
"&raw const ",
|
||||||
|
"const raw pointer",
|
||||||
|
"Converts a reference to a raw const pointer `*const T`. Often used when working with FFI or unsafe code.",
|
||||||
|
),
|
||||||
|
Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => (
|
||||||
|
"&raw mut ",
|
||||||
|
"mut raw pointer",
|
||||||
|
"Converts a mutable reference to a raw mutable pointer `*mut T`. Allows mutation in unsafe contexts.",
|
||||||
|
),
|
||||||
// some of these could be represented via `as` casts, but that's not too nice and
|
// some of these could be represented via `as` casts, but that's not too nice and
|
||||||
// handling everything as a prefix expr makes the `(` and `)` insertion easier
|
// handling everything as a prefix expr makes the `(` and `)` insertion easier
|
||||||
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
|
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
|
||||||
allow_edit = false;
|
allow_edit = false;
|
||||||
match cast {
|
match cast {
|
||||||
PointerCast::ReifyFnPointer => {
|
PointerCast::ReifyFnPointer => (
|
||||||
("<fn-item-to-fn-pointer>", "fn item to fn pointer")
|
"<fn-item-to-fn-pointer>",
|
||||||
}
|
"fn item to fn pointer",
|
||||||
|
"Converts a named function to a function pointer `fn()`. Useful when passing functions as values."
|
||||||
|
),
|
||||||
PointerCast::UnsafeFnPointer => (
|
PointerCast::UnsafeFnPointer => (
|
||||||
"<safe-fn-pointer-to-unsafe-fn-pointer>",
|
"<safe-fn-pointer-to-unsafe-fn-pointer>",
|
||||||
"safe fn pointer to unsafe fn pointer",
|
"safe fn pointer to unsafe fn pointer",
|
||||||
|
"Coerces a safe function pointer to an unsafe one. Allows calling it in an unsafe context."
|
||||||
|
),
|
||||||
|
PointerCast::ClosureFnPointer(Safety::Unsafe) => (
|
||||||
|
"<closure-to-unsafe-fn-pointer>",
|
||||||
|
"closure to unsafe fn pointer",
|
||||||
|
"Converts a non-capturing closure to an unsafe function pointer. Required for use in `extern` or unsafe APIs."
|
||||||
|
),
|
||||||
|
PointerCast::ClosureFnPointer(Safety::Safe) => (
|
||||||
|
"<closure-to-fn-pointer>",
|
||||||
|
"closure to fn pointer",
|
||||||
|
"Converts a non-capturing closure to a function pointer. Lets closures behave like plain functions."
|
||||||
|
),
|
||||||
|
PointerCast::MutToConstPointer => (
|
||||||
|
"<mut-ptr-to-const-ptr>",
|
||||||
|
"mut ptr to const ptr",
|
||||||
|
"Coerces `*mut T` to `*const T`. Safe because const pointers restrict what you can do."
|
||||||
|
),
|
||||||
|
PointerCast::ArrayToPointer => (
|
||||||
|
"<array-ptr-to-element-ptr>",
|
||||||
|
"array to pointer",
|
||||||
|
"Converts an array to a pointer to its first element. Similar to how arrays decay to pointers in C."
|
||||||
|
),
|
||||||
|
PointerCast::Unsize => (
|
||||||
|
"<unsize>",
|
||||||
|
"unsize coercion",
|
||||||
|
"Converts a sized type to an unsized one. Used for things like turning arrays into slices or concrete types into trait objects."
|
||||||
),
|
),
|
||||||
PointerCast::ClosureFnPointer(Safety::Unsafe) => {
|
|
||||||
("<closure-to-unsafe-fn-pointer>", "closure to unsafe fn pointer")
|
|
||||||
}
|
|
||||||
PointerCast::ClosureFnPointer(Safety::Safe) => {
|
|
||||||
("<closure-to-fn-pointer>", "closure to fn pointer")
|
|
||||||
}
|
|
||||||
PointerCast::MutToConstPointer => {
|
|
||||||
("<mut-ptr-to-const-ptr>", "mut ptr to const ptr")
|
|
||||||
}
|
|
||||||
PointerCast::ArrayToPointer => ("<array-ptr-to-element-ptr>", ""),
|
|
||||||
PointerCast::Unsize => ("<unsize>", "unsize"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
@ -162,9 +202,12 @@ pub(super) fn hints(
|
|||||||
linked_location: None,
|
linked_location: None,
|
||||||
tooltip: Some(config.lazy_tooltip(|| {
|
tooltip: Some(config.lazy_tooltip(|| {
|
||||||
InlayTooltip::Markdown(format!(
|
InlayTooltip::Markdown(format!(
|
||||||
"`{}` → `{}` ({coercion} coercion)",
|
"`{}` → `{}`\n\n**{}**\n\n{}",
|
||||||
source.display(sema.db, display_target),
|
source.display(sema.db, display_target),
|
||||||
target.display(sema.db, display_target),
|
target.display(sema.db, display_target),
|
||||||
|
coercion.chars().next().unwrap().to_uppercase().collect::<String>()
|
||||||
|
+ &coercion[1..],
|
||||||
|
detailed_tooltip
|
||||||
))
|
))
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
@ -175,7 +218,7 @@ pub(super) fn hints(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !postfix && needs_inner_parens {
|
if !postfix && needs_inner_parens {
|
||||||
pre.label.append_str("(");
|
(&mut pre.label).append_str("(");
|
||||||
}
|
}
|
||||||
if needs_outer_parens || (!postfix && needs_inner_parens) {
|
if needs_outer_parens || (!postfix && needs_inner_parens) {
|
||||||
post.label.append_str(")");
|
post.label.append_str(")");
|
||||||
|
@ -91,9 +91,9 @@ pub(super) fn hints(
|
|||||||
match_ast! {
|
match_ast! {
|
||||||
match parent {
|
match parent {
|
||||||
ast::Fn(it) => {
|
ast::Fn(it) => {
|
||||||
// FIXME: this could include parameters, but `HirDisplay` prints too much info
|
let hint_text = format_function_hint(&it, config.max_length?)
|
||||||
// and doesn't respect the max length either, so the hints end up way too long
|
.unwrap_or_else(|| format!("fn {}", it.name().map(|n| n.to_string()).unwrap_or_default()));
|
||||||
(format!("fn {}", it.name()?), it.name().map(name))
|
(hint_text, it.name().map(name))
|
||||||
},
|
},
|
||||||
ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
|
ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
|
||||||
ast::Const(it) => {
|
ast::Const(it) => {
|
||||||
@ -156,6 +156,47 @@ pub(super) fn hints(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_function_hint(func: &ast::Fn, max_length: usize) -> Option<String> {
|
||||||
|
let name = func.name()?;
|
||||||
|
let name_str = name.to_string();
|
||||||
|
|
||||||
|
let params = if let Some(param_list) = func.param_list() {
|
||||||
|
let mut param_parts = Vec::new();
|
||||||
|
let mut total_len = 0;
|
||||||
|
let max_param_len = max_length.saturating_sub(name_str.len() + 4);
|
||||||
|
|
||||||
|
for param in param_list.params() {
|
||||||
|
let param_text = if let Some(pat) = param.pat() {
|
||||||
|
if let Some(ty) = param.ty() { format!("{}: {}", pat, ty) } else { pat.to_string() }
|
||||||
|
} else if let Some(ty) = param.ty() {
|
||||||
|
format!("_: {}", ty)
|
||||||
|
} else {
|
||||||
|
let param_source = param.syntax().text().to_string();
|
||||||
|
if param_source.trim() == "..." { "...".to_string() } else { "_".to_string() }
|
||||||
|
};
|
||||||
|
|
||||||
|
let param_len = param_text.len() + if param_parts.is_empty() { 0 } else { 2 };
|
||||||
|
if total_len + param_len > max_param_len {
|
||||||
|
param_parts.push("...".to_string());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_len += param_len;
|
||||||
|
param_parts.push(param_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if param_parts.is_empty() {
|
||||||
|
"()".to_string()
|
||||||
|
} else {
|
||||||
|
format!("({})", param_parts.join(", "))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"()".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(format!("fn {}{}", name_str, params))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -166,7 +207,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn hints_closing_brace() {
|
fn hints_closing_brace() {
|
||||||
check_with_config(
|
check_with_config(
|
||||||
InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
|
InlayHintsConfig {
|
||||||
|
closing_brace_hints_min_lines: Some(2),
|
||||||
|
max_length: Some(30),
|
||||||
|
..DISABLED_CONFIG
|
||||||
|
},
|
||||||
r#"
|
r#"
|
||||||
fn a() {}
|
fn a() {}
|
||||||
|
|
||||||
@ -175,17 +220,17 @@ fn f() {
|
|||||||
|
|
||||||
fn g() {
|
fn g() {
|
||||||
}
|
}
|
||||||
//^ fn g
|
//^ fn g()
|
||||||
|
|
||||||
fn h<T>(with: T, arguments: u8, ...) {
|
fn h<T>(with: T, arguments: u8, ...) {
|
||||||
}
|
}
|
||||||
//^ fn h
|
//^ fn h(with: T, arguments: u8, ...)
|
||||||
|
|
||||||
trait Tr {
|
trait Tr {
|
||||||
fn f();
|
fn f();
|
||||||
fn g() {
|
fn g() {
|
||||||
}
|
}
|
||||||
//^ fn g
|
//^ fn g()
|
||||||
}
|
}
|
||||||
//^ trait Tr
|
//^ trait Tr
|
||||||
impl Tr for () {
|
impl Tr for () {
|
||||||
@ -222,7 +267,7 @@ fn f() {
|
|||||||
let v = vec![
|
let v = vec![
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
//^ fn f
|
//^ fn f()
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -230,7 +275,11 @@ fn f() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn hints_closing_brace_for_block_expr() {
|
fn hints_closing_brace_for_block_expr() {
|
||||||
check_with_config(
|
check_with_config(
|
||||||
InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
|
InlayHintsConfig {
|
||||||
|
closing_brace_hints_min_lines: Some(2),
|
||||||
|
max_length: Some(10),
|
||||||
|
..DISABLED_CONFIG
|
||||||
|
},
|
||||||
r#"
|
r#"
|
||||||
fn test() {
|
fn test() {
|
||||||
'end: {
|
'end: {
|
||||||
@ -258,7 +307,40 @@ fn test() {
|
|||||||
//^ 'a
|
//^ 'a
|
||||||
|
|
||||||
}
|
}
|
||||||
//^ fn test
|
//^ fn test()
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hints_closing_brace_function_parameters() {
|
||||||
|
check_with_config(
|
||||||
|
InlayHintsConfig {
|
||||||
|
closing_brace_hints_min_lines: Some(1),
|
||||||
|
max_length: Some(50),
|
||||||
|
..DISABLED_CONFIG
|
||||||
|
},
|
||||||
|
r#"
|
||||||
|
fn simple() {
|
||||||
|
let v = vec![
|
||||||
|
];
|
||||||
|
}
|
||||||
|
//^ fn simple()
|
||||||
|
|
||||||
|
fn with_params(x: i32, y: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
//^ fn with_params(x: i32, y: String)
|
||||||
|
|
||||||
|
fn long_params(very_long_parameter_name: ComplexType, another: AnotherType) {
|
||||||
|
|
||||||
|
}
|
||||||
|
//^ fn long_params(...)
|
||||||
|
|
||||||
|
fn many_params(a: i32, b: i32, c: i32, d: i32, e: i32) {
|
||||||
|
|
||||||
|
}
|
||||||
|
//^ fn many_params(a: i32, b: i32, c: i32, d: i32, ...)
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user