Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/ide-assists/src/handlers/convert_integer_literal.rs2
-rw-r--r--crates/ide/src/hover.rs60
-rw-r--r--crates/ide/src/hover/tests.rs309
-rw-r--r--crates/ide/src/markup.rs3
-rw-r--r--crates/syntax/src/ast/token_ext.rs26
6 files changed, 377 insertions, 25 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index f51fe80931..4267bd4efa 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -433,7 +433,7 @@ impl<'db> SemanticsImpl<'db> {
.find_map(|token| {
self.resolve_offset_in_format_args(
ast::String::cast(token)?,
- offset - quote.end(),
+ offset.checked_sub(quote.end())?,
)
})
.map(|(range, res)| (range + quote.end(), res));
diff --git a/crates/ide-assists/src/handlers/convert_integer_literal.rs b/crates/ide-assists/src/handlers/convert_integer_literal.rs
index ff2195f7e6..fd3378e8c2 100644
--- a/crates/ide-assists/src/handlers/convert_integer_literal.rs
+++ b/crates/ide-assists/src/handlers/convert_integer_literal.rs
@@ -20,7 +20,7 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
_ => return None,
};
let radix = literal.radix();
- let value = literal.value()?;
+ let value = literal.value().ok()?;
let suffix = literal.suffix();
let range = literal.syntax().text_range();
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 5ad119ace8..d06577d3db 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -15,7 +15,7 @@ use ide_db::{
FxIndexSet, RootDatabase,
};
use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
+use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
use crate::{
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)?;
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| {
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 8ef8f29576..587a6b66c4 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -1474,20 +1474,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]
fn test_hover_non_ascii_space_doc() {
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
+ ```
+ "#]],
+ );
+}
diff --git a/crates/ide/src/markup.rs b/crates/ide/src/markup.rs
index 411eb695fb..4a4e29fa33 100644
--- a/crates/ide/src/markup.rs
+++ b/crates/ide/src/markup.rs
@@ -35,4 +35,7 @@ impl Markup {
pub fn fenced_block(contents: impl fmt::Display) -> Markup {
format!("```rust\n{contents}\n```").into()
}
+ pub fn fenced_block_text(contents: impl fmt::Display) -> Markup {
+ format!("```text\n{contents}\n```").into()
+ }
}
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index ede392fc62..44e49d6d44 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -1,6 +1,9 @@
//! 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::{
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
@@ -391,10 +394,9 @@ impl ast::IntNumber {
(prefix, text, suffix)
}
- pub fn value(&self) -> Option<u128> {
+ pub fn value(&self) -> Result<u128, ParseIntError> {
let (_, text, _) = self.split_into_parts();
- let value = u128::from_str_radix(&text.replace('_', ""), self.radix() as u32).ok()?;
- Some(value)
+ u128::from_str_radix(&text.replace('_', ""), self.radix() as u32)
}
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();
- 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) {
- 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());
}
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]