From 811905fce8532617df9e3216829e60bcdfd9e935 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Sep 2024 12:40:41 +0200 Subject: [PATCH] Give InlineAsmOperand a HIR representation --- crates/hir-def/src/body.rs | 27 +++- crates/hir-def/src/body/lower.rs | 2 +- crates/hir-def/src/body/lower/asm.rs | 148 ++++++++++-------- crates/hir/src/lib.rs | 9 +- crates/hir/src/semantics.rs | 69 +++++--- crates/hir/src/semantics/source_to_def.rs | 21 ++- crates/hir/src/source_analyzer.rs | 22 +++ crates/ide-db/src/defs.rs | 32 ++-- crates/ide-db/src/rename.rs | 2 +- crates/ide-db/src/search.rs | 29 ++-- crates/ide/src/doc_links.rs | 4 +- crates/ide/src/moniker.rs | 4 +- crates/ide/src/navigation_target.rs | 2 +- crates/ide/src/syntax_highlighting/format.rs | 24 +-- .../ide/src/syntax_highlighting/highlight.rs | 2 +- crates/ide/src/syntax_highlighting/inject.rs | 2 +- .../test_data/highlight_asm.html | 32 ++-- .../test_data/highlight_strings.html | 8 +- crates/parser/src/grammar/expressions/atom.rs | 16 +- crates/parser/src/syntax_kind/generated.rs | 2 + .../test_data/parser/inline/ok/asm_expr.rast | 52 +++--- crates/syntax/rust.ungram | 8 +- crates/syntax/src/ast/generated/nodes.rs | 109 ++++++++++--- 23 files changed, 409 insertions(+), 217 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index f5fe8f8770..03507189fb 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -100,7 +100,14 @@ pub struct BodySourceMap { field_map_back: FxHashMap, pat_field_map_back: FxHashMap, - format_args_template_map: FxHashMap>, + template_map: Option< + Box<( + // format_args! + FxHashMap>, + // asm! + FxHashMap>, + )>, + >, expansions: FxHashMap>, MacroFileId>, @@ -426,7 +433,16 @@ impl BodySourceMap { node: InFile<&ast::FormatArgsExpr>, ) -> Option<&[(syntax::TextRange, Name)]> { let src = node.map(AstPtr::new).map(AstPtr::upcast::); - self.format_args_template_map.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref) + self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref) + } + + pub fn asm_template_args( + &self, + node: InFile<&ast::AsmExpr>, + ) -> Option<(ExprId, &[(syntax::TextRange, usize)])> { + let src = node.map(AstPtr::new).map(AstPtr::upcast::); + let expr = self.expr_map.get(&src)?; + Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref)) } /// Get a reference to the body source map's diagnostics. @@ -446,11 +462,14 @@ impl BodySourceMap { field_map_back, pat_field_map_back, expansions, - format_args_template_map, + template_map, diagnostics, binding_definitions, } = self; - format_args_template_map.shrink_to_fit(); + if let Some(template_map) = template_map { + template_map.0.shrink_to_fit(); + template_map.1.shrink_to_fit(); + } expr_map.shrink_to_fit(); expr_map_back.shrink_to_fit(); pat_map.shrink_to_fit(); diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index dfcb8b8120..9c547574ec 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1847,7 +1847,7 @@ impl ExprCollector<'_> { }, syntax_ptr, ); - self.source_map.format_args_template_map.insert(idx, mappings); + self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings); idx } diff --git a/crates/hir-def/src/body/lower/asm.rs b/crates/hir-def/src/body/lower/asm.rs index dafa3a859d..59b348b77d 100644 --- a/crates/hir-def/src/body/lower/asm.rs +++ b/crates/hir-def/src/body/lower/asm.rs @@ -1,4 +1,3 @@ -use hir_expand::name::Name; use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ @@ -25,7 +24,7 @@ impl ExprCollector<'_> { let mut named_pos: FxHashMap = Default::default(); let mut named_args: FxHashMap = Default::default(); let mut reg_args: FxHashSet = Default::default(); - for operand in asm.asm_operands() { + for piece in asm.asm_pieces() { let slot = operands.len(); let mut lower_reg = |reg: Option| { let reg = reg?; @@ -39,14 +38,14 @@ impl ExprCollector<'_> { } }; - let op = match operand { - ast::AsmOperand::AsmClobberAbi(clobber_abi) => { + let op = match piece { + ast::AsmPiece::AsmClobberAbi(clobber_abi) => { if let Some(abi_name) = clobber_abi.string_token() { clobber_abis.insert(Symbol::intern(abi_name.text())); } continue; } - ast::AsmOperand::AsmOptions(opt) => { + ast::AsmPiece::AsmOptions(opt) => { opt.asm_options().for_each(|opt| { options |= match opt.syntax().first_token().map_or(T![$], |it| it.kind()) { T![att_syntax] => AsmOptions::ATT_SYNTAX, @@ -63,71 +62,82 @@ impl ExprCollector<'_> { }); continue; } - ast::AsmOperand::AsmRegOperand(op) => { - let Some(dir_spec) = op.asm_dir_spec() else { - continue; - }; - let Some(reg) = lower_reg(op.asm_reg_spec()) else { - continue; - }; + ast::AsmPiece::AsmOperandNamed(op) => { if let Some(name) = op.name() { let sym = Symbol::intern(&name.text()); named_args.insert(sym.clone(), slot); named_pos.insert(slot, sym); } - if dir_spec.in_token().is_some() { - let expr = self - .collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr())); - AsmOperand::In { reg, expr } - } else if dir_spec.out_token().is_some() { - let expr = self - .collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr())); - AsmOperand::Out { reg, expr: Some(expr), late: false } - } else if dir_spec.lateout_token().is_some() { - let expr = self - .collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr())); - AsmOperand::Out { reg, expr: Some(expr), late: true } - } else if dir_spec.inout_token().is_some() { - let Some(op_expr) = op.asm_operand_expr() else { continue }; - let in_expr = self.collect_expr_opt(op_expr.in_expr()); - let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it)); - match out_expr { - Some(out_expr) => AsmOperand::SplitInOut { - reg, - in_expr, - out_expr: Some(out_expr), - late: false, - }, - None => AsmOperand::InOut { reg, expr: in_expr, late: false }, + let Some(op) = op.asm_operand() else { continue }; + match op { + ast::AsmOperand::AsmRegOperand(op) => { + let Some(dir_spec) = op.asm_dir_spec() else { + continue; + }; + let Some(reg) = lower_reg(op.asm_reg_spec()) else { + continue; + }; + if dir_spec.in_token().is_some() { + let expr = self.collect_expr_opt( + op.asm_operand_expr().and_then(|it| it.in_expr()), + ); + AsmOperand::In { reg, expr } + } else if dir_spec.out_token().is_some() { + let expr = self.collect_expr_opt( + op.asm_operand_expr().and_then(|it| it.in_expr()), + ); + AsmOperand::Out { reg, expr: Some(expr), late: false } + } else if dir_spec.lateout_token().is_some() { + let expr = self.collect_expr_opt( + op.asm_operand_expr().and_then(|it| it.in_expr()), + ); + AsmOperand::Out { reg, expr: Some(expr), late: true } + } else if dir_spec.inout_token().is_some() { + let Some(op_expr) = op.asm_operand_expr() else { continue }; + let in_expr = self.collect_expr_opt(op_expr.in_expr()); + let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it)); + match out_expr { + Some(out_expr) => AsmOperand::SplitInOut { + reg, + in_expr, + out_expr: Some(out_expr), + late: false, + }, + None => AsmOperand::InOut { reg, expr: in_expr, late: false }, + } + } else if dir_spec.inlateout_token().is_some() { + let Some(op_expr) = op.asm_operand_expr() else { continue }; + let in_expr = self.collect_expr_opt(op_expr.in_expr()); + let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it)); + match out_expr { + Some(out_expr) => AsmOperand::SplitInOut { + reg, + in_expr, + out_expr: Some(out_expr), + late: false, + }, + None => AsmOperand::InOut { reg, expr: in_expr, late: false }, + } + } else { + continue; + } } - } else if dir_spec.inlateout_token().is_some() { - let Some(op_expr) = op.asm_operand_expr() else { continue }; - let in_expr = self.collect_expr_opt(op_expr.in_expr()); - let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it)); - match out_expr { - Some(out_expr) => AsmOperand::SplitInOut { - reg, - in_expr, - out_expr: Some(out_expr), - late: false, - }, - None => AsmOperand::InOut { reg, expr: in_expr, late: false }, + ast::AsmOperand::AsmLabel(l) => { + AsmOperand::Label(self.collect_block_opt(l.block_expr())) + } + ast::AsmOperand::AsmConst(c) => { + AsmOperand::Const(self.collect_expr_opt(c.expr())) + } + ast::AsmOperand::AsmSym(s) => { + let Some(path) = + s.path().and_then(|p| self.expander.parse_path(self.db, p)) + else { + continue; + }; + AsmOperand::Sym(path) } - } else { - continue; } } - ast::AsmOperand::AsmLabel(l) => { - AsmOperand::Label(self.collect_block_opt(l.block_expr())) - } - ast::AsmOperand::AsmConst(c) => AsmOperand::Const(self.collect_expr_opt(c.expr())), - ast::AsmOperand::AsmSym(s) => { - let Some(path) = s.path().and_then(|p| self.expander.parse_path(self.db, p)) - else { - continue; - }; - AsmOperand::Sym(path) - } }; operands.push(op); } @@ -192,7 +202,7 @@ impl ExprCollector<'_> { rustc_parse_format::Piece::NextArgument(arg) => { // let span = arg_spans.next(); - let _operand_idx = match arg.position { + let operand_idx = match arg.position { rustc_parse_format::ArgumentIs(idx) | rustc_parse_format::ArgumentImplicitlyIs(idx) => { if idx >= operands.len() @@ -206,15 +216,15 @@ impl ExprCollector<'_> { } rustc_parse_format::ArgumentNamed(name) => { let name = Symbol::intern(name); - if let Some(position_span) = to_span(arg.position_span) { - mappings.push(( - position_span, - Name::new_symbol_root(name.clone()), - )); - } named_args.get(&name).copied() } }; + + if let Some(operand_idx) = operand_idx { + if let Some(position_span) = to_span(arg.position_span) { + mappings.push((position_span, operand_idx)); + } + } } } } @@ -224,7 +234,7 @@ impl ExprCollector<'_> { Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }), syntax_ptr, ); - self.source_map.format_args_template_map.insert(idx, mappings); + self.source_map.template_map.get_or_insert_with(Default::default).1.insert(idx, mappings); idx } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 81d6466c2f..c8b227123f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -43,7 +43,7 @@ use hir_def::{ body::{BodyDiagnostic, SyntheticSyntax}, data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, - hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, + hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode}, lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, @@ -5246,6 +5246,13 @@ impl Type { } } +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub struct InlineAsmOperand { + owner: DefWithBodyId, + expr: ExprId, + index: usize, +} + // FIXME: Document this #[derive(Debug)] pub struct Callable { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 4e6887295c..0ba0e44657 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -47,9 +47,9 @@ use crate::{ source_analyzer::{resolve_hir_path, SourceAnalyzer}, Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile, - ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, - ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, - TypeParam, Union, Variant, VariantDef, + InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, + OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField, + Type, TypeAlias, TypeParam, Union, Variant, VariantDef, }; const CONTINUE_NO_BREAKS: ControlFlow = ControlFlow::Continue(()); @@ -546,11 +546,11 @@ impl<'db> SemanticsImpl<'db> { ) } - /// Retrieves all the formatting parts of the format_args! template string. + /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string. pub fn as_format_args_parts( &self, string: &ast::String, - ) -> Option)>> { + ) -> Option>)>> { let quote = string.open_quote_text_range()?; let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; @@ -560,14 +560,31 @@ impl<'db> SemanticsImpl<'db> { let string = ast::String::cast(token)?; let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; - let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?; - let source_analyzer = self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); - let res = source_analyzer - .as_format_args_parts(self.db, format_args.as_ref())? - .map(|(range, res)| (range + quote.end(), res)) - .collect(); - Some(res) + let parent = literal.parent()?; + if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { + let source_analyzer = self.analyze_no_infer(format_args.syntax())?; + let format_args = self.wrap_node_infile(format_args); + let res = source_analyzer + .as_format_args_parts(self.db, format_args.as_ref())? + .map(|(range, res)| (range + quote.end(), res.map(Either::Left))) + .collect(); + Some(res) + } else { + let asm = ast::AsmExpr::cast(parent)?; + let source_analyzer = self.analyze_no_infer(asm.syntax())?; + let asm = self.wrap_node_infile(asm); + let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?; + let res = asm_parts + .iter() + .map(|&(range, index)| { + ( + range + quote.end(), + Some(Either::Right(InlineAsmOperand { owner, expr, index })), + ) + }) + .collect(); + Some(res) + } })() .map_or(ControlFlow::Continue(()), ControlFlow::Break) }) @@ -578,7 +595,7 @@ impl<'db> SemanticsImpl<'db> { &self, original_token: SyntaxToken, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { let original_string = ast::String::cast(original_token.clone())?; let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; let quote = original_string.open_quote_text_range()?; @@ -599,13 +616,26 @@ impl<'db> SemanticsImpl<'db> { &self, string: ast::String, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; - let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?; - let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); - source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) + let parent = literal.parent()?; + if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { + let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; + let format_args = self.wrap_node_infile(format_args); + source_analyzer + .resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) + .map(|(range, res)| (range, res.map(Either::Left))) + } else { + let asm = ast::AsmExpr::cast(parent)?; + let source_analyzer = &self.analyze_no_infer(asm.syntax())?; + let asm = self.wrap_node_infile(asm); + source_analyzer.resolve_offset_in_asm_template(asm.as_ref(), offset).map( + |(owner, (expr, range, index))| { + (range, Some(Either::Right(InlineAsmOperand { owner, expr, index }))) + }, + ) + } } /// Maps a node down by mapping its first and last token down. @@ -1781,6 +1811,7 @@ to_def_impls![ (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), + (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def), (MacroCallId, ast::MacroCall, macro_call_to_macro_call), ]; diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index edeb19030a..fc629b9c6d 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -110,7 +110,7 @@ use syntax::{ AstNode, AstPtr, SyntaxNode, }; -use crate::{db::HirDatabase, InFile}; +use crate::{db::HirDatabase, InFile, InlineAsmOperand}; #[derive(Default)] pub(super) struct SourceToDefCache { @@ -273,6 +273,25 @@ impl SourceToDefCtx<'_, '_> { ast::Adt::Union(it) => self.union_to_def(InFile::new(file_id, it)).map(AdtId::UnionId), } } + + pub(super) fn asm_operand_to_def( + &mut self, + src: InFile<&ast::AsmOperandNamed>, + ) -> Option { + let asm = src.value.syntax().parent().and_then(ast::AsmExpr::cast)?; + let index = asm + .asm_pieces() + .filter_map(|it| match it { + ast::AsmPiece::AsmOperandNamed(it) => Some(it), + _ => None, + }) + .position(|it| it == *src.value)?; + let container = self.find_pat_or_label_container(src.syntax_ref())?; + let (_, source_map) = self.db.body_with_source_map(container); + let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?; + Some(InlineAsmOperand { owner: container, expr, index }) + } + pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index be0116862b..f6f1da1b7d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -904,6 +904,20 @@ impl SourceAnalyzer { }) } + pub(crate) fn resolve_offset_in_asm_template( + &self, + asm: InFile<&ast::AsmExpr>, + offset: TextSize, + ) -> Option<(DefWithBodyId, (ExprId, TextRange, usize))> { + let (def, _, body_source_map) = self.def.as_ref()?; + let (expr, args) = body_source_map.asm_template_args(asm)?; + Some(*def).zip( + args.iter() + .find(|(range, _)| range.contains_inclusive(offset)) + .map(|(range, idx)| (expr, *range, *idx)), + ) + } + pub(crate) fn as_format_args_parts<'a>( &'a self, db: &'a dyn HirDatabase, @@ -927,6 +941,14 @@ impl SourceAnalyzer { )) } + pub(crate) fn as_asm_parts( + &self, + asm: InFile<&ast::AsmExpr>, + ) -> Option<(DefWithBodyId, (ExprId, &[(TextRange, usize)]))> { + let (def, _, body_source_map) = self.def.as_ref()?; + Some(*def).zip(body_source_map.asm_template_args(asm)) + } + fn resolve_impl_method_or_trait_def( &self, db: &dyn HirDatabase, diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 469f83644f..c134c9f672 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -10,8 +10,8 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, - Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, - ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, + Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro, + Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use span::Edition; @@ -51,7 +51,7 @@ pub enum Definition { ToolModule(ToolModule), ExternCrateDecl(ExternCrateDecl), InlineAsmRegOrRegClass(()), - InlineAsmRegOperand(()), + InlineAsmOperand(InlineAsmOperand), } impl Definition { @@ -91,7 +91,7 @@ impl Definition { | Definition::TupleField(_) | Definition::ToolModule(_) | Definition::InlineAsmRegOrRegClass(_) - | Definition::InlineAsmRegOperand(_) => return None, + | Definition::InlineAsmOperand(_) => return None, }; Some(module) } @@ -127,7 +127,7 @@ impl Definition { | Definition::Label(_) | Definition::DeriveHelper(_) | Definition::InlineAsmRegOrRegClass(_) - | Definition::InlineAsmRegOperand(_) => return None, + | Definition::InlineAsmOperand(_) => return None, }; Some(vis) } @@ -156,9 +156,7 @@ impl Definition { Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), Definition::ExternCrateDecl(it) => return it.alias_or_name(db), - Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmRegOperand(_) => { - return None - } // FIXME + Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => return None, // FIXME }; Some(name) } @@ -221,7 +219,7 @@ impl Definition { Definition::ToolModule(_) => None, Definition::DeriveHelper(_) => None, Definition::TupleField(_) => None, - Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmRegOperand(_) => None, + Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => None, }; docs.or_else(|| { @@ -280,7 +278,7 @@ impl Definition { } // FIXME Definition::InlineAsmRegOrRegClass(_) => "inline_asm_reg_or_reg_class".to_owned(), - Definition::InlineAsmRegOperand(_) => "inline_asm_reg_operand".to_owned(), + Definition::InlineAsmOperand(_) => "inline_asm_reg_operand".to_owned(), } } } @@ -442,7 +440,6 @@ impl NameClass { let _p = tracing::info_span!("NameClass::classify").entered(); let parent = name.syntax().parent()?; - let definition = match_ast! { match parent { ast::Item(it) => classify_item(sema, it)?, @@ -453,6 +450,7 @@ impl NameClass { ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), + ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?), _ => return None, } }; @@ -769,6 +767,18 @@ impl From for Definition { } } +impl From for Definition { + fn from(value: InlineAsmOperand) -> Self { + Definition::InlineAsmOperand(value) + } +} + +impl From> for Definition { + fn from(value: Either) -> Self { + value.either(Definition::from, Definition::from) + } +} + impl AsAssocItem for Definition { fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index e8299a4a46..0435b2f0c6 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -208,7 +208,7 @@ impl Definition { | Definition::TupleField(_) | Definition::InlineAsmRegOrRegClass(_) => return None, // FIXME: - Definition::InlineAsmRegOperand(_) => return None, + Definition::InlineAsmOperand(_) => return None, // FIXME: This should be doable in theory Definition::DeriveHelper(_) => return None, }; diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 12ce5a403f..4d0668ffea 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -8,10 +8,11 @@ use std::mem; use std::{cell::LazyCell, cmp::Reverse}; use base_db::{salsa::Database, SourceDatabase, SourceRootDatabase}; +use either::Either; use hir::{ sym, Adt, AsAssocItem, DefWithBody, FileRange, FileRangeWrapper, HasAttrs, HasContainer, - HasSource, HirFileIdExt, InFile, InFileWrapper, InRealFile, ItemContainer, ModuleSource, - PathResolution, Semantics, Visibility, + HasSource, HirFileIdExt, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, + ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; use parser::SyntaxKind; @@ -917,7 +918,7 @@ impl<'a> FindUsages<'a> { for offset in Self::match_indices(&text, finder, search_range) { tree.token_at_offset(offset).for_each(|token| { let Some(str_token) = ast::String::cast(token.clone()) else { return }; - if let Some((range, nameres)) = + if let Some((range, Some(nameres))) = sema.check_for_format_args_template(token, offset) { if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {} @@ -1087,19 +1088,19 @@ impl<'a> FindUsages<'a> { file_id: EditionedFileId, range: TextRange, token: ast::String, - res: Option, + res: Either, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { - match res.map(Definition::from) { - Some(def) if def == self.def => { - let reference = FileReference { - range, - name: FileReferenceNode::FormatStringEntry(token, range), - category: ReferenceCategory::READ, - }; - sink(file_id, reference) - } - _ => false, + let def = res.either(Definition::from, Definition::from); + if def == self.def { + let reference = FileReference { + range, + name: FileReferenceNode::FormatStringEntry(token, range), + category: ReferenceCategory::READ, + }; + sink(file_id, reference) + } else { + false } } diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 184486ec0a..ea16a11d56 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -221,7 +221,7 @@ pub(crate) fn resolve_doc_path_for_def( | Definition::Label(_) | Definition::DeriveHelper(_) | Definition::InlineAsmRegOrRegClass(_) - | Definition::InlineAsmRegOperand(_) => None, + | Definition::InlineAsmOperand(_) => None, } .map(Definition::from) } @@ -676,7 +676,7 @@ fn filename_and_frag_for_def( | Definition::ToolModule(_) | Definition::DeriveHelper(_) | Definition::InlineAsmRegOrRegClass(_) - | Definition::InlineAsmRegOperand(_) => return None, + | Definition::InlineAsmOperand(_) => return None, }; Some((def, res, None)) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 1f996f716d..14781b2129 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -223,7 +223,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Variable } } - Definition::Label(..) | Definition::InlineAsmRegOperand(_) => Variable, // For lack of a better variant + Definition::Label(..) | Definition::InlineAsmOperand(_) => Variable, // For lack of a better variant Definition::DeriveHelper(..) => Attribute, Definition::BuiltinAttr(..) => Attribute, Definition::ToolModule(..) => Module, @@ -323,7 +323,7 @@ pub(crate) fn def_to_moniker( | Definition::BuiltinAttr(_) | Definition::ToolModule(_) | Definition::InlineAsmRegOrRegClass(_) - | Definition::InlineAsmRegOperand(_) => return None, + | Definition::InlineAsmOperand(_) => return None, Definition::Local(local) => { if !local.is_param(db) { diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index eb28b78e60..68039ef309 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -245,7 +245,7 @@ impl TryToNav for Definition { | Definition::InlineAsmRegOrRegClass(_) | Definition::BuiltinAttr(_) => None, // FIXME - Definition::InlineAsmRegOperand(_) => None, + Definition::InlineAsmOperand(_) => None, // FIXME: The focus range should be set to the helper declaration Definition::DeriveHelper(it) => it.derive().try_to_nav(db), } diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 518e714547..7234108701 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs @@ -19,21 +19,21 @@ pub(super) fn highlight_format_string( expanded_string: &ast::String, range: TextRange, ) { - if !is_format_string(expanded_string) { + if is_format_string(expanded_string) { + // FIXME: Replace this with the HIR info we have now. + lex_format_specifiers(string, &mut |piece_range, kind| { + if let Some(highlight) = highlight_format_specifier(kind) { + stack.add(HlRange { + range: piece_range + range.start(), + highlight: highlight.into(), + binding_hash: None, + }); + } + }); + return; } - // FIXME: Replace this with the HIR info we have now. - lex_format_specifiers(string, &mut |piece_range, kind| { - if let Some(highlight) = highlight_format_specifier(kind) { - stack.add(HlRange { - range: piece_range + range.start(), - highlight: highlight.into(), - binding_hash: None, - }); - } - }); - if let Some(parts) = sema.as_format_args_parts(string) { parts.into_iter().for_each(|(range, res)| { if let Some(res) = res { diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index fe1d0b452a..96375937a1 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -537,7 +537,7 @@ pub(super) fn highlight_def( Definition::InlineAsmRegOrRegClass(_) => { Highlight::new(HlTag::Symbol(SymbolKind::InlineAsmRegOrRegClass)) } - Definition::InlineAsmRegOperand(_) => Highlight::new(HlTag::Symbol(SymbolKind::Local)), + Definition::InlineAsmOperand(_) => Highlight::new(HlTag::Symbol(SymbolKind::Local)), }; let def_crate = def.krate(db); diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index bff52943af..5583f1bc8d 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -316,7 +316,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::ToolModule(_) => SymbolKind::ToolModule, Definition::DeriveHelper(_) => SymbolKind::DeriveHelper, Definition::InlineAsmRegOrRegClass(_) => SymbolKind::InlineAsmRegOrRegClass, - Definition::InlineAsmRegOperand(_) => SymbolKind::Local, + Definition::InlineAsmOperand(_) => SymbolKind::Local, }; HlTag::Symbol(symbol) } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html b/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html index 9cedf012f7..d322a374b3 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html @@ -50,17 +50,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let foo = 1; let mut o = 0; core::arch::asm!( - "%input = OpLoad _ {0}", + "%input = OpLoad _ {0}", concat!("%result = ", "bar", " _ %input"), - "OpStore {1} %result", + "OpStore {1} %result", in(reg) &foo, in(reg) &mut o, ); let thread_id: usize; core::arch::asm!(" - mov {0}, gs:[0x30] - mov {0}, [{0}+0x48] + mov {0}, gs:[0x30] + mov {0}, [{0}+0x48] ", out(reg) thread_id, options(pure, readonly, nostack)); static UNMAP_BASE: usize; @@ -69,28 +69,28 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd const OffPtr: usize; const OffFn: usize; core::arch::asm!(" - push {free_type} - push {free_size} - push {base} + push {free_type} + push {free_size} + push {base} mov eax, fs:[30h] mov eax, [eax+8h] - add eax, {off_fn} - mov [eax-{off_fn}+{off_ptr}], eax + add eax, {off_fn} + mov [eax-{off_fn}+{off_ptr}], eax push eax - jmp {virtual_free} + jmp {virtual_free} ", - off_ptr = const OffPtr, - off_fn = const OffFn, + off_ptr = const OffPtr, + off_fn = const OffFn, - free_size = const 0, - free_type = const MEM_RELEASE, + free_size = const 0, + free_type = const MEM_RELEASE, - virtual_free = sym VirtualFree, + virtual_free = sym VirtualFree, - base = sym UNMAP_BASE, + base = sym UNMAP_BASE, options(noreturn), ); } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index b387808b29..37bbc1e1ee 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -166,8 +166,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let i: u64 = 3; let o: u64; core::arch::asm!( - "mov {0}, {1}", - "add {0}, 5", + "mov {0}, {1}", + "add {0}, 5", out(reg) o, in(reg) i, ); @@ -175,6 +175,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd const CONSTANT: () = (): let mut m = (); format_args!(concat!("{}"), "{}"); - format_args!("{} {} {} {} {} {} {backslash} {CONSTANT} {m}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash); - reuse_twice!("{backslash}"); + format_args!("{} {} {} {} {} {} {backslash} {CONSTANT} {m}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash); + reuse_twice!("{backslash}"); } \ No newline at end of file diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index d6ccf38e74..39ca26fc50 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs @@ -329,11 +329,11 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { break; } - let op = p.start(); + let op_n = p.start(); // Parse clobber_abi if p.eat_contextual_kw(T![clobber_abi]) { parse_clobber_abi(p); - op.complete(p, ASM_CLOBBER_ABI); + op_n.complete(p, ASM_CLOBBER_ABI); allow_templates = false; continue; } @@ -341,7 +341,7 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { // Parse options if p.eat_contextual_kw(T![options]) { parse_options(p); - op.complete(p, ASM_OPTIONS); + op_n.complete(p, ASM_OPTIONS); allow_templates = false; continue; } @@ -356,12 +356,14 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { false }; + let op = p.start(); let dir_spec = p.start(); if p.eat(T![in]) || p.eat_contextual_kw(T![out]) || p.eat_contextual_kw(T![lateout]) { dir_spec.complete(p, ASM_DIR_SPEC); parse_reg(p); expr(p); op.complete(p, ASM_REG_OPERAND); + op_n.complete(p, ASM_OPERAND_NAMED); } else if p.eat_contextual_kw(T![inout]) || p.eat_contextual_kw(T![inlateout]) { dir_spec.complete(p, ASM_DIR_SPEC); parse_reg(p); @@ -370,21 +372,26 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { expr(p); } op.complete(p, ASM_REG_OPERAND); + op_n.complete(p, ASM_OPERAND_NAMED); } else if p.eat_contextual_kw(T![label]) { dir_spec.abandon(p); block_expr(p); - op.complete(p, ASM_LABEL); + op.complete(p, ASM_OPERAND_NAMED); + op_n.complete(p, ASM_LABEL); } else if p.eat(T![const]) { dir_spec.abandon(p); expr(p); op.complete(p, ASM_CONST); + op_n.complete(p, ASM_OPERAND_NAMED); } else if p.eat_contextual_kw(T![sym]) { dir_spec.abandon(p); paths::type_path(p); op.complete(p, ASM_SYM); + op_n.complete(p, ASM_OPERAND_NAMED); } else if allow_templates { dir_spec.abandon(p); op.abandon(p); + op_n.abandon(p); if expr(p).is_none() { p.err_and_bump("expected asm template"); } @@ -392,6 +399,7 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { } else { dir_spec.abandon(p); op.abandon(p); + op_n.abandon(p); p.err_and_bump("expected asm operand"); if p.at(T!['}']) { break; diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index ee3adac158..288a07ef44 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -169,8 +169,10 @@ pub enum SyntaxKind { ASM_LABEL, ASM_OPERAND, ASM_OPERAND_EXPR, + ASM_OPERAND_NAMED, ASM_OPTION, ASM_OPTIONS, + ASM_PIECE, ASM_REG_OPERAND, ASM_REG_SPEC, ASM_SYM, diff --git a/crates/parser/test_data/parser/inline/ok/asm_expr.rast b/crates/parser/test_data/parser/inline/ok/asm_expr.rast index 2360135db7..4afa9daf59 100644 --- a/crates/parser/test_data/parser/inline/ok/asm_expr.rast +++ b/crates/parser/test_data/parser/inline/ok/asm_expr.rast @@ -35,43 +35,45 @@ SOURCE_FILE STRING "\"add {x}, {tmp}\"" COMMA "," WHITESPACE "\n " - ASM_REG_OPERAND + ASM_OPERAND_NAMED NAME IDENT "x" WHITESPACE " " EQ "=" WHITESPACE " " - ASM_DIR_SPEC - INOUT_KW "inout" - L_PAREN "(" - ASM_REG_SPEC - NAME_REF - IDENT "reg" - R_PAREN ")" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" + ASM_REG_OPERAND + ASM_DIR_SPEC + INOUT_KW "inout" + L_PAREN "(" + ASM_REG_SPEC + NAME_REF + IDENT "reg" + R_PAREN ")" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" COMMA "," WHITESPACE "\n " - ASM_REG_OPERAND + ASM_OPERAND_NAMED NAME IDENT "tmp" WHITESPACE " " EQ "=" WHITESPACE " " - ASM_DIR_SPEC - OUT_KW "out" - L_PAREN "(" - ASM_REG_SPEC - NAME_REF - IDENT "reg" - R_PAREN ")" - WHITESPACE " " - UNDERSCORE_EXPR - UNDERSCORE "_" + ASM_REG_OPERAND + ASM_DIR_SPEC + OUT_KW "out" + L_PAREN "(" + ASM_REG_SPEC + NAME_REF + IDENT "reg" + R_PAREN ")" + WHITESPACE " " + UNDERSCORE_EXPR + UNDERSCORE "_" COMMA "," WHITESPACE "\n " R_PAREN ")" diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 5dace66c32..52ad439e4d 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -395,7 +395,7 @@ OffsetOfExpr = // global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")" // format_string := STRING_LITERAL / RAW_STRING_LITERAL AsmExpr = - Attr* 'builtin' '#' 'asm' '(' template:(Expr (',' Expr)*) (AsmOperand (',' AsmOperand)*)? ','? ')' + Attr* 'builtin' '#' 'asm' '(' template:(Expr (',' Expr)*) (AsmPiece (',' AsmPiece)*)? ','? ')' // operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" AsmOperandExpr = in_expr:Expr ('=>' out_expr:Expr)? @@ -404,7 +404,7 @@ AsmDirSpec = 'in' | 'out' | 'lateout' | 'inout' | 'inlateout' // reg_spec := / "\"" "\"" AsmRegSpec = '@string' | NameRef // reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr -AsmRegOperand = (Name '=')? AsmDirSpec '(' AsmRegSpec ')' AsmOperandExpr +AsmRegOperand = AsmDirSpec '(' AsmRegSpec ')' AsmOperandExpr // clobber_abi := "clobber_abi(" *("," ) [","] ")" AsmClobberAbi = 'clobber_abi' '(' ('@string' (',' '@string')* ','?) ')' // option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" @@ -415,7 +415,9 @@ AsmLabel = 'label' BlockExpr AsmSym = 'sym' Path AsmConst = 'const' Expr // operand := reg_operand / clobber_abi / options -AsmOperand = AsmRegOperand | AsmClobberAbi | AsmOptions | AsmLabel | AsmSym | AsmConst +AsmOperand = AsmRegOperand | AsmLabel | AsmSym | AsmConst +AsmOperandNamed = (Name '=')? AsmOperand +AsmPiece = AsmOperandNamed | AsmClobberAbi | AsmOptions FormatArgsExpr = Attr* 'builtin' '#' 'format_args' '(' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 01d47c34bb..c81a19f3bd 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -118,7 +118,7 @@ pub struct AsmExpr { impl ast::HasAttrs for AsmExpr {} impl AsmExpr { #[inline] - pub fn asm_operands(&self) -> AstChildren { support::children(&self.syntax) } + pub fn asm_pieces(&self) -> AstChildren { support::children(&self.syntax) } #[inline] pub fn template(&self) -> AstChildren { support::children(&self.syntax) } #[inline] @@ -159,6 +159,18 @@ impl AsmOperandExpr { pub fn fat_arrow_token(&self) -> Option { support::token(&self.syntax, T![=>]) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmOperandNamed { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasName for AsmOperandNamed {} +impl AsmOperandNamed { + #[inline] + pub fn asm_operand(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AsmOption { pub(crate) syntax: SyntaxNode, @@ -217,7 +229,6 @@ impl AsmOptions { pub struct AsmRegOperand { pub(crate) syntax: SyntaxNode, } -impl ast::HasName for AsmRegOperand {} impl AsmRegOperand { #[inline] pub fn asm_dir_spec(&self) -> Option { support::child(&self.syntax) } @@ -229,8 +240,6 @@ impl AsmRegOperand { pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } #[inline] pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } - #[inline] - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2224,14 +2233,19 @@ impl ast::HasVisibility for Adt {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum AsmOperand { - AsmClobberAbi(AsmClobberAbi), AsmConst(AsmConst), AsmLabel(AsmLabel), - AsmOptions(AsmOptions), AsmRegOperand(AsmRegOperand), AsmSym(AsmSym), } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum AsmPiece { + AsmClobberAbi(AsmClobberAbi), + AsmOperandNamed(AsmOperandNamed), + AsmOptions(AsmOptions), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum AssocItem { Const(Const), @@ -2581,6 +2595,20 @@ impl AstNode for AsmOperandExpr { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for AsmOperandNamed { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for AsmOption { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION } @@ -4589,10 +4617,6 @@ impl AstNode for Adt { } } } -impl From for AsmOperand { - #[inline] - fn from(node: AsmClobberAbi) -> AsmOperand { AsmOperand::AsmClobberAbi(node) } -} impl From for AsmOperand { #[inline] fn from(node: AsmConst) -> AsmOperand { AsmOperand::AsmConst(node) } @@ -4601,10 +4625,6 @@ impl From for AsmOperand { #[inline] fn from(node: AsmLabel) -> AsmOperand { AsmOperand::AsmLabel(node) } } -impl From for AsmOperand { - #[inline] - fn from(node: AsmOptions) -> AsmOperand { AsmOperand::AsmOptions(node) } -} impl From for AsmOperand { #[inline] fn from(node: AsmRegOperand) -> AsmOperand { AsmOperand::AsmRegOperand(node) } @@ -4616,18 +4636,13 @@ impl From for AsmOperand { impl AstNode for AsmOperand { #[inline] fn can_cast(kind: SyntaxKind) -> bool { - matches!( - kind, - ASM_CLOBBER_ABI | ASM_CONST | ASM_LABEL | ASM_OPTIONS | ASM_REG_OPERAND | ASM_SYM - ) + matches!(kind, ASM_CONST | ASM_LABEL | ASM_REG_OPERAND | ASM_SYM) } #[inline] fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { - ASM_CLOBBER_ABI => AsmOperand::AsmClobberAbi(AsmClobberAbi { syntax }), ASM_CONST => AsmOperand::AsmConst(AsmConst { syntax }), ASM_LABEL => AsmOperand::AsmLabel(AsmLabel { syntax }), - ASM_OPTIONS => AsmOperand::AsmOptions(AsmOptions { syntax }), ASM_REG_OPERAND => AsmOperand::AsmRegOperand(AsmRegOperand { syntax }), ASM_SYM => AsmOperand::AsmSym(AsmSym { syntax }), _ => return None, @@ -4637,15 +4652,49 @@ impl AstNode for AsmOperand { #[inline] fn syntax(&self) -> &SyntaxNode { match self { - AsmOperand::AsmClobberAbi(it) => &it.syntax, AsmOperand::AsmConst(it) => &it.syntax, AsmOperand::AsmLabel(it) => &it.syntax, - AsmOperand::AsmOptions(it) => &it.syntax, AsmOperand::AsmRegOperand(it) => &it.syntax, AsmOperand::AsmSym(it) => &it.syntax, } } } +impl From for AsmPiece { + #[inline] + fn from(node: AsmClobberAbi) -> AsmPiece { AsmPiece::AsmClobberAbi(node) } +} +impl From for AsmPiece { + #[inline] + fn from(node: AsmOperandNamed) -> AsmPiece { AsmPiece::AsmOperandNamed(node) } +} +impl From for AsmPiece { + #[inline] + fn from(node: AsmOptions) -> AsmPiece { AsmPiece::AsmOptions(node) } +} +impl AstNode for AsmPiece { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, ASM_CLOBBER_ABI | ASM_OPERAND_NAMED | ASM_OPTIONS) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ASM_CLOBBER_ABI => AsmPiece::AsmClobberAbi(AsmClobberAbi { syntax }), + ASM_OPERAND_NAMED => AsmPiece::AsmOperandNamed(AsmOperandNamed { syntax }), + ASM_OPTIONS => AsmPiece::AsmOptions(AsmOptions { syntax }), + _ => return None, + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + AsmPiece::AsmClobberAbi(it) => &it.syntax, + AsmPiece::AsmOperandNamed(it) => &it.syntax, + AsmPiece::AsmOptions(it) => &it.syntax, + } + } +} impl From for AssocItem { #[inline] fn from(node: Const) -> AssocItem { AssocItem::Const(node) } @@ -6181,7 +6230,7 @@ impl AstNode for AnyHasName { fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - ASM_REG_OPERAND + ASM_OPERAND_NAMED | CONST | CONST_PARAM | ENUM @@ -6211,9 +6260,9 @@ impl AstNode for AnyHasName { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } -impl From for AnyHasName { +impl From for AnyHasName { #[inline] - fn from(node: AsmRegOperand) -> AnyHasName { AnyHasName { syntax: node.syntax } } + fn from(node: AsmOperandNamed) -> AnyHasName { AnyHasName { syntax: node.syntax } } } impl From for AnyHasName { #[inline] @@ -6460,6 +6509,11 @@ impl std::fmt::Display for AsmOperand { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AsmPiece { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AssocItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -6560,6 +6614,11 @@ impl std::fmt::Display for AsmOperandExpr { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AsmOperandNamed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AsmOption { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f)