Repository: rust-analyzer/rust-analyzer
Pull request #5587 (2020-07-30 12:18:25)

Finish use grammar
bors r+
🤖


Patch:
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index 947be3b9b4..01e7b7a44c 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -92,7 +92,7 @@ impl AutoImportAssets {
 
     fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> {
         let syntax_under_caret = path_under_caret.syntax().to_owned();
-        if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() {
+        if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() {
             return None;
         }
 
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index 1beccb61c0..c775fe25c5 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -28,7 +28,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
     let mut rewriter = SyntaxRewriter::default();
     let mut offset = ctx.offset();
 
-    if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) {
+    if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) {
         let (merged, to_delete) = next_prev()
             .filter_map(|dir| neighbor(&use_item, dir))
             .filter_map(|it| Some((it.clone(), it.use_tree()?)))
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index 3d51faa543..53496ede15 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -25,7 +25,7 @@ pub(crate) fn replace_qualified_name_with_use(
 ) -> Option<()> {
     let path: ast::Path = ctx.find_node_at_offset()?;
     // We don't want to mess with use statements
-    if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
+    if path.syntax().ancestors().find_map(ast::Use::cast).is_some() {
         return None;
     }
 
@@ -85,7 +85,7 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
             match child {
                 // Don't modify `use` items, as this can break the `use` item when injecting a new
                 // import into the use tree.
-                ast::UseItem(_it) => continue,
+                ast::Use(_it) => continue,
                 // Don't descend into submodules, they don't have the same `use` items in scope.
                 ast::Module(_it) => continue,
 
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs
index c05027eff1..617afe2e94 100644
--- a/crates/ra_assists/src/utils/insert_use.rs
+++ b/crates/ra_assists/src/utils/insert_use.rs
@@ -225,7 +225,7 @@ fn walk_use_tree_for_best_action(
                 current_use_tree
                     .syntax()
                     .ancestors()
-                    .find_map(ast::UseItem::cast)
+                    .find_map(ast::Use::cast)
                     .map(|it| it.syntax().clone()),
                 true,
             );
@@ -254,7 +254,7 @@ fn walk_use_tree_for_best_action(
             current_use_tree
                 .syntax()
                 .ancestors()
-                .find_map(ast::UseItem::cast)
+                .find_map(ast::Use::cast)
                 .map(|it| it.syntax().clone()),
             true,
         ),
@@ -304,7 +304,7 @@ fn walk_use_tree_for_best_action(
                 current_use_tree
                     .syntax()
                     .ancestors()
-                    .find_map(ast::UseItem::cast)
+                    .find_map(ast::Use::cast)
                     .map(|it| it.syntax().clone()),
                 true,
             );
@@ -377,7 +377,7 @@ fn best_action_for_target(
     let mut storage = Vec::with_capacity(16); // this should be the only allocation
     let best_action = container
         .children()
-        .filter_map(ast::UseItem::cast)
+        .filter_map(ast::Use::cast)
         .filter_map(|it| it.use_tree())
         .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target))
         .fold(None, |best, a| match best {
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index bfd574c5dc..5c57d8bde3 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -670,7 +670,7 @@ impl ExprCollector<'_> {
                     }
                     ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
                     ast::Item::ImplDef(_)
-                    | ast::Item::UseItem(_)
+                    | ast::Item::Use(_)
                     | ast::Item::ExternCrate(_)
                     | ast::Item::Module(_)
                     | ast::Item::MacroCall(_) => return None,
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index 4db7b2793f..0bab9c6d8b 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -411,7 +411,7 @@ macro_rules! mod_items {
 }
 
 mod_items! {
-    Import in imports -> ast::UseItem,
+    Import in imports -> ast::Use,
     ExternCrate in extern_crates -> ast::ExternCrate,
     Function in functions -> ast::FnDef,
     Struct in structs -> ast::StructDef,
@@ -482,7 +482,7 @@ pub struct Import {
     pub is_prelude: bool,
     /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
     /// `Import`s can map to the same `use` item.
-    pub ast_id: FileAstId<ast::UseItem>,
+    pub ast_id: FileAstId<ast::Use>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 8a36de3118..8bd0362dce 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -95,7 +95,7 @@ impl Ctx {
             ast::Item::TraitDef(_) | ast::Item::ImplDef(_) | ast::Item::ExternBlock(_) => {}
 
             // These don't have inner items.
-            ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::UseItem(_) => {}
+            ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
         };
 
         let attrs = Attrs::new(item, &self.hygiene);
@@ -110,7 +110,7 @@ impl Ctx {
             ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
             ast::Item::TraitDef(ast) => self.lower_trait(ast).map(Into::into),
             ast::Item::ImplDef(ast) => self.lower_impl(ast).map(Into::into),
-            ast::Item::UseItem(ast) => Some(ModItems(
+            ast::Item::Use(ast) => Some(ModItems(
                 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
             )),
             ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
@@ -469,7 +469,7 @@ impl Ctx {
         Some(id(self.data().impls.alloc(res)))
     }
 
-    fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
+    fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
         // FIXME: cfg_attr
         let is_prelude = use_item.has_atom_attr("prelude_import");
         let visibility = self.lower_visibility(use_item);
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 190d6d98d4..68b9f89c37 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -67,7 +67,7 @@ impl ModPath {
 
     /// Calls `cb` with all paths, represented by this use item.
     pub(crate) fn expand_use_item(
-        item_src: InFile<ast::UseItem>,
+        item_src: InFile<ast::Use>,
         hygiene: &Hygiene,
         mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
     ) {
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index c84d43d773..cc55f6dd6b 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -36,7 +36,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) expected_type: Option<Type>,
     pub(super) name_ref_syntax: Option<ast::NameRef>,
     pub(super) function_syntax: Option<ast::FnDef>,
-    pub(super) use_item_syntax: Option<ast::UseItem>,
+    pub(super) use_item_syntax: Option<ast::Use>,
     pub(super) record_lit_syntax: Option<ast::RecordLit>,
     pub(super) record_pat_syntax: Option<ast::RecordPat>,
     pub(super) record_field_syntax: Option<ast::RecordField>,
@@ -343,7 +343,7 @@ impl<'a> CompletionContext<'a> {
         }
 
         self.use_item_syntax =
-            self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);
+            self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::Use::cast);
 
         self.function_syntax = self
             .sema
diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs
index 315808890b..bad0791463 100644
--- a/crates/ra_ide/src/folding_ranges.rs
+++ b/crates/ra_ide/src/folding_ranges.rs
@@ -58,7 +58,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
             }
             NodeOrToken::Node(node) => {
                 // Fold groups of imports
-                if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
+                if node.kind() == USE && !visited_imports.contains(&node) {
                     if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                         res.push(Fold { range, kind: FoldKind::Imports })
                     }
@@ -83,7 +83,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
 fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
-        USE_ITEM => Some(FoldKind::Imports),
+        USE => Some(FoldKind::Imports),
         ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
         RECORD_FIELD_DEF_LIST
         | RECORD_FIELD_PAT_LIST
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index 3a0c7a31a8..8e836a77e1 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -7,7 +7,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) {
     p.bump(T![use]);
     use_tree(p, true);
     p.expect(T![;]);
-    m.complete(p, USE_ITEM);
+    m.complete(p, USE);
 }
 
 /// Parse a use 'tree', such as `some::path` in `use some::path;`
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index 116b58858f..4f35e0baa5 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -130,7 +130,7 @@ pub enum SyntaxKind {
     RET_TYPE,
     EXTERN_CRATE,
     MODULE,
-    USE_ITEM,
+    USE,
     STATIC_DEF,
     CONST_DEF,
     TRAIT_DEF,
diff --git a/crates/ra_ssr/src/replacing.rs b/crates/ra_ssr/src/replacing.rs
index 0943244ff9..4b3f5509c3 100644
--- a/crates/ra_ssr/src/replacing.rs
+++ b/crates/ra_ssr/src/replacing.rs
@@ -3,9 +3,8 @@
 use crate::matching::Var;
 use crate::{resolving::ResolvedRule, Match, SsrMatches};
 use ra_syntax::ast::{self, AstToken};
-use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize};
+use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextSize};
 use ra_text_edit::TextEdit;
-use rustc_hash::{FxHashMap, FxHashSet};
 
 /// Returns a text edit that will replace each match in `matches` with its corresponding replacement
 /// template. Placeholders in the template will have been substituted with whatever they matched to
@@ -39,79 +38,62 @@ struct ReplacementRenderer<'a> {
     file_src: &'a str,
     rules: &'a [ResolvedRule],
     rule: &'a ResolvedRule,
-    out: String,
-    // Map from a range within `out` to a token in `template` that represents a placeholder. This is
-    // used to validate that the generated source code doesn't split any placeholder expansions (see
-    // below).
-    placeholder_tokens_by_range: FxHashMap<TextRange, SyntaxToken>,
-    // Which placeholder tokens need to be wrapped in parenthesis in order to ensure that when `out`
-    // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1
-    // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis.
-    placeholder_tokens_requiring_parenthesis: FxHashSet<SyntaxToken>,
 }
 
 fn render_replace(match_info: &Match, file_src: &str, rules: &[ResolvedRule]) -> String {
+    let mut out = String::new();
     let rule = &rules[match_info.rule_index];
     let template = rule
         .template
         .as_ref()
         .expect("You called MatchFinder::edits after calling MatchFinder::add_search_pattern");
-    let mut renderer = ReplacementRenderer {
-        match_info,
-        file_src,
-        rules,
-        rule,
-        out: String::new(),
-        placeholder_tokens_requiring_parenthesis: FxHashSet::default(),
-        placeholder_tokens_by_range: FxHashMap::default(),
-    };
-    renderer.render_node(&template.node);
-    renderer.maybe_rerender_with_extra_parenthesis(&template.node);
+    let renderer = ReplacementRenderer { match_info, file_src, rules, rule };
+    renderer.render_node(&template.node, &mut out);
     for comment in &match_info.ignored_comments {
-        renderer.out.push_str(&comment.syntax().to_string());
+        out.push_str(&comment.syntax().to_string());
     }
-    renderer.out
+    out
 }
 
 impl ReplacementRenderer<'_> {
-    fn render_node_children(&mut self, node: &SyntaxNode) {
+    fn render_node_children(&self, node: &SyntaxNode, out: &mut String) {
         for node_or_token in node.children_with_tokens() {
-            self.render_node_or_token(&node_or_token);
+            self.render_node_or_token(&node_or_token, out);
         }
     }
 
-    fn render_node_or_token(&mut self, node_or_token: &SyntaxElement) {
+    fn render_node_or_token(&self, node_or_token: &SyntaxElement, out: &mut String) {
         match node_or_token {
             SyntaxElement::Token(token) => {
-                self.render_token(&token);
+                self.render_token(&token, out);
             }
             SyntaxElement::Node(child_node) => {
-                self.render_node(&child_node);
+                self.render_node(&child_node, out);
             }
         }
     }
 
-    fn render_node(&mut self, node: &SyntaxNode) {
+    fn render_node(&self, node: &SyntaxNode, out: &mut String) {
         use ra_syntax::ast::AstNode;
         if let Some(mod_path) = self.match_info.rendered_template_paths.get(&node) {
-            self.out.push_str(&mod_path.to_string());
+            out.push_str(&mod_path.to_string());
             // Emit everything except for the segment's name-ref, since we already effectively
             // emitted that as part of `mod_path`.
             if let Some(path) = ast::Path::cast(node.clone()) {
                 if let Some(segment) = path.segment() {
                     for node_or_token in segment.syntax().children_with_tokens() {
                         if node_or_token.kind() != SyntaxKind::NAME_REF {
-                            self.render_node_or_token(&node_or_token);
+                            self.render_node_or_token(&node_or_token, out);
                         }
                     }
                 }
             }
         } else {
-            self.render_node_children(&node);
+            self.render_node_children(&node, out);
         }
     }
 
-    fn render_token(&mut self, token: &SyntaxToken) {
+    fn render_token(&self, token: &SyntaxToken, out: &mut String) {
         if let Some(placeholder) = self.rule.get_placeholder(&token) {
             if let Some(placeholder_value) =
                 self.match_info.placeholder_values.get(&Var(placeholder.ident.to_string()))
@@ -125,23 +107,8 @@ impl ReplacementRenderer<'_> {
                     range.start(),
                     self.rules,
                 );
-                let needs_parenthesis =
-                    self.placeholder_tokens_requiring_parenthesis.contains(token);
                 edit.apply(&mut matched_text);
-                if needs_parenthesis {
-                    self.out.push('(');
-                }
-                self.placeholder_tokens_by_range.insert(
-                    TextRange::new(
-                        TextSize::of(&self.out),
-                        TextSize::of(&self.out) + TextSize::of(&matched_text),
-                    ),
-                    token.clone(),
-                );
-                self.out.push_str(&matched_text);
-                if needs_parenthesis {
-                    self.out.push(')');
-                }
+                out.push_str(&matched_text);
             } else {
                 // We validated that all placeholder references were valid before we
                 // started, so this shouldn't happen.
@@ -151,44 +118,7 @@ impl ReplacementRenderer<'_> {
                 );
             }
         } else {
-            self.out.push_str(token.text().as_str());
-        }
-    }
-
-    // Checks if the resulting code, when parsed doesn't split any placeholders due to different
-    // order of operations between the search pattern and the replacement template. If any do, then
-    // we rerender the template and wrap the problematic placeholders with parenthesis.
-    fn maybe_rerender_with_extra_parenthesis(&mut self, template: &SyntaxNode) {
-        if let Some(node) = parse_as_kind(&self.out, template.kind()) {
-            self.remove_node_ranges(node);
-            if self.placeholder_tokens_by_range.is_empty() {
-                return;
-            }
-            self.placeholder_tokens_requiring_parenthesis =
-                self.placeholder_tokens_by_range.values().cloned().collect();
-            self.out.clear();
-            self.render_node(template);
-        }
-    }
-
-    fn remove_node_ranges(&mut self, node: SyntaxNode) {
-        self.placeholder_tokens_by_range.remove(&node.text_range());
-        for child in node.children() {
-            self.remove_node_ranges(child);
-        }
-    }
-}
-
-fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option<SyntaxNode> {
-    use ra_syntax::ast::AstNode;
-    if ast::Expr::can_cast(kind) {
-        if let Ok(expr) = ast::Expr::parse(code) {
-            return Some(expr.syntax().clone());
-        }
-    } else if ast::Item::can_cast(kind) {
-        if let Ok(item) = ast::Item::parse(code) {
-            return Some(item.syntax().clone());
+            out.push_str(token.text().as_str());
         }
     }
-    None
 }
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs
index 0f512cb62d..213dc494ff 100644
--- a/crates/ra_ssr/src/search.rs
+++ b/crates/ra_ssr/src/search.rs
@@ -237,7 +237,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool {
     // and the code is `use foo::{baz, bar}`, we'll match `bar`, since it resolves to `foo::bar`.
     // However we'll then replace just the part we matched `bar`. We probably need to instead remove
     // `bar` and insert a new use declaration.
-    node.kind() != SyntaxKind::USE_ITEM
+    node.kind() != SyntaxKind::USE
 }
 
 impl UsageCache {
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 2e958fa231..6ebe10ff65 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -262,9 +262,9 @@ impl ast::PathSegment {
     }
 }
 
-impl ast::UseItem {
+impl ast::Use {
     #[must_use]
-    pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem {
+    pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::Use {
         if let Some(old) = self.use_tree() {
             return self.replace_descendant(old, use_tree);
         }
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 3fd7613678..be657699ff 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -213,12 +213,12 @@ impl UnionDef {
     }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UseItem {
+pub struct Use {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::AttrsOwner for UseItem {}
-impl ast::VisibilityOwner for UseItem {}
-impl UseItem {
+impl ast::AttrsOwner for Use {}
+impl ast::VisibilityOwner for Use {}
+impl Use {
     pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
     pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
     pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
@@ -268,6 +268,36 @@ pub struct Rename {
 impl ast::NameOwner for Rename {}
 impl Rename {
     pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
+    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UseTree {
+    pub(crate) syntax: SyntaxNode,
+}
+impl UseTree {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
+    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
+    pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
+    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Path {
+    pub(crate) syntax: SyntaxNode,
+}
+impl Path {
+    pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
+    pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UseTreeList {
+    pub(crate) syntax: SyntaxNode,
+}
+impl UseTreeList {
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Abi {
@@ -433,15 +463,6 @@ impl PathType {
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Path {
-    pub(crate) syntax: SyntaxNode,
-}
-impl Path {
-    pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct PointerType {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1178,26 +1199,6 @@ impl Param {
     pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UseTree {
-    pub(crate) syntax: SyntaxNode,
-}
-impl UseTree {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
-    pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
-    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UseTreeList {
-    pub(crate) syntax: SyntaxNode,
-}
-impl UseTreeList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct PathSegment {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1282,7 +1283,7 @@ pub enum Item {
     TraitDef(TraitDef),
     TypeAliasDef(TypeAliasDef),
     UnionDef(UnionDef),
-    UseItem(UseItem),
+    Use(Use),
 }
 impl ast::AttrsOwner for Item {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1561,8 +1562,8 @@ impl AstNode for UnionDef {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for UseItem {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_ITEM }
+impl AstNode for Use {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1627,6 +1628,39 @@ impl AstNode for Rename {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for UseTree {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Path {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for UseTreeList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for Abi {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -1825,17 +1859,6 @@ impl AstNode for PathType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Path {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
 impl AstNode for PointerType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == POINTER_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2672,28 +2695,6 @@ impl AstNode for Param {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for UseTree {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
-impl AstNode for UseTreeList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
 impl AstNode for PathSegment {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2810,15 +2811,16 @@ impl From<TypeAliasDef> for Item {
 impl From<UnionDef> for Item {
     fn from(node: UnionDef) -> Item { Item::UnionDef(node) }
 }
-impl From<UseItem> for Item {
-    fn from(node: UseItem) -> Item { Item::UseItem(node) }
+impl From<Use> for Item {
+    fn from(node: Use) -> Item { Item::Use(node) }
 }
 impl AstNode for Item {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             CONST_DEF | ENUM_DEF | EXTERN_BLOCK | EXTERN_CRATE | FN_DEF | IMPL_DEF | MACRO_CALL
-            | MODULE | STATIC_DEF | STRUCT_DEF | TRAIT_DEF | TYPE_ALIAS_DEF | UNION_DEF
-            | USE_ITEM => true,
+            | MODULE | STATIC_DEF | STRUCT_DEF | TRAIT_DEF | TYPE_ALIAS_DEF | UNION_DEF | USE => {
+                true
+            }
             _ => false,
         }
     }
@@ -2837,7 +2839,7 @@ impl AstNode for Item {
             TRAIT_DEF => Item::TraitDef(TraitDef { syntax }),
             TYPE_ALIAS_DEF => Item::TypeAliasDef(TypeAliasDef { syntax }),
             UNION_DEF => Item::UnionDef(UnionDef { syntax }),
-            USE_ITEM => Item::UseItem(UseItem { syntax }),
+            USE => Item::Use(Use { syntax }),
             _ => return None,
         };
         Some(res)
@@ -2857,7 +2859,7 @@ impl AstNode for Item {
             Item::TraitDef(it) => &it.syntax,
             Item::TypeAliasDef(it) => &it.syntax,
             Item::UnionDef(it) => &it.syntax,
-            Item::UseItem(it) => &it.syntax,
+            Item::Use(it) => &it.syntax,
         }
     }
 }
@@ -3530,7 +3532,7 @@ impl std::fmt::Display for UnionDef {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for UseItem {
+impl std::fmt::Display for Use {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -3560,6 +3562,21 @@ impl std::fmt::Display for Rename {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for UseTree {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
+impl std::fmt::Display for Path {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
+impl std::fmt::Display for UseTreeList {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for Abi {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -3650,11 +3667,6 @@ impl std::fmt::Display for PathType {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Path {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for PointerType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -4035,16 +4047,6 @@ impl std::fmt::Display for Param {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for UseTree {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
-impl std::fmt::Display for UseTreeList {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for PathSegment {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 2b05ed2d4a..0ff69bc2d1 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -60,7 +60,7 @@ pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::
     ast_from_text(&format!("use {{{}}};", use_trees))
 }
 
-pub fn use_item(use_tree: ast::UseTree) -> ast::UseItem {
+pub fn use_item(use_tree: ast::UseTree) -> ast::Use {
     ast_from_text(&format!("use {};", use_tree))
 }
 
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 083727c5cd..3a58217c47 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -100,7 +100,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "RET_TYPE",
         "EXTERN_CRATE",
         "MODULE",
-        "USE_ITEM",
+        "USE",
         "STATIC_DEF",
         "CONST_DEF",
         "TRAIT_DEF",
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 9b49712c13..c77fc8a8d0 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -543,6 +543,10 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
 }
 
 fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) {
+    if lower_comma_list(acc, grammar, rule) {
+        return;
+    }
+
     match rule {
         Rule::Node(node) => {
             let field = Field::Node { name: grammar[*node].name.clone(), src: FieldSrc::Shorthand };
@@ -595,6 +599,37 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) {
     }
 }
 
+// (T (',' T)* ','?)?
+fn lower_comma_list(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) -> bool {
+    let rule = match rule {
+        Rule::Opt(it) => it,
+        _ => return false,
+    };
+    let rule = match &**rule {
+        Rule::Seq(it) => it,
+        _ => return false,
+    };
+    let (node, repeat, trailing_comma) = match rule.as_slice() {
+        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
+            (node, repeat, trailing_comma)
+        }
+        _ => return false,
+    };
+    let repeat = match &**repeat {
+        Rule::Seq(it) => it,
+        _ => return false,
+    };
+    match repeat.as_slice() {
+        [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
+        _ => return false,
+    }
+    let name = grammar[*node].name.clone();
+    let label = pluralize(&to_lower_snake_case(&name));
+    let field = Field::Node { name: label.clone(), src: FieldSrc::Many(name) };
+    acc.push(field);
+    true
+}
+
 fn deduplicate_fields(ast: &mut AstSrc) {
     for node in &mut ast.nodes {
         let mut i = 0;
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
index e6e7c7518f..449b0242fb 100644
--- a/xtask/src/codegen/rust.ungram
+++ b/xtask/src/codegen/rust.ungram
@@ -17,7 +17,7 @@ Item =
 | TraitDef
 | TypeAliasDef
 | UnionDef
-| UseItem
+| Use
 
 Module =
   Attr* Visibility? 'mod' Name
@@ -29,6 +29,19 @@ ItemList =
 ExternCrate =
   Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
 
+Rename =
+  'as' (Name | '_')
+
+Use =
+  Attr* Visibility? 'use' UseTree ';'
+
+UseTree =
+  (Path? '::')? ('*' | UseTreeList )
+| Path Rename?
+
+UseTreeList =
+  '{' (UseTree (',' UseTree)* ','?)? '}'
+
 FnDef =
  Attr* Visibility? Abi? 'const' 'default' 'async' 'unsafe' 'fn' Name TypeParamList?
  ParamList RetType?
@@ -395,18 +408,6 @@ Param =
   Attr* Pat (':' ascribed_type:TypeRef)
 | '...'
 
-UseItem =
-  Attr* Visibility? 'use' UseTree ';'
-
-UseTree =
-  Path ('::' ('*' | UseTreeList))  Rename?
-
-UseTreeList =
-  '{' UseTree* '}'
-
-Rename =
-  'as' Name
-
 Path =
   (qualifier:Path '::')? segment:PathSegment
 


Test patch:
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs
index 68be1cb40c..3f2e29d9ed 100644
--- a/crates/ra_hir_def/src/item_tree/tests.rs
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -228,9 +228,9 @@ fn smoke() {
 
             top-level items:
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-            Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
+            Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-            Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
+            Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
             ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrate>(1) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index a4fa2cb447..f5ffff7ccb 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -664,7 +664,7 @@ fn replace_binary_op() {
     assert_ssr_transform(
         "$a + $b ==>> $b + $a",
         "fn f() {1 + 2 + 3 + 4}",
-        expect![[r#"fn f() {4 + (3 + (2 + 1))}"#]],
+        expect![["fn f() {4 + 3 + 2 + 1}"]],
     );
 }
 
@@ -773,32 +773,11 @@ fn preserves_whitespace_within_macro_expansion() {
             macro_rules! macro1 {
                 ($a:expr) => {$a}
             }
-            fn f() {macro1!(4 - (3 - 1   *   2)}
+            fn f() {macro1!(4 - 3 - 1   *   2}
             "#]],
     )
 }
 
-#[test]
-fn add_parenthesis_when_necessary() {
-    assert_ssr_transform(
-        "foo($a) ==>> $a.to_string()",
-        r#"
-        fn foo(_: i32) {}
-        fn bar3(v: i32) {
-            foo(1 + 2);
-            foo(-v);
-        }
-        "#,
-        expect![[r#"
-            fn foo(_: i32) {}
-            fn bar3(v: i32) {
-                (1 + 2).to_string();
-                (-v).to_string();
-            }
-        "#]],
-    )
-}
-
 #[test]
 fn match_failure_reasons() {
     let code = r#"
diff --git a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
index 6717995e9b..4cfd1bce4b 100644
--- a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
@@ -6,7 +6,7 @@ SOURCE_FILE@0..42
     BANG@22..23 "!"
   ERROR@23..24
     SLASH@23..24 "/"
-  USE_ITEM@24..28
+  USE@24..28
     USE_KW@24..27 "use"
     ERROR@27..28
       SLASH@27..28 "/"
diff --git a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
index b3bcf472a2..9a0f4665ef 100644
--- a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
+++ b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..12
-  USE_ITEM@0..12
+  USE@0..12
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..11
diff --git a/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
index 9588cf3b3a..0415085b06 100644
--- a/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
+++ b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..48
-  USE_ITEM@0..13
+  USE@0..13
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..12
@@ -14,10 +14,10 @@ SOURCE_FILE@0..48
             IDENT@9..12 "bar"
     SEMICOLON@12..13 ";"
   WHITESPACE@13..14 "\n"
-  USE_ITEM@14..17
+  USE@14..17
     USE_KW@14..17 "use"
   WHITESPACE@17..18 "\n"
-  USE_ITEM@18..33
+  USE@18..33
     USE_KW@18..21 "use"
     WHITESPACE@21..22 " "
     USE_TREE@22..32
@@ -31,7 +31,7 @@ SOURCE_FILE@0..48
             IDENT@29..32 "baz"
     SEMICOLON@32..33 ";"
   WHITESPACE@33..34 "\n"
-  USE_ITEM@34..37
+  USE@34..37
     USE_KW@34..37 "use"
   WHITESPACE@37..38 "\n"
   FN_DEF@38..47
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
index f926b67d26..ef6172f8a1 100644
--- a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
+++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..37
-  USE_ITEM@0..36
+  USE@0..36
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..36
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
index d2a5492733..284c8715b3 100644
--- a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..98
-  USE_ITEM@0..12
+  USE@0..12
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..11
@@ -9,7 +9,7 @@ SOURCE_FILE@0..98
           CRATE_KW@6..11 "crate"
     SEMICOLON@11..12 ";"
   WHITESPACE@12..13 "\n"
-  USE_ITEM@13..54
+  USE@13..54
     USE_KW@13..16 "use"
     WHITESPACE@16..17 " "
     USE_TREE@17..53
@@ -52,7 +52,7 @@ SOURCE_FILE@0..98
         R_CURLY@52..53 "}"
     SEMICOLON@53..54 ";"
   WHITESPACE@54..55 "\n"
-  USE_ITEM@55..72
+  USE@55..72
     USE_KW@55..58 "use"
     WHITESPACE@58..59 " "
     USE_TREE@59..71
@@ -66,7 +66,7 @@ SOURCE_FILE@0..98
           CRATE_KW@66..71 "crate"
     SEMICOLON@71..72 ";"
   WHITESPACE@72..73 "\n"
-  USE_ITEM@73..97
+  USE@73..97
     USE_KW@73..76 "use"
     WHITESPACE@76..77 " "
     USE_TREE@77..96
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
index d0360c4679..2049a9d724 100644
--- a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..67
-  USE_ITEM@0..12
+  USE@0..12
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..11
@@ -9,7 +9,7 @@ SOURCE_FILE@0..67
           SUPER_KW@6..11 "super"
     SEMICOLON@11..12 ";"
   WHITESPACE@12..13 "\n"
-  USE_ITEM@13..26
+  USE@13..26
     USE_KW@13..16 "use"
     WHITESPACE@16..17 " "
     USE_TREE@17..25
@@ -23,7 +23,7 @@ SOURCE_FILE@0..67
           SUPER_KW@20..25 "super"
     SEMICOLON@25..26 ";"
   WHITESPACE@26..27 "\n"
-  USE_ITEM@27..47
+  USE@27..47
     USE_KW@27..30 "use"
     WHITESPACE@30..31 " "
     USE_TREE@31..46
@@ -41,7 +41,7 @@ SOURCE_FILE@0..67
           SUPER_KW@41..46 "super"
     SEMICOLON@46..47 ";"
   WHITESPACE@47..48 "\n"
-  USE_ITEM@48..66
+  USE@48..66
     USE_KW@48..51 "use"
     WHITESPACE@51..52 " "
     USE_TREE@52..65
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
index 4f382b06c4..deadf56b4b 100644
--- a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..25
-  USE_ITEM@0..11
+  USE@0..11
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..10
@@ -9,7 +9,7 @@ SOURCE_FILE@0..25
           SELF_KW@6..10 "self"
     SEMICOLON@10..11 ";"
   WHITESPACE@11..12 "\n"
-  USE_ITEM@12..24
+  USE@12..24
     USE_KW@12..15 "use"
     WHITESPACE@15..16 " "
     USE_TREE@16..23
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast b/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
index da8505607e..2f59d0606c 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..13
-  USE_ITEM@0..12
+  USE@0..12
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..12
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
index cf3a90400a..1e80dd7e27 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..249
-  USE_ITEM@0..58
+  USE@0..58
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..57
@@ -51,7 +51,7 @@ SOURCE_FILE@0..249
   WHITESPACE@58..59 " "
   COMMENT@59..97 "// Rust 2018 (with a  ..."
   WHITESPACE@97..98 "\n"
-  USE_ITEM@98..121
+  USE@98..121
     USE_KW@98..101 "use"
     WHITESPACE@101..102 " "
     USE_TREE@102..120
@@ -77,7 +77,7 @@ SOURCE_FILE@0..249
   WHITESPACE@121..122 " "
   COMMENT@122..134 "// Rust 2015"
   WHITESPACE@134..135 "\n"
-  USE_ITEM@135..166
+  USE@135..166
     USE_KW@135..138 "use"
     WHITESPACE@138..139 " "
     USE_TREE@139..165
@@ -104,7 +104,7 @@ SOURCE_FILE@0..249
   WHITESPACE@166..167 " "
   COMMENT@167..179 "// Rust 2015"
   WHITESPACE@179..180 "\n"
-  USE_ITEM@180..205
+  USE@180..205
     USE_KW@180..183 "use"
     WHITESPACE@183..184 " "
     USE_TREE@184..204
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast b/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
index 9e898b7b9c..b3623c4455 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
@@ -1,12 +1,12 @@
 SOURCE_FILE@0..60
-  USE_ITEM@0..6
+  USE@0..6
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..5
       STAR@4..5 "*"
     SEMICOLON@5..6 ";"
   WHITESPACE@6..7 "\n"
-  USE_ITEM@7..15
+  USE@7..15
     USE_KW@7..10 "use"
     WHITESPACE@10..11 " "
     USE_TREE@11..14
@@ -14,7 +14,7 @@ SOURCE_FILE@0..60
       STAR@13..14 "*"
     SEMICOLON@14..15 ";"
   WHITESPACE@15..16 "\n"
-  USE_ITEM@16..36
+  USE@16..36
     USE_KW@16..19 "use"
     WHITESPACE@19..20 " "
     USE_TREE@20..35
@@ -35,7 +35,7 @@ SOURCE_FILE@0..60
         R_CURLY@34..35 "}"
     SEMICOLON@35..36 ";"
   WHITESPACE@36..37 "\n"
-  USE_ITEM@37..59
+  USE@37..59
     USE_KW@37..40 "use"
     WHITESPACE@40..41 " "
     USE_TREE@41..58
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast b/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
index 8e9061e1d6..60b517230e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..198
-  USE_ITEM@0..28
+  USE@0..28
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..27
@@ -20,7 +20,7 @@ SOURCE_FILE@0..198
           IDENT@18..27 "some_name"
     SEMICOLON@27..28 ";"
   WHITESPACE@28..29 "\n"
-  USE_ITEM@29..181
+  USE@29..181
     USE_KW@29..32 "use"
     WHITESPACE@32..33 " "
     USE_TREE@33..180
@@ -121,7 +121,7 @@ SOURCE_FILE@0..198
         R_CURLY@179..180 "}"
     SEMICOLON@180..181 ";"
   WHITESPACE@181..182 "\n"
-  USE_ITEM@182..197
+  USE@182..197
     USE_KW@182..185 "use"
     WHITESPACE@185..186 " "
     USE_TREE@186..196
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
index caa76fe8ad..702f2e0b0a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..16
-  USE_ITEM@0..15
+  USE@0..15
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..14
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
index 18cd5271ff..c4c5bc51e3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..37
-  USE_ITEM@0..18
+  USE@0..18
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..17
@@ -17,7 +17,7 @@ SOURCE_FILE@0..37
         R_CURLY@16..17 "}"
     SEMICOLON@17..18 ";"
   WHITESPACE@18..19 "\n"
-  USE_ITEM@19..36
+  USE@19..36
     USE_KW@19..22 "use"
     WHITESPACE@22..23 " "
     USE_TREE@23..35
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
index 015a7a7d22..82028096f8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..154
-  USE_ITEM@0..17
+  USE@0..17
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..16
@@ -12,7 +12,7 @@ SOURCE_FILE@0..154
   WHITESPACE@17..18 " "
   COMMENT@18..45 "// Rust 2018 - All fl ..."
   WHITESPACE@45..46 "\n"
-  USE_ITEM@46..61
+  USE@46..61
     USE_KW@46..49 "use"
     WHITESPACE@49..50 " "
     USE_TREE@50..60
@@ -24,7 +24,7 @@ SOURCE_FILE@0..154
   WHITESPACE@61..62 " "
   COMMENT@62..91 "// Rust 2018 - Anchor ..."
   WHITESPACE@91..92 "\n"
-  USE_ITEM@92..124
+  USE@92..124
     USE_KW@92..95 "use"
     WHITESPACE@95..96 " "
     USE_TREE@96..123
diff --git a/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast b/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
index 96b8a94fca..6be1cf9fc8 100644
--- a/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..19
-  USE_ITEM@0..8
+  USE@0..8
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..7
@@ -9,7 +9,7 @@ SOURCE_FILE@0..19
             IDENT@4..7 "foo"
     SEMICOLON@7..8 ";"
   WHITESPACE@8..9 "\n"
-  USE_ITEM@9..19
+  USE@9..19
     USE_KW@9..12 "use"
     WHITESPACE@12..13 " "
     USE_TREE@13..18
diff --git a/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast b/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
index 07272dc3ce..4d49e79337 100644
--- a/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..40
-  USE_ITEM@0..20
+  USE@0..20
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..19
@@ -20,7 +20,7 @@ SOURCE_FILE@0..40
             IDENT@16..19 "baz"
     SEMICOLON@19..20 ";"
   WHITESPACE@20..21 "\n"
-  USE_ITEM@21..39
+  USE@21..39
     USE_KW@21..24 "use"
     WHITESPACE@24..25 " "
     USE_TREE@25..38
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
index 05d9c05ad5..66ab136609 100644
--- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..38
-  USE_ITEM@0..14
+  USE@0..14
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..13
@@ -13,7 +13,7 @@ SOURCE_FILE@0..38
             IDENT@10..13 "foo"
     SEMICOLON@13..14 ";"
   WHITESPACE@14..15 "\n"
-  USE_ITEM@15..37
+  USE@15..37
     USE_KW@15..18 "use"
     WHITESPACE@18..19 " "
     USE_TREE@19..36
diff --git a/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast b/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
index 3642c107bb..4389d2d4bc 100644
--- a/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
@@ -1,12 +1,12 @@
 SOURCE_FILE@0..81
-  USE_ITEM@0..6
+  USE@0..6
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..5
       STAR@4..5 "*"
     SEMICOLON@5..6 ";"
   WHITESPACE@6..7 "\n"
-  USE_ITEM@7..15
+  USE@7..15
     USE_KW@7..10 "use"
     WHITESPACE@10..11 " "
     USE_TREE@11..14
@@ -14,7 +14,7 @@ SOURCE_FILE@0..81
       STAR@13..14 "*"
     SEMICOLON@14..15 ";"
   WHITESPACE@15..16 "\n"
-  USE_ITEM@16..25
+  USE@16..25
     USE_KW@16..19 "use"
     WHITESPACE@19..20 " "
     USE_TREE@20..24
@@ -24,7 +24,7 @@ SOURCE_FILE@0..81
         R_CURLY@23..24 "}"
     SEMICOLON@24..25 ";"
   WHITESPACE@25..26 "\n"
-  USE_ITEM@26..33
+  USE@26..33
     USE_KW@26..29 "use"
     WHITESPACE@29..30 " "
     USE_TREE@30..32
@@ -33,7 +33,7 @@ SOURCE_FILE@0..81
         R_CURLY@31..32 "}"
     SEMICOLON@32..33 ";"
   WHITESPACE@33..34 "\n"
-  USE_ITEM@34..45
+  USE@34..45
     USE_KW@34..37 "use"
     WHITESPACE@37..38 " "
     USE_TREE@38..44
@@ -45,7 +45,7 @@ SOURCE_FILE@0..81
       STAR@43..44 "*"
     SEMICOLON@44..45 ";"
   WHITESPACE@45..46 "\n"
-  USE_ITEM@46..58
+  USE@46..58
     USE_KW@46..49 "use"
     WHITESPACE@49..50 " "
     USE_TREE@50..57
@@ -59,7 +59,7 @@ SOURCE_FILE@0..81
         R_CURLY@56..57 "}"
     SEMICOLON@57..58 ";"
   WHITESPACE@58..59 "\n"
-  USE_ITEM@59..80
+  USE@59..80
     USE_KW@59..62 "use"
     WHITESPACE@62..63 " "
     USE_TREE@63..79
diff --git a/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast b/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
index cdddb42145..d7e93f7eb7 100644
--- a/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..55
-  USE_ITEM@0..15
+  USE@0..15
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
     USE_TREE@4..14
@@ -15,7 +15,7 @@ SOURCE_FILE@0..55
           IDENT@11..14 "bar"
     SEMICOLON@14..15 ";"
   WHITESPACE@15..16 "\n"
-  USE_ITEM@16..54
+  USE@16..54
     USE_KW@16..19 "use"
     WHITESPACE@19..20 " "
     USE_TREE@20..53
diff --git a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
index eb59d6e176..bbdf896d10 100644
--- a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
@@ -78,7 +78,7 @@ SOURCE_FILE@0..3813
       STRING@399..404 "\"128\""
     R_BRACK@404..405 "]"
   WHITESPACE@405..407 "\n\n"
-  USE_ITEM@407..427
+  USE@407..427
     USE_KW@407..410 "use"
     WHITESPACE@410..411 " "
     USE_TREE@411..426
@@ -98,7 +98,7 @@ SOURCE_FILE@0..3813
             IDENT@422..426 "Cell"
     SEMICOLON@426..427 ";"
   WHITESPACE@427..428 "\n"
-  USE_ITEM@428..447
+  USE@428..447
     USE_KW@428..431 "use"
     WHITESPACE@431..432 " "
     USE_TREE@432..446