aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/validation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/validation.rs')
-rw-r--r--crates/ra_syntax/src/validation.rs155
1 files changed, 71 insertions, 84 deletions
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 8a5f0e4b7..863859dca 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -5,92 +5,76 @@ mod block;
5use rustc_lexer::unescape; 5use rustc_lexer::unescape;
6 6
7use crate::{ 7use crate::{
8 ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, 8 ast, match_ast, AstNode, SyntaxError,
9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, 9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF},
10 SyntaxNode, SyntaxToken, TextUnit, T, 10 SyntaxNode, SyntaxToken, TextUnit, T,
11}; 11};
12 12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 13fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str {
14pub enum EscapeError { 14 use unescape::EscapeError as EE;
15 ZeroChars,
16 MoreThanOneChar,
17 LoneSlash,
18 InvalidEscape,
19 BareCarriageReturn,
20 EscapeOnlyChar,
21 TooShortHexEscape,
22 InvalidCharInHexEscape,
23 OutOfRangeHexEscape,
24 NoBraceInUnicodeEscape,
25 InvalidCharInUnicodeEscape,
26 EmptyUnicodeEscape,
27 UnclosedUnicodeEscape,
28 LeadingUnderscoreUnicodeEscape,
29 OverlongUnicodeEscape,
30 LoneSurrogateUnicodeEscape,
31 OutOfRangeUnicodeEscape,
32 UnicodeEscapeInByte,
33 NonAsciiCharInByte,
34}
35 15
36impl From<rustc_lexer::unescape::EscapeError> for EscapeError { 16 #[rustfmt::skip]
37 fn from(err: rustc_lexer::unescape::EscapeError) -> Self { 17 let err_message = match err {
38 match err { 18 EE::ZeroChars => {
39 rustc_lexer::unescape::EscapeError::ZeroChars => EscapeError::ZeroChars, 19 "Literal must not be empty"
40 rustc_lexer::unescape::EscapeError::MoreThanOneChar => EscapeError::MoreThanOneChar,
41 rustc_lexer::unescape::EscapeError::LoneSlash => EscapeError::LoneSlash,
42 rustc_lexer::unescape::EscapeError::InvalidEscape => EscapeError::InvalidEscape,
43 rustc_lexer::unescape::EscapeError::BareCarriageReturn
44 | rustc_lexer::unescape::EscapeError::BareCarriageReturnInRawString => {
45 EscapeError::BareCarriageReturn
46 }
47 rustc_lexer::unescape::EscapeError::EscapeOnlyChar => EscapeError::EscapeOnlyChar,
48 rustc_lexer::unescape::EscapeError::TooShortHexEscape => EscapeError::TooShortHexEscape,
49 rustc_lexer::unescape::EscapeError::InvalidCharInHexEscape => {
50 EscapeError::InvalidCharInHexEscape
51 }
52 rustc_lexer::unescape::EscapeError::OutOfRangeHexEscape => {
53 EscapeError::OutOfRangeHexEscape
54 }
55 rustc_lexer::unescape::EscapeError::NoBraceInUnicodeEscape => {
56 EscapeError::NoBraceInUnicodeEscape
57 }
58 rustc_lexer::unescape::EscapeError::InvalidCharInUnicodeEscape => {
59 EscapeError::InvalidCharInUnicodeEscape
60 }
61 rustc_lexer::unescape::EscapeError::EmptyUnicodeEscape => {
62 EscapeError::EmptyUnicodeEscape
63 }
64 rustc_lexer::unescape::EscapeError::UnclosedUnicodeEscape => {
65 EscapeError::UnclosedUnicodeEscape
66 }
67 rustc_lexer::unescape::EscapeError::LeadingUnderscoreUnicodeEscape => {
68 EscapeError::LeadingUnderscoreUnicodeEscape
69 }
70 rustc_lexer::unescape::EscapeError::OverlongUnicodeEscape => {
71 EscapeError::OverlongUnicodeEscape
72 }
73 rustc_lexer::unescape::EscapeError::LoneSurrogateUnicodeEscape => {
74 EscapeError::LoneSurrogateUnicodeEscape
75 }
76 rustc_lexer::unescape::EscapeError::OutOfRangeUnicodeEscape => {
77 EscapeError::OutOfRangeUnicodeEscape
78 }
79 rustc_lexer::unescape::EscapeError::UnicodeEscapeInByte => {
80 EscapeError::UnicodeEscapeInByte
81 }
82 rustc_lexer::unescape::EscapeError::NonAsciiCharInByte
83 | rustc_lexer::unescape::EscapeError::NonAsciiCharInByteString => {
84 EscapeError::NonAsciiCharInByte
85 }
86 } 20 }
87 } 21 EE::MoreThanOneChar => {
88} 22 "Literal must be one character long"
23 }
24 EE::LoneSlash => {
25 "Character must be escaped: `\\`"
26 }
27 EE::InvalidEscape => {
28 "Invalid escape"
29 }
30 EE::BareCarriageReturn | EE::BareCarriageReturnInRawString => {
31 "Character must be escaped: `\r`"
32 }
33 EE::EscapeOnlyChar => {
34 "Escape character `\\` must be escaped itself"
35 }
36 EE::TooShortHexEscape => {
37 "ASCII hex escape code must have exactly two digits"
38 }
39 EE::InvalidCharInHexEscape => {
40 "ASCII hex escape code must contain only hex characters"
41 }
42 EE::OutOfRangeHexEscape => {
43 "ASCII hex escape code must be at most 0x7F"
44 }
45 EE::NoBraceInUnicodeEscape => {
46 "Missing `{` to begin the unicode escape"
47 }
48 EE::InvalidCharInUnicodeEscape => {
49 "Unicode escape must contain only hex characters and underscores"
50 }
51 EE::EmptyUnicodeEscape => {
52 "Unicode escape must not be empty"
53 }
54 EE::UnclosedUnicodeEscape => {
55 "Missing '}' to terminate the unicode escape"
56 }
57 EE::LeadingUnderscoreUnicodeEscape => {
58 "Unicode escape code must not begin with an underscore"
59 }
60 EE::OverlongUnicodeEscape => {
61 "Unicode escape code must have at most 6 digits"
62 }
63 EE::LoneSurrogateUnicodeEscape => {
64 "Unicode escape code must not be a surrogate"
65 }
66 EE::OutOfRangeUnicodeEscape => {
67 "Unicode escape code must be at most 0x10FFFF"
68 }
69 EE::UnicodeEscapeInByte => {
70 "Byte literals must not contain unicode escapes"
71 }
72 EE::NonAsciiCharInByte | EE::NonAsciiCharInByteString => {
73 "Byte literals must not contain non-ASCII characters"
74 }
75 };
89 76
90impl From<rustc_lexer::unescape::EscapeError> for SyntaxErrorKind { 77 err_message
91 fn from(err: rustc_lexer::unescape::EscapeError) -> Self {
92 SyntaxErrorKind::EscapeError(err.into())
93 }
94} 78}
95 79
96pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { 80pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
@@ -118,6 +102,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
118} 102}
119 103
120fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { 104fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
105 // FIXME: move this function to outer scope (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366196658)
121 fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> { 106 fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> {
122 text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end)) 107 text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end))
123 } 108 }
@@ -125,9 +110,10 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
125 let token = literal.token(); 110 let token = literal.token();
126 let text = token.text().as_str(); 111 let text = token.text().as_str();
127 112
113 // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205)
128 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { 114 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| {
129 let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len); 115 let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len);
130 acc.push(SyntaxError::new(err.into(), off)); 116 acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
131 }; 117 };
132 118
133 match token.kind() { 119 match token.kind() {
@@ -195,7 +181,8 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax
195 if let Some(int_token) = int_token(name_ref) { 181 if let Some(int_token) = int_token(name_ref) {
196 if int_token.text().chars().any(|c| !c.is_digit(10)) { 182 if int_token.text().chars().any(|c| !c.is_digit(10)) {
197 errors.push(SyntaxError::new( 183 errors.push(SyntaxError::new(
198 SyntaxErrorKind::InvalidTupleIndexFormat, 184 "Tuple (struct) field access is only allowed through \
185 decimal integers with no underscores or suffix",
199 int_token.text_range(), 186 int_token.text_range(),
200 )); 187 ));
201 } 188 }
@@ -215,21 +202,21 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
215 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (), 202 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (),
216 _ => return, 203 _ => return,
217 } 204 }
205
218 let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast) 206 let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast)
219 { 207 {
220 Some(it) => it, 208 Some(it) => it,
221 None => return, 209 None => return,
222 }; 210 };
223 if impl_block.target_trait().is_some() { 211 if impl_block.target_trait().is_some() {
224 errors 212 errors.push(SyntaxError::new("Unnecessary visibility qualifier", vis.syntax.text_range()));
225 .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range()))
226 } 213 }
227} 214}
228 215
229fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { 216fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
230 if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() { 217 if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() {
231 errors.push(SyntaxError::new( 218 errors.push(SyntaxError::new(
232 SyntaxErrorKind::InclusiveRangeMissingEnd, 219 "An inclusive range must have an end expression",
233 expr.syntax().text_range(), 220 expr.syntax().text_range(),
234 )); 221 ));
235 } 222 }