aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs2
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs37
-rw-r--r--crates/ra_syntax/src/validation.rs119
4 files changed, 96 insertions, 64 deletions
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index f2ea5088e..45e3dd2d3 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -407,7 +407,7 @@ impl ast::Visibility {
407 } else if self.super_token().is_some() { 407 } else if self.super_token().is_some() {
408 VisibilityKind::PubSuper 408 VisibilityKind::PubSuper
409 } else if self.self_token().is_some() { 409 } else if self.self_token().is_some() {
410 VisibilityKind::PubSuper 410 VisibilityKind::PubSelf
411 } else { 411 } else {
412 VisibilityKind::Pub 412 VisibilityKind::Pub
413 } 413 }
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 81260680f..3f16592b6 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -1241,6 +1241,8 @@ pub struct PathSegment {
1241impl PathSegment { 1241impl PathSegment {
1242 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } 1242 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
1243 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } 1243 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
1244 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
1245 pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
1244 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } 1246 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
1245 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 1247 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
1246 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } 1248 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) }
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs
index f450ef4a2..1a5a6dc06 100644
--- a/crates/ra_syntax/src/parsing/lexer.rs
+++ b/crates/ra_syntax/src/parsing/lexer.rs
@@ -180,7 +180,7 @@ fn rustc_token_kind_to_syntax_kind(
180 return (syntax_kind, None); 180 return (syntax_kind, None);
181 181
182 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<&'static str>) { 182 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<&'static str>) {
183 use rustc_lexer::LiteralKind as LK; 183 use rustc_lexer::{LexRawStrError, LiteralKind as LK};
184 184
185 #[rustfmt::skip] 185 #[rustfmt::skip]
186 let syntax_kind = match *kind { 186 let syntax_kind = match *kind {
@@ -215,21 +215,28 @@ fn rustc_token_kind_to_syntax_kind(
215 return (BYTE_STRING, Some("Missing trailing `\"` symbol to terminate the byte string literal")) 215 return (BYTE_STRING, Some("Missing trailing `\"` symbol to terminate the byte string literal"))
216 } 216 }
217 217
218 LK::RawStr { started: true, terminated: true, .. } => RAW_STRING, 218 LK::RawStr(str) => match str.validate() {
219 LK::RawStr { started: true, terminated: false, .. } => { 219 Ok(_) => RAW_STRING,
220 return (RAW_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw string literal")) 220 Err(LexRawStrError::InvalidStarter) => return (RAW_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw string literal")),
221 } 221 Err(LexRawStrError::NoTerminator { expected, found, .. }) => if expected == found {
222 LK::RawStr { started: false, .. } => { 222 return (RAW_STRING, Some("Missing trailing `\"` to terminate the raw string literal"))
223 return (RAW_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw string literal")) 223 } else {
224 } 224 return (RAW_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw string literal"))
225
226 },
227 Err(LexRawStrError::TooManyDelimiters { .. }) => return (RAW_STRING, Some("Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols")),
228 },
229 LK::RawByteStr(str) => match str.validate() {
230 Ok(_) => RAW_BYTE_STRING,
231 Err(LexRawStrError::InvalidStarter) => return (RAW_BYTE_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw byte string literal")),
232 Err(LexRawStrError::NoTerminator { expected, found, .. }) => if expected == found {
233 return (RAW_BYTE_STRING, Some("Missing trailing `\"` to terminate the raw byte string literal"))
234 } else {
235 return (RAW_BYTE_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"))
225 236
226 LK::RawByteStr { started: true, terminated: true, .. } => RAW_BYTE_STRING, 237 },
227 LK::RawByteStr { started: true, terminated: false, .. } => { 238 Err(LexRawStrError::TooManyDelimiters { .. }) => return (RAW_BYTE_STRING, Some("Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols")),
228 return (RAW_BYTE_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw byte string literal")) 239 },
229 }
230 LK::RawByteStr { started: false, .. } => {
231 return (RAW_BYTE_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw byte string literal"))
232 }
233 }; 240 };
234 241
235 (syntax_kind, None) 242 (syntax_kind, None)
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index f0b3dec63..e075cd801 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -96,7 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
96 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), 96 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors),
97 ast::Visibility(it) => validate_visibility(it, &mut errors), 97 ast::Visibility(it) => validate_visibility(it, &mut errors),
98 ast::RangeExpr(it) => validate_range_expr(it, &mut errors), 98 ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
99 ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors), 99 ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
100 _ => (), 100 _ => (),
101 } 101 }
102 } 102 }
@@ -224,59 +224,82 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
224 } 224 }
225} 225}
226 226
227fn validate_crate_keyword_in_path_segment( 227fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxError>) {
228 segment: ast::PathSegment, 228 use ast::PathSegmentKind;
229 errors: &mut Vec<SyntaxError>,
230) {
231 const ERR_MSG: &str = "The `crate` keyword is only allowed as the first segment of a path";
232 229
233 let crate_token = match segment.crate_token() { 230 let path = segment.parent_path();
234 None => return, 231 let is_path_start = segment.coloncolon_token().is_none() && path.qualifier().is_none();
235 Some(it) => it, 232
236 }; 233 if let Some(token) = segment.self_token() {
234 if !is_path_start {
235 errors.push(SyntaxError::new(
236 "The `self` keyword is only allowed as the first segment of a path",
237 token.text_range(),
238 ));
239 }
240 } else if let Some(token) = segment.crate_token() {
241 if !is_path_start || use_prefix(path).is_some() {
242 errors.push(SyntaxError::new(
243 "The `crate` keyword is only allowed as the first segment of a path",
244 token.text_range(),
245 ));
246 }
247 } else if let Some(token) = segment.super_token() {
248 if !all_supers(&path) {
249 errors.push(SyntaxError::new(
250 "The `super` keyword may only be preceded by other `super`s",
251 token.text_range(),
252 ));
253 return;
254 }
237 255
238 // Disallow both ::crate and foo::crate 256 let mut curr_path = path;
239 let mut path = segment.parent_path(); 257 while let Some(prefix) = use_prefix(curr_path) {
240 if segment.coloncolon_token().is_some() || path.qualifier().is_some() { 258 if !all_supers(&prefix) {
241 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); 259 errors.push(SyntaxError::new(
242 return; 260 "The `super` keyword may only be preceded by other `super`s",
261 token.text_range(),
262 ));
263 return;
264 }
265 curr_path = prefix;
266 }
243 } 267 }
244 268
245 // For expressions and types, validation is complete, but we still have 269 fn use_prefix(mut path: ast::Path) -> Option<ast::Path> {
246 // to handle invalid UseItems like this: 270 for node in path.syntax().ancestors().skip(1) {
247 // 271 match_ast! {
248 // use foo:{crate::bar::baz}; 272 match node {
249 // 273 ast::UseTree(it) => if let Some(tree_path) = it.path() {
250 // To handle this we must inspect the parent `UseItem`s and `UseTree`s 274 // Even a top-level path exists within a `UseTree` so we must explicitly
251 // but right now we're looking deep inside the nested `Path` nodes because 275 // allow our path but disallow anything else
252 // `Path`s are left-associative: 276 if tree_path != path {
253 // 277 return Some(tree_path);
254 // ((crate)::bar)::baz) 278 }
255 // ^ current value of path 279 },
256 // 280 ast::UseTreeList(_it) => continue,
257 // So we need to climb to the top 281 ast::Path(parent) => path = parent,
258 while let Some(parent) = path.parent_path() { 282 _ => return None,
259 path = parent; 283 }
284 };
285 }
286 return None;
260 } 287 }
261 288
262 // Now that we've found the whole path we need to see if there's a prefix 289 fn all_supers(path: &ast::Path) -> bool {
263 // somewhere in the UseTree hierarchy. This check is arbitrarily deep 290 let segment = match path.segment() {
264 // because rust allows arbitrary nesting like so: 291 Some(it) => it,
265 // 292 None => return false,
266 // use {foo::{{{{crate::bar::baz}}}}};
267 for node in path.syntax().ancestors().skip(1) {
268 match_ast! {
269 match node {
270 ast::UseTree(it) => if let Some(tree_path) = it.path() {
271 // Even a top-level path exists within a `UseTree` so we must explicitly
272 // allow our path but disallow anything else
273 if tree_path != path {
274 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
275 }
276 },
277 ast::UseTreeList(_it) => continue,
278 _ => return,
279 }
280 }; 293 };
294
295 if segment.kind() != Some(PathSegmentKind::SuperKw) {
296 return false;
297 }
298
299 if let Some(ref subpath) = path.qualifier() {
300 return all_supers(subpath);
301 }
302
303 return true;
281 } 304 }
282} 305}