Repository: rust-analyzer/rust-analyzer
Pull request #1673 (2019-08-09 10:17:30)

Move numeric names inside of `NameRef`


Patch:
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 2ee121ccd0..beedac4572 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -273,8 +273,8 @@ fn name(p: &mut Parser) {
     name_r(p, TokenSet::empty())
 }
 
-fn name_ref(p: &mut Parser, allow_numeric_names: bool) {
-    if p.at(IDENT) || (allow_numeric_names && p.at(INT_NUMBER)) {
+fn name_ref(p: &mut Parser) {
+    if p.at(IDENT) {
         let m = p.start();
         p.bump();
         m.complete(p, NAME_REF);
@@ -287,6 +287,16 @@ fn name_ref(p: &mut Parser, allow_numeric_names: bool) {
     }
 }
 
+fn name_ref_or_index(p: &mut Parser) {
+    if p.at(IDENT) || p.at(INT_NUMBER) {
+        let m = p.start();
+        p.bump();
+        m.complete(p, NAME_REF);
+    } else {
+        p.err_and_bump("expected identifier");
+    }
+}
+
 fn error_block(p: &mut Parser, message: &str) {
     assert!(p.at(T!['{']));
     let m = p.start();
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 9f9e9cb0ee..9fd3a235d1 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -458,7 +458,7 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
     assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::]));
     let m = lhs.precede(p);
     p.bump();
-    name_ref(p, false);
+    name_ref(p);
     type_args::opt_type_arg_list(p, true);
     if p.at(T!['(']) {
         arg_list(p);
@@ -484,10 +484,8 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
     assert!(p.at(T![.]));
     let m = lhs.precede(p);
     p.bump();
-    if p.at(IDENT) {
-        name_ref(p, false)
-    } else if p.at(INT_NUMBER) {
-        p.bump();
+    if p.at(IDENT) || p.at(INT_NUMBER) {
+        name_ref_or_index(p)
     } else if p.at(FLOAT_NUMBER) {
         // FIXME: How to recover and instead parse INT + T![.]?
         p.bump();
@@ -587,7 +585,7 @@ pub(crate) fn named_field_list(p: &mut Parser) {
             IDENT | INT_NUMBER | T![#] => {
                 let m = p.start();
                 attributes::outer_attributes(p);
-                name_ref(p, true);
+                name_ref_or_index(p);
                 if p.eat(T![:]) {
                     expr(p);
                 }
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index b0081f3960..543af7c4bb 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -279,7 +279,7 @@ fn extern_crate_item(p: &mut Parser, m: Marker) {
     p.bump();
     assert!(p.at(T![crate]));
     p.bump();
-    name_ref(p, false);
+    name_ref(p);
     opt_alias(p);
     p.expect(T![;]);
     m.complete(p, EXTERN_CRATE_ITEM);
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
index 2c8f0f7e82..3537b0da11 100644
--- a/crates/ra_parser/src/grammar/paths.rs
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -71,7 +71,7 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
         }
         match p.current() {
             IDENT => {
-                name_ref(p, false);
+                name_ref(p);
                 opt_path_type_args(p, mode);
             }
             // test crate_path
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index f1d999dead..3db08b280d 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -38,12 +38,12 @@ fn type_arg(p: &mut Parser) {
         // test associated_type_bounds
         // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
         IDENT if p.nth(1) == T![:] => {
-            name_ref(p, false);
+            name_ref(p);
             type_params::bounds(p);
             m.complete(p, ASSOC_TYPE_ARG);
         }
         IDENT if p.nth(1) == T![=] => {
-            name_ref(p, false);
+            name_ref(p);
             p.bump();
             types::type_(p);
             m.complete(p, ASSOC_TYPE_ARG);
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 1f904434e8..2bb3c0a03e 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -1,13 +1,12 @@
 mod block;
-mod field_expr;
 
 use ra_rustc_lexer::unescape;
 
 use crate::{
     algo::visit::{visitor_ctx, VisitorCtx},
-    ast, SyntaxError, SyntaxErrorKind,
-    SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING},
-    SyntaxNode, TextUnit, T,
+    ast, AstNode, SyntaxError, SyntaxErrorKind,
+    SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING},
+    SyntaxNode, SyntaxToken, TextUnit, T,
 };
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -101,7 +100,8 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
         let _ = visitor_ctx(&mut errors)
             .visit::<ast::Literal, _>(validate_literal)
             .visit::<ast::Block, _>(block::validate_block_node)
-            .visit::<ast::FieldExpr, _>(field_expr::validate_field_expr_node)
+            .visit::<ast::FieldExpr, _>(|it, errors| validate_numeric_name(it.name_ref(), errors))
+            .visit::<ast::NamedField, _>(|it, errors| validate_numeric_name(it.name_ref(), errors))
             .accept(&node);
     }
     errors
@@ -189,3 +189,18 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) {
         }
     }
 }
+
+fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<SyntaxError>) {
+    if let Some(int_token) = int_token(name_ref) {
+        if int_token.text().chars().any(|c| !c.is_digit(10)) {
+            errors.push(SyntaxError::new(
+                SyntaxErrorKind::InvalidTupleIndexFormat,
+                int_token.text_range(),
+            ));
+        }
+    }
+
+    fn int_token(name_ref: Option<ast::NameRef>) -> Option<SyntaxToken> {
+        name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER)
+    }
+}
diff --git a/crates/ra_syntax/src/validation/field_expr.rs b/crates/ra_syntax/src/validation/field_expr.rs
deleted file mode 100644
index 004f199fd5..0000000000
--- a/crates/ra_syntax/src/validation/field_expr.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use crate::{
-    ast::{self, FieldKind},
-    SyntaxError,
-    SyntaxErrorKind::*,
-};
-
-pub(crate) fn validate_field_expr_node(node: ast::FieldExpr, errors: &mut Vec<SyntaxError>) {
-    if let Some(FieldKind::Index(idx)) = node.field_access() {
-        if idx.text().chars().any(|c| c < '0' || c > '9') {
-            errors.push(SyntaxError::new(InvalidTupleIndexFormat, idx.text_range()));
-        }
-    }
-}


Test patch:
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt
index a21b29c80a..465e79e7b2 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt
@@ -30,7 +30,8 @@ SOURCE_FILE@[0; 47)
                 NAME_REF@[25; 26)
                   IDENT@[25; 26) "x"
           DOT@[26; 27) "."
-          INT_NUMBER@[27; 31) "1i32"
+          NAME_REF@[27; 31)
+            INT_NUMBER@[27; 31) "1i32"
         SEMI@[31; 32) ";"
       WHITESPACE@[32; 37) "\n    "
       EXPR_STMT@[37; 44)
@@ -41,11 +42,11 @@ SOURCE_FILE@[0; 47)
                 NAME_REF@[37; 38)
                   IDENT@[37; 38) "x"
           DOT@[38; 39) "."
-          INT_NUMBER@[39; 43) "0x01"
+          NAME_REF@[39; 43)
+            INT_NUMBER@[39; 43) "0x01"
         SEMI@[43; 44) ";"
       WHITESPACE@[44; 45) "\n"
       R_CURLY@[45; 46) "}"
   WHITESPACE@[46; 47) "\n"
-error [17; 19): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix
 error [27; 31): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix
 error [39; 43): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt
index 78054ec5a2..1d2cf27615 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt
@@ -32,7 +32,8 @@ SOURCE_FILE@[0; 48)
                   NAME_REF@[26; 27)
                     IDENT@[26; 27) "x"
             DOT@[27; 28) "."
-            INT_NUMBER@[28; 29) "0"
+            NAME_REF@[28; 29)
+              INT_NUMBER@[28; 29) "0"
           DOT@[29; 30) "."
           NAME_REF@[30; 33)
             IDENT@[30; 33) "bar"
@@ -47,7 +48,8 @@ SOURCE_FILE@[0; 48)
                   NAME_REF@[39; 40)
                     IDENT@[39; 40) "x"
             DOT@[40; 41) "."
-            INT_NUMBER@[41; 42) "0"
+            NAME_REF@[41; 42)
+              INT_NUMBER@[41; 42) "0"
           ARG_LIST@[42; 44)
             L_PAREN@[42; 43) "("
             R_PAREN@[43; 44) ")"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt
index 99bd76ace3..7adb662de7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt
@@ -31,7 +31,8 @@ SOURCE_FILE@[0; 67)
                   NAME_REF@[28; 29)
                     IDENT@[28; 29) "x"
             DOT@[29; 30) "."
-            INT_NUMBER@[30; 31) "0"
+            NAME_REF@[30; 31)
+              INT_NUMBER@[30; 31) "0"
           DOT@[31; 32) "."
           AWAIT_KW@[32; 37) "await"
         SEMI@[37; 38) ";"
@@ -48,7 +49,8 @@ SOURCE_FILE@[0; 67)
                         NAME_REF@[43; 44)
                           IDENT@[43; 44) "x"
                   DOT@[44; 45) "."
-                  INT_NUMBER@[45; 46) "0"
+                  NAME_REF@[45; 46)
+                    INT_NUMBER@[45; 46) "0"
                 ARG_LIST@[46; 48)
                   L_PAREN@[46; 47) "("
                   R_PAREN@[47; 48) ")"