Skip to content

Commit

Permalink
Support more IDE features for asm operands
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Sep 5, 2024
1 parent f3b6965 commit bdb734b
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 40 deletions.
13 changes: 11 additions & 2 deletions src/tools/rust-analyzer/crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub struct BodySourceMap {
// format_args!
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
// asm!
FxHashMap<ExprId, Vec<(syntax::TextRange, usize)>>,
FxHashMap<ExprId, Vec<(syntax::TextRange, usize, Option<Name>)>>,
)>,
>,

Expand Down Expand Up @@ -439,7 +439,7 @@ impl BodySourceMap {
pub fn asm_template_args(
&self,
node: InFile<&ast::AsmExpr>,
) -> Option<(ExprId, &[(syntax::TextRange, usize)])> {
) -> Option<(ExprId, &[(syntax::TextRange, usize, Option<Name>)])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
let expr = self.expr_map.get(&src)?;
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
Expand Down Expand Up @@ -482,4 +482,13 @@ impl BodySourceMap {
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
}

pub fn template_map(
&self,
) -> Option<&(
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, usize, Option<Name>)>>,
)> {
self.template_map.as_deref()
}
}
14 changes: 9 additions & 5 deletions src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use hir_expand::name::Name;
use intern::Symbol;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
Expand Down Expand Up @@ -202,27 +203,30 @@ impl ExprCollector<'_> {
rustc_parse_format::Piece::NextArgument(arg) => {
// let span = arg_spans.next();

let operand_idx = match arg.position {
let (operand_idx, name) = match arg.position {
rustc_parse_format::ArgumentIs(idx)
| rustc_parse_format::ArgumentImplicitlyIs(idx) => {
if idx >= operands.len()
|| named_pos.contains_key(&idx)
|| reg_args.contains(&idx)
{
None
(None, None)
} else {
Some(idx)
(Some(idx), None)
}
}
rustc_parse_format::ArgumentNamed(name) => {
let name = Symbol::intern(name);
named_args.get(&name).copied()
(
named_args.get(&name).copied(),
Some(Name::new_symbol_root(name)),
)
}
};

if let Some(operand_idx) = operand_idx {
if let Some(position_span) = to_span(arg.position_span) {
mappings.push((position_span, operand_idx));
mappings.push((position_span, operand_idx, name));
}
}
}
Expand Down
27 changes: 25 additions & 2 deletions src/tools/rust-analyzer/crates/hir/src/has_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use tt::TextRange;

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

pub trait HasSource {
Expand Down Expand Up @@ -292,3 +292,26 @@ impl HasSource for ExternCrateDecl {
Some(self.id.lookup(db.upcast()).source(db.upcast()))
}
}

impl HasSource for InlineAsmOperand {
type Ast = ast::AsmOperandNamed;
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
let (_body, source_map) = db.body_with_source_map(self.owner);
if let Ok(src) = source_map.expr_syntax(self.expr) {
let root = src.file_syntax(db.upcast());
return src
.map(|ast| match ast.to_node(&root) {
ast::Expr::AsmExpr(asm) => asm
.asm_pieces()
.filter_map(|it| match it {
ast::AsmPiece::AsmOperandNamed(it) => Some(it),
_ => None,
})
.nth(self.index),
_ => None,
})
.transpose();
}
None
}
}
16 changes: 16 additions & 0 deletions src/tools/rust-analyzer/crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5253,6 +5253,22 @@ pub struct InlineAsmOperand {
index: usize,
}

impl InlineAsmOperand {
pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
self.owner.into()
}

pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
db.body_with_source_map(self.owner)
.1
.template_map()?
.1
.get(&self.expr)?
.get(self.index)
.and_then(|(_, _, name)| name.clone())
}
}

// FIXME: Document this
#[derive(Debug)]
pub struct Callable {
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ impl<'db> SemanticsImpl<'db> {
let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?;
let res = asm_parts
.iter()
.map(|&(range, index)| {
.map(|&(range, index, _)| {
(
range + quote.end(),
Some(Either::Right(InlineAsmOperand { owner, expr, index })),
Expand Down
6 changes: 3 additions & 3 deletions src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,8 +913,8 @@ impl SourceAnalyzer {
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)),
.find(|(range, _, _)| range.contains_inclusive(offset))
.map(|(range, idx, _)| (expr, *range, *idx)),
)
}

Expand Down Expand Up @@ -944,7 +944,7 @@ impl SourceAnalyzer {
pub(crate) fn as_asm_parts(
&self,
asm: InFile<&ast::AsmExpr>,
) -> Option<(DefWithBodyId, (ExprId, &[(TextRange, usize)]))> {
) -> Option<(DefWithBodyId, (ExprId, &[(TextRange, usize, Option<Name>)]))> {
let (def, _, body_source_map) = self.def.as_ref()?;
Some(*def).zip(body_source_map.asm_template_args(asm))
}
Expand Down
7 changes: 4 additions & 3 deletions src/tools/rust-analyzer/crates/ide-db/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ impl Definition {
Definition::Label(it) => it.module(db),
Definition::ExternCrateDecl(it) => it.module(db),
Definition::DeriveHelper(it) => it.derive().module(db),
Definition::InlineAsmOperand(it) => it.parent(db).module(db),
Definition::BuiltinAttr(_)
| Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
| Definition::TupleField(_)
| Definition::ToolModule(_)
| Definition::InlineAsmRegOrRegClass(_)
| Definition::InlineAsmOperand(_) => return None,
| Definition::InlineAsmRegOrRegClass(_) => return None,
};
Some(module)
}
Expand Down Expand Up @@ -156,7 +156,8 @@ 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::InlineAsmOperand(_) => return None, // FIXME
Definition::InlineAsmRegOrRegClass(_) => return None,
Definition::InlineAsmOperand(op) => return op.name(db),
};
Some(name)
}
Expand Down
3 changes: 1 addition & 2 deletions src/tools/rust-analyzer/crates/ide-db/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,14 @@ impl Definition {
.and_then(syn_ctx_is_root)
}
}
Definition::InlineAsmOperand(it) => name_range(it, sema).and_then(syn_ctx_is_root),
Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
| Definition::BuiltinAttr(_)
| Definition::SelfType(_)
| Definition::ToolModule(_)
| Definition::TupleField(_)
| Definition::InlineAsmRegOrRegClass(_) => return None,
// FIXME:
Definition::InlineAsmOperand(_) => return None,
// FIXME: This should be doable in theory
Definition::DeriveHelper(_) => return None,
};
Expand Down
18 changes: 17 additions & 1 deletion src/tools/rust-analyzer/crates/ide-db/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,23 @@ impl Definition {
};
}

if let Definition::InlineAsmOperand(op) = self {
let def = match op.parent(db) {
DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()),
// FIXME: implement
DefWithBody::InTypeConst(_) => return SearchScope::empty(),
};
return match def {
Some(def) => SearchScope::file_range(
def.as_ref().original_file_range_with_macro_call_body(db),
),
None => SearchScope::single_file(file_id),
};
}

if let Definition::SelfType(impl_) = self {
return match impl_.source(db).map(|src| src.syntax().cloned()) {
Some(def) => SearchScope::file_range(
Expand Down Expand Up @@ -909,7 +926,6 @@ impl<'a> FindUsages<'a> {
let finder = &Finder::new(name);
let include_self_kw_refs =
self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self")));

for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) {
self.sema.db.unwind_if_cancelled();
let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone());
Expand Down
30 changes: 27 additions & 3 deletions src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,15 +237,14 @@ impl TryToNav for Definition {
Definition::Trait(it) => it.try_to_nav(db),
Definition::TraitAlias(it) => it.try_to_nav(db),
Definition::TypeAlias(it) => it.try_to_nav(db),
Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
Definition::ExternCrateDecl(it) => it.try_to_nav(db),
Definition::InlineAsmOperand(it) => it.try_to_nav(db),
Definition::BuiltinLifetime(_)
| Definition::BuiltinType(_)
| Definition::TupleField(_)
| Definition::ToolModule(_)
| Definition::InlineAsmRegOrRegClass(_)
| Definition::BuiltinAttr(_) => None,
// FIXME
Definition::InlineAsmOperand(_) => None,
// FIXME: The focus range should be set to the helper declaration
Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
}
Expand Down Expand Up @@ -696,6 +695,31 @@ impl TryToNav for hir::ConstParam {
}
}

impl TryToNav for hir::InlineAsmOperand {
fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let InFile { file_id, value } = &self.source(db)?;
let file_id = *file_id;
Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
|(FileRange { file_id, range: full_range }, focus_range)| {
let edition = self.parent(db).module(db).krate().edition(db);
NavigationTarget {
file_id,
name: self
.name(db)
.map_or_else(|| "_".into(), |it| it.display(db, edition).to_smolstr()),
alias: None,
kind: Some(SymbolKind::Local),
full_range,
focus_range,
container_name: None,
description: None,
docs: None,
}
},
))
}
}

#[derive(Debug)]
pub struct UpmappingResult<T> {
/// The macro call site.
Expand Down
48 changes: 48 additions & 0 deletions src/tools/rust-analyzer/crates/ide/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2975,6 +2975,54 @@ fn test() {
);
}

#[test]
fn asm_operand() {
check(
"bose",
r#"
//- minicore: asm
fn test() {
core::arch::asm!(
"push {base}",
base$0 = const 0
);
}
"#,
r#"
fn test() {
core::arch::asm!(
"push {bose}",
bose = const 0
);
}
"#,
);
}

#[test]
fn asm_operand2() {
check(
"bose",
r#"
//- minicore: asm
fn test() {
core::arch::asm!(
"push {base$0}",
base = const 0
);
}
"#,
r#"
fn test() {
core::arch::asm!(
"push {bose}",
bose = const 0
);
}
"#,
);
}

#[test]
fn rename_path_inside_use_tree() {
check(
Expand Down
Loading

0 comments on commit bdb734b

Please sign in to comment.