aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs96
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs4
-rw-r--r--crates/ra_syntax/src/validation.rs61
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
2use crate::db::AstDatabase; 2use crate::db::AstDatabase;
3use crate::{ 3use 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
8use crate::quote; 8use 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
64fn 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
93fn line_expand( 64fn 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
157fn 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
182fn column_expand( 122fn 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)]
285mod tests { 215mod 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
115fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { 114fn 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 _ => (),