mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +00:00
Auto merge of #16370 - Veykril:hover-lit, r=Veykril
feat: Hover for literals showing additional value information
This commit is contained in:
commit
e2df3f2ad6
6 changed files with 377 additions and 25 deletions
|
@ -433,7 +433,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
.find_map(|token| {
|
.find_map(|token| {
|
||||||
self.resolve_offset_in_format_args(
|
self.resolve_offset_in_format_args(
|
||||||
ast::String::cast(token)?,
|
ast::String::cast(token)?,
|
||||||
offset - quote.end(),
|
offset.checked_sub(quote.end())?,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|(range, res)| (range + quote.end(), res));
|
.map(|(range, res)| (range + quote.end(), res));
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let radix = literal.radix();
|
let radix = literal.radix();
|
||||||
let value = literal.value()?;
|
let value = literal.value().ok()?;
|
||||||
let suffix = literal.suffix();
|
let suffix = literal.suffix();
|
||||||
|
|
||||||
let range = literal.syntax().text_range();
|
let range = literal.syntax().text_range();
|
||||||
|
|
|
@ -15,7 +15,7 @@ use ide_db::{
|
||||||
FxIndexSet, RootDatabase,
|
FxIndexSet, RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
|
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
doc_links::token_as_doc_comment,
|
doc_links::token_as_doc_comment,
|
||||||
|
@ -268,6 +268,64 @@ fn hover_simple(
|
||||||
let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
|
let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
|
||||||
render::closure_expr(sema, config, c)
|
render::closure_expr(sema, config, c)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
// tokens
|
||||||
|
.or_else(|| {
|
||||||
|
let mut res = HoverResult::default();
|
||||||
|
match_ast! {
|
||||||
|
match original_token {
|
||||||
|
ast::String(string) => {
|
||||||
|
res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?));
|
||||||
|
},
|
||||||
|
ast::ByteString(string) => {
|
||||||
|
res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?));
|
||||||
|
},
|
||||||
|
ast::CString(string) => {
|
||||||
|
let val = string.value()?;
|
||||||
|
res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?));
|
||||||
|
},
|
||||||
|
ast::Char(char) => {
|
||||||
|
let mut res = HoverResult::default();
|
||||||
|
res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?));
|
||||||
|
},
|
||||||
|
ast::Byte(byte) => {
|
||||||
|
res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?));
|
||||||
|
},
|
||||||
|
ast::FloatNumber(num) => {
|
||||||
|
res.markup = if num.suffix() == Some("f32") {
|
||||||
|
match num.value_f32() {
|
||||||
|
Ok(num) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{e}"))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match num.value() {
|
||||||
|
Ok(num) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{e}"))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
ast::IntNumber(num) => {
|
||||||
|
res.markup = match num.value() {
|
||||||
|
Ok(num) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0x{num:b})"))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
Markup::fenced_block_text(format_args!("{e}"))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_ => return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(res)
|
||||||
});
|
});
|
||||||
|
|
||||||
result.map(|mut res: HoverResult| {
|
result.map(|mut res: HoverResult| {
|
||||||
|
|
|
@ -1473,20 +1473,6 @@ fn foo(Foo { b$0ar }: &Foo) {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_hover_through_literal_string_in_builtin_macro() {
|
|
||||||
check_hover_no_result(
|
|
||||||
r#"
|
|
||||||
#[rustc_builtin_macro]
|
|
||||||
macro_rules! format {}
|
|
||||||
|
|
||||||
fn foo() {
|
|
||||||
format!("hel$0lo {}", 0);
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hover_non_ascii_space_doc() {
|
fn test_hover_non_ascii_space_doc() {
|
||||||
check(
|
check(
|
||||||
|
@ -6778,3 +6764,298 @@ fn main() {
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0"🦀\u{1f980}\\\x41";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*"🦀\u{1f980}\\\x41"*
|
||||||
|
```text
|
||||||
|
🦀🦀\A
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0r"🦀\u{1f980}\\\x41";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*r"🦀\u{1f980}\\\x41"*
|
||||||
|
```text
|
||||||
|
🦀\u{1f980}\\\x41
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cstring_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0c"🦀\u{1f980}\\\x41";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*c"🦀\u{1f980}\\\x41"*
|
||||||
|
```text
|
||||||
|
🦀🦀\A
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn byte_string_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0b"\xF0\x9F\xA6\x80\\";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*b"\xF0\x9F\xA6\x80\\"*
|
||||||
|
```text
|
||||||
|
[240, 159, 166, 128, 92]
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0br"\xF0\x9F\xA6\x80\\";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*br"\xF0\x9F\xA6\x80\\"*
|
||||||
|
```text
|
||||||
|
[92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn byte_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0b'\xF0';
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*b'\xF0'*
|
||||||
|
```text
|
||||||
|
0xF0
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0b'\\';
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*b'\\'*
|
||||||
|
```text
|
||||||
|
0x5C
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn char_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0'\x41';
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*'\x41'*
|
||||||
|
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0'\\';
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*'\\'*
|
||||||
|
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0'\u{1f980}';
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*'\u{1f980}'*
|
||||||
|
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn float_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$01.0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*1.0*
|
||||||
|
```text
|
||||||
|
1 (bits: 0x3FF0000000000000)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$01.0f32;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*1.0f32*
|
||||||
|
```text
|
||||||
|
1 (bits: 0x3F800000)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0134e12;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*134e12*
|
||||||
|
```text
|
||||||
|
134000000000000 (bits: 0x42DE77D399980000)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$01523527134274733643531312.0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*1523527134274733643531312.0*
|
||||||
|
```text
|
||||||
|
1523527134274733600000000 (bits: 0x44F429E9249F629B)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$00.1ea123;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*0.1ea123*
|
||||||
|
```text
|
||||||
|
invalid float literal
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_literal() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$034325236457856836345234;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*34325236457856836345234*
|
||||||
|
```text
|
||||||
|
34325236457856836345234 (0x744C659178614489D92|0x111010001001100011001011001000101111000011000010100010010001001110110010010)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0134_123424_21;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*134_123424_21*
|
||||||
|
```text
|
||||||
|
13412342421 (0x31F701A95|0x1100011111011100000001101010010101)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$00x12423423;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*0x12423423*
|
||||||
|
```text
|
||||||
|
306328611 (0x12423423|0x10010010000100011010000100011)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$00b1111_1111;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*0b1111_1111*
|
||||||
|
```text
|
||||||
|
255 (0xFF|0x11111111)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$00o12345;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*0o12345*
|
||||||
|
```text
|
||||||
|
5349 (0x14E5|0x1010011100101)
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$00xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F*
|
||||||
|
```text
|
||||||
|
number too large to fit in target type
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -35,4 +35,7 @@ impl Markup {
|
||||||
pub fn fenced_block(contents: impl fmt::Display) -> Markup {
|
pub fn fenced_block(contents: impl fmt::Display) -> Markup {
|
||||||
format!("```rust\n{contents}\n```").into()
|
format!("```rust\n{contents}\n```").into()
|
||||||
}
|
}
|
||||||
|
pub fn fenced_block_text(contents: impl fmt::Display) -> Markup {
|
||||||
|
format!("```text\n{contents}\n```").into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
//! There are many AstNodes, but only a few tokens, so we hand-write them here.
|
//! There are many AstNodes, but only a few tokens, so we hand-write them here.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
|
num::{ParseFloatError, ParseIntError},
|
||||||
|
};
|
||||||
|
|
||||||
use rustc_lexer::unescape::{
|
use rustc_lexer::unescape::{
|
||||||
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
||||||
|
@ -391,10 +394,9 @@ impl ast::IntNumber {
|
||||||
(prefix, text, suffix)
|
(prefix, text, suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> Option<u128> {
|
pub fn value(&self) -> Result<u128, ParseIntError> {
|
||||||
let (_, text, _) = self.split_into_parts();
|
let (_, text, _) = self.split_into_parts();
|
||||||
let value = u128::from_str_radix(&text.replace('_', ""), self.radix() as u32).ok()?;
|
u128::from_str_radix(&text.replace('_', ""), self.radix() as u32)
|
||||||
Some(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suffix(&self) -> Option<&str> {
|
pub fn suffix(&self) -> Option<&str> {
|
||||||
|
@ -445,9 +447,14 @@ impl ast::FloatNumber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> Option<f64> {
|
pub fn value(&self) -> Result<f64, ParseFloatError> {
|
||||||
let (text, _) = self.split_into_parts();
|
let (text, _) = self.split_into_parts();
|
||||||
text.replace('_', "").parse::<f64>().ok()
|
text.replace('_', "").parse::<f64>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_f32(&self) -> Result<f32, ParseFloatError> {
|
||||||
|
let (text, _) = self.split_into_parts();
|
||||||
|
text.replace('_', "").parse::<f32>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,12 +491,15 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
|
fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
|
||||||
assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
|
assert_eq!(
|
||||||
|
FloatNumber { syntax: make::tokens::literal(lit) }.value().ok(),
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
|
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
|
fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
|
||||||
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
|
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value().ok(), expected.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue