diff options
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 96 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 61 |
3 files changed, 41 insertions, 120 deletions
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index e9e275670..f3f959ac6 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! Builtin macro | 1 | //! Builtin macro |
2 | use crate::db::AstDatabase; | 2 | use crate::db::AstDatabase; |
3 | use crate::{ | 3 | use crate::{ |
4 | ast::{self, AstNode}, | 4 | ast::{self}, |
5 | name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, TextUnit, | 5 | name, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind, TextUnit, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::quote; | 8 | use crate::quote; |
@@ -61,48 +61,13 @@ register_builtin! { | |||
61 | (format_args_nl, FormatArgsNl) => format_args_expand | 61 | (format_args_nl, FormatArgsNl) => format_args_expand |
62 | } | 62 | } |
63 | 63 | ||
64 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { | ||
65 | let file_id = file.original_file(db); | ||
66 | |||
67 | // FIXME: if the file is coming from macro, we return a dummy value for now. | ||
68 | if file.call_node(db).map(|it| it.file_id != file_id.into()).unwrap_or(true) { | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | let text = db.file_text(file_id); | ||
73 | let mut line_num = 1; | ||
74 | |||
75 | let pos = pos.to_usize(); | ||
76 | if pos > text.len() { | ||
77 | // FIXME: `pos` at the moment could be an offset inside the "wrong" file | ||
78 | // in this case, when we know it's wrong, we return a dummy value | ||
79 | return 0; | ||
80 | } | ||
81 | // Count line end | ||
82 | for (i, c) in text.chars().enumerate() { | ||
83 | if i == pos { | ||
84 | break; | ||
85 | } | ||
86 | if c == '\n' { | ||
87 | line_num += 1; | ||
88 | } | ||
89 | } | ||
90 | line_num | ||
91 | } | ||
92 | |||
93 | fn line_expand( | 64 | fn line_expand( |
94 | db: &dyn AstDatabase, | 65 | _db: &dyn AstDatabase, |
95 | id: MacroCallId, | 66 | _id: MacroCallId, |
96 | _tt: &tt::Subtree, | 67 | _tt: &tt::Subtree, |
97 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 68 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
98 | let loc = db.lookup_intern_macro(id); | 69 | // dummy implementation for type-checking purposes |
99 | 70 | let line_num = 0; | |
100 | let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | ||
101 | let arg_start = arg.text_range().start(); | ||
102 | |||
103 | let file = id.as_file(); | ||
104 | let line_num = to_line_number(db, file, arg_start); | ||
105 | |||
106 | let expanded = quote! { | 71 | let expanded = quote! { |
107 | #line_num | 72 | #line_num |
108 | }; | 73 | }; |
@@ -154,48 +119,13 @@ fn option_env_expand( | |||
154 | Ok(expanded) | 119 | Ok(expanded) |
155 | } | 120 | } |
156 | 121 | ||
157 | fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { | ||
158 | let file_id = file.original_file(db); | ||
159 | // FIXME: if the file is coming from macro, we return a dummy value for now. | ||
160 | if file.call_node(db).map(|it| it.file_id != file_id.into()).unwrap_or(true) { | ||
161 | return 0; | ||
162 | } | ||
163 | let text = db.file_text(file_id); | ||
164 | |||
165 | let pos = pos.to_usize(); | ||
166 | if pos > text.len() { | ||
167 | // FIXME: `pos` at the moment could be an offset inside the "wrong" file | ||
168 | // in this case we return a dummy value so that we don't `panic!` | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | let mut col_num = 1; | ||
173 | for c in text[..pos].chars().rev() { | ||
174 | if c == '\n' { | ||
175 | break; | ||
176 | } | ||
177 | col_num += 1; | ||
178 | } | ||
179 | col_num | ||
180 | } | ||
181 | |||
182 | fn column_expand( | 122 | fn column_expand( |
183 | db: &dyn AstDatabase, | 123 | _db: &dyn AstDatabase, |
184 | id: MacroCallId, | 124 | _id: MacroCallId, |
185 | _tt: &tt::Subtree, | 125 | _tt: &tt::Subtree, |
186 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 126 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
187 | let loc = db.lookup_intern_macro(id); | 127 | // dummy implementation for type-checking purposes |
188 | let macro_call = match loc.kind { | 128 | let col_num = 0; |
189 | crate::MacroCallKind::FnLike(ast_id) => ast_id.to_node(db), | ||
190 | _ => panic!("column macro called as attr"), | ||
191 | }; | ||
192 | |||
193 | let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | ||
194 | let col_start = macro_call.syntax().text_range().start(); | ||
195 | |||
196 | let file = id.as_file(); | ||
197 | let col_num = to_col_number(db, file, col_start); | ||
198 | |||
199 | let expanded = quote! { | 129 | let expanded = quote! { |
200 | #col_num | 130 | #col_num |
201 | }; | 131 | }; |
@@ -284,7 +214,7 @@ fn format_args_expand( | |||
284 | #[cfg(test)] | 214 | #[cfg(test)] |
285 | mod tests { | 215 | mod tests { |
286 | use super::*; | 216 | use super::*; |
287 | use crate::{name::AsName, test_db::TestDB, MacroCallKind, MacroCallLoc}; | 217 | use crate::{name::AsName, test_db::TestDB, AstNode, MacroCallKind, MacroCallLoc}; |
288 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 218 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
289 | use ra_syntax::ast::NameOwner; | 219 | use ra_syntax::ast::NameOwner; |
290 | 220 | ||
@@ -330,7 +260,7 @@ mod tests { | |||
330 | "#, | 260 | "#, |
331 | ); | 261 | ); |
332 | 262 | ||
333 | assert_eq!(expanded, "13"); | 263 | assert_eq!(expanded, "0"); |
334 | } | 264 | } |
335 | 265 | ||
336 | #[test] | 266 | #[test] |
@@ -343,7 +273,7 @@ mod tests { | |||
343 | "#, | 273 | "#, |
344 | ); | 274 | ); |
345 | 275 | ||
346 | assert_eq!(expanded, "4"); | 276 | assert_eq!(expanded, "0"); |
347 | } | 277 | } |
348 | 278 | ||
349 | #[test] | 279 | #[test] |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 9d09d93a7..652420ea8 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -374,7 +374,7 @@ fn main() { | |||
374 | } | 374 | } |
375 | "#), | 375 | "#), |
376 | @r###" | 376 | @r###" |
377 | ![0; 1) '6': i32 | 377 | ![0; 1) '0': i32 |
378 | [64; 88) '{ ...!(); }': () | 378 | [64; 88) '{ ...!(); }': () |
379 | [74; 75) 'x': i32 | 379 | [74; 75) 'x': i32 |
380 | "### | 380 | "### |
@@ -412,7 +412,7 @@ fn main() { | |||
412 | } | 412 | } |
413 | "#), | 413 | "#), |
414 | @r###" | 414 | @r###" |
415 | ![0; 2) '13': i32 | 415 | ![0; 1) '0': i32 |
416 | [66; 92) '{ ...!(); }': () | 416 | [66; 92) '{ ...!(); }': () |
417 | [76; 77) 'x': i32 | 417 | [76; 77) 'x': i32 |
418 | "### | 418 | "### |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 222ac15f8..445e3b3e4 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -111,55 +111,46 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
111 | errors | 111 | errors |
112 | } | 112 | } |
113 | 113 | ||
114 | // FIXME: kill duplication | ||
115 | fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | 114 | fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { |
115 | fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> { | ||
116 | text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end)) | ||
117 | } | ||
118 | |||
116 | let token = literal.token(); | 119 | let token = literal.token(); |
117 | let text = token.text().as_str(); | 120 | let text = token.text().as_str(); |
121 | |||
122 | let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { | ||
123 | let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len); | ||
124 | acc.push(SyntaxError::new(err.into(), off)); | ||
125 | }; | ||
126 | |||
118 | match token.kind() { | 127 | match token.kind() { |
119 | BYTE => { | 128 | BYTE => { |
120 | if let Some(end) = text.rfind('\'') { | 129 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape::unescape_byte) { |
121 | if let Some(without_quotes) = text.get(2..end) { | 130 | push_err(2, e); |
122 | if let Err((off, err)) = unescape::unescape_byte(without_quotes) { | ||
123 | let off = token.text_range().start() + TextUnit::from_usize(off + 2); | ||
124 | acc.push(SyntaxError::new(err.into(), off)) | ||
125 | } | ||
126 | } | ||
127 | } | 131 | } |
128 | } | 132 | } |
129 | CHAR => { | 133 | CHAR => { |
130 | if let Some(end) = text.rfind('\'') { | 134 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape::unescape_char) { |
131 | if let Some(without_quotes) = text.get(1..end) { | 135 | push_err(1, e); |
132 | if let Err((off, err)) = unescape::unescape_char(without_quotes) { | ||
133 | let off = token.text_range().start() + TextUnit::from_usize(off + 1); | ||
134 | acc.push(SyntaxError::new(err.into(), off)) | ||
135 | } | ||
136 | } | ||
137 | } | 136 | } |
138 | } | 137 | } |
139 | BYTE_STRING => { | 138 | BYTE_STRING => { |
140 | if let Some(end) = text.rfind('\"') { | 139 | if let Some(without_quotes) = unquote(text, 2, '"') { |
141 | if let Some(without_quotes) = text.get(2..end) { | 140 | unescape::unescape_byte_str(without_quotes, &mut |range, char| { |
142 | unescape::unescape_byte_str(without_quotes, &mut |range, char| { | 141 | if let Err(err) = char { |
143 | if let Err(err) = char { | 142 | push_err(2, (range.start, err)); |
144 | let off = range.start; | 143 | } |
145 | let off = token.text_range().start() + TextUnit::from_usize(off + 2); | 144 | }) |
146 | acc.push(SyntaxError::new(err.into(), off)) | ||
147 | } | ||
148 | }) | ||
149 | } | ||
150 | } | 145 | } |
151 | } | 146 | } |
152 | STRING => { | 147 | STRING => { |
153 | if let Some(end) = text.rfind('\"') { | 148 | if let Some(without_quotes) = unquote(text, 1, '"') { |
154 | if let Some(without_quotes) = text.get(1..end) { | 149 | unescape::unescape_str(without_quotes, &mut |range, char| { |
155 | unescape::unescape_str(without_quotes, &mut |range, char| { | 150 | if let Err(err) = char { |
156 | if let Err(err) = char { | 151 | push_err(1, (range.start, err)); |
157 | let off = range.start; | 152 | } |
158 | let off = token.text_range().start() + TextUnit::from_usize(off + 1); | 153 | }) |
159 | acc.push(SyntaxError::new(err.into(), off)) | ||
160 | } | ||
161 | }) | ||
162 | } | ||
163 | } | 154 | } |
164 | } | 155 | } |
165 | _ => (), | 156 | _ => (), |