mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Support length for ByteStrings
I am not confident that my added byte string parsing is right.
This commit is contained in:
parent
8b147624ff
commit
73023c0299
8 changed files with 85 additions and 33 deletions
|
@ -1022,7 +1022,10 @@ impl From<ast::LiteralKind> for Literal {
|
|||
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
|
||||
Literal::Float(Default::default(), ty)
|
||||
}
|
||||
LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
|
||||
LiteralKind::ByteString(bs) => {
|
||||
let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
|
||||
Literal::ByteString(text)
|
||||
}
|
||||
LiteralKind::String(_) => Literal::String(Default::default()),
|
||||
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
|
||||
LiteralKind::Bool(val) => Literal::Bool(val),
|
||||
|
|
|
@ -16,7 +16,7 @@ use stdx::always;
|
|||
use syntax::ast::RangeOp;
|
||||
|
||||
use crate::{
|
||||
autoderef, dummy_usize_const,
|
||||
autoderef,
|
||||
lower::lower_to_chalk_mutability,
|
||||
mapping::from_chalk,
|
||||
method_resolution, op,
|
||||
|
@ -24,8 +24,9 @@ use crate::{
|
|||
static_lifetime, to_chalk_trait_id,
|
||||
traits::FnTrait,
|
||||
utils::{generics, Generics},
|
||||
AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
|
||||
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
AdtId, Binders, CallableDefId, ConcreteConst, ConstValue, FnPointer, FnSig, FnSubst,
|
||||
InEnvironment, Interner, ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty,
|
||||
TyBuilder, TyExt, TyKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -758,11 +759,18 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
|
||||
.intern(&Interner)
|
||||
}
|
||||
Literal::ByteString(..) => {
|
||||
Literal::ByteString(bs) => {
|
||||
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
|
||||
|
||||
let array_type =
|
||||
TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
|
||||
let len = ConstData {
|
||||
ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
|
||||
value: ConstValue::Concrete(ConcreteConst {
|
||||
interned: ConstScalar::Usize(bs.len() as u64),
|
||||
}),
|
||||
}
|
||||
.intern(&Interner);
|
||||
|
||||
let array_type = TyKind::Array(byte_type, len).intern(&Interner);
|
||||
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
|
||||
}
|
||||
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
|
||||
|
|
|
@ -496,7 +496,7 @@ fn infer_literals() {
|
|||
26..30 '5f32': f32
|
||||
36..40 '5f64': f64
|
||||
46..53 '"hello"': &str
|
||||
59..67 'b"bytes"': &[u8; _]
|
||||
59..67 'b"bytes"': &[u8; 5]
|
||||
73..76 ''c'': char
|
||||
82..86 'b'b'': u8
|
||||
92..96 '3.14': f64
|
||||
|
@ -504,7 +504,7 @@ fn infer_literals() {
|
|||
112..117 'false': bool
|
||||
123..127 'true': bool
|
||||
133..197 'r#" ... "#': &str
|
||||
203..213 'br#"yolo"#': &[u8; _]
|
||||
203..213 'br#"yolo"#': &[u8; 4]
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use ide_assists::utils::extract_trivial_expression;
|
|||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
algo::non_trivia_sibling,
|
||||
ast::{self, AstNode, AstToken},
|
||||
ast::{self, AstNode, AstToken, IsString},
|
||||
Direction, NodeOrToken, SourceFile,
|
||||
SyntaxKind::{self, USE_TREE, WHITESPACE},
|
||||
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
||||
|
|
|
@ -6,7 +6,7 @@ use either::Either;
|
|||
use hir::{InFile, Semantics};
|
||||
use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
ast::{self, AstNode, IsString},
|
||||
AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use syntax::{ast, AstToken, TextRange, TextSize};
|
||||
use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use syntax::{ast, AstToken, SyntaxKind::STRING};
|
||||
use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
|
|
|
@ -143,6 +143,30 @@ impl QuoteOffsets {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IsString: AstToken {
|
||||
fn quote_offsets(&self) -> Option<QuoteOffsets> {
|
||||
let text = self.text();
|
||||
let offsets = QuoteOffsets::new(text)?;
|
||||
let o = self.syntax().text_range().start();
|
||||
let offsets = QuoteOffsets {
|
||||
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
|
||||
contents: offsets.contents + o,
|
||||
};
|
||||
Some(offsets)
|
||||
}
|
||||
fn text_range_between_quotes(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.contents)
|
||||
}
|
||||
fn open_quote_text_range(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.quotes.0)
|
||||
}
|
||||
fn close_quote_text_range(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.quotes.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsString for ast::String {}
|
||||
|
||||
impl ast::String {
|
||||
pub fn is_raw(&self) -> bool {
|
||||
self.text().starts_with('r')
|
||||
|
@ -187,32 +211,49 @@ impl ast::String {
|
|||
(false, false) => Some(Cow::Owned(buf)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn quote_offsets(&self) -> Option<QuoteOffsets> {
|
||||
let text = self.text();
|
||||
let offsets = QuoteOffsets::new(text)?;
|
||||
let o = self.syntax().text_range().start();
|
||||
let offsets = QuoteOffsets {
|
||||
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
|
||||
contents: offsets.contents + o,
|
||||
};
|
||||
Some(offsets)
|
||||
}
|
||||
pub fn text_range_between_quotes(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.contents)
|
||||
}
|
||||
pub fn open_quote_text_range(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.quotes.0)
|
||||
}
|
||||
pub fn close_quote_text_range(&self) -> Option<TextRange> {
|
||||
self.quote_offsets().map(|it| it.quotes.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsString for ast::ByteString {}
|
||||
|
||||
impl ast::ByteString {
|
||||
pub fn is_raw(&self) -> bool {
|
||||
self.text().starts_with("br")
|
||||
}
|
||||
|
||||
pub fn value(&self) -> Option<Cow<'_, [u8]>> {
|
||||
if self.is_raw() {
|
||||
let text = self.text();
|
||||
let text =
|
||||
&text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
return Some(Cow::Borrowed(text.as_bytes()));
|
||||
}
|
||||
|
||||
let text = self.text();
|
||||
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut text_iter = text.chars();
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
(Ok(c), false) => buf.push(c as u8),
|
||||
(Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
|
||||
(Ok(c), true) => {
|
||||
buf.reserve_exact(text.len());
|
||||
buf.extend_from_slice(&text[..char_range.start].as_bytes());
|
||||
buf.push(c as u8);
|
||||
}
|
||||
(Err(_), _) => has_error = true,
|
||||
});
|
||||
|
||||
match (has_error, buf.capacity() == 0) {
|
||||
(true, _) => None,
|
||||
(false, true) => Some(Cow::Borrowed(text.as_bytes())),
|
||||
(false, false) => Some(Cow::Owned(buf)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
Loading…
Reference in a new issue