Skip to content

Commit 6e0c33d

Browse files
committed
Auto merge of rust-lang#17220 - Veykril:hov-lit, r=Veykril
fix: Improve confusing literal hovers
2 parents 197856d + 3e510eb commit 6e0c33d

File tree

12 files changed

+262
-171
lines changed

12 files changed

+262
-171
lines changed

src/tools/rust-analyzer/crates/hir-def/src/hir.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,15 @@ impl From<ast::LiteralKind> for Literal {
136136
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
137137
}
138138
LiteralKind::ByteString(bs) => {
139-
let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
139+
let text = bs.value().map_or_else(|_| Default::default(), Box::from);
140140
Literal::ByteString(text)
141141
}
142142
LiteralKind::String(s) => {
143-
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
143+
let text = s.value().map_or_else(|_| Default::default(), Box::from);
144144
Literal::String(text)
145145
}
146146
LiteralKind::CString(s) => {
147-
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
147+
let text = s.value().map_or_else(|_| Default::default(), Box::from);
148148
Literal::CString(text)
149149
}
150150
LiteralKind::Byte(b) => {

src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,21 +441,21 @@ fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> {
441441
let span = lit.span;
442442
let lit = ast::make::tokens::literal(&lit.to_string());
443443
let token = ast::String::cast(lit)?;
444-
token.value().map(|it| (it.into_owned(), span))
444+
token.value().ok().map(|it| (it.into_owned(), span))
445445
}
446446

447447
fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> {
448448
let span = lit.span;
449449
let lit = ast::make::tokens::literal(&lit.to_string());
450450
let token = ast::Char::cast(lit)?;
451-
token.value().zip(Some(span))
451+
token.value().ok().zip(Some(span))
452452
}
453453

454454
fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec<u8>, Span)> {
455455
let span = lit.span;
456456
let lit = ast::make::tokens::literal(&lit.to_string());
457457
let token = ast::ByteString::cast(lit)?;
458-
token.value().map(|it| (it.into_owned(), span))
458+
token.value().ok().map(|it| (it.into_owned(), span))
459459
}
460460

461461
fn compile_error_expand(

src/tools/rust-analyzer/crates/hir/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,20 @@ impl BuiltinType {
25432543
matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
25442544
}
25452545

2546+
pub fn is_f32(&self) -> bool {
2547+
matches!(
2548+
self.inner,
2549+
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32)
2550+
)
2551+
}
2552+
2553+
pub fn is_f64(&self) -> bool {
2554+
matches!(
2555+
self.inner,
2556+
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64)
2557+
)
2558+
}
2559+
25462560
pub fn is_char(&self) -> bool {
25472561
matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
25482562
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
2525
if token.is_raw() {
2626
return None;
2727
}
28-
let value = token.value()?;
28+
let value = token.value().ok()?;
2929
let target = token.syntax().text_range();
3030
acc.add(
3131
AssistId("make_raw_string", AssistKind::RefactorRewrite),
@@ -64,7 +64,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
6464
if !token.is_raw() {
6565
return None;
6666
}
67-
let value = token.value()?;
67+
let value = token.value().ok()?;
6868
let target = token.syntax().text_range();
6969
acc.add(
7070
AssistId("make_usual_string", AssistKind::RefactorRewrite),
@@ -398,12 +398,12 @@ string"###;
398398
}
399399

400400
#[test]
401-
fn remove_hash_doesnt_work() {
401+
fn remove_hash_does_not_work() {
402402
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#);
403403
}
404404

405405
#[test]
406-
fn remove_hash_no_hash_doesnt_work() {
406+
fn remove_hash_no_hash_does_not_work() {
407407
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#);
408408
}
409409

src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
2525
// ```
2626
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
2727
let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
28-
let value = token.value()?;
28+
let value = token.value().ok()?;
2929
let target = token.syntax().text_range();
3030

3131
if value.chars().take(2).count() != 1 {

src/tools/rust-analyzer/crates/ide/src/goto_definition.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ fn try_lookup_include_path(
123123
{
124124
return None;
125125
}
126-
let path = token.value()?;
126+
let path = token.value().ok()?;
127127

128128
let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
129129
let size = sema.db.file_text(file_id).len().try_into().ok()?;
@@ -179,11 +179,11 @@ fn try_filter_trait_item_definition(
179179
AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
180180
let trait_ = assoc.implemented_trait(db)?;
181181
let name = def.name(db)?;
182-
let discri_value = discriminant(&assoc);
182+
let discriminant_value = discriminant(&assoc);
183183
trait_
184184
.items(db)
185185
.iter()
186-
.filter(|itm| discriminant(*itm) == discri_value)
186+
.filter(|itm| discriminant(*itm) == discriminant_value)
187187
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
188188
.map(|it| it.collect())
189189
}

src/tools/rust-analyzer/crates/ide/src/hover.rs

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ide_db::{
1515
FxIndexSet, RootDatabase,
1616
};
1717
use itertools::{multizip, Itertools};
18-
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
18+
use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
1919

2020
use crate::{
2121
doc_links::token_as_doc_comment,
@@ -298,61 +298,8 @@ fn hover_simple(
298298
})
299299
// tokens
300300
.or_else(|| {
301-
let mut res = HoverResult::default();
302-
match_ast! {
303-
match original_token {
304-
ast::String(string) => {
305-
res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?));
306-
},
307-
ast::ByteString(string) => {
308-
res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?));
309-
},
310-
ast::CString(string) => {
311-
let val = string.value()?;
312-
res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?));
313-
},
314-
ast::Char(char) => {
315-
let mut res = HoverResult::default();
316-
res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?));
317-
},
318-
ast::Byte(byte) => {
319-
res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?));
320-
},
321-
ast::FloatNumber(num) => {
322-
res.markup = if num.suffix() == Some("f32") {
323-
match num.value_f32() {
324-
Ok(num) => {
325-
Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
326-
},
327-
Err(e) => {
328-
Markup::fenced_block_text(format_args!("{e}"))
329-
},
330-
}
331-
} else {
332-
match num.value() {
333-
Ok(num) => {
334-
Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
335-
},
336-
Err(e) => {
337-
Markup::fenced_block_text(format_args!("{e}"))
338-
},
339-
}
340-
};
341-
},
342-
ast::IntNumber(num) => {
343-
res.markup = match num.value() {
344-
Ok(num) => {
345-
Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})"))
346-
},
347-
Err(e) => {
348-
Markup::fenced_block_text(format_args!("{e}"))
349-
},
350-
};
351-
},
352-
_ => return None
353-
}
354-
}
355-
Some(res)
301+
render::literal(sema, original_token.clone())
302+
.map(|markup| HoverResult { markup, actions: vec![] })
356303
});
357304

358305
result.map(|mut res: HoverResult| {

src/tools/rust-analyzer/crates/ide/src/hover/render.rs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ use ide_db::{
1717
};
1818
use itertools::Itertools;
1919
use stdx::format_to;
20-
use syntax::{
21-
algo,
22-
ast::{self, RecordPat},
23-
match_ast, AstNode, Direction, SyntaxToken, T,
24-
};
20+
use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T};
2521

2622
use crate::{
2723
doc_links::{remove_links, rewrite_links},
@@ -276,7 +272,7 @@ pub(super) fn keyword(
276272
pub(super) fn struct_rest_pat(
277273
sema: &Semantics<'_, RootDatabase>,
278274
_config: &HoverConfig,
279-
pattern: &RecordPat,
275+
pattern: &ast::RecordPat,
280276
) -> HoverResult {
281277
let missing_fields = sema.record_pattern_missing_fields(pattern);
282278

@@ -526,6 +522,60 @@ pub(super) fn definition(
526522
markup(docs.map(Into::into), desc, mod_path)
527523
}
528524

525+
pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Markup> {
526+
let lit = token.parent().and_then(ast::Literal::cast)?;
527+
let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
528+
sema.type_of_pat(&p)?
529+
} else {
530+
sema.type_of_expr(&ast::Expr::Literal(lit))?
531+
}
532+
.original;
533+
534+
let value = match_ast! {
535+
match token {
536+
ast::String(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
537+
ast::ByteString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("{it:?}")),
538+
ast::CString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| std::str::from_utf8(it).map_or_else(|e| format!("{e:?}"), ToOwned::to_owned)),
539+
ast::Char(char) => char .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
540+
ast::Byte(byte) => byte .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")),
541+
ast::FloatNumber(num) => {
542+
let (text, _) = num.split_into_parts();
543+
let text = text.replace('_', "");
544+
if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) {
545+
match text.parse::<f32>() {
546+
Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
547+
Err(e) => Err(e.to_string()),
548+
}
549+
} else {
550+
match text.parse::<f64>() {
551+
Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
552+
Err(e) => Err(e.to_string()),
553+
}
554+
}
555+
},
556+
ast::IntNumber(num) => match num.value() {
557+
Ok(num) => Ok(format!("{num} (0x{num:X}|0b{num:b})")),
558+
Err(e) => Err(e.to_string()),
559+
},
560+
_ => return None
561+
}
562+
};
563+
let ty = ty.display(sema.db);
564+
565+
let mut s = format!("```rust\n{ty}\n```\n___\n\n");
566+
match value {
567+
Ok(value) => {
568+
if let Some(newline) = value.find('\n') {
569+
format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline])
570+
} else {
571+
format_to!(s, "value of literal: {value}")
572+
}
573+
}
574+
Err(error) => format_to!(s, "invalid literal: {error}"),
575+
}
576+
Some(s.into())
577+
}
578+
529579
fn render_notable_trait_comment(
530580
db: &RootDatabase,
531581
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],

0 commit comments

Comments
 (0)