From d57b993adec18a4629b0a1669f2ee714984d8536 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov <aleksey.kladov@gmail.com> Date: Fri, 20 Sep 2019 16:53:05 +0300 Subject: fix infinite loop in the parser closes #1866 --- crates/ra_parser/src/grammar/items/use_item.rs | 18 +++++--- .../test_data/parser/err/0036_partial_use.rs | 2 + .../test_data/parser/err/0036_partial_use.txt | 51 ++++++++++++++++++++++ 3 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/err/0036_partial_use.rs create mode 100644 crates/ra_syntax/test_data/parser/err/0036_partial_use.txt diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs index 2af2ad315..63ac37e9e 100644 --- a/crates/ra_parser/src/grammar/items/use_item.rs +++ b/crates/ra_parser/src/grammar/items/use_item.rs @@ -3,7 +3,7 @@ use super::*; pub(super) fn use_item(p: &mut Parser, m: Marker) { assert!(p.at(T![use])); p.bump(T![use]); - use_tree(p); + use_tree(p, true); p.expect(T![;]); m.complete(p, USE_ITEM); } @@ -12,7 +12,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) { /// Note that this is called both by `use_item` and `use_tree_list`, /// so handles both `some::path::{inner::path}` and `inner::path` in /// `use some::path::{inner::path};` -fn use_tree(p: &mut Parser) { +fn use_tree(p: &mut Parser, top_level: bool) { let m = p.start(); match p.current() { // Finish the use_tree for cases of e.g. @@ -101,10 +101,14 @@ fn use_tree(p: &mut Parser) { } _ => { m.abandon(p); - p.err_recover( - "expected one of `*`, `::`, `{`, `self`, `super` or an identifier", - ITEM_RECOVERY_SET, - ); + let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier"; + if top_level { + p.err_recover(msg, ITEM_RECOVERY_SET); + } else { + // if we are parsing a nested tree, we have to eat a token to + // main balanced `{}` + p.err_and_bump(msg); + } return; } } @@ -116,7 +120,7 @@ pub(crate) fn use_tree_list(p: &mut Parser) { let m = p.start(); p.bump(T!['{']); while !p.at(EOF) && !p.at(T!['}']) { - use_tree(p); + use_tree(p, false); if !p.at(T!['}']) { p.expect(T![,]); } diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs new file mode 100644 index 000000000..d521a5bb2 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs @@ -0,0 +1,2 @@ +use std::{error::Error; +use std::io; diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt new file mode 100644 index 000000000..181f408c8 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt @@ -0,0 +1,51 @@ +SOURCE_FILE@[0; 37) + USE_ITEM@[0; 36) + USE_KW@[0; 3) "use" + WHITESPACE@[3; 4) " " + USE_TREE@[4; 36) + PATH@[4; 7) + PATH_SEGMENT@[4; 7) + NAME_REF@[4; 7) + IDENT@[4; 7) "std" + COLONCOLON@[7; 9) "::" + USE_TREE_LIST@[9; 36) + L_CURLY@[9; 10) "{" + USE_TREE@[10; 22) + PATH@[10; 22) + PATH@[10; 15) + PATH_SEGMENT@[10; 15) + NAME_REF@[10; 15) + IDENT@[10; 15) "error" + COLONCOLON@[15; 17) "::" + PATH_SEGMENT@[17; 22) + NAME_REF@[17; 22) + IDENT@[17; 22) "Error" + ERROR@[22; 23) + SEMI@[22; 23) ";" + WHITESPACE@[23; 24) "\n" + ERROR@[24; 27) + USE_KW@[24; 27) "use" + WHITESPACE@[27; 28) " " + USE_TREE@[28; 35) + PATH@[28; 35) + PATH@[28; 31) + PATH_SEGMENT@[28; 31) + NAME_REF@[28; 31) + IDENT@[28; 31) "std" + COLONCOLON@[31; 33) "::" + PATH_SEGMENT@[33; 35) + NAME_REF@[33; 35) + IDENT@[33; 35) "io" + ERROR@[35; 36) + SEMI@[35; 36) ";" + WHITESPACE@[36; 37) "\n" +error 22: expected COMMA +error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier +error 23: expected COMMA +error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier +error 27: expected COMMA +error 35: expected COMMA +error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier +error 36: expected COMMA +error 36: expected R_CURLY +error 36: expected SEMI -- cgit v1.2.3