Unnamed repository; edit this file 'description' to name the repository.
Refactor ide handling for paths in derive inputs
Lukas Wirth 2021-10-28
parent f4ba64e · commit 3018ffd
-rw-r--r--crates/ide/src/doc_links.rs6
-rw-r--r--crates/ide/src/goto_definition.rs2
-rw-r--r--crates/ide/src/hover/tests.rs3
-rw-r--r--crates/ide/src/static_index.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html13
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs10
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs7
-rw-r--r--crates/ide_db/src/defs.rs29
-rw-r--r--crates/ide_db/src/helpers.rs80
-rw-r--r--crates/ide_db/src/helpers/famous_defs.rs13
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs21
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
-rw-r--r--crates/syntax/src/ast/generated/tokens.rs21
-rw-r--r--crates/syntax/src/tests/sourcegen_ast.rs2
15 files changed, 142 insertions, 77 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index c184b014ba..8c47b809b9 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -4,7 +4,7 @@ mod intra_doc_links;
use either::Either;
use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
-use pulldown_cmark_to_cmark::{cmark_with_options, Options as CmarkOptions};
+use pulldown_cmark_to_cmark::{cmark_with_options, Options as CMarkOptions};
use stdx::format_to;
use url::Url;
@@ -65,7 +65,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
doc,
&mut out,
None,
- CmarkOptions { code_block_backticks: 3, ..Default::default() },
+ CMarkOptions { code_block_backticks: 3, ..Default::default() },
)
.ok();
out
@@ -103,7 +103,7 @@ pub(crate) fn remove_links(markdown: &str) -> String {
doc,
&mut out,
None,
- CmarkOptions { code_block_backticks: 3, ..Default::default() },
+ CMarkOptions { code_block_backticks: 3, ..Default::default() },
)
.ok();
out
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 1f0b9aaaa1..1edb17739b 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1371,6 +1371,7 @@ impl Twait for Stwuct {
fn goto_def_derive_input() {
check(
r#"
+//- minicore:derive
#[rustc_builtin_macro]
pub macro Copy {}
// ^^^^
@@ -1380,6 +1381,7 @@ struct Foo;
);
check(
r#"
+//- minicore:derive
mod foo {
#[rustc_builtin_macro]
pub macro Copy {}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index b6cec50038..2aa54fc33f 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3651,6 +3651,7 @@ use crate as foo$0;
fn hover_attribute_in_macro() {
check(
r#"
+//- minicore:derive
macro_rules! identity {
($struct:item) => {
$struct
@@ -3681,6 +3682,7 @@ identity!{
fn hover_derive_input() {
check(
r#"
+//- minicore:derive
#[rustc_builtin_macro]
pub macro Copy {}
#[derive(Copy$0)]
@@ -3700,6 +3702,7 @@ struct Foo;
);
check(
r#"
+//- minicore:derive
mod foo {
#[rustc_builtin_macro]
pub macro Copy {}
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 5e98ac1756..75249a959d 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -266,12 +266,10 @@ enum E { X(Foo) }
fn derives() {
check_all_ranges(
r#"
+//- minicore:derive
#[rustc_builtin_macro]
pub macro Copy {}
//^^^^
-#[rustc_builtin_macro]
-pub macro derive {}
- //^^^^^^
#[derive(Copy)]
//^^^^^^ ^^^^
struct Hello(i32);
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 1285c2f846..2bf83da4df 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,7 +3,7 @@
use hir::{AsAssocItem, HasVisibility, Semantics};
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
- helpers::{try_resolve_derive_input_at, FamousDefs},
+ helpers::{try_resolve_derive_input, FamousDefs},
RootDatabase, SymbolKind,
};
use rustc_hash::FxHashMap;
@@ -56,8 +56,8 @@ fn token(
T![?] => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
IDENT if parent_matches::<ast::TokenTree>(&token) => {
if let Some(attr) = token.ancestors().nth(2).and_then(ast::Attr::cast) {
- match try_resolve_derive_input_at(sema, &attr, &token) {
- Some(makro) => highlight_def(sema, krate, Definition::Macro(makro)),
+ match try_resolve_derive_input(sema, &attr, &ast::Ident::cast(token).unwrap()) {
+ Some(res) => highlight_def(sema, krate, Definition::from(res)),
None => HlTag::None.into(),
}
} else {
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 05e6739830..1a10a78d24 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -43,15 +43,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
-<span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
-
-<span class="comment">// Needed for function consuming vs normal</span>
-<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">marker</span> <span class="brace">{</span>
- <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
- <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Copy</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="brace">}</span>
-
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="builtin_attr attribute">identity</span><span class="attribute attribute">]</span>
<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
@@ -95,7 +86,7 @@ proc_macros::<span class="macro">mirror!</span> <span class="brace">{</span>
<span class="brace">}</span>
<span class="brace">}</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">derive</span><span class="parenthesis attribute">(</span><span class="macro attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
+<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="macro attribute">derive</span><span class="parenthesis attribute">(</span><span class="macro attribute default_library library">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
<span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span>
<span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
<span class="brace">}</span>
@@ -135,7 +126,7 @@ proc_macros::<span class="macro">mirror!</span> <span class="brace">{</span>
<span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
<span class="brace">}</span>
-<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="trait default_library library">Copy</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
<span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 850de3908f..42d34040fa 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -11,19 +11,11 @@ fn test_highlighting() {
check_highlighting(
r#"
//- proc_macros: identity, mirror
+//- minicore: derive, copy
//- /main.rs crate:main deps:foo
use inner::{self as inner_mod};
mod inner {}
-#[rustc_builtin_macro]
-macro Copy {}
-
-// Needed for function consuming vs normal
-pub mod marker {
- #[lang = "copy"]
- pub trait Copy {}
-}
-
#[proc_macros::identity]
pub mod ops {
#[lang = "fn_once"]
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 1ec3932a2d..c877748246 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -3,7 +3,7 @@ use ide_db::helpers::{
insert_use::{insert_use, ImportScope},
mod_path_to_ast,
};
-use syntax::{ast, AstNode, SyntaxNode};
+use syntax::{ast, AstNode, AstToken, SyntaxNode};
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
@@ -128,9 +128,10 @@ pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets,
.find_node_at_offset_with_descend::<ast::IdentPat>()
.filter(ast::IdentPat::is_simple_ident)
{
- ImportAssets::for_ident_pat(&pat, &ctx.sema).zip(Some(pat.syntax().clone()))
+ ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone()))
} else {
- None
+ let ident = ctx.find_token_at_offset()?;
+ ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(ident.syntax().parent())
}
}
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index effa694aae..5bc8e8764f 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -12,10 +12,10 @@ use hir::{
};
use syntax::{
ast::{self, AstNode},
- match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
+ match_ast, AstToken, SyntaxKind, SyntaxNode, SyntaxToken,
};
-use crate::{helpers::try_resolve_derive_input_at, RootDatabase};
+use crate::{helpers::try_resolve_derive_input, RootDatabase};
// FIXME: a more precise name would probably be `Symbol`?
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -38,19 +38,20 @@ impl Definition {
Some(parent) => parent,
None => return Default::default(),
};
- let attr = parent
- .ancestors()
- .find_map(ast::TokenTree::cast)
- .and_then(|tt| tt.parent_meta())
- .and_then(|meta| meta.parent_attr());
- if let Some(attr) = attr {
- try_resolve_derive_input_at(&sema, &attr, &token)
- .map(Definition::Macro)
- .into_iter()
- .collect()
- } else {
- Self::from_node(sema, &parent)
+ if let Some(ident) = ast::Ident::cast(token.clone()) {
+ let attr = parent
+ .ancestors()
+ .find_map(ast::TokenTree::cast)
+ .and_then(|tt| tt.parent_meta())
+ .and_then(|meta| meta.parent_attr());
+ if let Some(attr) = attr {
+ return try_resolve_derive_input(&sema, &attr, &ident)
+ .map(Into::into)
+ .into_iter()
+ .collect();
+ }
}
+ Self::from_node(sema, &parent)
}
pub fn from_node(sema: &Semantics<RootDatabase>, node: &SyntaxNode) -> ArrayVec<Definition, 2> {
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 173e55b33f..f6a1a55218 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -7,14 +7,16 @@ pub mod merge_imports;
pub mod node_ext;
pub mod rust_doc;
-use std::collections::VecDeque;
+use std::{collections::VecDeque, iter};
use base_db::FileId;
use either::Either;
-use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
+use hir::{ItemInNs, MacroDef, ModuleDef, Name, PathResolution, Semantics};
+use itertools::Itertools;
use syntax::{
- ast::{self, make, HasLoopBody},
- AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent, T,
+ ast::{self, make, HasLoopBody, Ident},
+ AstNode, AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
+ T,
};
use crate::RootDatabase;
@@ -29,33 +31,59 @@ pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
}
}
-/// Resolves the path at the cursor token as a derive macro if it inside a token tree of a derive attribute.
-pub fn try_resolve_derive_input_at(
+/// Parses and returns the derive path at the cursor position in the given attribute, if it is a derive.
+/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
+///
+/// The returned path is synthesized from TokenTree tokens and as such cannot be used with the [`Semantics`].
+pub fn get_path_in_derive_attr(
sema: &hir::Semantics<RootDatabase>,
- derive_attr: &ast::Attr,
- cursor: &SyntaxToken,
-) -> Option<MacroDef> {
- use itertools::Itertools;
- if cursor.kind() != T![ident] {
+ attr: &ast::Attr,
+ cursor: &Ident,
+) -> Option<ast::Path> {
+ let cursor = cursor.syntax();
+ let path = attr.path()?;
+ let tt = attr.token_tree()?;
+ if !tt.syntax().text_range().contains_range(cursor.text_range()) {
return None;
}
- let tt = match derive_attr.as_simple_call() {
- Some((name, tt))
- if name == "derive" && tt.syntax().text_range().contains_range(cursor.text_range()) =>
- {
- tt
- }
- _ => return None,
- };
- let tokens: Vec<_> = cursor
+ let scope = sema.scope(attr.syntax());
+ let resolved_attr = sema.resolve_path(&path)?;
+ let derive = FamousDefs(sema, scope.krate()).core_macros_builtin_derive()?;
+ if PathResolution::Macro(derive) != resolved_attr {
+ return None;
+ }
+
+ let first = cursor
.siblings_with_tokens(Direction::Prev)
- .flat_map(SyntaxElement::into_token)
+ .filter_map(SyntaxElement::into_token)
.take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,])
- .collect();
- let path = ast::Path::parse(&tokens.into_iter().rev().join("")).ok()?;
- sema.scope(tt.syntax())
- .speculative_resolve_as_mac(&path)
- .filter(|mac| mac.kind() == hir::MacroKind::Derive)
+ .last()?;
+ let path_tokens = first
+ .siblings_with_tokens(Direction::Next)
+ .filter_map(SyntaxElement::into_token)
+ .take_while(|tok| tok != cursor);
+
+ ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok()
+}
+
+/// Parses and resolves the path at the cursor position in the given attribute, if it is a derive.
+/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
+pub fn try_resolve_derive_input(
+ sema: &hir::Semantics<RootDatabase>,
+ attr: &ast::Attr,
+ cursor: &Ident,
+) -> Option<PathResolution> {
+ let path = get_path_in_derive_attr(sema, attr, cursor)?;
+ let scope = sema.scope(attr.syntax());
+ // FIXME: This double resolve shouldn't be necessary
+ // It's only here so we prefer macros over other namespaces
+ match scope.speculative_resolve_as_mac(&path) {
+ Some(mac) if mac.kind() == hir::MacroKind::Derive => Some(PathResolution::Macro(mac)),
+ Some(_) => return None,
+ None => scope
+ .speculative_resolve(&path)
+ .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
+ }
}
/// Picks the token with the highest rank returned by the passed in function.
diff --git a/crates/ide_db/src/helpers/famous_defs.rs b/crates/ide_db/src/helpers/famous_defs.rs
index b5e3907cfa..e8993d327f 100644
--- a/crates/ide_db/src/helpers/famous_defs.rs
+++ b/crates/ide_db/src/helpers/famous_defs.rs
@@ -1,5 +1,5 @@
//! See [`FamousDefs`].
-use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
+use hir::{Crate, Enum, MacroDef, Module, ScopeDef, Semantics, Trait};
use crate::RootDatabase;
@@ -80,6 +80,10 @@ impl FamousDefs<'_, '_> {
self.find_trait("core:marker:Copy")
}
+ pub fn core_macros_builtin_derive(&self) -> Option<MacroDef> {
+ self.find_macro("core:macros:builtin:derive")
+ }
+
pub fn alloc(&self) -> Option<Crate> {
self.find_crate("alloc")
}
@@ -110,6 +114,13 @@ impl FamousDefs<'_, '_> {
}
}
+ fn find_macro(&self, path: &str) -> Option<MacroDef> {
+ match self.find_def(path)? {
+ hir::ScopeDef::MacroDef(it) => Some(it),
+ _ => None,
+ }
+ }
+
fn find_enum(&self, path: &str) -> Option<Enum> {
match self.find_def(path)? {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index f1e8ee4935..0b3ecd095b 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -8,10 +8,11 @@ use rustc_hash::FxHashSet;
use syntax::{
ast::{self, HasName},
utils::path_to_string_stripping_turbo_fish,
- AstNode, SyntaxNode,
+ AstNode, AstToken, SyntaxNode,
};
use crate::{
+ helpers::get_path_in_derive_attr,
items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
RootDatabase,
};
@@ -119,7 +120,7 @@ impl ImportAssets {
})
}
- pub fn for_ident_pat(pat: &ast::IdentPat, sema: &Semantics<RootDatabase>) -> Option<Self> {
+ pub fn for_ident_pat(sema: &Semantics<RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
if !pat.is_simple_ident() {
return None;
}
@@ -132,6 +133,22 @@ impl ImportAssets {
})
}
+ pub fn for_derive_ident(sema: &Semantics<RootDatabase>, ident: &ast::Ident) -> Option<Self> {
+ let attr = ident.syntax().ancestors().find_map(ast::Attr::cast)?;
+ let path = get_path_in_derive_attr(sema, &attr, ident)?;
+
+ if let Some(_) = path.qualifier() {
+ return None;
+ }
+ let name = NameToImport::Exact(path.segment()?.name_ref()?.to_string());
+ let candidate_node = attr.syntax().clone();
+ Some(Self {
+ import_candidate: ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
+ module_with_candidate: sema.scope(&candidate_node).module()?,
+ candidate_node,
+ })
+ }
+
pub fn for_fuzzy_path(
module_with_candidate: Module,
qualifier: Option<ast::Path>,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 473b7a870f..ea39f799b7 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -673,7 +673,7 @@ pub(crate) fn location(
Ok(loc)
}
-/// Perefer using `location_link`, if the client has the cap.
+/// Prefer using `location_link`, if the client has the cap.
pub(crate) fn location_from_nav(
snap: &GlobalStateSnapshot,
nav: NavigationTarget,
diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs
index 83fd5ce899..30f23b9d96 100644
--- a/crates/syntax/src/ast/generated/tokens.rs
+++ b/crates/syntax/src/ast/generated/tokens.rs
@@ -131,3 +131,24 @@ impl AstToken for FloatNumber {
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Ident {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Ident {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Ident {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index a1a96581b4..36fedd2f0b 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -560,7 +560,7 @@ impl Field {
fn lower(grammar: &Grammar) -> AstSrc {
let mut res = AstSrc {
- tokens: "Whitespace Comment String ByteString IntNumber FloatNumber"
+ tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Ident"
.split_ascii_whitespace()
.map(|it| it.to_string())
.collect::<Vec<_>>(),