mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Merge #6486
6486: Cleanup API r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
c365329911
5 changed files with 84 additions and 96 deletions
|
@ -14,7 +14,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
|
||||||
// const _: i32 = 0b1010;
|
// const _: i32 = 0b1010;
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
let literal = ctx.find_node_at_offset::<ast::Literal>()?.as_int_number()?;
|
let literal = ctx.find_node_at_offset::<ast::Literal>()?;
|
||||||
|
let literal = match literal.kind() {
|
||||||
|
ast::LiteralKind::IntNumber(it) => it,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
let radix = literal.radix();
|
let radix = literal.radix();
|
||||||
let value = literal.value()?;
|
let value = literal.value()?;
|
||||||
let suffix = literal.suffix();
|
let suffix = literal.suffix();
|
||||||
|
|
|
@ -953,18 +953,19 @@ impl From<ast::BinOp> for BinaryOp {
|
||||||
impl From<ast::LiteralKind> for Literal {
|
impl From<ast::LiteralKind> for Literal {
|
||||||
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
|
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
|
||||||
match ast_lit_kind {
|
match ast_lit_kind {
|
||||||
LiteralKind::IntNumber { suffix } => {
|
LiteralKind::IntNumber(lit) => {
|
||||||
let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it));
|
if let Some(float_suffix) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
|
||||||
|
return Literal::Float(Default::default(), Some(float_suffix));
|
||||||
Literal::Int(Default::default(), known_name)
|
}
|
||||||
|
let ty = lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it));
|
||||||
|
Literal::Int(Default::default(), ty)
|
||||||
}
|
}
|
||||||
LiteralKind::FloatNumber { suffix } => {
|
LiteralKind::FloatNumber(lit) => {
|
||||||
let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it));
|
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
|
||||||
|
Literal::Float(Default::default(), ty)
|
||||||
Literal::Float(Default::default(), known_name)
|
|
||||||
}
|
}
|
||||||
LiteralKind::ByteString => Literal::ByteString(Default::default()),
|
LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
|
||||||
LiteralKind::String => Literal::String(Default::default()),
|
LiteralKind::String(_) => Literal::String(Default::default()),
|
||||||
LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)),
|
LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)),
|
||||||
LiteralKind::Bool(val) => Literal::Bool(val),
|
LiteralKind::Bool(val) => Literal::Bool(val),
|
||||||
LiteralKind::Char => Literal::Char(Default::default()),
|
LiteralKind::Char => Literal::Char(Default::default()),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, support, AstChildren, AstNode},
|
ast::{self, support, AstChildren, AstNode},
|
||||||
AstToken, SmolStr,
|
AstToken,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxToken, T,
|
SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
@ -298,12 +298,12 @@ impl ast::ArrayExpr {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum LiteralKind {
|
pub enum LiteralKind {
|
||||||
String,
|
String(ast::String),
|
||||||
ByteString,
|
ByteString(ast::ByteString),
|
||||||
|
IntNumber(ast::IntNumber),
|
||||||
|
FloatNumber(ast::FloatNumber),
|
||||||
Char,
|
Char,
|
||||||
Byte,
|
Byte,
|
||||||
IntNumber { suffix: Option<SmolStr> },
|
|
||||||
FloatNumber { suffix: Option<SmolStr> },
|
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,53 +315,25 @@ impl ast::Literal {
|
||||||
.and_then(|e| e.into_token())
|
.and_then(|e| e.into_token())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_int_number(&self) -> Option<ast::IntNumber> {
|
|
||||||
ast::IntNumber::cast(self.token())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_string(&self) -> Option<ast::String> {
|
|
||||||
ast::String::cast(self.token())
|
|
||||||
}
|
|
||||||
pub fn as_byte_string(&self) -> Option<ast::ByteString> {
|
|
||||||
ast::ByteString::cast(self.token())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_suffix(text: &str, possible_suffixes: &[&str]) -> Option<SmolStr> {
|
|
||||||
possible_suffixes
|
|
||||||
.iter()
|
|
||||||
.find(|&suffix| text.ends_with(suffix))
|
|
||||||
.map(|&suffix| SmolStr::new(suffix))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> LiteralKind {
|
pub fn kind(&self) -> LiteralKind {
|
||||||
let token = self.token();
|
let token = self.token();
|
||||||
|
|
||||||
|
if let Some(t) = ast::IntNumber::cast(token.clone()) {
|
||||||
|
return LiteralKind::IntNumber(t);
|
||||||
|
}
|
||||||
|
if let Some(t) = ast::FloatNumber::cast(token.clone()) {
|
||||||
|
return LiteralKind::FloatNumber(t);
|
||||||
|
}
|
||||||
|
if let Some(t) = ast::String::cast(token.clone()) {
|
||||||
|
return LiteralKind::String(t);
|
||||||
|
}
|
||||||
|
if let Some(t) = ast::ByteString::cast(token.clone()) {
|
||||||
|
return LiteralKind::ByteString(t);
|
||||||
|
}
|
||||||
|
|
||||||
match token.kind() {
|
match token.kind() {
|
||||||
INT_NUMBER => {
|
|
||||||
// FYI: there was a bug here previously, thus the if statement below is necessary.
|
|
||||||
// The lexer treats e.g. `1f64` as an integer literal. See
|
|
||||||
// https://github.com/rust-analyzer/rust-analyzer/issues/1592
|
|
||||||
// and the comments on the linked PR.
|
|
||||||
let text = token.text();
|
|
||||||
if let suffix @ Some(_) = Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES) {
|
|
||||||
LiteralKind::FloatNumber { suffix }
|
|
||||||
} else {
|
|
||||||
LiteralKind::IntNumber {
|
|
||||||
suffix: Self::find_suffix(&text, &ast::IntNumber::SUFFIXES),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FLOAT_NUMBER => {
|
|
||||||
let text = token.text();
|
|
||||||
LiteralKind::FloatNumber {
|
|
||||||
suffix: Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
STRING => LiteralKind::String,
|
|
||||||
T![true] => LiteralKind::Bool(true),
|
T![true] => LiteralKind::Bool(true),
|
||||||
T![false] => LiteralKind::Bool(false),
|
T![false] => LiteralKind::Bool(false),
|
||||||
BYTE_STRING => LiteralKind::ByteString,
|
|
||||||
CHAR => LiteralKind::Char,
|
CHAR => LiteralKind::Char,
|
||||||
BYTE => LiteralKind::Byte,
|
BYTE => LiteralKind::Byte,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -517,10 +517,9 @@ impl HasFormatSpecifier for ast::String {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::IntNumber {
|
impl ast::IntNumber {
|
||||||
#[rustfmt::skip]
|
const SUFFIXES: &'static [&'static str] = &[
|
||||||
pub(crate) const SUFFIXES: &'static [&'static str] = &[
|
"u8", "u16", "u32", "u64", "u128", "usize", // Unsigned.
|
||||||
"u8", "u16", "u32", "u64", "u128", "usize",
|
"i8", "i16", "i32", "i64", "i128", "isize", // Signed.
|
||||||
"i8", "i16", "i32", "i64", "i128", "isize",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn radix(&self) -> Radix {
|
pub fn radix(&self) -> Radix {
|
||||||
|
@ -555,9 +554,24 @@ impl ast::IntNumber {
|
||||||
|
|
||||||
pub fn suffix(&self) -> Option<&str> {
|
pub fn suffix(&self) -> Option<&str> {
|
||||||
let text = self.text();
|
let text = self.text();
|
||||||
// FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid
|
// FIXME: don't check a fixed set of suffixes, `1_0_1_l_o_l` is valid
|
||||||
// syntax, suffix is `lol`.
|
// syntax, suffix is `l_o_l`.
|
||||||
ast::IntNumber::SUFFIXES.iter().find_map(|suffix| {
|
ast::IntNumber::SUFFIXES.iter().chain(ast::FloatNumber::SUFFIXES.iter()).find_map(
|
||||||
|
|suffix| {
|
||||||
|
if text.ends_with(suffix) {
|
||||||
|
return Some(&text[text.len() - suffix.len()..]);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ast::FloatNumber {
|
||||||
|
const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
|
||||||
|
pub fn suffix(&self) -> Option<&str> {
|
||||||
|
let text = self.text();
|
||||||
|
ast::FloatNumber::SUFFIXES.iter().find_map(|suffix| {
|
||||||
if text.ends_with(suffix) {
|
if text.ends_with(suffix) {
|
||||||
return Some(&text[text.len() - suffix.len()..]);
|
return Some(&text[text.len() - suffix.len()..]);
|
||||||
}
|
}
|
||||||
|
@ -566,10 +580,6 @@ impl ast::IntNumber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::FloatNumber {
|
|
||||||
pub(crate) const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum Radix {
|
pub enum Radix {
|
||||||
Binary = 2,
|
Binary = 2,
|
||||||
|
|
|
@ -4,7 +4,7 @@ mod block;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo, ast, match_ast, AstNode, SyntaxError,
|
algo, ast, match_ast, AstNode, SyntaxError,
|
||||||
SyntaxKind::{BYTE, CHAR, CONST, FN, INT_NUMBER, TYPE_ALIAS},
|
SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
|
||||||
SyntaxNode, SyntaxToken, TextSize, T,
|
SyntaxNode, SyntaxToken, TextSize, T,
|
||||||
};
|
};
|
||||||
use rowan::Direction;
|
use rowan::Direction;
|
||||||
|
@ -121,41 +121,42 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
|
||||||
acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
|
acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(s) = literal.as_string() {
|
match literal.kind() {
|
||||||
if !s.is_raw() {
|
ast::LiteralKind::String(s) => {
|
||||||
if let Some(without_quotes) = unquote(text, 1, '"') {
|
if !s.is_raw() {
|
||||||
unescape_literal(without_quotes, Mode::Str, &mut |range, char| {
|
if let Some(without_quotes) = unquote(text, 1, '"') {
|
||||||
if let Err(err) = char {
|
unescape_literal(without_quotes, Mode::Str, &mut |range, char| {
|
||||||
push_err(1, (range.start, err));
|
if let Err(err) = char {
|
||||||
}
|
push_err(1, (range.start, err));
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ast::LiteralKind::ByteString(s) => {
|
||||||
if let Some(s) = literal.as_byte_string() {
|
if !s.is_raw() {
|
||||||
if !s.is_raw() {
|
if let Some(without_quotes) = unquote(text, 2, '"') {
|
||||||
if let Some(without_quotes) = unquote(text, 2, '"') {
|
unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
|
||||||
unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
|
if let Err(err) = char {
|
||||||
if let Err(err) = char {
|
push_err(2, (range.start, err));
|
||||||
push_err(2, (range.start, err));
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ast::LiteralKind::Char => {
|
||||||
|
|
||||||
match token.kind() {
|
|
||||||
BYTE => {
|
|
||||||
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
|
|
||||||
push_err(2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CHAR => {
|
|
||||||
if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
|
if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
|
||||||
push_err(1, e);
|
push_err(1, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
ast::LiteralKind::Byte => {
|
||||||
|
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
|
||||||
|
push_err(2, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::LiteralKind::IntNumber(_)
|
||||||
|
| ast::LiteralKind::FloatNumber(_)
|
||||||
|
| ast::LiteralKind::Bool(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue