From eb460333907a44c37bf7287b31c653877c3358c2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 6 Nov 2020 19:01:25 +0100 Subject: [PATCH] More orthogonal API --- .../src/handlers/convert_integer_literal.rs | 23 +++---- crates/syntax/src/ast/token_ext.rs | 63 +++++++++---------- 2 files changed, 38 insertions(+), 48 deletions(-) diff --git a/crates/assists/src/handlers/convert_integer_literal.rs b/crates/assists/src/handlers/convert_integer_literal.rs index 6d477c045e4..5957834d307 100644 --- a/crates/assists/src/handlers/convert_integer_literal.rs +++ b/crates/assists/src/handlers/convert_integer_literal.rs @@ -1,4 +1,4 @@ -use syntax::{ast, ast::Radix, AstNode}; +use syntax::{ast, ast::Radix, AstToken}; use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; @@ -14,15 +14,13 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; // const _: i32 = 0b1010; // ``` pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let literal = ctx.find_node_at_offset::()?; - let (radix, value) = literal.as_int_number()?.value()?; + let literal = ctx.find_node_at_offset::()?.as_int_number()?; + let radix = literal.radix(); + let value = literal.value()?; + let suffix = literal.suffix(); let range = literal.syntax().text_range(); let group_id = GroupLabel("Convert integer base".into()); - let suffix = match literal.kind() { - ast::LiteralKind::IntNumber { suffix } => suffix, - _ => return None, - }; for &target_radix in Radix::ALL { if target_radix == radix { @@ -36,16 +34,11 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Radix::Hexadecimal => format!("0x{:X}", value), }; - let label = format!( - "Convert {} to {}{}", - literal, - converted, - suffix.as_deref().unwrap_or_default() - ); + let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default()); // Appends the type suffix back into the new literal if it exists. - if let Some(suffix) = &suffix { - converted.push_str(&suffix); + if let Some(suffix) = suffix { + converted.push_str(suffix); } acc.add_group( diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 5623799b475..8d3fad5a6c6 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -166,6 +166,7 @@ impl HasStringValue for ast::String { } } +// FIXME: merge `ast::RawString` and `ast::String`. impl HasStringValue for ast::RawString { fn value(&self) -> Option> { let text = self.text().as_str(); @@ -544,29 +545,46 @@ impl ast::IntNumber { "i8", "i16", "i32", "i64", "i128", "isize", ]; - // FIXME: should probably introduce string token type? - // https://github.com/rust-analyzer/rust-analyzer/issues/6308 - pub fn value(&self) -> Option<(Radix, u128)> { + pub fn radix(&self) -> Radix { + match self.text().get(..2).unwrap_or_default() { + "0b" => Radix::Binary, + "0o" => Radix::Octal, + "0x" => Radix::Hexadecimal, + _ => Radix::Decimal, + } + } + + pub fn value(&self) -> Option { let token = self.syntax(); let mut text = token.text().as_str(); - for suffix in ast::IntNumber::SUFFIXES { - if let Some(without_suffix) = text.strip_suffix(suffix) { - text = without_suffix; - break; - } + if let Some(suffix) = self.suffix() { + text = &text[..text.len() - suffix.len()] } + let radix = self.radix(); + text = &text[radix.prefix_len()..]; + let buf; if text.contains("_") { buf = text.replace('_', ""); text = buf.as_str(); }; - let radix = Radix::identify(text)?; - let digits = &text[radix.prefix_len()..]; - let value = u128::from_str_radix(digits, radix as u32).ok()?; - Some((radix, value)) + let value = u128::from_str_radix(text, radix as u32).ok()?; + Some(value) + } + + pub fn suffix(&self) -> Option<&str> { + let text = self.text(); + // FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid + // syntax, suffix is `lol`. + ast::IntNumber::SUFFIXES.iter().find_map(|suffix| { + if text.ends_with(suffix) { + return Some(&text[text.len() - suffix.len()..]); + } + None + }) } } @@ -586,27 +604,6 @@ impl Radix { pub const ALL: &'static [Radix] = &[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal]; - fn identify(literal_text: &str) -> Option { - // We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible. - if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) { - return Some(Self::Decimal); - } - - let res = match &literal_text[..2] { - "0b" => Radix::Binary, - "0o" => Radix::Octal, - "0x" => Radix::Hexadecimal, - _ => Radix::Decimal, - }; - - // Checks that all characters after the base prefix are all valid digits for that base. - if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) { - Some(res) - } else { - None - } - } - const fn prefix_len(&self) -> usize { match self { Self::Decimal => 0,