Skip to content

Commit bdb734b

Browse files
committed
Support more IDE features for asm operands
1 parent f3b6965 commit bdb734b

File tree

13 files changed

+180
-40
lines changed

13 files changed

+180
-40
lines changed

src/tools/rust-analyzer/crates/hir-def/src/body.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub struct BodySourceMap {
105105
// format_args!
106106
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
107107
// asm!
108-
FxHashMap<ExprId, Vec<(syntax::TextRange, usize)>>,
108+
FxHashMap<ExprId, Vec<(syntax::TextRange, usize, Option<Name>)>>,
109109
)>,
110110
>,
111111

@@ -439,7 +439,7 @@ impl BodySourceMap {
439439
pub fn asm_template_args(
440440
&self,
441441
node: InFile<&ast::AsmExpr>,
442-
) -> Option<(ExprId, &[(syntax::TextRange, usize)])> {
442+
) -> Option<(ExprId, &[(syntax::TextRange, usize, Option<Name>)])> {
443443
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
444444
let expr = self.expr_map.get(&src)?;
445445
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
@@ -482,4 +482,13 @@ impl BodySourceMap {
482482
diagnostics.shrink_to_fit();
483483
binding_definitions.shrink_to_fit();
484484
}
485+
486+
pub fn template_map(
487+
&self,
488+
) -> Option<&(
489+
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
490+
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, usize, Option<Name>)>>,
491+
)> {
492+
self.template_map.as_deref()
493+
}
485494
}

src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use hir_expand::name::Name;
12
use intern::Symbol;
23
use rustc_hash::{FxHashMap, FxHashSet};
34
use syntax::{
@@ -202,27 +203,30 @@ impl ExprCollector<'_> {
202203
rustc_parse_format::Piece::NextArgument(arg) => {
203204
// let span = arg_spans.next();
204205

205-
let operand_idx = match arg.position {
206+
let (operand_idx, name) = match arg.position {
206207
rustc_parse_format::ArgumentIs(idx)
207208
| rustc_parse_format::ArgumentImplicitlyIs(idx) => {
208209
if idx >= operands.len()
209210
|| named_pos.contains_key(&idx)
210211
|| reg_args.contains(&idx)
211212
{
212-
None
213+
(None, None)
213214
} else {
214-
Some(idx)
215+
(Some(idx), None)
215216
}
216217
}
217218
rustc_parse_format::ArgumentNamed(name) => {
218219
let name = Symbol::intern(name);
219-
named_args.get(&name).copied()
220+
(
221+
named_args.get(&name).copied(),
222+
Some(Name::new_symbol_root(name)),
223+
)
220224
}
221225
};
222226

223227
if let Some(operand_idx) = operand_idx {
224228
if let Some(position_span) = to_span(arg.position_span) {
225-
mappings.push((position_span, operand_idx));
229+
mappings.push((position_span, operand_idx, name));
226230
}
227231
}
228232
}

src/tools/rust-analyzer/crates/hir/src/has_source.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use tt::TextRange;
1414

1515
use crate::{
1616
db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
17-
Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait,
18-
TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant,
17+
InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static,
18+
Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant,
1919
};
2020

2121
pub trait HasSource {
@@ -292,3 +292,26 @@ impl HasSource for ExternCrateDecl {
292292
Some(self.id.lookup(db.upcast()).source(db.upcast()))
293293
}
294294
}
295+
296+
impl HasSource for InlineAsmOperand {
297+
type Ast = ast::AsmOperandNamed;
298+
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
299+
let (_body, source_map) = db.body_with_source_map(self.owner);
300+
if let Ok(src) = source_map.expr_syntax(self.expr) {
301+
let root = src.file_syntax(db.upcast());
302+
return src
303+
.map(|ast| match ast.to_node(&root) {
304+
ast::Expr::AsmExpr(asm) => asm
305+
.asm_pieces()
306+
.filter_map(|it| match it {
307+
ast::AsmPiece::AsmOperandNamed(it) => Some(it),
308+
_ => None,
309+
})
310+
.nth(self.index),
311+
_ => None,
312+
})
313+
.transpose();
314+
}
315+
None
316+
}
317+
}

src/tools/rust-analyzer/crates/hir/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5253,6 +5253,22 @@ pub struct InlineAsmOperand {
52535253
index: usize,
52545254
}
52555255

5256+
impl InlineAsmOperand {
5257+
pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
5258+
self.owner.into()
5259+
}
5260+
5261+
pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
5262+
db.body_with_source_map(self.owner)
5263+
.1
5264+
.template_map()?
5265+
.1
5266+
.get(&self.expr)?
5267+
.get(self.index)
5268+
.and_then(|(_, _, name)| name.clone())
5269+
}
5270+
}
5271+
52565272
// FIXME: Document this
52575273
#[derive(Debug)]
52585274
pub struct Callable {

src/tools/rust-analyzer/crates/hir/src/semantics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ impl<'db> SemanticsImpl<'db> {
576576
let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?;
577577
let res = asm_parts
578578
.iter()
579-
.map(|&(range, index)| {
579+
.map(|&(range, index, _)| {
580580
(
581581
range + quote.end(),
582582
Some(Either::Right(InlineAsmOperand { owner, expr, index })),

src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,8 @@ impl SourceAnalyzer {
913913
let (expr, args) = body_source_map.asm_template_args(asm)?;
914914
Some(*def).zip(
915915
args.iter()
916-
.find(|(range, _)| range.contains_inclusive(offset))
917-
.map(|(range, idx)| (expr, *range, *idx)),
916+
.find(|(range, _, _)| range.contains_inclusive(offset))
917+
.map(|(range, idx, _)| (expr, *range, *idx)),
918918
)
919919
}
920920

@@ -944,7 +944,7 @@ impl SourceAnalyzer {
944944
pub(crate) fn as_asm_parts(
945945
&self,
946946
asm: InFile<&ast::AsmExpr>,
947-
) -> Option<(DefWithBodyId, (ExprId, &[(TextRange, usize)]))> {
947+
) -> Option<(DefWithBodyId, (ExprId, &[(TextRange, usize, Option<Name>)]))> {
948948
let (def, _, body_source_map) = self.def.as_ref()?;
949949
Some(*def).zip(body_source_map.asm_template_args(asm))
950950
}

src/tools/rust-analyzer/crates/ide-db/src/defs.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ impl Definition {
8585
Definition::Label(it) => it.module(db),
8686
Definition::ExternCrateDecl(it) => it.module(db),
8787
Definition::DeriveHelper(it) => it.derive().module(db),
88+
Definition::InlineAsmOperand(it) => it.parent(db).module(db),
8889
Definition::BuiltinAttr(_)
8990
| Definition::BuiltinType(_)
9091
| Definition::BuiltinLifetime(_)
9192
| Definition::TupleField(_)
9293
| Definition::ToolModule(_)
93-
| Definition::InlineAsmRegOrRegClass(_)
94-
| Definition::InlineAsmOperand(_) => return None,
94+
| Definition::InlineAsmRegOrRegClass(_) => return None,
9595
};
9696
Some(module)
9797
}
@@ -156,7 +156,8 @@ impl Definition {
156156
Definition::ToolModule(_) => return None, // FIXME
157157
Definition::DeriveHelper(it) => it.name(db),
158158
Definition::ExternCrateDecl(it) => return it.alias_or_name(db),
159-
Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => return None, // FIXME
159+
Definition::InlineAsmRegOrRegClass(_) => return None,
160+
Definition::InlineAsmOperand(op) => return op.name(db),
160161
};
161162
Some(name)
162163
}

src/tools/rust-analyzer/crates/ide-db/src/rename.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,14 @@ impl Definition {
200200
.and_then(syn_ctx_is_root)
201201
}
202202
}
203+
Definition::InlineAsmOperand(it) => name_range(it, sema).and_then(syn_ctx_is_root),
203204
Definition::BuiltinType(_)
204205
| Definition::BuiltinLifetime(_)
205206
| Definition::BuiltinAttr(_)
206207
| Definition::SelfType(_)
207208
| Definition::ToolModule(_)
208209
| Definition::TupleField(_)
209210
| Definition::InlineAsmRegOrRegClass(_) => return None,
210-
// FIXME:
211-
Definition::InlineAsmOperand(_) => return None,
212211
// FIXME: This should be doable in theory
213212
Definition::DeriveHelper(_) => return None,
214213
};

src/tools/rust-analyzer/crates/ide-db/src/search.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,23 @@ impl Definition {
319319
};
320320
}
321321

322+
if let Definition::InlineAsmOperand(op) = self {
323+
let def = match op.parent(db) {
324+
DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
325+
DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
326+
DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
327+
DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()),
328+
// FIXME: implement
329+
DefWithBody::InTypeConst(_) => return SearchScope::empty(),
330+
};
331+
return match def {
332+
Some(def) => SearchScope::file_range(
333+
def.as_ref().original_file_range_with_macro_call_body(db),
334+
),
335+
None => SearchScope::single_file(file_id),
336+
};
337+
}
338+
322339
if let Definition::SelfType(impl_) = self {
323340
return match impl_.source(db).map(|src| src.syntax().cloned()) {
324341
Some(def) => SearchScope::file_range(
@@ -909,7 +926,6 @@ impl<'a> FindUsages<'a> {
909926
let finder = &Finder::new(name);
910927
let include_self_kw_refs =
911928
self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self")));
912-
913929
for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) {
914930
self.sema.db.unwind_if_cancelled();
915931
let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone());

src/tools/rust-analyzer/crates/ide/src/navigation_target.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,14 @@ impl TryToNav for Definition {
237237
Definition::Trait(it) => it.try_to_nav(db),
238238
Definition::TraitAlias(it) => it.try_to_nav(db),
239239
Definition::TypeAlias(it) => it.try_to_nav(db),
240-
Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
240+
Definition::ExternCrateDecl(it) => it.try_to_nav(db),
241+
Definition::InlineAsmOperand(it) => it.try_to_nav(db),
241242
Definition::BuiltinLifetime(_)
242243
| Definition::BuiltinType(_)
243244
| Definition::TupleField(_)
244245
| Definition::ToolModule(_)
245246
| Definition::InlineAsmRegOrRegClass(_)
246247
| Definition::BuiltinAttr(_) => None,
247-
// FIXME
248-
Definition::InlineAsmOperand(_) => None,
249248
// FIXME: The focus range should be set to the helper declaration
250249
Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
251250
}
@@ -696,6 +695,31 @@ impl TryToNav for hir::ConstParam {
696695
}
697696
}
698697

698+
impl TryToNav for hir::InlineAsmOperand {
699+
fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
700+
let InFile { file_id, value } = &self.source(db)?;
701+
let file_id = *file_id;
702+
Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
703+
|(FileRange { file_id, range: full_range }, focus_range)| {
704+
let edition = self.parent(db).module(db).krate().edition(db);
705+
NavigationTarget {
706+
file_id,
707+
name: self
708+
.name(db)
709+
.map_or_else(|| "_".into(), |it| it.display(db, edition).to_smolstr()),
710+
alias: None,
711+
kind: Some(SymbolKind::Local),
712+
full_range,
713+
focus_range,
714+
container_name: None,
715+
description: None,
716+
docs: None,
717+
}
718+
},
719+
))
720+
}
721+
}
722+
699723
#[derive(Debug)]
700724
pub struct UpmappingResult<T> {
701725
/// The macro call site.

src/tools/rust-analyzer/crates/ide/src/rename.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,54 @@ fn test() {
29752975
);
29762976
}
29772977

2978+
#[test]
2979+
fn asm_operand() {
2980+
check(
2981+
"bose",
2982+
r#"
2983+
//- minicore: asm
2984+
fn test() {
2985+
core::arch::asm!(
2986+
"push {base}",
2987+
base$0 = const 0
2988+
);
2989+
}
2990+
"#,
2991+
r#"
2992+
fn test() {
2993+
core::arch::asm!(
2994+
"push {bose}",
2995+
bose = const 0
2996+
);
2997+
}
2998+
"#,
2999+
);
3000+
}
3001+
3002+
#[test]
3003+
fn asm_operand2() {
3004+
check(
3005+
"bose",
3006+
r#"
3007+
//- minicore: asm
3008+
fn test() {
3009+
core::arch::asm!(
3010+
"push {base$0}",
3011+
base = const 0
3012+
);
3013+
}
3014+
"#,
3015+
r#"
3016+
fn test() {
3017+
core::arch::asm!(
3018+
"push {bose}",
3019+
bose = const 0
3020+
);
3021+
}
3022+
"#,
3023+
);
3024+
}
3025+
29783026
#[test]
29793027
fn rename_path_inside_use_tree() {
29803028
check(

0 commit comments

Comments
 (0)