summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /src/tools/rust-analyzer/crates/ide
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide')
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/extend_selection.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs92
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs79
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs81
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs227
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs54
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs218
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/interpret_function.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs620
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs129
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs93
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs100
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html48
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_hir.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_mir.rs6
41 files changed, 1551 insertions, 614 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index 2aee203c4..0943574ec 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -14,9 +14,10 @@ doctest = false
[dependencies]
cov-mark = "2.0.0-pre.1"
crossbeam-channel = "0.5.5"
-either = "1.7.0"
-itertools = "0.10.5"
-tracing = "0.1.35"
+arrayvec = "0.7.4"
+either.workspace = true
+itertools.workspace = true
+tracing.workspace = true
oorandom = "11.1.3"
pulldown-cmark-to-cmark = "10.0.4"
pulldown-cmark = { version = "0.9.1", default-features = false }
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index fb79b5dc2..d7f82b4af 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -1,4 +1,4 @@
-use hir::{HasSource, InFile, Semantics};
+use hir::{HasSource, InFile, InRealFile, Semantics};
use ide_db::{
base_db::{FileId, FilePosition, FileRange},
defs::Definition,
@@ -149,8 +149,8 @@ pub(crate) fn annotations(
node: InFile<T>,
source_file_id: FileId,
) -> Option<(TextRange, Option<TextRange>)> {
- if let Some(InFile { file_id, value }) = node.original_ast_node(db) {
- if file_id == source_file_id.into() {
+ if let Some(InRealFile { file_id, value }) = node.original_ast_node(db) {
+ if file_id == source_file_id {
return Some((
value.syntax().text_range(),
value.name().map(|name| name.syntax().text_range()),
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index f834f2ce5..458b852e2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -1,6 +1,8 @@
//! Entry point for call-hierarchy
-use hir::Semantics;
+use std::iter;
+
+use hir::{DescendPreference, Semantics};
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token,
@@ -66,7 +68,10 @@ pub(crate) fn incoming_calls(
def.try_to_nav(sema.db)
});
if let Some(nav) = nav {
- calls.add(nav, sema.original_range(name.syntax()).range);
+ calls.add(nav.call_site, sema.original_range(name.syntax()).range);
+ if let Some(other) = nav.def_site {
+ calls.add(other, sema.original_range(name.syntax()).range);
+ }
}
}
}
@@ -87,7 +92,7 @@ pub(crate) fn outgoing_calls(
})?;
let mut calls = CallLocations::default();
- sema.descend_into_macros(token, offset)
+ sema.descend_into_macros(DescendPreference::None, token)
.into_iter()
.filter_map(|it| it.parent_ancestors().nth(1).and_then(ast::Item::cast))
.filter_map(|item| match item {
@@ -117,8 +122,9 @@ pub(crate) fn outgoing_calls(
function.try_to_nav(db).zip(Some(range))
}
}?;
- Some((nav_target, range))
+ Some(nav_target.into_iter().zip(iter::repeat(range)))
})
+ .flatten()
.for_each(|(nav, range)| calls.add(nav, range));
Some(calls.into_items())
@@ -149,7 +155,7 @@ mod tests {
fn check_hierarchy(
ra_fixture: &str,
- expected: Expect,
+ expected_nav: Expect,
expected_incoming: Expect,
expected_outgoing: Expect,
) {
@@ -158,7 +164,7 @@ mod tests {
let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
assert_eq!(navs.len(), 1);
let nav = navs.pop().unwrap();
- expected.assert_eq(&nav.debug_render());
+ expected_nav.assert_eq(&nav.debug_render());
let item_pos =
FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 37a177622..9760f9daf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -12,7 +12,9 @@ use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions
use stdx::format_to;
use url::Url;
-use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs};
+use hir::{
+ db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, DescendPreference, HasAttrs,
+};
use ide_db::{
base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase},
defs::{Definition, NameClass, NameRefClass},
@@ -144,7 +146,7 @@ pub(crate) fn external_docs(
kind if kind.is_trivia() => 0,
_ => 1,
})?;
- let token = sema.descend_into_macros_single(token, offset);
+ let token = sema.descend_into_macros_single(DescendPreference::None, token);
let node = token.parent()?;
let definition = match_ast! {
@@ -286,7 +288,7 @@ impl DocCommentToken {
let original_start = doc_token.text_range().start();
let relative_comment_offset = offset - original_start - prefix_len;
- sema.descend_into_macros(doc_token, offset).into_iter().find_map(|t| {
+ sema.descend_into_macros(DescendPreference::None, doc_token).into_iter().find_map(|t| {
let (node, descended_prefix_len) = match_ast! {
match t {
ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),
@@ -602,7 +604,17 @@ fn filename_and_frag_for_def(
}
Definition::Const(c) => format!("const.{}.html", c.name(db)?.display(db.upcast())),
Definition::Static(s) => format!("static.{}.html", s.name(db).display(db.upcast())),
- Definition::Macro(mac) => format!("macro.{}.html", mac.name(db).display(db.upcast())),
+ Definition::Macro(mac) => match mac.kind(db) {
+ hir::MacroKind::Declarative
+ | hir::MacroKind::BuiltIn
+ | hir::MacroKind::Attr
+ | hir::MacroKind::ProcMacro => {
+ format!("macro.{}.html", mac.name(db).display(db.upcast()))
+ }
+ hir::MacroKind::Derive => {
+ format!("derive.{}.html", mac.name(db).display(db.upcast()))
+ }
+ },
Definition::Field(field) => {
let def = match field.parent_def(db) {
hir::VariantDef::Struct(it) => Definition::Adt(it.into()),
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 9ae70ae66..f388aea4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -1,4 +1,4 @@
-use std::ffi::OsStr;
+use std::{ffi::OsStr, iter};
use expect_test::{expect, Expect};
use hir::Semantics;
@@ -63,10 +63,12 @@ fn check_doc_links(ra_fixture: &str) {
let defs = extract_definitions_from_docs(&docs);
let actual: Vec<_> = defs
.into_iter()
- .map(|(_, link, ns)| {
+ .flat_map(|(_, link, ns)| {
let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
.unwrap_or_else(|| panic!("Failed to resolve {link}"));
- let nav_target = def.try_to_nav(sema.db).unwrap();
+ def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link))
+ })
+ .map(|(nav_target, link)| {
let range =
FileRange { file_id: nav_target.file_id, range: nav_target.focus_or_full_range() };
(range, link)
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 119a9c7c3..024053eff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -1,4 +1,4 @@
-use hir::Semantics;
+use hir::{DescendPreference, InFile, MacroFileIdExt, Semantics};
use ide_db::{
base_db::FileId, helpers::pick_best_token,
syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase,
@@ -14,12 +14,12 @@ pub struct ExpandedMacro {
// Feature: Expand Macro Recursively
//
-// Shows the full macro expansion of the macro at current cursor.
+// Shows the full macro expansion of the macro at the current caret position.
//
// |===
// | Editor | Action Name
//
-// | VS Code | **rust-analyzer: Expand macro recursively**
+// | VS Code | **rust-analyzer: Expand macro recursively at caret**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
@@ -40,16 +40,20 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
// struct Bar;
// ```
- let derive =
- sema.descend_into_macros(tok.clone(), 0.into()).into_iter().find_map(|descended| {
- let hir_file = sema.hir_file_for(&descended.parent()?);
- if !hir_file.is_derive_attr_pseudo_expansion(db) {
+ let derive = sema
+ .descend_into_macros(DescendPreference::None, tok.clone())
+ .into_iter()
+ .find_map(|descended| {
+ let macro_file = sema.hir_file_for(&descended.parent()?).macro_file()?;
+ if !macro_file.is_derive_attr_pseudo_expansion(db) {
return None;
}
let name = descended.parent_ancestors().filter_map(ast::Path::cast).last()?.to_string();
// up map out of the #[derive] expansion
- let token = hir::InFile::new(hir_file, descended).upmap(db)?.value;
+ let InFile { file_id, value: tokens } =
+ hir::InMacroFile::new(macro_file, descended).upmap_once(db);
+ let token = sema.parse_or_expand(file_id).covering_element(tokens[0]).into_token()?;
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
let expansions = sema.expand_derive_macro(&attr)?;
let idx = attr
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
index 3d89599c5..b706e959d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
@@ -1,6 +1,6 @@
use std::iter::successors;
-use hir::Semantics;
+use hir::{DescendPreference, Semantics};
use ide_db::RootDatabase;
use syntax::{
algo::{self, skip_trivia_token},
@@ -108,7 +108,7 @@ fn try_extend_selection(
let node = shallowest_node(&node);
- if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
+ if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) {
if let Some(range) = extend_list_item(&node) {
return Some(range);
}
@@ -141,9 +141,9 @@ fn extend_tokens_from_range(
// compute original mapped token range
let extended = {
let fst_expanded =
- sema.descend_into_macros_single(first_token.clone(), original_range.start());
+ sema.descend_into_macros_single(DescendPreference::None, first_token.clone());
let lst_expanded =
- sema.descend_into_macros_single(last_token.clone(), original_range.end());
+ sema.descend_into_macros_single(DescendPreference::None, last_token.clone());
let mut lca =
algo::least_common_ancestor(&fst_expanded.parent()?, &lst_expanded.parent()?)?;
lca = shallowest_node(&lca);
@@ -154,10 +154,10 @@ fn extend_tokens_from_range(
};
// Compute parent node range
- let validate = |offset: TextSize| {
+ let validate = || {
let extended = &extended;
move |token: &SyntaxToken| -> bool {
- let expanded = sema.descend_into_macros_single(token.clone(), offset);
+ let expanded = sema.descend_into_macros_single(DescendPreference::None, token.clone());
let parent = match expanded.parent() {
Some(it) => it,
None => return false,
@@ -171,14 +171,14 @@ fn extend_tokens_from_range(
let token = token.prev_token()?;
skip_trivia_token(token, Direction::Prev)
})
- .take_while(validate(original_range.start()))
+ .take_while(validate())
.last()?;
let last = successors(Some(last_token), |token| {
let token = token.next_token()?;
skip_trivia_token(token, Direction::Next)
})
- .take_while(validate(original_range.end()))
+ .take_while(validate())
.last()?;
let range = first.text_range().cover(last.text_range());
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 7e0fab426..fae100743 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -1,4 +1,4 @@
-use hir::{AsAssocItem, Semantics};
+use hir::{AsAssocItem, DescendPreference, Semantics};
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
RootDatabase,
@@ -29,7 +29,7 @@ pub(crate) fn goto_declaration(
.find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
let range = original_token.text_range();
let info: Vec<NavigationTarget> = sema
- .descend_into_macros(original_token, offset)
+ .descend_into_macros(DescendPreference::None, original_token)
.iter()
.filter_map(|token| {
let parent = token.parent()?;
@@ -66,6 +66,7 @@ pub(crate) fn goto_declaration(
let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
item.try_to_nav(db)
})
+ .flatten()
.collect();
if info.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index e09b9f391..7491879a6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -4,7 +4,7 @@ use crate::{
doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget,
RangeInfo, TryToNav,
};
-use hir::{AsAssocItem, AssocItem, Semantics};
+use hir::{AsAssocItem, AssocItem, DescendPreference, Semantics};
use ide_db::{
base_db::{AnchoredPath, FileId, FileLoader},
defs::{Definition, IdentClass},
@@ -52,21 +52,34 @@ pub(crate) fn goto_definition(
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {
let nav = def.try_to_nav(db)?;
- Some(RangeInfo::new(link_range, vec![nav]))
+ Some(RangeInfo::new(link_range, nav.collect()))
});
}
+
+ if let Some((range, resolution)) =
+ sema.check_for_format_args_template(original_token.clone(), offset)
+ {
+ return Some(RangeInfo::new(
+ range,
+ match resolution {
+ Some(res) => def_to_nav(db, Definition::from(res)),
+ None => vec![],
+ },
+ ));
+ }
+
let navs = sema
- .descend_into_macros(original_token.clone(), offset)
+ .descend_into_macros(DescendPreference::None, original_token.clone())
.into_iter()
.filter_map(|token| {
let parent = token.parent()?;
- if let Some(tt) = ast::TokenTree::cast(parent) {
+ if let Some(tt) = ast::TokenTree::cast(parent.clone()) {
if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), file_id) {
return Some(vec![x]);
}
}
Some(
- IdentClass::classify_token(sema, &token)?
+ IdentClass::classify_node(sema, &parent)?
.definitions()
.into_iter()
.flat_map(|def| {
@@ -75,6 +88,7 @@ pub(crate) fn goto_definition(
.resolved_crate(db)
.map(|it| it.root_module().to_nav(sema.db))
.into_iter()
+ .flatten()
.collect();
}
try_filter_trait_item_definition(sema, &def)
@@ -125,6 +139,7 @@ fn try_lookup_include_path(
docs: None,
})
}
+
/// finds the trait definition of an impl'd item, except function
/// e.g.
/// ```rust
@@ -153,13 +168,13 @@ fn try_filter_trait_item_definition(
.iter()
.filter(|itm| discriminant(*itm) == discri_value)
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
- .map(|it| vec![it])
+ .map(|it| it.collect())
}
}
}
fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
- def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
+ def.try_to_nav(db).map(|it| it.collect()).unwrap_or_default()
}
#[cfg(test)]
@@ -399,11 +414,11 @@ fn bar() {
//- /lib.rs
macro_rules! define_fn {
() => (fn foo() {})
+ //^^^
}
define_fn!();
//^^^^^^^^^^^^^
-
fn bar() {
$0foo();
}
@@ -807,18 +822,13 @@ mod confuse_index { fn foo(); }
fn goto_through_format() {
check(
r#"
+//- minicore: fmt
#[macro_export]
macro_rules! format {
($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! format_args {
- ($fmt:expr) => ({ /* compiler built-in */ });
- ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
-}
pub mod __export {
- pub use crate::format_args;
+ pub use core::format_args;
fn foo() {} // for index confusion
}
fn foo() -> i8 {}
@@ -1738,9 +1748,9 @@ macro_rules! foo {
fn $ident(Foo { $ident }: Foo) {}
}
}
-foo!(foo$0);
- //^^^
- //^^^
+ foo!(foo$0);
+ //^^^
+ //^^^
"#,
);
check(
@@ -2057,4 +2067,18 @@ fn f2() {
"#,
);
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+ let a = "world";
+ // ^
+ format_args!("hello {a$0}");
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 544c6b423..6384db39d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -1,4 +1,4 @@
-use hir::{AsAssocItem, Impl, Semantics};
+use hir::{AsAssocItem, DescendPreference, Impl, Semantics};
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token,
@@ -34,7 +34,7 @@ pub(crate) fn goto_implementation(
})?;
let range = original_token.text_range();
let navs =
- sema.descend_into_macros(original_token, offset)
+ sema.descend_into_macros(DescendPreference::None, original_token)
.into_iter()
.filter_map(|token| token.parent().and_then(ast::NameLike::cast))
.filter_map(|node| match &node {
@@ -82,7 +82,11 @@ pub(crate) fn goto_implementation(
}
fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
- Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()
+ Impl::all_for_type(sema.db, ty)
+ .into_iter()
+ .filter_map(|imp| imp.try_to_nav(sema.db))
+ .flatten()
+ .collect()
}
fn impls_for_trait(
@@ -92,6 +96,7 @@ fn impls_for_trait(
Impl::all_for_trait(sema.db, trait_)
.into_iter()
.filter_map(|imp| imp.try_to_nav(sema.db))
+ .flatten()
.collect()
}
@@ -109,6 +114,7 @@ fn impls_for_trait_item(
})?;
item.try_to_nav(sema.db)
})
+ .flatten()
.collect()
}
@@ -249,7 +255,7 @@ impl T for &Foo {}
r#"
//- minicore: copy, derive
#[derive(Copy)]
-//^^^^^^^^^^^^^^^
+ //^^^^
struct Foo$0;
"#,
);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index 955923d76..ad393d980 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -1,3 +1,4 @@
+use hir::{DescendPreference, GenericParam};
use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase};
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};
@@ -30,14 +31,45 @@ pub(crate) fn goto_type_definition(
let mut res = Vec::new();
let mut push = |def: Definition| {
- if let Some(nav) = def.try_to_nav(db) {
- if !res.contains(&nav) {
- res.push(nav);
+ if let Some(navs) = def.try_to_nav(db) {
+ for nav in navs {
+ if !res.contains(&nav) {
+ res.push(nav);
+ }
}
}
};
+ let mut process_ty = |ty: hir::Type| {
+ // collect from each `ty` into the `res` result vec
+ let ty = ty.strip_references();
+ ty.walk(db, |t| {
+ if let Some(adt) = t.as_adt() {
+ push(adt.into());
+ } else if let Some(trait_) = t.as_dyn_trait() {
+ push(trait_.into());
+ } else if let Some(traits) = t.as_impl_traits(db) {
+ traits.for_each(|it| push(it.into()));
+ } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
+ push(trait_.into());
+ }
+ });
+ };
+ if let Some((range, resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
+ if let Some(ty) = resolution.and_then(|res| match Definition::from(res) {
+ Definition::Const(it) => Some(it.ty(db)),
+ Definition::Static(it) => Some(it.ty(db)),
+ Definition::GenericParam(GenericParam::ConstParam(it)) => Some(it.ty(db)),
+ Definition::Local(it) => Some(it.ty(db)),
+ Definition::Adt(hir::Adt::Struct(it)) => Some(it.ty(db)),
+ _ => None,
+ }) {
+ process_ty(ty);
+ }
+ return Some(RangeInfo::new(range, res));
+ }
+
let range = token.text_range();
- sema.descend_into_macros(token, offset)
+ sema.descend_into_macros(DescendPreference::None, token)
.into_iter()
.filter_map(|token| {
let ty = sema
@@ -75,21 +107,7 @@ pub(crate) fn goto_type_definition(
});
ty
})
- .for_each(|ty| {
- // collect from each `ty` into the `res` result vec
- let ty = ty.strip_references();
- ty.walk(db, |t| {
- if let Some(adt) = t.as_adt() {
- push(adt.into());
- } else if let Some(trait_) = t.as_dyn_trait() {
- push(trait_.into());
- } else if let Some(traits) = t.as_impl_traits(db) {
- traits.for_each(|it| push(it.into()));
- } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
- push(trait_.into());
- }
- });
- });
+ .for_each(process_ty);
Some(RangeInfo::new(range, res))
}
@@ -328,4 +346,40 @@ fn foo(x$0: Bar<Baz<Foo>, Baz<usize>) {}
"#,
);
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+struct Bar;
+ // ^^^
+ fn test() {
+ let a = Bar;
+ format_args!("hello {a$0}");
+}
+"#,
+ );
+ check(
+ r#"
+//- minicore: fmt
+struct Bar;
+ // ^^^
+ fn test() {
+ format_args!("hello {Bar$0}");
+}
+"#,
+ );
+ check(
+ r#"
+//- minicore: fmt
+struct Bar;
+ // ^^^
+const BAR: Bar = Bar;
+fn test() {
+ format_args!("hello {BAR$0}");
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 46a0464e9..3aed007f3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -1,4 +1,6 @@
-use hir::Semantics;
+use std::iter;
+
+use hir::{DescendPreference, Semantics};
use ide_db::{
base_db::{FileId, FilePosition, FileRange},
defs::{Definition, IdentClass},
@@ -15,7 +17,6 @@ use syntax::{
SyntaxKind::{self, IDENT, INT_NUMBER},
SyntaxNode, SyntaxToken, TextRange, T,
};
-use text_edit::TextSize;
use crate::{navigation_target::ToNav, references, NavigationTarget, TryToNav};
@@ -43,7 +44,7 @@ pub struct HighlightRelatedConfig {
//
// . if on an identifier, highlights all references to that identifier in the current file
// .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
-// . if on an `async` or `await token, highlights all yield points for that async context
+// . if on an `async` or `await` token, highlights all yield points for that async context
// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
@@ -116,7 +117,7 @@ fn highlight_closure_captures(
local
.sources(sema.db)
.into_iter()
- .map(|x| x.to_nav(sema.db))
+ .flat_map(|x| x.to_nav(sema.db))
.filter(|decl| decl.file_id == file_id)
.filter_map(|decl| decl.focus_range)
.map(move |range| HighlightedRange { range, category })
@@ -132,7 +133,16 @@ fn highlight_references(
token: SyntaxToken,
FilePosition { file_id, offset }: FilePosition,
) -> Option<Vec<HighlightedRange>> {
- let defs = find_defs(sema, token.clone(), offset);
+ let defs = if let Some((range, resolution)) =
+ sema.check_for_format_args_template(token.clone(), offset)
+ {
+ match resolution.map(Definition::from) {
+ Some(def) => iter::once(def).collect(),
+ None => return Some(vec![HighlightedRange { range, category: None }]),
+ }
+ } else {
+ find_defs(sema, token.clone())
+ };
let usages = defs
.iter()
.filter_map(|&d| {
@@ -206,7 +216,7 @@ fn highlight_references(
local
.sources(sema.db)
.into_iter()
- .map(|x| x.to_nav(sema.db))
+ .flat_map(|x| x.to_nav(sema.db))
.filter(|decl| decl.file_id == file_id)
.filter_map(|decl| decl.focus_range)
.map(|range| HighlightedRange { range, category })
@@ -215,21 +225,27 @@ fn highlight_references(
});
}
def => {
- let hl_range = match def {
+ let navs = match def {
Definition::Module(module) => {
- Some(NavigationTarget::from_module_to_decl(sema.db, module))
+ NavigationTarget::from_module_to_decl(sema.db, module)
+ }
+ def => match def.try_to_nav(sema.db) {
+ Some(it) => it,
+ None => continue,
+ },
+ };
+ for nav in navs {
+ if nav.file_id != file_id {
+ continue;
+ }
+ let hl_range = nav.focus_range.map(|range| {
+ let category = references::decl_mutability(&def, node, range)
+ .then_some(ReferenceCategory::Write);
+ HighlightedRange { range, category }
+ });
+ if let Some(hl_range) = hl_range {
+ res.insert(hl_range);
}
- def => def.try_to_nav(sema.db),
- }
- .filter(|decl| decl.file_id == file_id)
- .and_then(|decl| decl.focus_range)
- .map(|range| {
- let category = references::decl_mutability(&def, node, range)
- .then_some(ReferenceCategory::Write);
- HighlightedRange { range, category }
- });
- if let Some(hl_range) = hl_range {
- res.insert(hl_range);
}
}
}
@@ -456,12 +472,8 @@ fn cover_range(r0: Option<TextRange>, r1: Option<TextRange>) -> Option<TextRange
}
}
-fn find_defs(
- sema: &Semantics<'_, RootDatabase>,
- token: SyntaxToken,
- offset: TextSize,
-) -> FxHashSet<Definition> {
- sema.descend_into_macros(token, offset)
+fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSet<Definition> {
+ sema.descend_into_macros(DescendPreference::None, token)
.into_iter()
.filter_map(|token| IdentClass::classify_token(sema, &token))
.map(IdentClass::definitions_no_ops)
@@ -1623,4 +1635,21 @@ fn f2<T: Foo>(t: T) {
"#,
);
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+ let a = "foo";
+ // ^
+ format_args!("hello {a} {a$0} {}", a);
+ // ^read
+ // ^read
+ // ^read
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 21934b948..5ad119ace 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -6,7 +6,7 @@ mod tests;
use std::iter;
use either::Either;
-use hir::{db::DefDatabase, HasSource, LangItem, Semantics};
+use hir::{db::DefDatabase, DescendPreference, HasSource, LangItem, Semantics};
use ide_db::{
base_db::FileRange,
defs::{Definition, IdentClass, NameRefClass, OperatorClass},
@@ -21,6 +21,7 @@ use crate::{
doc_links::token_as_doc_comment,
markdown_remove::remove_markdown,
markup::Markup,
+ navigation_target::UpmappingResult,
runnables::{runnable_fn, runnable_mod},
FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
};
@@ -73,7 +74,7 @@ impl HoverAction {
it.module(db)?,
it.name(db).map(|name| name.display(db).to_string()),
),
- nav: it.try_to_nav(db)?,
+ nav: it.try_to_nav(db)?.call_site(),
})
})
.collect();
@@ -150,6 +151,19 @@ fn hover_simple(
});
}
+ if let Some((range, resolution)) =
+ sema.check_for_format_args_template(original_token.clone(), offset)
+ {
+ let res = hover_for_definition(
+ sema,
+ file_id,
+ Definition::from(resolution?),
+ &original_token.parent()?,
+ config,
+ )?;
+ return Some(RangeInfo::new(range, res));
+ }
+
let in_attr = original_token
.parent_ancestors()
.filter_map(ast::Item::cast)
@@ -161,11 +175,10 @@ fn hover_simple(
// prefer descending the same token kind in attribute expansions, in normal macros text
// equivalency is more important
- let descended = if in_attr {
- [sema.descend_into_macros_with_kind_preference(original_token.clone(), offset)].into()
- } else {
- sema.descend_into_macros_with_same_text(original_token.clone(), offset)
- };
+ let descended = sema.descend_into_macros(
+ if in_attr { DescendPreference::SameKind } else { DescendPreference::SameText },
+ original_token.clone(),
+ );
let descended = || descended.iter();
let result = descended()
@@ -180,26 +193,24 @@ fn hover_simple(
descended()
.filter_map(|token| {
let node = token.parent()?;
- let class = IdentClass::classify_token(sema, token)?;
- if let IdentClass::Operator(OperatorClass::Await(_)) = class {
+ match IdentClass::classify_node(sema, &node)? {
// It's better for us to fall back to the keyword hover here,
// rendering poll is very confusing
- return None;
+ IdentClass::Operator(OperatorClass::Await(_)) => None,
+
+ IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
+ decl,
+ ..
+ }) => Some(vec![(Definition::ExternCrateDecl(decl), node)]),
+
+ class => Some(
+ class
+ .definitions()
+ .into_iter()
+ .zip(iter::repeat(node))
+ .collect::<Vec<_>>(),
+ ),
}
- if let IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
- decl,
- ..
- }) = class
- {
- return Some(vec![(Definition::ExternCrateDecl(decl), node)]);
- }
- Some(
- class
- .definitions()
- .into_iter()
- .zip(iter::once(node).cycle())
- .collect::<Vec<_>>(),
- )
})
.flatten()
.unique_by(|&(def, _)| def)
@@ -300,11 +311,11 @@ pub(crate) fn hover_for_definition(
sema: &Semantics<'_, RootDatabase>,
file_id: FileId,
definition: Definition,
- node: &SyntaxNode,
+ scope_node: &SyntaxNode,
config: &HoverConfig,
) -> Option<HoverResult> {
let famous_defs = match &definition {
- Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
+ Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())),
_ => None,
};
render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| {
@@ -332,22 +343,26 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
}
let adt = match def {
- Definition::Trait(it) => return it.try_to_nav(db).map(to_action),
+ Definition::Trait(it) => {
+ return it.try_to_nav(db).map(UpmappingResult::call_site).map(to_action)
+ }
Definition::Adt(it) => Some(it),
Definition::SelfType(it) => it.self_ty(db).as_adt(),
_ => None,
}?;
- adt.try_to_nav(db).map(to_action)
+ adt.try_to_nav(db).map(UpmappingResult::call_site).map(to_action)
}
fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
match def {
- Definition::Function(it) => it.try_to_nav(db).map(|nav_target| {
- HoverAction::Reference(FilePosition {
- file_id: nav_target.file_id,
- offset: nav_target.focus_or_full_range().start(),
+ Definition::Function(it) => {
+ it.try_to_nav(db).map(UpmappingResult::call_site).map(|nav_target| {
+ HoverAction::Reference(FilePosition {
+ file_id: nav_target.file_id,
+ offset: nav_target.focus_or_full_range().start(),
+ })
})
- }),
+ }
_ => None,
}
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index f72ce37d1..d0a02fd0d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -402,10 +402,9 @@ pub(super) fn definition(
|&it| it.layout(db),
|_| {
let var_def = it.parent_def(db);
- let id = it.index();
match var_def {
hir::VariantDef::Struct(s) => {
- Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(id))
+ Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it))
}
_ => None,
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 81d6db564..d5ec336fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1136,7 +1136,9 @@ impl Thing {
```
```rust
- struct Thing
+ struct Thing {
+ x: u32,
+ }
```
"#]],
);
@@ -1155,7 +1157,9 @@ impl Thing {
```
```rust
- struct Thing
+ struct Thing {
+ x: u32,
+ }
```
"#]],
);
@@ -1174,7 +1178,9 @@ impl Thing {
```
```rust
- enum Thing
+ enum Thing {
+ A,
+ }
```
"#]],
);
@@ -1193,7 +1199,9 @@ impl Thing {
```
```rust
- enum Thing
+ enum Thing {
+ A,
+ }
```
"#]],
);
@@ -2005,7 +2013,10 @@ fn test_hover_layout_of_enum() {
```
```rust
- enum Foo // size = 16 (0x10), align = 8, niches = 254
+ enum Foo {
+ Variant1(u8, u16),
+ Variant2(i32, u8, i64),
+ } // size = 16 (0x10), align = 8, niches = 254
```
"#]],
);
@@ -2346,7 +2357,7 @@ fn main() { let s$0t = S{ f1:0 }; }
focus_range: 7..8,
name: "S",
kind: Struct,
- description: "struct S",
+ description: "struct S {\n f1: u32,\n}",
},
},
],
@@ -2379,7 +2390,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
focus_range: 24..25,
name: "S",
kind: Struct,
- description: "struct S<T>",
+ description: "struct S<T> {\n f1: T,\n}",
},
},
HoverGotoTypeData {
@@ -2392,7 +2403,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
focus_range: 7..10,
name: "Arg",
kind: Struct,
- description: "struct Arg",
+ description: "struct Arg(u32);",
},
},
],
@@ -2438,7 +2449,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
focus_range: 24..25,
name: "S",
kind: Struct,
- description: "struct S<T>",
+ description: "struct S<T> {\n f1: T,\n}",
},
},
HoverGotoTypeData {
@@ -2451,7 +2462,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
focus_range: 7..10,
name: "Arg",
kind: Struct,
- description: "struct Arg",
+ description: "struct Arg(u32);",
},
},
],
@@ -2487,7 +2498,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
focus_range: 7..8,
name: "A",
kind: Struct,
- description: "struct A",
+ description: "struct A(u32);",
},
},
HoverGotoTypeData {
@@ -2500,7 +2511,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
focus_range: 22..23,
name: "B",
kind: Struct,
- description: "struct B",
+ description: "struct B(u32);",
},
},
HoverGotoTypeData {
@@ -2514,7 +2525,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
name: "C",
kind: Struct,
container_name: "M",
- description: "pub struct C",
+ description: "pub struct C(u32);",
},
},
],
@@ -2704,7 +2715,7 @@ fn main() { let s$0t = foo(); }
focus_range: 39..41,
name: "S1",
kind: Struct,
- description: "struct S1",
+ description: "struct S1 {}",
},
},
HoverGotoTypeData {
@@ -2717,7 +2728,7 @@ fn main() { let s$0t = foo(); }
focus_range: 52..54,
name: "S2",
kind: Struct,
- description: "struct S2",
+ description: "struct S2 {}",
},
},
],
@@ -2808,7 +2819,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
focus_range: 36..37,
name: "S",
kind: Struct,
- description: "struct S",
+ description: "struct S {}",
},
},
],
@@ -2908,7 +2919,7 @@ fn foo(ar$0g: &impl Foo<S>) {}
focus_range: 23..24,
name: "S",
kind: Struct,
- description: "struct S",
+ description: "struct S {}",
},
},
],
@@ -2945,7 +2956,7 @@ fn main() { let s$0t = foo(); }
focus_range: 49..50,
name: "B",
kind: Struct,
- description: "struct B<T>",
+ description: "struct B<T> {}",
},
},
HoverGotoTypeData {
@@ -3034,7 +3045,7 @@ fn foo(ar$0g: &dyn Foo<S>) {}
focus_range: 23..24,
name: "S",
kind: Struct,
- description: "struct S",
+ description: "struct S {}",
},
},
],
@@ -3082,7 +3093,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
focus_range: 50..51,
name: "B",
kind: Struct,
- description: "struct B<T>",
+ description: "struct B<T> {}",
},
},
HoverGotoTypeData {
@@ -3108,7 +3119,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
focus_range: 65..66,
name: "S",
kind: Struct,
- description: "struct S",
+ description: "struct S {}",
},
},
],
@@ -3335,7 +3346,7 @@ struct S$0T<const C: usize = 1, T = Foo>(T);
```
```rust
- struct ST<const C: usize = 1, T = Foo>
+ struct ST<const C: usize = 1, T = Foo>(T);
```
"#]],
);
@@ -3356,7 +3367,7 @@ struct S$0T<const C: usize = {40 + 2}, T = Foo>(T);
```
```rust
- struct ST<const C: usize = {const}, T = Foo>
+ struct ST<const C: usize = {const}, T = Foo>(T);
```
"#]],
);
@@ -3378,7 +3389,7 @@ struct S$0T<const C: usize = VAL, T = Foo>(T);
```
```rust
- struct ST<const C: usize = VAL, T = Foo>
+ struct ST<const C: usize = VAL, T = Foo>(T);
```
"#]],
);
@@ -5266,38 +5277,46 @@ pub fn foo() {}
#[test]
fn hover_feature() {
check(
- r#"#![feature(box_syntax$0)]"#,
- expect![[r##"
- *box_syntax*
- ```
- box_syntax
- ```
- ___
+ r#"#![feature(intrinsics$0)]"#,
+ expect![[r#"
+ *intrinsics*
+ ```
+ intrinsics
+ ```
+ ___
- # `box_syntax`
+ # `intrinsics`
- The tracking issue for this feature is: [#49733]
+ The tracking issue for this feature is: None.
- [#49733]: https://github.com/rust-lang/rust/issues/49733
+ Intrinsics are never intended to be stable directly, but intrinsics are often
+ exported in some sort of stable manner. Prefer using the stable interfaces to
+ the intrinsic directly when you can.
- See also [`box_patterns`](box-patterns.md)
+ ------------------------
- ------------------------
- Currently the only stable way to create a `Box` is via the `Box::new` method.
- Also it is not possible in stable Rust to destructure a `Box` in a match
- pattern. The unstable `box` keyword can be used to create a `Box`. An example
- usage would be:
+ These are imported as if they were FFI functions, with the special
+ `rust-intrinsic` ABI. For example, if one was in a freestanding
+ context, but wished to be able to `transmute` between types, and
+ perform efficient pointer arithmetic, one would import those functions
+ via a declaration like
- ```rust
- #![feature(box_syntax)]
+ ```rust
+ #![feature(intrinsics)]
+ #![allow(internal_features)]
+ # fn main() {}
- fn main() {
- let b = box 5;
- }
- ```
+ extern "rust-intrinsic" {
+ fn transmute<T, U>(x: T) -> U;
- "##]],
+ fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+ }
+ ```
+
+ As with any other FFI functions, these are always `unsafe` to call.
+
+ "#]],
)
}
@@ -5927,7 +5946,7 @@ pub struct Foo(i32);
```
```rust
- pub struct Foo // size = 4, align = 4
+ pub struct Foo(i32); // size = 4, align = 4
```
---
@@ -6594,3 +6613,115 @@ fn test() {
"#]],
);
}
+
+#[test]
+fn format_args_implicit() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+let aaaaa = "foo";
+format_args!("{aaaaa$0}");
+}
+"#,
+ expect![[r#"
+ *aaaaa*
+
+ ```rust
+ let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn format_args_implicit2() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+let aaaaa = "foo";
+format_args!("{$0aaaaa}");
+}
+"#,
+ expect![[r#"
+ *aaaaa*
+
+ ```rust
+ let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn format_args_implicit_raw() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+let aaaaa = "foo";
+format_args!(r"{$0aaaaa}");
+}
+"#,
+ expect![[r#"
+ *aaaaa*
+
+ ```rust
+ let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn format_args_implicit_nested() {
+ check(
+ r#"
+//- minicore: fmt
+macro_rules! foo {
+ ($($tt:tt)*) => {
+ format_args!($($tt)*)
+ }
+}
+fn test() {
+let aaaaa = "foo";
+foo!(r"{$0aaaaa}");
+}
+"#,
+ expect![[r#"
+ *aaaaa*
+
+ ```rust
+ let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn method_call_without_parens() {
+ check(
+ r#"
+struct S;
+impl S {
+ fn foo<T>(&self, t: T) {}
+}
+
+fn main() {
+ S.foo$0;
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ test::S
+ ```
+
+ ```rust
+ fn foo<T>(&self, t: T)
+ ```
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index a5d070fe7..e82d730e4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -31,6 +31,7 @@ mod discriminant;
mod fn_lifetime_fn;
mod implicit_static;
mod param_name;
+mod implicit_drop;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InlayHintsConfig {
@@ -45,6 +46,7 @@ pub struct InlayHintsConfig {
pub closure_return_type_hints: ClosureReturnTypeHints,
pub closure_capture_hints: bool,
pub binding_mode_hints: bool,
+ pub implicit_drop_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
pub hide_named_constructor_hints: bool,
@@ -124,6 +126,7 @@ pub enum InlayKind {
Lifetime,
Parameter,
Type,
+ Drop,
}
#[derive(Debug)]
@@ -312,6 +315,7 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
}
self.make_new_part();
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
+ let location = location.call_site();
let location =
FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
self.location = Some(location);
@@ -418,6 +422,11 @@ fn ty_to_text_edit(
Some(builder.finish())
}
+pub enum RangeLimit {
+ Fixed(TextRange),
+ NearestParent(TextSize),
+}
+
// Feature: Inlay Hints
//
// rust-analyzer shows additional information inline with the source code.
@@ -439,7 +448,7 @@ fn ty_to_text_edit(
pub(crate) fn inlay_hints(
db: &RootDatabase,
file_id: FileId,
- range_limit: Option<TextRange>,
+ range_limit: Option<RangeLimit>,
config: &InlayHintsConfig,
) -> Vec<InlayHint> {
let _p = profile::span("inlay_hints");
@@ -454,13 +463,31 @@ pub(crate) fn inlay_hints(
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
match range_limit {
- Some(range) => match file.covering_element(range) {
+ Some(RangeLimit::Fixed(range)) => match file.covering_element(range) {
NodeOrToken::Token(_) => return acc,
NodeOrToken::Node(n) => n
.descendants()
.filter(|descendant| range.intersect(descendant.text_range()).is_some())
.for_each(hints),
},
+ Some(RangeLimit::NearestParent(position)) => {
+ match file.token_at_offset(position).left_biased() {
+ Some(token) => {
+ if let Some(parent_block) =
+ token.parent_ancestors().find_map(ast::BlockExpr::cast)
+ {
+ parent_block.syntax().descendants().for_each(hints)
+ } else if let Some(parent_item) =
+ token.parent_ancestors().find_map(ast::Item::cast)
+ {
+ parent_item.syntax().descendants().for_each(hints)
+ } else {
+ return acc;
+ }
+ }
+ None => return acc,
+ }
+ }
None => file.descendants().for_each(hints),
};
}
@@ -503,7 +530,10 @@ fn hints(
ast::Item(it) => match it {
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
ast::Item::Impl(_) => None,
- ast::Item::Fn(it) => fn_lifetime_fn::hints(hints, config, it),
+ ast::Item::Fn(it) => {
+ implicit_drop::hints(hints, sema, config, &it);
+ fn_lifetime_fn::hints(hints, config, it)
+ },
// static type elisions
ast::Item::Static(it) => implicit_static::hints(hints, config, Either::Left(it)),
ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
@@ -563,6 +593,7 @@ mod tests {
use hir::ClosureStyle;
use itertools::Itertools;
use test_utils::extract_annotations;
+ use text_edit::{TextRange, TextSize};
use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
use crate::DiscriminantHints;
@@ -590,6 +621,7 @@ mod tests {
max_length: None,
closing_brace_hints_min_lines: None,
fields_to_resolve: InlayFieldsToResolve::empty(),
+ implicit_drop_hints: false,
};
pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
type_hints: true,
@@ -629,6 +661,22 @@ mod tests {
expect.assert_debug_eq(&inlay_hints)
}
+ #[track_caller]
+ pub(super) fn check_expect_clear_loc(
+ config: InlayHintsConfig,
+ ra_fixture: &str,
+ expect: Expect,
+ ) {
+ let (analysis, file_id) = fixture::file(ra_fixture);
+ let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
+ inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| {
+ if let Some(loc) = &mut hint.linked_location {
+ loc.range = TextRange::empty(TextSize::from(0));
+ }
+ });
+ expect.assert_debug_eq(&inlay_hints)
+ }
+
/// Computes inlay hints for the fixture, applies all the provided text edits and then runs
/// expect test.
#[track_caller]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 680035c72..45b51e355 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -177,7 +177,11 @@ mod tests {
use syntax::{TextRange, TextSize};
use test_utils::extract_annotations;
- use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints};
+ use crate::{
+ fixture,
+ inlay_hints::{InlayHintsConfig, RangeLimit},
+ ClosureReturnTypeHints,
+ };
use crate::inlay_hints::tests::{
check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
@@ -400,7 +404,7 @@ fn main() {
.inlay_hints(
&InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
file_id,
- Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
+ Some(RangeLimit::Fixed(TextRange::new(TextSize::from(500), TextSize::from(600)))),
)
.unwrap();
let actual =
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 12e46c0f8..c9e9a2237 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -78,7 +78,9 @@ mod tests {
use expect_test::expect;
use crate::{
- inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+ inlay_hints::tests::{
+ check_expect, check_expect_clear_loc, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
+ },
InlayHintsConfig,
};
@@ -444,7 +446,7 @@ fn main() {
#[test]
fn shorten_iterator_chaining_hints() {
- check_expect(
+ check_expect_clear_loc(
InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
r#"
//- minicore: iterators
@@ -484,7 +486,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 0..0,
},
),
tooltip: "",
@@ -497,7 +499,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 0..0,
},
),
tooltip: "",
@@ -522,7 +524,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 0..0,
},
),
tooltip: "",
@@ -535,7 +537,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 0..0,
},
),
tooltip: "",
@@ -560,7 +562,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 0..0,
},
),
tooltip: "",
@@ -573,7 +575,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 0..0,
},
),
tooltip: "",
@@ -598,7 +600,7 @@ fn main() {
file_id: FileId(
0,
),
- range: 24..30,
+ range: 0..0,
},
),
tooltip: "",
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index d691303c1..2f8b95951 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -2,6 +2,7 @@
//!
//! Tests live in [`bind_pat`][super::bind_pat] module.
use ide_db::{base_db::FileId, famous_defs::FamousDefs};
+use stdx::TupleExt;
use syntax::ast::{self, AstNode};
use text_edit::{TextRange, TextSize};
@@ -73,7 +74,9 @@ pub(super) fn hints(
capture.display_place(sema.db)
),
None,
- source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)),
+ source.name().and_then(|name| {
+ name.syntax().original_file_range_opt(sema.db).map(TupleExt::head)
+ }),
);
acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
new file mode 100644
index 000000000..9cbaed090
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -0,0 +1,218 @@
+//! Implementation of "implicit drop" inlay hints:
+//! ```no_run
+//! fn main() {
+//! let x = vec![2];
+//! if some_condition() {
+//! /* drop(x) */return;
+//! }
+//! }
+//! ```
+use hir::{
+ db::{DefDatabase as _, HirDatabase as _},
+ mir::{MirSpan, TerminatorKind},
+ ChalkTyInterner, DefWithBody, Semantics,
+};
+use ide_db::{base_db::FileRange, RootDatabase};
+
+use syntax::{
+ ast::{self, AstNode},
+ match_ast,
+};
+
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+
+pub(super) fn hints(
+ acc: &mut Vec<InlayHint>,
+ sema: &Semantics<'_, RootDatabase>,
+ config: &InlayHintsConfig,
+ def: &ast::Fn,
+) -> Option<()> {
+ if !config.implicit_drop_hints {
+ return None;
+ }
+
+ let def = sema.to_def(def)?;
+ let def: DefWithBody = def.into();
+
+ let source_map = sema.db.body_with_source_map(def.into()).1;
+
+ let hir = sema.db.body(def.into());
+ let mir = sema.db.mir_body(def.into()).ok()?;
+
+ let local_to_binding = mir.local_to_binding_map();
+
+ for (_, bb) in mir.basic_blocks.iter() {
+ let terminator = bb.terminator.as_ref()?;
+ if let TerminatorKind::Drop { place, .. } = terminator.kind {
+ if !place.projection.is_empty() {
+ continue; // Ignore complex cases for now
+ }
+ if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() {
+ continue; // Arguably only ADTs have significant drop impls
+ }
+ let Some(binding) = local_to_binding.get(place.local) else {
+ continue; // Ignore temporary values
+ };
+ let range = match terminator.span {
+ MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
+ Ok(s) => {
+ let root = &s.file_syntax(sema.db);
+ let expr = s.value.to_node(root);
+ let expr = expr.syntax();
+ match_ast! {
+ match expr {
+ ast::BlockExpr(x) => x.stmt_list().and_then(|x| x.r_curly_token()).map(|x| x.text_range()).unwrap_or_else(|| expr.text_range()),
+ // make the inlay hint appear after the semicolon if there is
+ _ => {
+ let nearest_semicolon = nearest_token_after_node(expr, syntax::SyntaxKind::SEMICOLON);
+ nearest_semicolon.map(|x| x.text_range()).unwrap_or_else(|| expr.text_range())
+ },
+ }
+ }
+ }
+ Err(_) => continue,
+ },
+ MirSpan::PatId(p) => match source_map.pat_syntax(p) {
+ Ok(s) => s.value.text_range(),
+ Err(_) => continue,
+ },
+ MirSpan::Unknown => continue,
+ };
+ let binding = &hir.bindings[*binding];
+ let binding_source = binding
+ .definitions
+ .first()
+ .and_then(|d| source_map.pat_syntax(*d).ok())
+ .and_then(|d| {
+ Some(FileRange { file_id: d.file_id.file_id()?, range: d.value.text_range() })
+ });
+ let name = binding.name.to_smol_str();
+ if name.starts_with("<ra@") {
+ continue; // Ignore desugared variables
+ }
+ let mut label = InlayHintLabel::simple(
+ name,
+ Some(crate::InlayTooltip::String("moz".into())),
+ binding_source,
+ );
+ label.prepend_str("drop(");
+ label.append_str(")");
+ acc.push(InlayHint {
+ range,
+ position: InlayHintPosition::After,
+ pad_left: true,
+ pad_right: true,
+ kind: InlayKind::Drop,
+ needs_resolve: label.needs_resolve(),
+ label,
+ text_edit: None,
+ })
+ }
+ }
+
+ Some(())
+}
+
+fn nearest_token_after_node(
+ node: &syntax::SyntaxNode,
+ token_type: syntax::SyntaxKind,
+) -> Option<syntax::SyntaxToken> {
+ node.siblings_with_tokens(syntax::Direction::Next)
+ .filter_map(|it| it.as_token().map(|it| it.clone()))
+ .filter(|it| it.kind() == token_type)
+ .next()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
+ InlayHintsConfig,
+ };
+
+ const ONLY_DROP_CONFIG: InlayHintsConfig =
+ InlayHintsConfig { implicit_drop_hints: true, ..DISABLED_CONFIG };
+
+ #[test]
+ fn basic() {
+ check_with_config(
+ ONLY_DROP_CONFIG,
+ r#"
+ struct X;
+ fn f() {
+ let x = X;
+ if 2 == 5 {
+ return;
+ //^ drop(x)
+ }
+ }
+ //^ drop(x)
+"#,
+ );
+ }
+
+ #[test]
+ fn no_hint_for_copy_types_and_mutable_references() {
+ // `T: Copy` and `T = &mut U` types do nothing on drop, so we should hide drop inlay hint for them.
+ check_with_config(
+ ONLY_DROP_CONFIG,
+ r#"
+//- minicore: copy, derive
+
+ struct X(i32, i32);
+ #[derive(Clone, Copy)]
+ struct Y(i32, i32);
+ fn f() {
+ let a = 2;
+ let b = a + 4;
+ let mut x = X(a, b);
+ let mut y = Y(a, b);
+ let mx = &mut x;
+ let my = &mut y;
+ let c = a + b;
+ }
+ //^ drop(x)
+"#,
+ );
+ }
+
+ #[test]
+ fn try_operator() {
+ // We currently show drop inlay hint for every `?` operator that may potentialy drop something. We probably need to
+ // make it configurable as it doesn't seem very useful.
+ check_with_config(
+ ONLY_DROP_CONFIG,
+ r#"
+//- minicore: copy, try, option
+
+ struct X;
+ fn f() -> Option<()> {
+ let x = X;
+ let t_opt = Some(2);
+ let t = t_opt?;
+ //^ drop(x)
+ Some(())
+ }
+ //^ drop(x)
+"#,
+ );
+ }
+
+ #[test]
+ fn if_let() {
+ check_with_config(
+ ONLY_DROP_CONFIG,
+ r#"
+ struct X;
+ fn f() {
+ let x = X;
+ if let X = x {
+ let y = X;
+ }
+ //^ drop(y)
+ }
+ //^ drop(x)
+"#,
+ );
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
index d06ffd535..216974904 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
@@ -1,10 +1,10 @@
use hir::Semantics;
-use ide_db::base_db::SourceDatabaseExt;
-use ide_db::RootDatabase;
-use ide_db::{base_db::FilePosition, LineIndexDatabase};
+use ide_db::{
+ base_db::{FilePosition, SourceDatabaseExt},
+ LineIndexDatabase, RootDatabase,
+};
use std::{fmt::Write, time::Instant};
-use syntax::TextRange;
-use syntax::{algo::find_node_at_offset, ast, AstNode};
+use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
// Feature: Interpret Function
//
@@ -28,7 +28,9 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<Strin
let sema = Semantics::new(db);
let source_file = sema.parse(position.file_id);
- let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
+ let item = ancestors_at_offset(source_file.syntax(), position.offset)
+ .filter(|it| !ast::MacroCall::can_cast(it.kind()))
+ .find_map(ast::Item::cast)?;
let def = match item {
ast::Item::Fn(it) => sema.to_def(&it)?,
_ => return None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index aee03d218..a19952e4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -8,8 +8,9 @@
//! in this crate.
// For proving that RootDatabase is RefUnwindSafe.
+#![warn(rust_2018_idioms, unused_lifetimes)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#![recursion_limit = "128"]
-#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#[allow(unused)]
macro_rules! eprintln {
@@ -93,13 +94,13 @@ pub use crate::{
inlay_hints::{
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
- InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+ InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, RangeLimit,
},
join_lines::JoinLinesConfig,
markup::Markup,
moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation},
move_item::Direction,
- navigation_target::NavigationTarget,
+ navigation_target::{NavigationTarget, UpmappingResult},
prime_caches::ParallelPrimeCachesProgress,
references::ReferenceSearchResult,
rename::RenameError,
@@ -132,7 +133,9 @@ pub use ide_db::{
symbol_index::Query,
RootDatabase, SymbolKind,
};
-pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, ExprFillDefaultMode, Severity};
+pub use ide_diagnostics::{
+ Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode, Severity,
+};
pub use ide_ssr::SsrError;
pub use syntax::{TextRange, TextSize};
pub use text_edit::{Indel, TextEdit};
@@ -229,7 +232,7 @@ impl Analysis {
// `AnalysisHost` for creating a fully-featured analysis.
pub fn from_single_file(text: String) -> (Analysis, FileId) {
let mut host = AnalysisHost::default();
- let file_id = FileId(0);
+ let file_id = FileId::from_raw(0);
let mut file_set = FileSet::default();
file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
let source_root = SourceRoot::new_local(file_set);
@@ -396,7 +399,7 @@ impl Analysis {
&self,
config: &InlayHintsConfig,
file_id: FileId,
- range: Option<TextRange>,
+ range: Option<RangeLimit>,
) -> Cancellable<Vec<InlayHint>> {
self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
}
@@ -412,6 +415,7 @@ impl Analysis {
symbol_index::world_symbols(db, query)
.into_iter() // xx: should we make this a par iter?
.filter_map(|s| s.try_to_nav(db))
+ .map(UpmappingResult::call_site)
.collect::<Vec<_>>()
})
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 2ca2b5b1d..8e8bb5e01 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -1,7 +1,7 @@
//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
//! for LSIF and LSP.
-use hir::{AsAssocItem, AssocItemContainer, Crate, Semantics};
+use hir::{AsAssocItem, AssocItemContainer, Crate, DescendPreference, Semantics};
use ide_db::{
base_db::{CrateOrigin, FilePosition, LangCrateOrigin},
defs::{Definition, IdentClass},
@@ -99,7 +99,7 @@ pub(crate) fn moniker(
});
}
let navs = sema
- .descend_into_macros(original_token.clone(), offset)
+ .descend_into_macros(DescendPreference::None, original_token.clone())
.into_iter()
.filter_map(|token| {
IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 32f211c6b..6cb7d7724 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -2,10 +2,11 @@
use std::fmt;
+use arrayvec::ArrayVec;
use either::Either;
use hir::{
- symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource, HirDisplay, HirFileId,
- InFile, LocalSource, ModuleSource,
+ db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource,
+ HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
};
use ide_db::{
base_db::{FileId, FileRange},
@@ -40,6 +41,8 @@ pub struct NavigationTarget {
/// comments, and `focus_range` is the range of the identifier.
///
/// Clients should place the cursor on this range when navigating to this target.
+ ///
+ /// This range must be contained within [`Self::full_range`].
pub focus_range: Option<TextRange>,
pub name: SmolStr,
pub kind: Option<SymbolKind>,
@@ -70,15 +73,15 @@ impl fmt::Debug for NavigationTarget {
}
pub(crate) trait ToNav {
- fn to_nav(&self, db: &RootDatabase) -> NavigationTarget;
+ fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget>;
}
pub(crate) trait TryToNav {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget>;
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>>;
}
impl<T: TryToNav, U: TryToNav> TryToNav for Either<T, U> {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
Either::Left(it) => it.try_to_nav(db),
Either::Right(it) => it.try_to_nav(db),
@@ -91,23 +94,30 @@ impl NavigationTarget {
self.focus_range.unwrap_or(self.full_range)
}
- pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
+ pub(crate) fn from_module_to_decl(
+ db: &RootDatabase,
+ module: hir::Module,
+ ) -> UpmappingResult<NavigationTarget> {
let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
- if let Some(InFile { value, file_id }) = &module.declaration_source(db) {
- let (file_id, full_range, focus_range) =
- orig_range_with_focus(db, *file_id, value.syntax(), value.name());
- let mut res = NavigationTarget::from_syntax(
- file_id,
- name,
- focus_range,
- full_range,
- SymbolKind::Module,
- );
- res.docs = module.docs(db);
- res.description = Some(module.display(db).to_string());
- return res;
+ match module.declaration_source(db) {
+ Some(InFile { value, file_id }) => {
+ orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ let mut res = NavigationTarget::from_syntax(
+ file_id,
+ name.clone(),
+ focus_range,
+ full_range,
+ SymbolKind::Module,
+ );
+ res.docs = module.docs(db);
+ res.description = Some(module.display(db).to_string());
+ res
+ },
+ )
+ }
+ _ => module.to_nav(db),
}
- module.to_nav(db)
}
#[cfg(test)]
@@ -133,13 +143,14 @@ impl NavigationTarget {
db: &RootDatabase,
InFile { file_id, value }: InFile<&dyn ast::HasName>,
kind: SymbolKind,
- ) -> NavigationTarget {
- let name = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into());
+ ) -> UpmappingResult<NavigationTarget> {
+ let name: SmolStr = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into());
- let (file_id, full_range, focus_range) =
- orig_range_with_focus(db, file_id, value.syntax(), value.name());
-
- NavigationTarget::from_syntax(file_id, name, focus_range, full_range, kind)
+ orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind)
+ },
+ )
}
fn from_syntax(
@@ -164,48 +175,51 @@ impl NavigationTarget {
}
impl TryToNav for FileSymbol {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
- let full_range = self.loc.original_range(db);
- let focus_range = self.loc.original_name_range(db).and_then(|it| {
- if it.file_id == full_range.file_id {
- Some(it.range)
- } else {
- None
- }
- });
-
- Some(NavigationTarget {
- file_id: full_range.file_id,
- name: self
- .is_alias
- .then(|| self.def.name(db))
- .flatten()
- .map_or_else(|| self.name.clone(), |it| it.to_smol_str()),
- alias: self.is_alias.then(|| self.name.clone()),
- kind: Some(hir::ModuleDefId::from(self.def).into()),
- full_range: full_range.range,
- focus_range,
- container_name: self.container_name.clone(),
- description: match self.def {
- hir::ModuleDef::Module(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Function(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Adt(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Variant(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Const(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Static(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Trait(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::TraitAlias(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::TypeAlias(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::Macro(it) => Some(it.display(db).to_string()),
- hir::ModuleDef::BuiltinType(_) => None,
- },
- docs: None,
- })
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
+ let root = db.parse_or_expand(self.loc.hir_file_id);
+ self.loc.ptr.to_node(&root);
+ Some(
+ orig_range_with_focus(
+ db,
+ self.loc.hir_file_id,
+ &self.loc.ptr.to_node(&root),
+ Some(self.loc.name_ptr.to_node(&root)),
+ )
+ .map(|(FileRange { file_id, range: full_range }, focus_range)| {
+ NavigationTarget {
+ file_id,
+ name: self
+ .is_alias
+ .then(|| self.def.name(db))
+ .flatten()
+ .map_or_else(|| self.name.clone(), |it| it.to_smol_str()),
+ alias: self.is_alias.then(|| self.name.clone()),
+ kind: Some(hir::ModuleDefId::from(self.def).into()),
+ full_range,
+ focus_range,
+ container_name: self.container_name.clone(),
+ description: match self.def {
+ hir::ModuleDef::Module(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Function(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Adt(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Variant(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Const(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Static(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Trait(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::TraitAlias(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::TypeAlias(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::Macro(it) => Some(it.display(db).to_string()),
+ hir::ModuleDef::BuiltinType(_) => None,
+ },
+ docs: None,
+ }
+ }),
+ )
}
}
impl TryToNav for Definition {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
Definition::Local(it) => Some(it.to_nav(db)),
Definition::Label(it) => Some(it.to_nav(db)),
@@ -233,7 +247,7 @@ impl TryToNav for Definition {
}
impl TryToNav for hir::ModuleDef {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
hir::ModuleDef::Function(it) => it.try_to_nav(db),
@@ -331,22 +345,26 @@ where
D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay,
D::Ast: ast::HasName,
{
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let src = self.source(db)?;
- let mut res = NavigationTarget::from_named(
- db,
- src.as_ref().map(|it| it as &dyn ast::HasName),
- D::KIND,
- );
- res.docs = self.docs(db);
- res.description = Some(self.display(db).to_string());
- res.container_name = self.container_name(db);
- Some(res)
+ Some(
+ NavigationTarget::from_named(
+ db,
+ src.as_ref().map(|it| it as &dyn ast::HasName),
+ D::KIND,
+ )
+ .map(|mut res| {
+ res.docs = self.docs(db);
+ res.description = Some(self.display(db).to_string());
+ res.container_name = self.container_name(db);
+ res
+ }),
+ )
}
}
impl ToNav for hir::Module {
- fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+ fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
let InFile { file_id, value } = self.definition_source(db);
let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
@@ -355,97 +373,125 @@ impl ToNav for hir::Module {
ModuleSource::Module(node) => (node.syntax(), node.name()),
ModuleSource::BlockExpr(node) => (node.syntax(), None),
};
- let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus);
- NavigationTarget::from_syntax(file_id, name, focus_range, full_range, SymbolKind::Module)
+
+ orig_range_with_focus(db, file_id, syntax, focus).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ NavigationTarget::from_syntax(
+ file_id,
+ name.clone(),
+ focus_range,
+ full_range,
+ SymbolKind::Module,
+ )
+ },
+ )
}
}
impl TryToNav for hir::Impl {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let InFile { file_id, value } = self.source(db)?;
- let derive_attr = self.as_builtin_derive(db);
+ let derive_path = self.as_builtin_derive_path(db);
- let (focus, syntax) = match &derive_attr {
- Some(attr) => (None, attr.value.syntax()),
- None => (value.self_ty(), value.syntax()),
+ let (file_id, focus, syntax) = match &derive_path {
+ Some(attr) => (attr.file_id.into(), None, attr.value.syntax()),
+ None => (file_id, value.self_ty(), value.syntax()),
};
- let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus);
- Some(NavigationTarget::from_syntax(
- file_id,
- "impl".into(),
- focus_range,
- full_range,
- SymbolKind::Impl,
+ Some(orig_range_with_focus(db, file_id, syntax, focus).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ NavigationTarget::from_syntax(
+ file_id,
+ "impl".into(),
+ focus_range,
+ full_range,
+ SymbolKind::Impl,
+ )
+ },
))
}
}
impl TryToNav for hir::ExternCrateDecl {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let src = self.source(db)?;
let InFile { file_id, value } = src;
let focus = value
.rename()
.map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right));
- let (file_id, full_range, focus_range) =
- orig_range_with_focus(db, file_id, value.syntax(), focus);
- let mut res = NavigationTarget::from_syntax(
- file_id,
- self.alias_or_name(db).unwrap_or_else(|| self.name(db)).to_smol_str(),
- focus_range,
- full_range,
- SymbolKind::Module,
- );
- res.docs = self.docs(db);
- res.description = Some(self.display(db).to_string());
- res.container_name = container_name(db, *self);
- Some(res)
+ Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ let mut res = NavigationTarget::from_syntax(
+ file_id,
+ self.alias_or_name(db).unwrap_or_else(|| self.name(db)).to_smol_str(),
+ focus_range,
+ full_range,
+ SymbolKind::Module,
+ );
+
+ res.docs = self.docs(db);
+ res.description = Some(self.display(db).to_string());
+ res.container_name = container_name(db, *self);
+ res
+ },
+ ))
}
}
impl TryToNav for hir::Field {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let src = self.source(db)?;
let field_source = match &src.value {
FieldSource::Named(it) => {
- let mut res =
- NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
- res.docs = self.docs(db);
- res.description = Some(self.display(db).to_string());
- res
- }
- FieldSource::Pos(it) => {
- let FileRange { file_id, range } =
- src.with_value(it.syntax()).original_file_range(db);
- NavigationTarget::from_syntax(file_id, "".into(), None, range, SymbolKind::Field)
+ NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map(
+ |mut res| {
+ res.docs = self.docs(db);
+ res.description = Some(self.display(db).to_string());
+ res
+ },
+ )
}
+ FieldSource::Pos(it) => orig_range(db, src.file_id, it.syntax()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ NavigationTarget::from_syntax(
+ file_id,
+ format!("{}", self.index()).into(),
+ focus_range,
+ full_range,
+ SymbolKind::Field,
+ )
+ },
+ ),
};
Some(field_source)
}
}
impl TryToNav for hir::Macro {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let src = self.source(db)?;
let name_owner: &dyn ast::HasName = match &src.value {
Either::Left(it) => it,
Either::Right(it) => it,
};
- let mut res = NavigationTarget::from_named(
- db,
- src.as_ref().with_value(name_owner),
- self.kind(db).into(),
- );
- res.docs = self.docs(db);
- Some(res)
+ Some(
+ NavigationTarget::from_named(
+ db,
+ src.as_ref().with_value(name_owner),
+ self.kind(db).into(),
+ )
+ .map(|mut res| {
+ res.docs = self.docs(db);
+ res
+ }),
+ )
}
}
impl TryToNav for hir::Adt {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
hir::Adt::Struct(it) => it.try_to_nav(db),
hir::Adt::Union(it) => it.try_to_nav(db),
@@ -455,7 +501,7 @@ impl TryToNav for hir::Adt {
}
impl TryToNav for hir::AssocItem {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
AssocItem::Function(it) => it.try_to_nav(db),
AssocItem::Const(it) => it.try_to_nav(db),
@@ -465,7 +511,7 @@ impl TryToNav for hir::AssocItem {
}
impl TryToNav for hir::GenericParam {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
match self {
hir::GenericParam::TypeParam(it) => it.try_to_nav(db),
hir::GenericParam::ConstParam(it) => it.try_to_nav(db),
@@ -475,7 +521,7 @@ impl TryToNav for hir::GenericParam {
}
impl ToNav for LocalSource {
- fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+ fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
let InFile { file_id, value } = &self.source;
let file_id = *file_id;
let local = self.local;
@@ -484,60 +530,61 @@ impl ToNav for LocalSource {
Either::Right(it) => (it.syntax(), it.name()),
};
- let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, node, name);
-
- let name = local.name(db).to_smol_str();
- let kind = if local.is_self(db) {
- SymbolKind::SelfParam
- } else if local.is_param(db) {
- SymbolKind::ValueParam
- } else {
- SymbolKind::Local
- };
- NavigationTarget {
- file_id,
- name,
- alias: None,
- kind: Some(kind),
- full_range,
- focus_range,
- container_name: None,
- description: None,
- docs: None,
- }
+ orig_range_with_focus(db, file_id, node, name).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| {
+ let name = local.name(db).to_smol_str();
+ let kind = if local.is_self(db) {
+ SymbolKind::SelfParam
+ } else if local.is_param(db) {
+ SymbolKind::ValueParam
+ } else {
+ SymbolKind::Local
+ };
+ NavigationTarget {
+ file_id,
+ name,
+ alias: None,
+ kind: Some(kind),
+ full_range,
+ focus_range,
+ container_name: None,
+ description: None,
+ docs: None,
+ }
+ },
+ )
}
}
impl ToNav for hir::Local {
- fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+ fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
self.primary_source(db).to_nav(db)
}
}
impl ToNav for hir::Label {
- fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+ fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
let InFile { file_id, value } = self.source(db);
let name = self.name(db).to_smol_str();
- let (file_id, full_range, focus_range) =
- orig_range_with_focus(db, file_id, value.syntax(), value.lifetime());
-
- NavigationTarget {
- file_id,
- name,
- alias: None,
- kind: Some(SymbolKind::Label),
- full_range,
- focus_range,
- container_name: None,
- description: None,
- docs: None,
- }
+ orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
+ file_id,
+ name: name.clone(),
+ alias: None,
+ kind: Some(SymbolKind::Label),
+ full_range,
+ focus_range,
+ container_name: None,
+ description: None,
+ docs: None,
+ },
+ )
}
}
impl TryToNav for hir::TypeParam {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let InFile { file_id, value } = self.merge().source(db)?;
let name = self.name(db).to_smol_str();
@@ -556,51 +603,51 @@ impl TryToNav for hir::TypeParam {
};
let focus = value.as_ref().either(|it| it.name(), |it| it.name());
- let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus);
-
- Some(NavigationTarget {
- file_id,
- name,
- alias: None,
- kind: Some(SymbolKind::TypeParam),
- full_range,
- focus_range,
- container_name: None,
- description: None,
- docs: None,
- })
+ Some(orig_range_with_focus(db, file_id, syntax, focus).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
+ file_id,
+ name: name.clone(),
+ alias: None,
+ kind: Some(SymbolKind::TypeParam),
+ full_range,
+ focus_range,
+ container_name: None,
+ description: None,
+ docs: None,
+ },
+ ))
}
}
impl TryToNav for hir::TypeOrConstParam {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
self.split(db).try_to_nav(db)
}
}
impl TryToNav for hir::LifetimeParam {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let InFile { file_id, value } = self.source(db)?;
let name = self.name(db).to_smol_str();
- let FileRange { file_id, range } =
- InFile::new(file_id, value.syntax()).original_file_range(db);
- Some(NavigationTarget {
- file_id,
- name,
- alias: None,
- kind: Some(SymbolKind::LifetimeParam),
- full_range: range,
- focus_range: Some(range),
- container_name: None,
- description: None,
- docs: None,
- })
+ Some(orig_range(db, file_id, value.syntax()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
+ file_id,
+ name: name.clone(),
+ alias: None,
+ kind: Some(SymbolKind::LifetimeParam),
+ full_range,
+ focus_range,
+ container_name: None,
+ description: None,
+ docs: None,
+ },
+ ))
}
}
impl TryToNav for hir::ConstParam {
- fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+ fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
let InFile { file_id, value } = self.merge().source(db)?;
let name = self.name(db).to_smol_str();
@@ -612,35 +659,178 @@ impl TryToNav for hir::ConstParam {
}
};
- let (file_id, full_range, focus_range) =
- orig_range_with_focus(db, file_id, value.syntax(), value.name());
- Some(NavigationTarget {
- file_id,
- name,
- alias: None,
- kind: Some(SymbolKind::ConstParam),
- full_range,
- focus_range,
- container_name: None,
- description: None,
- docs: None,
- })
+ Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
+ |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
+ file_id,
+ name: name.clone(),
+ alias: None,
+ kind: Some(SymbolKind::ConstParam),
+ full_range,
+ focus_range,
+ container_name: None,
+ description: None,
+ docs: None,
+ },
+ ))
+ }
+}
+
+#[derive(Debug)]
+pub struct UpmappingResult<T> {
+ /// The macro call site.
+ pub call_site: T,
+ /// The macro definition site, if relevant.
+ pub def_site: Option<T>,
+}
+
+impl<T> UpmappingResult<T> {
+ pub fn call_site(self) -> T {
+ self.call_site
+ }
+
+ pub fn collect<FI: FromIterator<T>>(self) -> FI {
+ FI::from_iter(self.into_iter())
+ }
+}
+
+impl<T> IntoIterator for UpmappingResult<T> {
+ type Item = T;
+
+ type IntoIter = <ArrayVec<T, 2> as IntoIterator>::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.def_site
+ .into_iter()
+ .chain(Some(self.call_site))
+ .collect::<ArrayVec<_, 2>>()
+ .into_iter()
}
}
+impl<T> UpmappingResult<T> {
+ fn map<U>(self, f: impl Fn(T) -> U) -> UpmappingResult<U> {
+ UpmappingResult { call_site: f(self.call_site), def_site: self.def_site.map(f) }
+ }
+}
+
+/// Returns the original range of the syntax node, and the range of the name mapped out of macro expansions
+/// May return two results if the mapped node originates from a macro definition in which case the
+/// second result is the creating macro call.
fn orig_range_with_focus(
db: &RootDatabase,
hir_file: HirFileId,
value: &SyntaxNode,
name: Option<impl AstNode>,
-) -> (FileId, TextRange, Option<TextRange>) {
- let FileRange { file_id, range: full_range } =
- InFile::new(hir_file, value).original_file_range(db);
- let focus_range = name
- .and_then(|it| InFile::new(hir_file, it.syntax()).original_file_range_opt(db))
- .and_then(|range| if range.file_id == file_id { Some(range.range) } else { None });
-
- (file_id, full_range, focus_range)
+) -> UpmappingResult<(FileRange, Option<TextRange>)> {
+ let Some(name) = name else { return orig_range(db, hir_file, value) };
+
+ let call_range = || {
+ db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id)
+ .kind
+ .original_call_range(db)
+ };
+
+ let def_range = || {
+ db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id)
+ .def
+ .definition_range(db)
+ };
+
+ let value_range = InFile::new(hir_file, value).original_file_range_opt(db);
+ let ((call_site_range, call_site_focus), def_site) =
+ match InFile::new(hir_file, name.syntax()).original_file_range_opt(db) {
+ // call site name
+ Some((focus_range, ctxt)) if ctxt.is_root() => {
+ // Try to upmap the node as well, if it ends up in the def site, go back to the call site
+ (
+ (
+ match value_range {
+ // name is in the node in the macro input so we can return it
+ Some((range, ctxt))
+ if ctxt.is_root()
+ && range.file_id == focus_range.file_id
+ && range.range.contains_range(focus_range.range) =>
+ {
+ range
+ }
+ // name lies outside the node, so instead point to the macro call which
+ // *should* contain the name
+ _ => call_range(),
+ },
+ Some(focus_range),
+ ),
+ // no def site relevant
+ None,
+ )
+ }
+
+ // def site name
+ // FIXME: This can be de improved
+ Some((focus_range, _ctxt)) => {
+ match value_range {
+ // but overall node is in macro input
+ Some((range, ctxt)) if ctxt.is_root() => (
+ // node mapped up in call site, show the node
+ (range, None),
+ // def site, if the name is in the (possibly) upmapped def site range, show the
+ // def site
+ {
+ let (def_site, _) = def_range().original_node_file_range(db);
+ (def_site.file_id == focus_range.file_id
+ && def_site.range.contains_range(focus_range.range))
+ .then_some((def_site, Some(focus_range)))
+ },
+ ),
+ // node is in macro def, just show the focus
+ _ => (
+ // show the macro call
+ (call_range(), None),
+ Some((focus_range, Some(focus_range))),
+ ),
+ }
+ }
+ // lost name? can't happen for single tokens
+ None => return orig_range(db, hir_file, value),
+ };
+
+ UpmappingResult {
+ call_site: (
+ call_site_range,
+ call_site_focus.and_then(|FileRange { file_id, range }| {
+ if call_site_range.file_id == file_id && call_site_range.range.contains_range(range)
+ {
+ Some(range)
+ } else {
+ None
+ }
+ }),
+ ),
+ def_site: def_site.map(|(def_site_range, def_site_focus)| {
+ (
+ def_site_range,
+ def_site_focus.and_then(|FileRange { file_id, range }| {
+ if def_site_range.file_id == file_id
+ && def_site_range.range.contains_range(range)
+ {
+ Some(range)
+ } else {
+ None
+ }
+ }),
+ )
+ }),
+ }
+}
+
+fn orig_range(
+ db: &RootDatabase,
+ hir_file: HirFileId,
+ value: &SyntaxNode,
+) -> UpmappingResult<(FileRange, Option<TextRange>)> {
+ UpmappingResult {
+ call_site: (InFile::new(hir_file, value).original_file_range(db), None),
+ def_site: None,
+ }
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 506f9452c..413dbf9c5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -45,11 +45,11 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
Some(module) => sema
.to_def(&module)
.into_iter()
- .map(|module| NavigationTarget::from_module_to_decl(db, module))
+ .flat_map(|module| NavigationTarget::from_module_to_decl(db, module))
.collect(),
None => sema
.to_module_defs(position.file_id)
- .map(|module| NavigationTarget::from_module_to_decl(db, module))
+ .flat_map(|module| NavigationTarget::from_module_to_decl(db, module))
.collect(),
}
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 2d0295692..6c0fb0baf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -9,7 +9,9 @@
//! at the index that the match starts at and its tree parent is
//! resolved to the search element definition, we get a reference.
-use hir::{PathResolution, Semantics};
+use std::collections::HashMap;
+
+use hir::{DescendPreference, PathResolution, Semantics};
use ide_db::{
base_db::FileId,
defs::{Definition, NameClass, NameRefClass},
@@ -60,19 +62,6 @@ pub(crate) fn find_all_refs(
let syntax = sema.parse(position.file_id).syntax().clone();
let make_searcher = |literal_search: bool| {
move |def: Definition| {
- let declaration = match def {
- Definition::Module(module) => {
- Some(NavigationTarget::from_module_to_decl(sema.db, module))
- }
- def => def.try_to_nav(sema.db),
- }
- .map(|nav| {
- let decl_range = nav.focus_or_full_range();
- Declaration {
- is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
- nav,
- }
- });
let mut usages =
def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
@@ -80,7 +69,7 @@ pub(crate) fn find_all_refs(
retain_adt_literal_usages(&mut usages, def, sema);
}
- let references = usages
+ let mut references = usages
.into_iter()
.map(|(file_id, refs)| {
(
@@ -91,8 +80,30 @@ pub(crate) fn find_all_refs(
.collect(),
)
})
- .collect();
-
+ .collect::<HashMap<_, Vec<_>, _>>();
+ let declaration = match def {
+ Definition::Module(module) => {
+ Some(NavigationTarget::from_module_to_decl(sema.db, module))
+ }
+ def => def.try_to_nav(sema.db),
+ }
+ .map(|nav| {
+ let (nav, extra_ref) = match nav.def_site {
+ Some(call) => (call, Some(nav.call_site)),
+ None => (nav.call_site, None),
+ };
+ if let Some(extra_ref) = extra_ref {
+ references
+ .entry(extra_ref.file_id)
+ .or_default()
+ .push((extra_ref.focus_or_full_range(), None));
+ }
+ let decl_range = nav.focus_or_full_range();
+ Declaration {
+ is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
+ nav,
+ }
+ });
ReferenceSearchResult { declaration, references }
}
};
@@ -109,7 +120,7 @@ pub(crate) fn find_all_refs(
}
None => {
let search = make_searcher(false);
- Some(find_defs(sema, &syntax, position.offset)?.map(search).collect())
+ Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
}
}
}
@@ -118,15 +129,27 @@ pub(crate) fn find_defs<'a>(
sema: &'a Semantics<'_, RootDatabase>,
syntax: &SyntaxNode,
offset: TextSize,
-) -> Option<impl Iterator<Item = Definition> + 'a> {
+) -> Option<impl IntoIterator<Item = Definition> + 'a> {
let token = syntax.token_at_offset(offset).find(|t| {
matches!(
t.kind(),
- IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
+ IDENT
+ | INT_NUMBER
+ | LIFETIME_IDENT
+ | STRING
+ | T![self]
+ | T![super]
+ | T![crate]
+ | T![Self]
)
- });
- token.map(|token| {
- sema.descend_into_macros_with_same_text(token, offset)
+ })?;
+
+ if let Some((_, resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
+ return resolution.map(Definition::from).map(|it| vec![it]);
+ }
+
+ Some(
+ sema.descend_into_macros(DescendPreference::SameText, token)
.into_iter()
.filter_map(|it| ast::NameLike::cast(it.parent()?))
.filter_map(move |name_like| {
@@ -162,7 +185,8 @@ pub(crate) fn find_defs<'a>(
};
Some(def)
})
- })
+ .collect(),
+ )
}
pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool {
@@ -684,6 +708,32 @@ enum Foo {
}
#[test]
+ fn test_self() {
+ check(
+ r#"
+struct S$0<T> {
+ t: PhantomData<T>,
+}
+
+impl<T> S<T> {
+ fn new() -> Self {
+ Self {
+ t: Default::default(),
+ }
+ }
+}
+"#,
+ expect![[r#"
+ S Struct FileId(0) 0..38 7..8
+
+ FileId(0) 48..49
+ FileId(0) 71..75
+ FileId(0) 86..90
+ "#]],
+ )
+ }
+
+ #[test]
fn test_find_all_refs_two_modules() {
check(
r#"
@@ -843,7 +893,7 @@ pub(super) struct Foo$0 {
check_with_scope(
code,
- Some(SearchScope::single_file(FileId(2))),
+ Some(SearchScope::single_file(FileId::from_raw(2))),
expect![[r#"
quux Function FileId(0) 19..35 26..30
@@ -1142,7 +1192,7 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
}
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 55..57 55..57
+ 'a LifetimeParam FileId(0) 55..57
FileId(0) 63..65
FileId(0) 71..73
@@ -1160,7 +1210,7 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
type Foo<'a, T> where T: 'a$0 = &'a T;
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 9..11 9..11
+ 'a LifetimeParam FileId(0) 9..11
FileId(0) 25..27
FileId(0) 31..33
@@ -1182,7 +1232,7 @@ impl<'a> Foo<'a> for &'a () {
}
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 47..49 47..49
+ 'a LifetimeParam FileId(0) 47..49
FileId(0) 55..57
FileId(0) 64..66
@@ -2066,4 +2116,27 @@ fn main() { r#fn(); }
"#]],
);
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+ let a = "foo";
+ format_args!("hello {a} {a$0} {}", a);
+ // ^
+ // ^
+ // ^
+}
+"#,
+ expect![[r#"
+ a Local FileId(0) 20..21 20..21
+
+ FileId(0) 56..57 Read
+ FileId(0) 60..61 Read
+ FileId(0) 68..69 Read
+ "#]],
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index ac9df5ed6..1febfabfc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -4,16 +4,18 @@
//! tests. This module also implements a couple of magic tricks, like renaming
//! `self` and to `self` (to switch between associated function and method).
-use hir::{AsAssocItem, InFile, Semantics};
+use hir::{AsAssocItem, HirFileIdExt, InFile, Semantics};
use ide_db::{
- base_db::FileId,
+ base_db::{FileId, FileRange},
defs::{Definition, NameClass, NameRefClass},
rename::{bail, format_err, source_edit_from_references, IdentifierKind},
RootDatabase,
};
use itertools::Itertools;
use stdx::{always, never};
-use syntax::{ast, utils::is_raw_identifier, AstNode, SmolStr, SyntaxNode, TextRange, TextSize};
+use syntax::{
+ ast, utils::is_raw_identifier, AstNode, SmolStr, SyntaxKind, SyntaxNode, TextRange, TextSize,
+};
use text_edit::TextEdit;
@@ -34,23 +36,20 @@ pub(crate) fn prepare_rename(
let syntax = source_file.syntax();
let res = find_definitions(&sema, syntax, position)?
- .map(|(name_like, def)| {
+ .map(|(frange, kind, def)| {
// ensure all ranges are valid
if def.range_for_rename(&sema).is_none() {
bail!("No references found at position")
}
- let Some(frange) = sema.original_range_opt(name_like.syntax()) else {
- bail!("No references found at position");
- };
always!(
frange.range.contains_inclusive(position.offset)
&& frange.file_id == position.file_id
);
- Ok(match name_like {
- ast::NameLike::Lifetime(_) => {
+ Ok(match kind {
+ SyntaxKind::LIFETIME => {
TextRange::new(frange.range.start() + TextSize::from(1), frange.range.end())
}
_ => frange.range,
@@ -93,7 +92,7 @@ pub(crate) fn rename(
let defs = find_definitions(&sema, syntax, position)?;
let ops: RenameResult<Vec<SourceChange>> = defs
- .map(|(_namelike, def)| {
+ .map(|(.., def)| {
if let Definition::Local(local) = def {
if let Some(self_param) = local.as_self_param(sema.db) {
cov_mark::hit!(rename_self_to_param);
@@ -134,11 +133,27 @@ pub(crate) fn will_rename_file(
fn find_definitions(
sema: &Semantics<'_, RootDatabase>,
syntax: &SyntaxNode,
- position: FilePosition,
-) -> RenameResult<impl Iterator<Item = (ast::NameLike, Definition)>> {
- let symbols = sema
- .find_nodes_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
- .map(|name_like| {
+ FilePosition { file_id, offset }: FilePosition,
+) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition)>> {
+ let token = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING));
+
+ if let Some((range, Some(resolution))) =
+ token.and_then(|token| sema.check_for_format_args_template(token, offset))
+ {
+ return Ok(vec![(
+ FileRange { file_id, range },
+ SyntaxKind::STRING,
+ Definition::from(resolution),
+ )]
+ .into_iter());
+ }
+
+ let symbols =
+ sema.find_nodes_at_offset_with_descend::<ast::NameLike>(syntax, offset).map(|name_like| {
+ let kind = name_like.syntax().kind();
+ let range = sema
+ .original_range_opt(name_like.syntax())
+ .ok_or_else(|| format_err!("No references found at position"))?;
let res = match &name_like {
// renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
ast::NameLike::Name(name)
@@ -163,7 +178,6 @@ fn find_definitions(
Definition::Local(local_def)
}
})
- .map(|def| (name_like.clone(), def))
.ok_or_else(|| format_err!("No references found at position")),
ast::NameLike::NameRef(name_ref) => {
NameRefClass::classify(sema, name_ref)
@@ -187,7 +201,7 @@ fn find_definitions(
{
Err(format_err!("Renaming aliases is currently unsupported"))
} else {
- Ok((name_like.clone(), def))
+ Ok(def)
}
})
}
@@ -203,11 +217,10 @@ fn find_definitions(
_ => None,
})
})
- .map(|def| (name_like, def))
.ok_or_else(|| format_err!("No references found at position"))
}
};
- res
+ res.map(|def| (range, kind, def))
});
let res: RenameResult<Vec<_>> = symbols.collect();
@@ -218,7 +231,7 @@ fn find_definitions(
Err(format_err!("No references found at position"))
} else {
// remove duplicates, comparing `Definition`s
- Ok(v.into_iter().unique_by(|t| t.1))
+ Ok(v.into_iter().unique_by(|&(.., def)| def).collect::<Vec<_>>().into_iter())
}
}
Err(e) => Err(e),
@@ -2663,4 +2676,44 @@ struct A;
"error: Cannot rename a non-local definition.",
)
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ "fbar",
+ r#"
+//- minicore: fmt
+fn test() {
+ let foo = "foo";
+ format_args!("hello {foo} {foo$0} {}", foo);
+}
+"#,
+ r#"
+fn test() {
+ let fbar = "foo";
+ format_args!("hello {fbar} {fbar} {}", fbar);
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn implicit_format_args2() {
+ check(
+ "fo",
+ r#"
+//- minicore: fmt
+fn test() {
+ let foo = "foo";
+ format_args!("hello {foo} {foo$0} {}", foo);
+}
+"#,
+ r#"
+fn test() {
+ let fo = "foo";
+ format_args!("hello {fo} {fo} {}", fo);
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 2d528c642..d334e66d3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -2,14 +2,14 @@ use std::fmt;
use ast::HasName;
use cfg::CfgExpr;
-use hir::{db::HirDatabase, AsAssocItem, HasAttrs, HasSource, Semantics};
+use hir::{db::HirDatabase, AsAssocItem, HasAttrs, HasSource, HirFileIdExt, Semantics};
use ide_assists::utils::test_related_attribute;
use ide_db::{
base_db::{FilePosition, FileRange},
defs::Definition,
documentation::docs_from_attrs,
helpers::visit_file_defs,
- search::SearchScope,
+ search::{FileReferenceNode, SearchScope},
FxHashMap, FxHashSet, RootDatabase, SymbolKind,
};
use itertools::Itertools;
@@ -142,7 +142,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
Definition::Function(it) => it.source(db).map(|src| src.file_id),
_ => None,
};
- if let Some(file_id) = file_id.filter(|file| file.call_node(db).is_some()) {
+ if let Some(file_id) = file_id.filter(|file| file.macro_file().is_some()) {
in_macro_expansion.entry(file_id).or_default().push(runnable);
return;
}
@@ -240,7 +240,7 @@ fn find_related_tests(
.flatten();
for ref_ in defs {
let name_ref = match ref_.name {
- ast::NameLike::NameRef(name_ref) => name_ref,
+ FileReferenceNode::NameRef(name_ref) => name_ref,
_ => continue,
};
if let Some(fn_def) =
@@ -308,11 +308,7 @@ pub(crate) fn runnable_fn(
sema: &Semantics<'_, RootDatabase>,
def: hir::Function,
) -> Option<Runnable> {
- let name = def.name(sema.db).to_smol_str();
-
- let root = def.module(sema.db).krate().root_module();
-
- let kind = if name == "main" && def.module(sema.db) == root {
+ let kind = if def.is_main(sema.db) {
RunnableKind::Bin
} else {
let test_id = || {
@@ -320,7 +316,9 @@ pub(crate) fn runnable_fn(
let def: hir::ModuleDef = def.into();
def.canonical_path(sema.db)
};
- canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name))
+ canonical_path
+ .map(TestId::Path)
+ .unwrap_or(TestId::Name(def.name(sema.db).to_smol_str()))
};
if def.is_test(sema.db) {
@@ -337,7 +335,8 @@ pub(crate) fn runnable_fn(
sema.db,
def.source(sema.db)?.as_ref().map(|it| it as &dyn ast::HasName),
SymbolKind::Function,
- );
+ )
+ .call_site();
let cfg = def.attrs(sema.db).cfg();
Some(Runnable { use_name_in_title: false, nav, kind, cfg })
}
@@ -359,7 +358,7 @@ pub(crate) fn runnable_mod(
let attrs = def.attrs(sema.db);
let cfg = attrs.cfg();
- let nav = NavigationTarget::from_module_to_decl(sema.db, def);
+ let nav = NavigationTarget::from_module_to_decl(sema.db, def).call_site();
Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::TestMod { path }, cfg })
}
@@ -372,7 +371,7 @@ pub(crate) fn runnable_impl(
return None;
}
let cfg = attrs.cfg();
- let nav = def.try_to_nav(sema.db)?;
+ let nav = def.try_to_nav(sema.db)?.call_site();
let ty = def.self_ty(sema.db);
let adt_name = ty.as_adt()?.name(sema.db);
let mut ty_args = ty.generic_parameters(sema.db).peekable();
@@ -409,7 +408,7 @@ fn runnable_mod_outline_definition(
match def.definition_source(sema.db).value {
hir::ModuleSource::SourceFile(_) => Some(Runnable {
use_name_in_title: false,
- nav: def.to_nav(sema.db),
+ nav: def.to_nav(sema.db).call_site(),
kind: RunnableKind::TestMod { path },
cfg,
}),
@@ -467,7 +466,8 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
let mut nav = match def {
Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def),
def => def.try_to_nav(db)?,
- };
+ }
+ .call_site();
nav.focus_range = None;
nav.description = None;
nav.docs = None;
@@ -587,6 +587,9 @@ mod tests {
$0
fn main() {}
+#[export_name = "main"]
+fn __cortex_m_rt_main_trampoline() {}
+
#[test]
fn test_foo() {}
@@ -604,7 +607,7 @@ mod not_a_root {
fn main() {}
}
"#,
- &[TestMod, Bin, Test, Test, Test, Bench],
+ &[TestMod, Bin, Bin, Test, Test, Test, Bench],
expect![[r#"
[
Runnable {
@@ -613,7 +616,7 @@ mod not_a_root {
file_id: FileId(
0,
),
- full_range: 0..190,
+ full_range: 0..253,
name: "",
kind: Module,
},
@@ -642,8 +645,22 @@ mod not_a_root {
file_id: FileId(
0,
),
- full_range: 15..39,
- focus_range: 26..34,
+ full_range: 15..76,
+ focus_range: 42..71,
+ name: "__cortex_m_rt_main_trampoline",
+ kind: Function,
+ },
+ kind: Bin,
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 78..102,
+ focus_range: 89..97,
name: "test_foo",
kind: Function,
},
@@ -663,8 +680,8 @@ mod not_a_root {
file_id: FileId(
0,
),
- full_range: 41..92,
- focus_range: 73..87,
+ full_range: 104..155,
+ focus_range: 136..150,
name: "test_full_path",
kind: Function,
},
@@ -684,8 +701,8 @@ mod not_a_root {
file_id: FileId(
0,
),
- full_range: 94..128,
- focus_range: 115..123,
+ full_range: 157..191,
+ focus_range: 178..186,
name: "test_foo",
kind: Function,
},
@@ -705,8 +722,8 @@ mod not_a_root {
file_id: FileId(
0,
),
- full_range: 130..152,
- focus_range: 142..147,
+ full_range: 193..215,
+ focus_range: 205..210,
name: "bench",
kind: Function,
},
@@ -1655,12 +1672,18 @@ macro_rules! gen2 {
}
}
}
+macro_rules! gen_main {
+ () => {
+ fn main() {}
+ }
+}
mod tests {
gen!();
}
gen2!();
+gen_main!();
"#,
- &[TestMod, TestMod, Test, Test, TestMod],
+ &[TestMod, TestMod, Test, Test, TestMod, Bin],
expect![[r#"
[
Runnable {
@@ -1669,7 +1692,7 @@ gen2!();
file_id: FileId(
0,
),
- full_range: 0..237,
+ full_range: 0..315,
name: "",
kind: Module,
},
@@ -1684,8 +1707,8 @@ gen2!();
file_id: FileId(
0,
),
- full_range: 202..227,
- focus_range: 206..211,
+ full_range: 267..292,
+ focus_range: 271..276,
name: "tests",
kind: Module,
description: "mod tests",
@@ -1701,7 +1724,7 @@ gen2!();
file_id: FileId(
0,
),
- full_range: 218..225,
+ full_range: 283..290,
name: "foo_test",
kind: Function,
},
@@ -1721,7 +1744,7 @@ gen2!();
file_id: FileId(
0,
),
- full_range: 228..236,
+ full_range: 293..301,
name: "foo_test2",
kind: Function,
},
@@ -1741,7 +1764,7 @@ gen2!();
file_id: FileId(
0,
),
- full_range: 228..236,
+ full_range: 293..301,
name: "tests2",
kind: Module,
description: "mod tests2",
@@ -1751,6 +1774,19 @@ gen2!();
},
cfg: None,
},
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 302..314,
+ name: "main",
+ kind: Function,
+ },
+ kind: Bin,
+ cfg: None,
+ },
]
"#]],
);
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index e020b52e1..990376a49 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -4,7 +4,10 @@
use std::collections::BTreeSet;
use either::Either;
-use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait};
+use hir::{
+ AssocItem, DescendPreference, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics,
+ Trait,
+};
use ide_db::{
active_parameter::{callable_for_node, generic_def_for_node},
base_db::FilePosition,
@@ -79,7 +82,7 @@ pub(crate) fn signature_help(
// if the cursor is sandwiched between two space tokens and the call is unclosed
// this prevents us from leaving the CallExpression
.and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
- let token = sema.descend_into_macros_single(token, offset);
+ let token = sema.descend_into_macros_single(DescendPreference::None, token);
for node in token.parent_ancestors() {
match_ast! {
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index aabd26da2..3724dc282 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -3,7 +3,7 @@
use std::collections::HashMap;
-use hir::{db::HirDatabase, Crate, Module};
+use hir::{db::HirDatabase, Crate, HirFileIdExt, Module};
use ide_db::helpers::get_definition;
use ide_db::{
base_db::{FileId, FileRange, SourceDatabaseExt},
@@ -13,6 +13,7 @@ use ide_db::{
use syntax::{AstNode, SyntaxKind::*, TextRange, T};
use crate::inlay_hints::InlayFieldsToResolve;
+use crate::navigation_target::UpmappingResult;
use crate::{
hover::hover_for_definition,
inlay_hints::AdjustmentHintsMode,
@@ -118,6 +119,7 @@ impl StaticIndex<'_> {
adjustment_hints: crate::AdjustmentHints::Never,
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
+ implicit_drop_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
closure_style: hir::ClosureStyle::ImplFn,
@@ -165,9 +167,8 @@ impl StaticIndex<'_> {
} else {
let it = self.tokens.insert(TokenStaticData {
hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
- definition: def.try_to_nav(self.db).map(|it| FileRange {
- file_id: it.file_id,
- range: it.focus_or_full_range(),
+ definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
+ FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
}),
references: vec![],
moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
@@ -178,7 +179,7 @@ impl StaticIndex<'_> {
let token = self.tokens.get_mut(id).unwrap();
token.references.push(ReferenceData {
range: FileRange { range, file_id },
- is_definition: match def.try_to_nav(self.db) {
+ is_definition: match def.try_to_nav(self.db).map(UpmappingResult::call_site) {
Some(it) => it.file_id == file_id && it.focus_or_full_range() == range,
None => false,
},
@@ -242,6 +243,7 @@ mod tests {
}
}
+ #[track_caller]
fn check_definitions(ra_fixture: &str) {
let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
let s = StaticIndex::compute(&analysis);
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index c9ee460a1..e7f97ebe6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -2,7 +2,7 @@ use std::{fmt, marker::PhantomData};
use hir::{
db::{AstIdMapQuery, AttrsQuery, BlockDefMapQuery, ParseMacroExpansionQuery},
- Attr, Attrs, ExpandResult, MacroFile, Module,
+ Attr, Attrs, ExpandResult, MacroFileId, Module,
};
use ide_db::{
base_db::{
@@ -199,8 +199,12 @@ impl StatCollect<FileId, Parse<ast::SourceFile>> for SyntaxTreeStats<false> {
}
}
-impl<M> StatCollect<MacroFile, ExpandResult<(Parse<SyntaxNode>, M)>> for SyntaxTreeStats<true> {
- fn collect_entry(&mut self, _: MacroFile, value: Option<ExpandResult<(Parse<SyntaxNode>, M)>>) {
+impl<M> StatCollect<MacroFileId, ExpandResult<(Parse<SyntaxNode>, M)>> for SyntaxTreeStats<true> {
+ fn collect_entry(
+ &mut self,
+ _: MacroFileId,
+ value: Option<ExpandResult<(Parse<SyntaxNode>, M)>>,
+ ) {
self.total += 1;
self.retained += value.is_some() as usize;
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index bb01c81d6..307812156 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -13,7 +13,7 @@ mod html;
#[cfg(test)]
mod tests;
-use hir::{Name, Semantics};
+use hir::{DescendPreference, Name, Semantics};
use ide_db::{FxHashMap, RootDatabase, SymbolKind};
use syntax::{
ast::{self, IsString},
@@ -245,7 +245,7 @@ fn traverse(
let mut macro_highlighter = MacroHighlighter::default();
// FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree
- // an an attribute nested in a macro call will not emit `inside_attribute`
+ // an attribute nested in a macro call will not emit `inside_attribute`
let mut inside_attribute = false;
let mut inside_macro_call = false;
@@ -393,13 +393,18 @@ fn traverse(
// Attempt to descend tokens into macro-calls.
let res = match element {
NodeOrToken::Token(token) if token.kind() != COMMENT => {
- let token = match attr_or_derive_item {
- Some(AttrOrDerive::Attr(_)) => {
- sema.descend_into_macros_with_kind_preference(token, 0.into())
- }
- Some(AttrOrDerive::Derive(_)) | None => {
- sema.descend_into_macros_single(token, 0.into())
- }
+ let token = if token.kind() == STRING {
+ // for strings, try to prefer a string that has not been lost in a token
+ // tree
+ // FIXME: This should be done for everything, but check perf first
+ sema.descend_into_macros(DescendPreference::SameKind, token)
+ .into_iter()
+ .max_by_key(|it| {
+ it.parent().map_or(false, |it| it.kind() != TOKEN_TREE)
+ })
+ .unwrap()
+ } else {
+ sema.descend_into_macros_single(DescendPreference::SameKind, token)
};
match token.parent().and_then(ast::NameLike::cast) {
// Remap the token into the wrapping single token nodes
@@ -441,7 +446,7 @@ fn traverse(
{
continue;
}
- highlight_format_string(hl, &string, &expanded_string, range);
+ highlight_format_string(hl, sema, krate, &string, &expanded_string, range);
if !string.is_raw() {
highlight_escape_string(hl, &string, range.start());
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
index 2ef131594..518e71454 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
@@ -1,14 +1,20 @@
//! Syntax highlighting for format macro strings.
use ide_db::{
+ defs::Definition,
syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
SymbolKind,
};
use syntax::{ast, TextRange};
-use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag};
+use crate::{
+ syntax_highlighting::{highlight::highlight_def, highlights::Highlights},
+ HlRange, HlTag,
+};
pub(super) fn highlight_format_string(
stack: &mut Highlights,
+ sema: &hir::Semantics<'_, ide_db::RootDatabase>,
+ krate: hir::Crate,
string: &ast::String,
expanded_string: &ast::String,
range: TextRange,
@@ -27,6 +33,18 @@ pub(super) fn highlight_format_string(
});
}
});
+
+ if let Some(parts) = sema.as_format_args_parts(string) {
+ parts.into_iter().for_each(|(range, res)| {
+ if let Some(res) = res {
+ stack.add(HlRange {
+ range,
+ highlight: highlight_def(sema, krate, Definition::from(res)),
+ binding_hash: None,
+ })
+ }
+ })
+ }
}
fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 7d00282fc..0558f658f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,6 +1,6 @@
//! Computes color for a single element.
-use hir::{AsAssocItem, HasVisibility, Semantics};
+use hir::{AsAssocItem, HasVisibility, MacroFileIdExt, Semantics};
use ide_db::{
defs::{Definition, IdentClass, NameClass, NameRefClass},
FxHashMap, RootDatabase, SymbolKind,
@@ -218,7 +218,10 @@ fn highlight_name_ref(
// We can fix this for derive attributes since derive helpers are recorded, but not for
// general attributes.
None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR)
- && !sema.hir_file_for(name_ref.syntax()).is_derive_attr_pseudo_expansion(sema.db) =>
+ && !sema
+ .hir_file_for(name_ref.syntax())
+ .macro_file()
+ .map_or(false, |it| it.is_derive_attr_pseudo_expansion(sema.db)) =>
{
return HlTag::Symbol(SymbolKind::Attribute).into();
}
@@ -348,7 +351,7 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
hash((name, shadow_count))
}
-fn highlight_def(
+pub(super) fn highlight_def(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
def: Definition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index 06b66b302..e8b3a38c9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -43,7 +43,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
</style>
-<pre><code><span class="module crate_root library">proc_macros</span><span class="operator">::</span><span class="macro library">mirror</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
+<pre><code><span class="keyword">use</span> <span class="module crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="function library">mirror</span><span class="comma">,</span> <span class="function library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
+
+<span class="macro library">mirror</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
<span class="brace macro">{</span>
<span class="comma macro">,</span><span class="builtin_type macro">i32</span> <span class="colon macro">:</span><span class="field declaration macro public">x</span> <span class="keyword macro">pub</span>
<span class="comma macro">,</span><span class="builtin_type macro">i32</span> <span class="colon macro">:</span><span class="field declaration macro public">y</span> <span class="keyword macro">pub</span>
@@ -90,17 +92,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="brace">}</span>
<span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">include</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="macro">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
- <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 64e614cec..84a823363 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -48,47 +48,38 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="brace">}</span><span class="parenthesis">)</span>
<span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
<span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration">panic_2015</span> <span class="brace">{</span>
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
- <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic<span class="parenthesis">(</span><span class="string_literal">"explicit panic"</span><span class="parenthesis">)</span>
+ panic<span class="parenthesis">(</span><span class="string_literal">"explicit panic"</span><span class="parenthesis">)</span>
<span class="parenthesis">)</span><span class="comma">,</span>
<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="colon">:</span>literal <span class="punctuation">$</span><span class="parenthesis">(</span><span class="comma">,</span><span class="parenthesis">)</span><span class="punctuation">?</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
- <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="parenthesis">)</span>
+ panic<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="parenthesis">)</span>
<span class="parenthesis">)</span><span class="comma">,</span>
<span class="comment">// Use `panic_str` instead of `panic_display::&lt;&str&gt;` for non_fmt_panic lint.</span>
<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="colon">:</span>expr <span class="punctuation">$</span><span class="parenthesis">(</span><span class="comma">,</span><span class="parenthesis">)</span><span class="punctuation">?</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
- <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_str<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="parenthesis">)</span>
+ panic_str<span class="parenthesis">(</span><span class="punctuation">$</span>msg<span class="parenthesis">)</span>
<span class="parenthesis">)</span><span class="comma">,</span>
<span class="comment">// Special-case the single-argument case for const_panic.</span>
<span class="parenthesis">(</span><span class="string_literal">"{}"</span><span class="comma">,</span> <span class="punctuation">$</span>arg<span class="colon">:</span>expr <span class="punctuation">$</span><span class="parenthesis">(</span><span class="comma">,</span><span class="parenthesis">)</span><span class="punctuation">?</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
- <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_display<span class="parenthesis">(</span><span class="punctuation">&</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span>
+ panic_display<span class="parenthesis">(</span><span class="punctuation">&</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span>
<span class="parenthesis">)</span><span class="comma">,</span>
<span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
- <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_fmt<span class="parenthesis">(</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+ panic_fmt<span class="parenthesis">(</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
<span class="parenthesis">)</span><span class="comma">,</span>
<span class="brace">}</span>
<span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="parenthesis attribute">(</span><span class="none attribute">std_panic</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">panic</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">assert</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">asm</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span>
-
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">reuse_twice</span> <span class="brace">{</span>
+ <span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="colon">:</span>literal<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">{</span>stringify<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="semicolon">;</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\n</span><span class="char_literal">'</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\t</span><span class="char_literal">'</span><span class="semicolon">;</span>
@@ -165,20 +156,23 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more {}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{} asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
- <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
- <span class="string_literal macro">"mov {0}, {1}"</span><span class="comma macro">,</span>
- <span class="string_literal macro">"add {0}, 5"</span><span class="comma macro">,</span>
+ <span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
+ <span class="string_literal macro">"mov </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>
+ <span class="string_literal macro">"add </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, 5"</span><span class="comma macro">,</span>
<span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
<span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
- <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="keyword">const</span> <span class="constant declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span>
+ <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">m</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable reference">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="constant">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable mutable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+ <span class="macro">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable reference">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 542d89925..afb6c555b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -47,9 +47,12 @@ struct Foo;
fn macros() {
check_highlighting(
r#"
-//- proc_macros: mirror
+//- proc_macros: mirror, identity, derive_identity
+//- minicore: fmt, include, concat
//- /lib.rs crate:lib
-proc_macros::mirror! {
+use proc_macros::{mirror, identity, DeriveIdentity};
+
+mirror! {
{
,i32 :x pub
,i32 :y pub
@@ -96,12 +99,6 @@ macro without_args {
}
}
-#[rustc_builtin_macro]
-macro_rules! concat {}
-#[rustc_builtin_macro]
-macro_rules! include {}
-#[rustc_builtin_macro]
-macro_rules! format_args {}
include!(concat!("foo/", "foo.rs"));
@@ -401,53 +398,44 @@ fn test_string_highlighting() {
// thus, we have to copy the macro definition from `std`
check_highlighting(
r#"
-//- minicore: fmt
+//- minicore: fmt, assert, asm, concat, panic
macro_rules! println {
($($arg:tt)*) => ({
$crate::io::_print(format_args_nl!($($arg)*));
})
}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! format_args_nl {}
mod panic {
pub macro panic_2015 {
() => (
- $crate::panicking::panic("explicit panic")
+ panic("explicit panic")
),
($msg:literal $(,)?) => (
- $crate::panicking::panic($msg)
+ panic($msg)
),
// Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
($msg:expr $(,)?) => (
- $crate::panicking::panic_str($msg)
+ panic_str($msg)
),
// Special-case the single-argument case for const_panic.
("{}", $arg:expr $(,)?) => (
- $crate::panicking::panic_display(&$arg)
+ panic_display(&$arg)
),
($fmt:expr, $($arg:tt)+) => (
- $crate::panicking::panic_fmt(const_format_args!($fmt, $($arg)+))
+ panic_fmt(const_format_args!($fmt, $($arg)+))
),
}
}
-#[rustc_builtin_macro(std_panic)]
-#[macro_export]
-macro_rules! panic {}
-#[rustc_builtin_macro]
-macro_rules! assert {}
-#[rustc_builtin_macro]
-macro_rules! asm {}
-#[rustc_builtin_macro]
-macro_rules! concat {}
-
macro_rules! toho {
() => ($crate::panic!("not yet implemented"));
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
}
+macro_rules! reuse_twice {
+ ($literal:literal) => {{stringify!($literal); format_args!($literal)}};
+}
+
fn main() {
let a = '\n';
let a = '\t';
@@ -538,8 +526,11 @@ fn main() {
in(reg) i,
);
+ const CONSTANT: () = ():
+ let mut m = ();
format_args!(concat!("{}"), "{}");
- format_args!("{} {} {} {} {} {}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash);
+ format_args!("{} {} {} {} {} {} {backslash} {CONSTANT} {m}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash);
+ reuse_twice!("{backslash}");
}"#,
expect_file!["./test_data/highlight_strings.html"],
false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index b40509715..d21850bcf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -47,7 +47,7 @@ struct ExtendedTextEdit {
// - typing `=` between two expressions adds `;` when in statement position
// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position
// - typing `.` in a chain method call auto-indents
-// - typing `{` in front of an expression inserts a closing `}` after the expression
+// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression
// - typing `{` in a use item adds a closing `}` in the right place
//
// VS Code::
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
index d2bbbf6d2..9abe54cd3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
@@ -1,7 +1,7 @@
use hir::{DefWithBody, Semantics};
use ide_db::base_db::FilePosition;
use ide_db::RootDatabase;
-use syntax::{algo::find_node_at_offset, ast, AstNode};
+use syntax::{algo::ancestors_at_offset, ast, AstNode};
// Feature: View Hir
//
@@ -19,7 +19,9 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
let sema = Semantics::new(db);
let source_file = sema.parse(position.file_id);
- let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
+ let item = ancestors_at_offset(source_file.syntax(), position.offset)
+ .filter(|it| !ast::MacroCall::can_cast(it.kind()))
+ .find_map(ast::Item::cast)?;
let def: DefWithBody = match item {
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
ast::Item::Const(it) => sema.to_def(&it)?.into(),
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 2f6332abd..3802978f4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -55,6 +55,7 @@ impl fmt::Display for RecursiveMemoryLayout {
}
}
+#[derive(Copy, Clone)]
enum FieldOrTupleIdx {
Field(Field),
TupleIdx(usize),
@@ -71,13 +72,6 @@ impl FieldOrTupleIdx {
FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(),
}
}
-
- fn index(&self) -> usize {
- match *self {
- FieldOrTupleIdx::Field(f) => f.index(),
- FieldOrTupleIdx::TupleIdx(i) => i,
- }
- }
}
// Feature: View Memory Layout
@@ -138,7 +132,10 @@ pub(crate) fn view_memory_layout(
return;
}
- fields.sort_by_key(|(f, _)| layout.field_offset(f.index()).unwrap());
+ fields.sort_by_key(|&(f, _)| match f {
+ FieldOrTupleIdx::Field(f) => layout.field_offset(f).unwrap_or(0),
+ FieldOrTupleIdx::TupleIdx(f) => layout.tuple_field_offset(f).unwrap_or(0),
+ });
let children_start = nodes.len();
nodes[parent_idx].children_start = children_start as i64;
@@ -151,7 +148,10 @@ pub(crate) fn view_memory_layout(
typename: child_ty.display(db).to_string(),
size: child_layout.size(),
alignment: child_layout.align(),
- offset: layout.field_offset(field.index()).unwrap_or(0),
+ offset: match *field {
+ FieldOrTupleIdx::Field(f) => layout.field_offset(f).unwrap_or(0),
+ FieldOrTupleIdx::TupleIdx(f) => layout.tuple_field_offset(f).unwrap_or(0),
+ },
parent_idx: parent_idx as i64,
children_start: -1,
children_len: 0,
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
index a36aba58b..08d810c13 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
@@ -1,7 +1,7 @@
use hir::{DefWithBody, Semantics};
use ide_db::base_db::FilePosition;
use ide_db::RootDatabase;
-use syntax::{algo::find_node_at_offset, ast, AstNode};
+use syntax::{algo::ancestors_at_offset, ast, AstNode};
// Feature: View Mir
//
@@ -18,7 +18,9 @@ fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> {
let sema = Semantics::new(db);
let source_file = sema.parse(position.file_id);
- let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
+ let item = ancestors_at_offset(source_file.syntax(), position.offset)
+ .filter(|it| !ast::MacroCall::can_cast(it.kind()))
+ .find_map(ast::Item::cast)?;
let def: DefWithBody = match item {
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
ast::Item::Const(it) => sema.to_def(&it)?.into(),