Skip to content

Commit

Permalink
Auto merge of #17220 - Veykril:hov-lit, r=Veykril
Browse files Browse the repository at this point in the history
fix: Improve confusing literal hovers
  • Loading branch information
bors committed May 13, 2024
2 parents 9db1258 + 5b696ba commit 40ab5e5
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 171 deletions.
6 changes: 3 additions & 3 deletions crates/hir-def/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,15 @@ impl From<ast::LiteralKind> for Literal {
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
}
LiteralKind::ByteString(bs) => {
let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
let text = bs.value().map_or_else(|_| Default::default(), Box::from);
Literal::ByteString(text)
}
LiteralKind::String(s) => {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
let text = s.value().map_or_else(|_| Default::default(), Box::from);
Literal::String(text)
}
LiteralKind::CString(s) => {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
let text = s.value().map_or_else(|_| Default::default(), Box::from);
Literal::CString(text)
}
LiteralKind::Byte(b) => {
Expand Down
6 changes: 3 additions & 3 deletions crates/hir-expand/src/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,21 +441,21 @@ fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> {
let span = lit.span;
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::String::cast(lit)?;
token.value().map(|it| (it.into_owned(), span))
token.value().ok().map(|it| (it.into_owned(), span))
}

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

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

fn compile_error_expand(
Expand Down
14 changes: 14 additions & 0 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,20 @@ impl BuiltinType {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
}

pub fn is_f32(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32)
)
}

pub fn is_f64(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64)
)
}

pub fn is_char(&self) -> bool {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
}
Expand Down
8 changes: 4 additions & 4 deletions crates/ide-assists/src/handlers/raw_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
if token.is_raw() {
return None;
}
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();
acc.add(
AssistId("make_raw_string", AssistKind::RefactorRewrite),
Expand Down Expand Up @@ -64,7 +64,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
if !token.is_raw() {
return None;
}
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();
acc.add(
AssistId("make_usual_string", AssistKind::RefactorRewrite),
Expand Down Expand Up @@ -398,12 +398,12 @@ string"###;
}

#[test]
fn remove_hash_doesnt_work() {
fn remove_hash_does_not_work() {
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#);
}

#[test]
fn remove_hash_no_hash_doesnt_work() {
fn remove_hash_no_hash_does_not_work() {
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();

if value.chars().take(2).count() != 1 {
Expand Down
6 changes: 3 additions & 3 deletions crates/ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ fn try_lookup_include_path(
{
return None;
}
let path = token.value()?;
let path = token.value().ok()?;

let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
let size = sema.db.file_text(file_id).len().try_into().ok()?;
Expand Down Expand Up @@ -179,11 +179,11 @@ fn try_filter_trait_item_definition(
AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
let trait_ = assoc.implemented_trait(db)?;
let name = def.name(db)?;
let discri_value = discriminant(&assoc);
let discriminant_value = discriminant(&assoc);
trait_
.items(db)
.iter()
.filter(|itm| discriminant(*itm) == discri_value)
.filter(|itm| discriminant(*itm) == discriminant_value)
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
.map(|it| it.collect())
}
Expand Down
59 changes: 3 additions & 56 deletions crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ide_db::{
FxIndexSet, RootDatabase,
};
use itertools::{multizip, Itertools};
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};

use crate::{
doc_links::token_as_doc_comment,
Expand Down Expand Up @@ -298,61 +298,8 @@ fn hover_simple(
})
// 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}|0b{num:b})"))
},
Err(e) => {
Markup::fenced_block_text(format_args!("{e}"))
},
};
},
_ => return None
}
}
Some(res)
render::literal(sema, original_token.clone())
.map(|markup| HoverResult { markup, actions: vec![] })
});

result.map(|mut res: HoverResult| {
Expand Down
62 changes: 56 additions & 6 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ use ide_db::{
};
use itertools::Itertools;
use stdx::format_to;
use syntax::{
algo,
ast::{self, RecordPat},
match_ast, AstNode, Direction, SyntaxToken, T,
};
use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T};

use crate::{
doc_links::{remove_links, rewrite_links},
Expand Down Expand Up @@ -276,7 +272,7 @@ pub(super) fn keyword(
pub(super) fn struct_rest_pat(
sema: &Semantics<'_, RootDatabase>,
_config: &HoverConfig,
pattern: &RecordPat,
pattern: &ast::RecordPat,
) -> HoverResult {
let missing_fields = sema.record_pattern_missing_fields(pattern);

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

pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Markup> {
let lit = token.parent().and_then(ast::Literal::cast)?;
let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
sema.type_of_pat(&p)?
} else {
sema.type_of_expr(&ast::Expr::Literal(lit))?
}
.original;

let value = match_ast! {
match token {
ast::String(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
ast::ByteString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("{it:?}")),
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)),
ast::Char(char) => char .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
ast::Byte(byte) => byte .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")),
ast::FloatNumber(num) => {
let (text, _) = num.split_into_parts();
let text = text.replace('_', "");
if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) {
match text.parse::<f32>() {
Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
Err(e) => Err(e.to_string()),
}
} else {
match text.parse::<f64>() {
Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
Err(e) => Err(e.to_string()),
}
}
},
ast::IntNumber(num) => match num.value() {
Ok(num) => Ok(format!("{num} (0x{num:X}|0b{num:b})")),
Err(e) => Err(e.to_string()),
},
_ => return None
}
};
let ty = ty.display(sema.db);

let mut s = format!("```rust\n{ty}\n```\n___\n\n");
match value {
Ok(value) => {
if let Some(newline) = value.find('\n') {
format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline])
} else {
format_to!(s, "value of literal: {value}")
}
}
Err(error) => format_to!(s, "invalid literal: {error}"),
}
Some(s.into())
}

fn render_notable_trait_comment(
db: &RootDatabase,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
Expand Down

0 comments on commit 40ab5e5

Please sign in to comment.