mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +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));
|
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
|
||||||
Literal::Float(Default::default(), ty)
|
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::String(_) => Literal::String(Default::default()),
|
||||||
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
|
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
|
||||||
LiteralKind::Bool(val) => Literal::Bool(val),
|
LiteralKind::Bool(val) => Literal::Bool(val),
|
||||||
|
|
|
@ -16,7 +16,7 @@ use stdx::always;
|
||||||
use syntax::ast::RangeOp;
|
use syntax::ast::RangeOp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef, dummy_usize_const,
|
autoderef,
|
||||||
lower::lower_to_chalk_mutability,
|
lower::lower_to_chalk_mutability,
|
||||||
mapping::from_chalk,
|
mapping::from_chalk,
|
||||||
method_resolution, op,
|
method_resolution, op,
|
||||||
|
@ -24,8 +24,9 @@ use crate::{
|
||||||
static_lifetime, to_chalk_trait_id,
|
static_lifetime, to_chalk_trait_id,
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
utils::{generics, Generics},
|
utils::{generics, Generics},
|
||||||
AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
|
AdtId, Binders, CallableDefId, ConcreteConst, ConstValue, FnPointer, FnSig, FnSubst,
|
||||||
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
InEnvironment, Interner, ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty,
|
||||||
|
TyBuilder, TyExt, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -758,11 +759,18 @@ impl<'a> InferenceContext<'a> {
|
||||||
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
|
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
|
||||||
.intern(&Interner)
|
.intern(&Interner)
|
||||||
}
|
}
|
||||||
Literal::ByteString(..) => {
|
Literal::ByteString(bs) => {
|
||||||
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
|
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
|
||||||
|
|
||||||
let array_type =
|
let len = ConstData {
|
||||||
TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
|
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)
|
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
|
||||||
}
|
}
|
||||||
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
|
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
|
||||||
|
|
|
@ -496,7 +496,7 @@ fn infer_literals() {
|
||||||
26..30 '5f32': f32
|
26..30 '5f32': f32
|
||||||
36..40 '5f64': f64
|
36..40 '5f64': f64
|
||||||
46..53 '"hello"': &str
|
46..53 '"hello"': &str
|
||||||
59..67 'b"bytes"': &[u8; _]
|
59..67 'b"bytes"': &[u8; 5]
|
||||||
73..76 ''c'': char
|
73..76 ''c'': char
|
||||||
82..86 'b'b'': u8
|
82..86 'b'b'': u8
|
||||||
92..96 '3.14': f64
|
92..96 '3.14': f64
|
||||||
|
@ -504,7 +504,7 @@ fn infer_literals() {
|
||||||
112..117 'false': bool
|
112..117 'false': bool
|
||||||
123..127 'true': bool
|
123..127 'true': bool
|
||||||
133..197 'r#" ... "#': &str
|
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 itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::non_trivia_sibling,
|
algo::non_trivia_sibling,
|
||||||
ast::{self, AstNode, AstToken},
|
ast::{self, AstNode, AstToken, IsString},
|
||||||
Direction, NodeOrToken, SourceFile,
|
Direction, NodeOrToken, SourceFile,
|
||||||
SyntaxKind::{self, USE_TREE, WHITESPACE},
|
SyntaxKind::{self, USE_TREE, WHITESPACE},
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use either::Either;
|
||||||
use hir::{InFile, Semantics};
|
use hir::{InFile, Semantics};
|
||||||
use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
|
use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode, IsString},
|
||||||
AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use syntax::{ast, AstToken, TextRange, TextSize};
|
use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
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};
|
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 {
|
impl ast::String {
|
||||||
pub fn is_raw(&self) -> bool {
|
pub fn is_raw(&self) -> bool {
|
||||||
self.text().starts_with('r')
|
self.text().starts_with('r')
|
||||||
|
@ -187,32 +211,49 @@ impl ast::String {
|
||||||
(false, false) => Some(Cow::Owned(buf)),
|
(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 {
|
impl ast::ByteString {
|
||||||
pub fn is_raw(&self) -> bool {
|
pub fn is_raw(&self) -> bool {
|
||||||
self.text().starts_with("br")
|
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)]
|
#[derive(Debug)]
|
||||||
|
|
Loading…
Reference in a new issue