Skip to content

Commit 8e130a2

Browse files
hvitvedCopilot
andcommitted
Rust: Remove parenthesized expression and pattern nodes
Extract parenthesized expressions and patterns as their inner entities, and update QL consumers and generated schema. Preserve comments and attributes on the unwrapped nodes, with regression tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 915bfa8 commit 8e130a2

58 files changed

Lines changed: 529 additions & 1192 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎rust/ast-generator/src/main.rs‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ fn should_enum_be_skipped(name: &str) -> bool {
7676
fn should_node_be_skipped(name: &str) -> bool {
7777
name == "TypeAnchor" // we flatten TypeAnchor into PathSegment in the extractor
7878
|| name == "MacroStmts" // we workaround a getter bug in the extractor
79+
|| name == "ParenExpr" // parenthesized expressions are extracted as their inner expression
80+
|| name == "ParenPat" // parenthesized patterns are extracted as their inner pattern
7981
}
8082

8183
fn should_node_be_skipped_in_extractor(name: &str) -> bool {
@@ -133,6 +135,7 @@ fn get_additional_fields(node_name: &str) -> Vec<FieldInfo> {
133135
FieldInfo::body("body", "TokenTree"),
134136
],
135137
"MacroCall" => vec![FieldInfo::body("token_tree", "TokenTree")],
138+
"MacroExpr" | "RecordExpr" => vec![FieldInfo::list("attrs", "AnyAttr")],
136139
"FormatArgsExpr" => vec![FieldInfo::list("args", "FormatArgsArg")],
137140
"ArgList" => vec![FieldInfo::list("args", "Expr")],
138141
"Fn" => vec![FieldInfo::body("body", "BlockExpr")],
@@ -349,6 +352,7 @@ struct EnumVariantInfo {
349352
name: String,
350353
snake_case_name: String,
351354
variant_ast_name: String,
355+
emission: String,
352356
}
353357

354358
#[derive(Serialize)]
@@ -365,6 +369,8 @@ struct ExtractorNodeFieldInfo {
365369
name: String,
366370
method: String,
367371
snake_case_ty: String,
372+
attributes: bool,
373+
parenthesized_attrs: bool,
368374
string: bool,
369375
predicate: bool,
370376
optional: bool,
@@ -399,10 +405,16 @@ fn enum_to_extractor_info(node: &AstEnumSrc) -> ExtractorEnumInfo {
399405
.map(|v| {
400406
let name = class_name(v);
401407
let snake_case_name = to_lower_snake_case(v);
408+
let emission = match v.as_str() {
409+
"ParenExpr" => "self.emit_parenthesized_expr(inner)".to_owned(),
410+
"ParenPat" => "self.emit_parenthesized_pat(inner)".to_owned(),
411+
_ => format!("self.emit_{snake_case_name}(inner).map(Into::into)"),
412+
};
402413
EnumVariantInfo {
403414
name,
404415
snake_case_name,
405416
variant_ast_name: v.to_string(),
417+
emission,
406418
}
407419
})
408420
.collect(),
@@ -412,6 +424,7 @@ fn enum_to_extractor_info(node: &AstEnumSrc) -> ExtractorEnumInfo {
412424

413425
fn field_info_to_extractor_info(name: &str, field: &FieldInfo) -> ExtractorNodeFieldInfo {
414426
let name = property_name(name, &field.name);
427+
let attributes = name == "attrs";
415428
match &field.ty {
416429
FieldType::String => ExtractorNodeFieldInfo {
417430
name,
@@ -440,6 +453,7 @@ fn field_info_to_extractor_info(name: &str, field: &FieldInfo) -> ExtractorNodeF
440453
},
441454
FieldType::List(ty) => ExtractorNodeFieldInfo {
442455
name,
456+
attributes,
443457
method: if ty == "AnyAttr" {
444458
"attrs_with_doc".to_owned()
445459
} else {
@@ -453,12 +467,19 @@ fn field_info_to_extractor_info(name: &str, field: &FieldInfo) -> ExtractorNodeF
453467
}
454468
fn node_to_extractor_info(node: &AstNodeSrc) -> ExtractorNodeInfo {
455469
let fields = get_fields(node);
456-
let has_attrs = fields.iter().any(|f| f.name == "attrs");
470+
let parenthesized_attrs = matches!(node.name.as_str(), "MacroExpr" | "RecordExpr");
457471
let name = class_name(&node.name);
458-
let fields = fields
472+
let fields: Vec<_> = fields
459473
.iter()
460474
.map(|f| field_info_to_extractor_info(&name, f))
475+
.map(|mut f| {
476+
f.parenthesized_attrs = parenthesized_attrs && f.name == "attrs";
477+
f
478+
})
461479
.collect();
480+
let has_attrs = fields
481+
.iter()
482+
.any(|f| f.name == "attrs" && !f.parenthesized_attrs);
462483
ExtractorNodeInfo {
463484
name,
464485
snake_case_name: to_lower_snake_case(&node.name),

‎rust/ast-generator/templates/extractor.mustache‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Translator<'_> {
1818
{{>pre_emission}}
1919
let label = match node {
2020
{{#variants}}
21-
ast::{{ast_name}}::{{variant_ast_name}}(inner) => self.emit_{{snake_case_name}}(inner).map(Into::into),
21+
ast::{{ast_name}}::{{variant_ast_name}}(inner) => {{{emission}}},
2222
{{/variants}}
2323
}?;
2424
{{>post_emission}}
@@ -33,6 +33,18 @@ impl Translator<'_> {
3333
if self.should_be_excluded(node) { return None; }
3434
{{/has_attrs}}
3535
{{#fields}}
36+
{{#attributes}}
37+
{{#parenthesized_attrs}}
38+
let attrs = self.take_parenthesized_expr_attrs(node.syntax());
39+
{{/parenthesized_attrs}}
40+
{{^parenthesized_attrs}}
41+
let mut attrs = self.take_parenthesized_expr_attrs(node.syntax());
42+
attrs.extend(node.{{method}}().filter_map(|x| self.emit_{{snake_case_ty}}(&x)));
43+
{{/parenthesized_attrs}}
44+
{{/attributes}}
45+
{{/fields}}
46+
{{#fields}}
47+
{{^attributes}}
3648
let {{name}} =
3749
{{#predicate}}
3850
node.{{method}}().is_some()
@@ -50,11 +62,17 @@ impl Translator<'_> {
5062
if self.should_skip_bodies() { None } else { node.{{method}}().and_then(|x| self.emit_{{snake_case_ty}}(&x)) }
5163
{{/body}}
5264
;
65+
{{/attributes}}
5366
{{/fields}}
5467
let label = self.trap.emit(generated::{{name}} {
5568
id: TrapId::Star,
5669
{{#fields}}
70+
{{#attributes}}
71+
attrs,
72+
{{/attributes}}
73+
{{^attributes}}
5774
{{name}},
75+
{{/attributes}}
5876
{{/fields}}
5977
});
6078
self.emit_location(label, node);

‎rust/extractor/src/generated/.generated.list‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎rust/extractor/src/generated/top.rs‎

Lines changed: 8 additions & 122 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎rust/extractor/src/translate/base.rs‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use ra_ap_syntax::{
2020
use ra_ap_syntax_bridge::{
2121
DocCommentDesugarMode, syntax_node_to_token_tree, token_tree_to_syntax_node,
2222
};
23+
use std::collections::HashMap;
2324
use std::path::{Path, PathBuf};
2425

2526
impl Emission<ast::Item> for Translator<'_> {
@@ -132,6 +133,7 @@ pub struct Translator<'db> {
132133
pub semantics: Option<&'db Semantics<'db, RootDatabase>>,
133134
source_kind: SourceKind,
134135
pub(crate) macro_context_depth: usize,
136+
parenthesized_expr_attrs: HashMap<SyntaxNode, Vec<Label<generated::AnyAttr>>>,
135137
diagnostic_count: usize,
136138
/// When emitting a reconstructed built-in derive expansion, holds the span map of the
137139
/// synthesized syntax tree. Those nodes are not registered in the semantics cache, so
@@ -162,6 +164,7 @@ impl<'db> Translator<'db> {
162164
semantics: semantic_info.map(|i| i.semantics),
163165
source_kind,
164166
macro_context_depth: 0,
167+
parenthesized_expr_attrs: HashMap::new(),
165168
diagnostic_count: 0,
166169
builtin_derive_span_map: None,
167170
}
@@ -523,6 +526,55 @@ impl<'db> Translator<'db> {
523526
})
524527
}
525528

529+
pub(crate) fn emit_parenthesized_expr(
530+
&mut self,
531+
node: &ast::ParenExpr,
532+
) -> Option<Label<generated::Expr>> {
533+
if self.should_be_excluded(node) {
534+
return None;
535+
}
536+
537+
let mut attrs = self.take_parenthesized_expr_attrs(node.syntax());
538+
attrs.extend(
539+
node.attrs_with_doc()
540+
.filter_map(|attr| self.emit_any_attr(&attr)),
541+
);
542+
let result = node.expr().and_then(|expr| {
543+
let syntax = expr.syntax().clone();
544+
self.parenthesized_expr_attrs
545+
.entry(syntax.clone())
546+
.or_default()
547+
.extend(attrs);
548+
let result = self.emit_expr(&expr);
549+
self.parenthesized_expr_attrs.remove(&syntax);
550+
result
551+
});
552+
if let Some(label) = result {
553+
self.emit_tokens(node, label.into(), node.syntax().children_with_tokens());
554+
}
555+
result
556+
}
557+
558+
pub(crate) fn emit_parenthesized_pat(
559+
&mut self,
560+
node: &ast::ParenPat,
561+
) -> Option<Label<generated::Pat>> {
562+
let result = node.pat().and_then(|pat| self.emit_pat(&pat));
563+
if let Some(label) = result {
564+
self.emit_tokens(node, label.into(), node.syntax().children_with_tokens());
565+
}
566+
result
567+
}
568+
569+
pub(crate) fn take_parenthesized_expr_attrs(
570+
&mut self,
571+
node: &SyntaxNode,
572+
) -> Vec<Label<generated::AnyAttr>> {
573+
self.parenthesized_expr_attrs
574+
.remove(node)
575+
.unwrap_or_default()
576+
}
577+
526578
pub(crate) fn should_skip_bodies(&self) -> bool {
527579
self.source_kind == SourceKind::Library
528580
}

0 commit comments

Comments
 (0)