diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-16 02:53:12 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-16 02:53:12 +0100 |
commit | a57bd59f351600c408ef9d2a4df3f2c10e817d0d (patch) | |
tree | 73af1b67227643ef4e8caa77ba50f2ad738ddd4e /crates/syntax | |
parent | 92abc56bc928fb2a11b8f5b2a37e3c9ee31102d7 (diff) | |
parent | de0ed9860d86c3b905a967b1a7b5243499d32d67 (diff) |
Merge #8813
8813: Get some more array lengths! r=lf- a=lf-
This is built on #8799 and thus contains its changes. I'll rebase it onto master when that one gets merged. It adds support for r-a understanding the length of:
* `let a: [u8; 2] = ...`
* `let a = b"aaa"`
* `let a = [0u8; 4]`
I have added support for getting the values of byte strings, which was not previously there. I am least confident in the correctness of this part and it probably needs some more tests, as we currently have only one test that exercised that part (!).
Fixes #2922.
Co-authored-by: Jade <[email protected]>
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/token_ext.rs | 81 |
1 files changed, 61 insertions, 20 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 29d25a58a..4b1e1ccee 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -143,6 +143,30 @@ impl QuoteOffsets { | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | pub trait IsString: AstToken { | ||
147 | fn quote_offsets(&self) -> Option<QuoteOffsets> { | ||
148 | let text = self.text(); | ||
149 | let offsets = QuoteOffsets::new(text)?; | ||
150 | let o = self.syntax().text_range().start(); | ||
151 | let offsets = QuoteOffsets { | ||
152 | quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o), | ||
153 | contents: offsets.contents + o, | ||
154 | }; | ||
155 | Some(offsets) | ||
156 | } | ||
157 | fn text_range_between_quotes(&self) -> Option<TextRange> { | ||
158 | self.quote_offsets().map(|it| it.contents) | ||
159 | } | ||
160 | fn open_quote_text_range(&self) -> Option<TextRange> { | ||
161 | self.quote_offsets().map(|it| it.quotes.0) | ||
162 | } | ||
163 | fn close_quote_text_range(&self) -> Option<TextRange> { | ||
164 | self.quote_offsets().map(|it| it.quotes.1) | ||
165 | } | ||
166 | } | ||
167 | |||
168 | impl IsString for ast::String {} | ||
169 | |||
146 | impl ast::String { | 170 | impl ast::String { |
147 | pub fn is_raw(&self) -> bool { | 171 | pub fn is_raw(&self) -> bool { |
148 | self.text().starts_with('r') | 172 | self.text().starts_with('r') |
@@ -187,32 +211,49 @@ impl ast::String { | |||
187 | (false, false) => Some(Cow::Owned(buf)), | 211 | (false, false) => Some(Cow::Owned(buf)), |
188 | } | 212 | } |
189 | } | 213 | } |
190 | |||
191 | pub fn quote_offsets(&self) -> Option<QuoteOffsets> { | ||
192 | let text = self.text(); | ||
193 | let offsets = QuoteOffsets::new(text)?; | ||
194 | let o = self.syntax().text_range().start(); | ||
195 | let offsets = QuoteOffsets { | ||
196 | quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o), | ||
197 | contents: offsets.contents + o, | ||
198 | }; | ||
199 | Some(offsets) | ||
200 | } | ||
201 | pub fn text_range_between_quotes(&self) -> Option<TextRange> { | ||
202 | self.quote_offsets().map(|it| it.contents) | ||
203 | } | ||
204 | pub fn open_quote_text_range(&self) -> Option<TextRange> { | ||
205 | self.quote_offsets().map(|it| it.quotes.0) | ||
206 | } | ||
207 | pub fn close_quote_text_range(&self) -> Option<TextRange> { | ||
208 | self.quote_offsets().map(|it| it.quotes.1) | ||
209 | } | ||
210 | } | 214 | } |
211 | 215 | ||
216 | impl IsString for ast::ByteString {} | ||
217 | |||
212 | impl ast::ByteString { | 218 | impl ast::ByteString { |
213 | pub fn is_raw(&self) -> bool { | 219 | pub fn is_raw(&self) -> bool { |
214 | self.text().starts_with("br") | 220 | self.text().starts_with("br") |
215 | } | 221 | } |
222 | |||
223 | pub fn value(&self) -> Option<Cow<'_, [u8]>> { | ||
224 | if self.is_raw() { | ||
225 | let text = self.text(); | ||
226 | let text = | ||
227 | &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | ||
228 | return Some(Cow::Borrowed(text.as_bytes())); | ||
229 | } | ||
230 | |||
231 | let text = self.text(); | ||
232 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | ||
233 | |||
234 | let mut buf: Vec<u8> = Vec::new(); | ||
235 | let mut text_iter = text.chars(); | ||
236 | let mut has_error = false; | ||
237 | unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match ( | ||
238 | unescaped_char, | ||
239 | buf.capacity() == 0, | ||
240 | ) { | ||
241 | (Ok(c), false) => buf.push(c as u8), | ||
242 | (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (), | ||
243 | (Ok(c), true) => { | ||
244 | buf.reserve_exact(text.len()); | ||
245 | buf.extend_from_slice(&text[..char_range.start].as_bytes()); | ||
246 | buf.push(c as u8); | ||
247 | } | ||
248 | (Err(_), _) => has_error = true, | ||
249 | }); | ||
250 | |||
251 | match (has_error, buf.capacity() == 0) { | ||
252 | (true, _) => None, | ||
253 | (false, true) => Some(Cow::Borrowed(text.as_bytes())), | ||
254 | (false, false) => Some(Cow::Owned(buf)), | ||
255 | } | ||
256 | } | ||
216 | } | 257 | } |
217 | 258 | ||
218 | #[derive(Debug)] | 259 | #[derive(Debug)] |