mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
15b867b5db
commit
b2f6fd4f96
217 changed files with 12639 additions and 3059 deletions
|
@ -107,7 +107,18 @@ pub(crate) fn remove_links(markdown: &str) -> String {
|
|||
out
|
||||
}
|
||||
|
||||
/// Retrieve a link to documentation for the given symbol.
|
||||
// Feature: Open Docs
|
||||
//
|
||||
// Retrieve a link to documentation for the given symbol.
|
||||
//
|
||||
// The simplest way to use this feature is via the context menu. Right-click on
|
||||
// the selected item. The context menu opens. Select **Open Docs**.
|
||||
//
|
||||
// |===
|
||||
// | Editor | Action Name
|
||||
//
|
||||
// | VS Code | **rust-analyzer: Open Docs**
|
||||
// |===
|
||||
pub(crate) fn external_docs(
|
||||
db: &RootDatabase,
|
||||
position: &FilePosition,
|
||||
|
@ -181,6 +192,7 @@ pub(crate) fn resolve_doc_path_for_def(
|
|||
Definition::Const(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::Static(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::Trait(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
|
||||
Definition::Field(it) => it.resolve_doc_path(db, link, ns),
|
||||
|
@ -493,6 +505,7 @@ fn filename_and_frag_for_def(
|
|||
None => String::from("index.html"),
|
||||
},
|
||||
Definition::Trait(t) => format!("trait.{}.html", t.name(db)),
|
||||
Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db)),
|
||||
Definition::TypeAlias(t) => format!("type.{}.html", t.name(db)),
|
||||
Definition::BuiltinType(t) => format!("primitive.{}.html", t.name()),
|
||||
Definition::Function(f) => format!("fn.{}.html", f.name(db)),
|
||||
|
|
|
@ -149,6 +149,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
|
|||
ast::Enum(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Enum)),
|
||||
ast::Variant(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Variant)),
|
||||
ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)),
|
||||
ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)),
|
||||
ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)),
|
||||
ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)),
|
||||
ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)),
|
||||
|
@ -262,6 +263,8 @@ enum E { X, Y(i32) }
|
|||
type T = ();
|
||||
static S: i32 = 92;
|
||||
const C: i32 = 92;
|
||||
trait Tr {}
|
||||
trait Alias = Tr;
|
||||
|
||||
impl E {}
|
||||
|
||||
|
@ -457,11 +460,33 @@ fn g() {}
|
|||
),
|
||||
deprecated: false,
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "Tr",
|
||||
navigation_range: 239..241,
|
||||
node_range: 233..244,
|
||||
kind: SymbolKind(
|
||||
Trait,
|
||||
),
|
||||
detail: None,
|
||||
deprecated: false,
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "Alias",
|
||||
navigation_range: 251..256,
|
||||
node_range: 245..262,
|
||||
kind: SymbolKind(
|
||||
TraitAlias,
|
||||
),
|
||||
detail: None,
|
||||
deprecated: false,
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "impl E",
|
||||
navigation_range: 239..240,
|
||||
node_range: 234..243,
|
||||
navigation_range: 269..270,
|
||||
node_range: 264..273,
|
||||
kind: SymbolKind(
|
||||
Impl,
|
||||
),
|
||||
|
@ -471,8 +496,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "impl fmt::Debug for E",
|
||||
navigation_range: 265..266,
|
||||
node_range: 245..269,
|
||||
navigation_range: 295..296,
|
||||
node_range: 275..299,
|
||||
kind: SymbolKind(
|
||||
Impl,
|
||||
),
|
||||
|
@ -482,8 +507,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "mc",
|
||||
navigation_range: 284..286,
|
||||
node_range: 271..303,
|
||||
navigation_range: 314..316,
|
||||
node_range: 301..333,
|
||||
kind: SymbolKind(
|
||||
Macro,
|
||||
),
|
||||
|
@ -493,8 +518,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "mcexp",
|
||||
navigation_range: 334..339,
|
||||
node_range: 305..356,
|
||||
navigation_range: 364..369,
|
||||
node_range: 335..386,
|
||||
kind: SymbolKind(
|
||||
Macro,
|
||||
),
|
||||
|
@ -504,8 +529,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "mcexp",
|
||||
navigation_range: 387..392,
|
||||
node_range: 358..409,
|
||||
navigation_range: 417..422,
|
||||
node_range: 388..439,
|
||||
kind: SymbolKind(
|
||||
Macro,
|
||||
),
|
||||
|
@ -515,8 +540,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "obsolete",
|
||||
navigation_range: 428..436,
|
||||
node_range: 411..441,
|
||||
navigation_range: 458..466,
|
||||
node_range: 441..471,
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
|
@ -528,8 +553,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "very_obsolete",
|
||||
navigation_range: 481..494,
|
||||
node_range: 443..499,
|
||||
navigation_range: 511..524,
|
||||
node_range: 473..529,
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
|
@ -541,8 +566,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "Some region name",
|
||||
navigation_range: 501..528,
|
||||
node_range: 501..528,
|
||||
navigation_range: 531..558,
|
||||
node_range: 531..558,
|
||||
kind: Region,
|
||||
detail: None,
|
||||
deprecated: false,
|
||||
|
@ -550,8 +575,8 @@ fn g() {}
|
|||
StructureNode {
|
||||
parent: None,
|
||||
label: "m",
|
||||
navigation_range: 568..569,
|
||||
node_range: 543..606,
|
||||
navigation_range: 598..599,
|
||||
node_range: 573..636,
|
||||
kind: SymbolKind(
|
||||
Module,
|
||||
),
|
||||
|
@ -560,22 +585,22 @@ fn g() {}
|
|||
},
|
||||
StructureNode {
|
||||
parent: Some(
|
||||
20,
|
||||
22,
|
||||
),
|
||||
label: "dontpanic",
|
||||
navigation_range: 543..563,
|
||||
node_range: 543..563,
|
||||
navigation_range: 573..593,
|
||||
node_range: 573..593,
|
||||
kind: Region,
|
||||
detail: None,
|
||||
deprecated: false,
|
||||
},
|
||||
StructureNode {
|
||||
parent: Some(
|
||||
20,
|
||||
22,
|
||||
),
|
||||
label: "f",
|
||||
navigation_range: 575..576,
|
||||
node_range: 572..581,
|
||||
navigation_range: 605..606,
|
||||
node_range: 602..611,
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
|
@ -586,11 +611,11 @@ fn g() {}
|
|||
},
|
||||
StructureNode {
|
||||
parent: Some(
|
||||
20,
|
||||
22,
|
||||
),
|
||||
label: "g",
|
||||
navigation_range: 598..599,
|
||||
node_range: 582..604,
|
||||
navigation_range: 628..629,
|
||||
node_range: 612..634,
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
|
|
|
@ -764,6 +764,13 @@ trait Foo$0 { }
|
|||
"#,
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait Foo$0 = ;
|
||||
//^^^
|
||||
"#,
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
mod bar$0 { }
|
||||
|
@ -1065,6 +1072,23 @@ fn f() -> impl Sub<Item$0 = u8> {}
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {
|
||||
check(
|
||||
r#"
|
||||
mod bar {
|
||||
pub struct Foo {}
|
||||
//^^^
|
||||
pub fn Foo() {}
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
let _foo_enum: bar::Foo$0 = bar::Foo {};
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_assoc_ty() {
|
||||
check_unresolved(
|
||||
|
@ -1406,7 +1430,6 @@ include!("included.rs$0");
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod goto_impl_of_trait_fn {
|
||||
use super::check;
|
||||
#[test]
|
||||
|
|
|
@ -14,7 +14,7 @@ use syntax::{
|
|||
SyntaxNode, SyntaxToken, TextRange, T,
|
||||
};
|
||||
|
||||
use crate::{references, NavigationTarget, TryToNav};
|
||||
use crate::{navigation_target::ToNav, references, NavigationTarget, TryToNav};
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct HighlightedRange {
|
||||
|
@ -98,32 +98,39 @@ fn highlight_references(
|
|||
category: access,
|
||||
});
|
||||
let mut res = FxHashSet::default();
|
||||
|
||||
let mut def_to_hl_range = |def| {
|
||||
let hl_range = match def {
|
||||
Definition::Module(module) => {
|
||||
Some(NavigationTarget::from_module_to_decl(sema.db, module))
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
for &def in &defs {
|
||||
match def {
|
||||
Definition::Local(local) => local
|
||||
.associated_locals(sema.db)
|
||||
.iter()
|
||||
.for_each(|&local| def_to_hl_range(Definition::Local(local))),
|
||||
def => def_to_hl_range(def),
|
||||
Definition::Local(local) => {
|
||||
let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write);
|
||||
local
|
||||
.sources(sema.db)
|
||||
.into_iter()
|
||||
.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 })
|
||||
.for_each(|x| {
|
||||
res.insert(x);
|
||||
});
|
||||
}
|
||||
def => {
|
||||
let hl_range = match def {
|
||||
Definition::Module(module) => {
|
||||
Some(NavigationTarget::from_module_to_decl(sema.db, module))
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ pub struct HoverConfig {
|
|||
pub documentation: bool,
|
||||
pub keywords: bool,
|
||||
pub format: HoverDocFormat,
|
||||
pub interpret_tests: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -3,7 +3,8 @@ use std::fmt::Display;
|
|||
|
||||
use either::Either;
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo,
|
||||
db::DefDatabase, Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay,
|
||||
MirEvalError, Semantics, TypeInfo,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
|
@ -402,7 +403,20 @@ pub(super) fn definition(
|
|||
))
|
||||
}),
|
||||
Definition::Module(it) => label_and_docs(db, it),
|
||||
Definition::Function(it) => label_and_docs(db, it),
|
||||
Definition::Function(it) => label_and_layout_info_and_docs(db, it, |_| {
|
||||
if !config.interpret_tests {
|
||||
return None;
|
||||
}
|
||||
match it.eval(db) {
|
||||
Ok(()) => Some("pass".into()),
|
||||
Err(MirEvalError::Panic) => Some("fail".into()),
|
||||
Err(MirEvalError::MirLowerError(f, e)) => {
|
||||
let name = &db.function_data(f).name;
|
||||
Some(format!("error: fail to lower {name} due {e:?}"))
|
||||
}
|
||||
Err(e) => Some(format!("error: {e:?}")),
|
||||
}
|
||||
}),
|
||||
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, |&it| {
|
||||
let layout = it.layout(db).ok()?;
|
||||
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
|
||||
|
@ -410,7 +424,7 @@ pub(super) fn definition(
|
|||
Definition::Variant(it) => label_value_and_docs(db, it, |&it| {
|
||||
if !it.parent_enum(db).is_data_carrying(db) {
|
||||
match it.eval(db) {
|
||||
Ok(x) => Some(format!("{x}")),
|
||||
Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }),
|
||||
Err(_) => it.value(db).map(|x| format!("{x:?}")),
|
||||
}
|
||||
} else {
|
||||
|
@ -418,9 +432,9 @@ pub(super) fn definition(
|
|||
}
|
||||
}),
|
||||
Definition::Const(it) => label_value_and_docs(db, it, |it| {
|
||||
let body = it.eval(db);
|
||||
let body = it.render_eval(db);
|
||||
match body {
|
||||
Ok(x) => Some(format!("{x}")),
|
||||
Ok(x) => Some(x),
|
||||
Err(_) => {
|
||||
let source = it.source(db)?;
|
||||
let mut body = source.value.body()?.syntax().clone();
|
||||
|
@ -440,6 +454,7 @@ pub(super) fn definition(
|
|||
Some(body.to_string())
|
||||
}),
|
||||
Definition::Trait(it) => label_and_docs(db, it),
|
||||
Definition::TraitAlias(it) => label_and_docs(db, it),
|
||||
Definition::TypeAlias(it) => label_and_docs(db, it),
|
||||
Definition::BuiltinType(it) => {
|
||||
return famous_defs
|
||||
|
@ -620,8 +635,8 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
|||
let ty = it.ty(db);
|
||||
let ty = ty.display_truncated(db, None);
|
||||
let is_mut = if it.is_mut(db) { "mut " } else { "" };
|
||||
let desc = match it.source(db).value {
|
||||
Either::Left(ident) => {
|
||||
let desc = match it.primary_source(db).into_ident_pat() {
|
||||
Some(ident) => {
|
||||
let name = it.name(db);
|
||||
let let_kw = if ident
|
||||
.syntax()
|
||||
|
@ -634,7 +649,7 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
|||
};
|
||||
format!("{let_kw}{is_mut}{name}: {ty}")
|
||||
}
|
||||
Either::Right(_) => format!("{is_mut}self: {ty}"),
|
||||
None => format!("{is_mut}self: {ty}"),
|
||||
};
|
||||
markup(None, desc, None)
|
||||
}
|
||||
|
|
|
@ -4,16 +4,19 @@ use syntax::TextRange;
|
|||
|
||||
use crate::{fixture, HoverConfig, HoverDocFormat};
|
||||
|
||||
const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
|
||||
links_in_hover: false,
|
||||
documentation: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
keywords: true,
|
||||
interpret_tests: false,
|
||||
};
|
||||
|
||||
fn check_hover_no_result(ra_fixture: &str) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: true,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
|
||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -25,12 +28,7 @@ fn check(ra_fixture: &str, expect: Expect) {
|
|||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: true,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
|
||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||
)
|
||||
.unwrap()
|
||||
|
@ -47,12 +45,7 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
|
|||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: false,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
&HOVER_BASE_CONFIG,
|
||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||
)
|
||||
.unwrap()
|
||||
|
@ -71,9 +64,8 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
|
|||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: true,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::PlainText,
|
||||
..HOVER_BASE_CONFIG
|
||||
},
|
||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||
)
|
||||
|
@ -91,12 +83,7 @@ fn check_actions(ra_fixture: &str, expect: Expect) {
|
|||
let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: true,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
|
||||
FileRange { file_id, range: position.range_or_empty() },
|
||||
)
|
||||
.unwrap()
|
||||
|
@ -106,34 +93,13 @@ fn check_actions(ra_fixture: &str, expect: Expect) {
|
|||
|
||||
fn check_hover_range(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, range) = fixture::range(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: false,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
range,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap();
|
||||
expect.assert_eq(hover.info.markup.as_str())
|
||||
}
|
||||
|
||||
fn check_hover_range_no_results(ra_fixture: &str) {
|
||||
let (analysis, range) = fixture::range(ra_fixture);
|
||||
let hover = analysis
|
||||
.hover(
|
||||
&HoverConfig {
|
||||
links_in_hover: false,
|
||||
documentation: true,
|
||||
keywords: true,
|
||||
format: HoverDocFormat::Markdown,
|
||||
},
|
||||
range,
|
||||
)
|
||||
.unwrap();
|
||||
let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap();
|
||||
assert!(hover.is_none());
|
||||
}
|
||||
|
||||
|
@ -490,7 +456,6 @@ fn hover_field_offset() {
|
|||
// Hovering over the field when instantiating
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
|
@ -512,7 +477,6 @@ fn hover_shows_struct_field_info() {
|
|||
// Hovering over the field when instantiating
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
struct Foo { field_a: u32 }
|
||||
|
||||
fn main() {
|
||||
|
@ -535,7 +499,6 @@ fn main() {
|
|||
// Hovering over the field in the definition
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
struct Foo { field_a$0: u32 }
|
||||
|
||||
fn main() {
|
||||
|
@ -610,6 +573,27 @@ const foo$0: u32 = {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_eval_complex_constants() {
|
||||
check(
|
||||
r#"
|
||||
struct X { f1: (), f2: i32 }
|
||||
const foo$0: (i8, X, i64) = (1, X { f2: 5 - 1, f1: () }, 1 - 2);
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const foo: (i8, X, i64) = (1, X { f1: (), f2: 4 }, -1)
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_default_generic_types() {
|
||||
check(
|
||||
|
@ -1467,8 +1451,6 @@ fn my() {}
|
|||
fn test_hover_struct_doc_comment() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
|
||||
/// This is an example
|
||||
/// multiline doc
|
||||
///
|
||||
|
@ -1527,7 +1509,7 @@ fn foo() { let bar = Ba$0r; }
|
|||
```
|
||||
|
||||
```rust
|
||||
struct Bar
|
||||
struct Bar // size = 0, align = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -1556,7 +1538,7 @@ fn foo() { let bar = Ba$0r; }
|
|||
```
|
||||
|
||||
```rust
|
||||
struct Bar
|
||||
struct Bar // size = 0, align = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -1584,7 +1566,7 @@ pub struct B$0ar
|
|||
```
|
||||
|
||||
```rust
|
||||
pub struct Bar
|
||||
pub struct Bar // size = 0, align = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -1611,7 +1593,7 @@ pub struct B$0ar
|
|||
```
|
||||
|
||||
```rust
|
||||
pub struct Bar
|
||||
pub struct Bar // size = 0, align = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -2913,8 +2895,6 @@ fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
|
|||
fn hover_field_pat_shorthand_ref_match_ergonomics() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
|
||||
struct S {
|
||||
f: i32,
|
||||
}
|
||||
|
@ -3506,8 +3486,8 @@ impl<const LEN: usize> Foo<LEN$0> {}
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn hover_const_eval_variant() {
|
||||
// show hex for <10
|
||||
fn hover_const_eval_discriminant() {
|
||||
// Don't show hex for <10
|
||||
check(
|
||||
r#"
|
||||
#[repr(u8)]
|
||||
|
@ -3532,7 +3512,7 @@ enum E {
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// show hex for >10
|
||||
// Show hex for >10
|
||||
check(
|
||||
r#"
|
||||
#[repr(u8)]
|
||||
|
@ -3656,7 +3636,7 @@ trait T {
|
|||
}
|
||||
impl T for i32 {
|
||||
const AA: A = A {
|
||||
i: 2
|
||||
i: 2 + 3
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
|
@ -3671,9 +3651,7 @@ fn main() {
|
|||
```
|
||||
|
||||
```rust
|
||||
const AA: A = A {
|
||||
i: 2
|
||||
}
|
||||
const AA: A = A { i: 5 }
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
@ -3792,7 +3770,6 @@ const FOO$0: usize = 1 << 3;
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// show hex for >10
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
|
@ -3850,7 +3827,7 @@ const FOO$0: i32 = 2 - 3;
|
|||
```
|
||||
|
||||
```rust
|
||||
const FOO: i32 = -1
|
||||
const FOO: i32 = -1 (0xFFFFFFFF)
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -4011,6 +3988,28 @@ const FOO$0: f32 = 1f32;
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// Don't show `<ref-not-supported>` in const hover
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: &i32 = &2;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const FOO: &i32 = &2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
//show f64 typecasted from float
|
||||
check(
|
||||
r#"
|
||||
|
@ -4354,8 +4353,6 @@ fn main() {
|
|||
fn hover_intra_doc_links() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
|
||||
pub mod theitem {
|
||||
/// This is the item. Cool!
|
||||
pub struct TheItem;
|
||||
|
@ -4496,7 +4493,7 @@ trait A where
|
|||
fn string_shadowed_with_inner_items() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:alloc target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
//- /main.rs crate:main deps:alloc
|
||||
|
||||
/// Custom `String` type.
|
||||
struct String;
|
||||
|
@ -5191,7 +5188,7 @@ foo_macro!(
|
|||
```
|
||||
|
||||
```rust
|
||||
pub struct Foo
|
||||
pub struct Foo // size = 0, align = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -5205,8 +5202,6 @@ foo_macro!(
|
|||
fn hover_intra_in_attr() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
|
||||
#[doc = "Doc comment for [`Foo$0`]"]
|
||||
pub struct Foo(i32);
|
||||
"#,
|
||||
|
@ -5295,7 +5290,7 @@ pub struct Type;
|
|||
```
|
||||
|
||||
```rust
|
||||
const KONST: dep::Type = $crate::Type
|
||||
const KONST: dep::Type = Type
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
@ -5327,8 +5322,6 @@ enum Enum {
|
|||
fn hover_record_variant_field() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
|
||||
|
||||
enum Enum {
|
||||
RecordV { field$0: u32 }
|
||||
}
|
||||
|
@ -5647,3 +5640,204 @@ fn main() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assoc_fn_in_block_local_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(crate) fn foo() {}
|
||||
}
|
||||
};
|
||||
}
|
||||
fn test() {
|
||||
S::foo$0();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test::S
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(crate) fn foo()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
const _: () = {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(crate) fn foo() {}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
fn test() {
|
||||
S::foo$0();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test::S
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(crate) fn foo()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
mod inner {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(super) fn foo() {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn test() {
|
||||
crate::S::foo$0();
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test::S
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(super) fn foo()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assoc_const_in_block_local_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(crate) const A: () = ();
|
||||
}
|
||||
};
|
||||
}
|
||||
fn test() {
|
||||
S::A$0;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*A*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(crate) const A: () = ()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
const _: () = {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(crate) const A: () = ();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
fn test() {
|
||||
S::A$0;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*A*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(crate) const A: () = ()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
mod m {
|
||||
mod inner {
|
||||
const _: () = {
|
||||
impl crate::S {
|
||||
pub(super) const A: () = ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn test() {
|
||||
crate::S::A$0;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*A*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
pub(super) const A: () = ()
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_as_method_call_fallback() {
|
||||
check(
|
||||
r#"
|
||||
struct S { f: u32 }
|
||||
fn test() {
|
||||
S { f: 0 }.f$0();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*f*
|
||||
|
||||
```rust
|
||||
test::S
|
||||
```
|
||||
|
||||
```rust
|
||||
f: u32 // size = 4, align = 4, offset = 0
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -606,14 +606,13 @@ fn a() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn bug() {
|
||||
fn let_stmt_explicit_ty() {
|
||||
check_with_config(
|
||||
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
fn main() {
|
||||
// These should be identical, but they are not...
|
||||
|
||||
let () = return;
|
||||
//^^^^^^<never-to-any>
|
||||
let (): () = return;
|
||||
//^^^^^^<never-to-any>
|
||||
}
|
||||
|
|
|
@ -176,15 +176,12 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir
|
|||
mod tests {
|
||||
// This module also contains tests for super::closure_ret
|
||||
|
||||
use expect_test::expect;
|
||||
use syntax::{TextRange, TextSize};
|
||||
use test_utils::extract_annotations;
|
||||
|
||||
use crate::{fixture, inlay_hints::InlayHintsConfig};
|
||||
|
||||
use crate::inlay_hints::tests::{
|
||||
check, check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
|
||||
};
|
||||
use crate::inlay_hints::tests::{check, check_with_config, DISABLED_CONFIG, TEST_CONFIG};
|
||||
use crate::ClosureReturnTypeHints;
|
||||
|
||||
#[track_caller]
|
||||
|
@ -278,8 +275,7 @@ fn main() {
|
|||
#[test]
|
||||
fn iterator_hint_regression_issue_12674() {
|
||||
// Ensure we don't crash while solving the projection type of iterators.
|
||||
check_expect(
|
||||
InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
|
||||
let (analysis, file_id) = fixture::file(
|
||||
r#"
|
||||
//- minicore: iterators
|
||||
struct S<T>(T);
|
||||
|
@ -302,107 +298,18 @@ impl<'a, T> Iterator for SliceIter<'a, T> {
|
|||
|
||||
fn main(a: SliceIter<'_, Container>) {
|
||||
a
|
||||
.filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
|
||||
.map(|e| e);
|
||||
.filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
|
||||
.map(|e| e);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
InlayHint {
|
||||
range: 484..554,
|
||||
kind: Chaining,
|
||||
label: [
|
||||
"impl ",
|
||||
InlayHintLabelPart {
|
||||
text: "Iterator",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2611..2619,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
"<",
|
||||
InlayHintLabelPart {
|
||||
text: "Item",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2643..2647,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
" = impl ",
|
||||
InlayHintLabelPart {
|
||||
text: "Iterator",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2611..2619,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
"<",
|
||||
InlayHintLabelPart {
|
||||
text: "Item",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2643..2647,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
" = &&str>>",
|
||||
],
|
||||
},
|
||||
InlayHint {
|
||||
range: 484..485,
|
||||
kind: Chaining,
|
||||
label: [
|
||||
"",
|
||||
InlayHintLabelPart {
|
||||
text: "SliceIter",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 289..298,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
"<",
|
||||
InlayHintLabelPart {
|
||||
text: "Container",
|
||||
linked_location: Some(
|
||||
FileRange {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 238..247,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
">",
|
||||
],
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
"#,
|
||||
);
|
||||
analysis
|
||||
.inlay_hints(
|
||||
&InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
|
||||
file_id,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -435,7 +435,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2611..2619,
|
||||
range: 3386..3394,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
@ -448,7 +448,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2643..2647,
|
||||
range: 3418..3422,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
@ -468,7 +468,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2611..2619,
|
||||
range: 3386..3394,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
@ -481,7 +481,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2643..2647,
|
||||
range: 3418..3422,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
@ -501,7 +501,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2611..2619,
|
||||
range: 3386..3394,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
@ -514,7 +514,7 @@ fn main() {
|
|||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 2643..2647,
|
||||
range: 3418..3422,
|
||||
},
|
||||
),
|
||||
tooltip: "",
|
||||
|
|
|
@ -59,8 +59,14 @@ fn variant_hints(
|
|||
},
|
||||
kind: InlayKind::Discriminant,
|
||||
label: InlayHintLabel::simple(
|
||||
match &d {
|
||||
Ok(v) => format!("{}", v),
|
||||
match d {
|
||||
Ok(x) => {
|
||||
if x >= 10 {
|
||||
format!("{x} ({x:#X})")
|
||||
} else {
|
||||
format!("{x}")
|
||||
}
|
||||
}
|
||||
Err(_) => "?".into(),
|
||||
},
|
||||
Some(InlayTooltip::String(match &d {
|
||||
|
|
|
@ -55,6 +55,7 @@ mod syntax_tree;
|
|||
mod typing;
|
||||
mod view_crate_graph;
|
||||
mod view_hir;
|
||||
mod view_mir;
|
||||
mod view_item_tree;
|
||||
mod shuffle_crate_graph;
|
||||
|
||||
|
@ -308,6 +309,10 @@ impl Analysis {
|
|||
self.with_db(|db| view_hir::view_hir(db, position))
|
||||
}
|
||||
|
||||
pub fn view_mir(&self, position: FilePosition) -> Cancellable<String> {
|
||||
self.with_db(|db| view_mir::view_mir(db, position))
|
||||
}
|
||||
|
||||
pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {
|
||||
self.with_db(|db| view_item_tree::view_item_tree(db, file_id))
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ impl Markup {
|
|||
pub fn as_str(&self) -> &str {
|
||||
self.text.as_str()
|
||||
}
|
||||
pub fn fenced_block(contents: &impl fmt::Display) -> Markup {
|
||||
pub fn fenced_block(contents: impl fmt::Display) -> Markup {
|
||||
format!("```rust\n{contents}\n```").into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,6 +208,9 @@ pub(crate) fn def_to_moniker(
|
|||
Definition::Trait(trait_) => {
|
||||
MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type }
|
||||
}
|
||||
Definition::TraitAlias(ta) => {
|
||||
MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::Type }
|
||||
}
|
||||
Definition::TypeAlias(ta) => {
|
||||
MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter }
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -
|
|||
SyntaxKind::MACRO_CALL,
|
||||
SyntaxKind::TYPE_ALIAS,
|
||||
SyntaxKind::TRAIT,
|
||||
SyntaxKind::TRAIT_ALIAS,
|
||||
SyntaxKind::IMPL,
|
||||
SyntaxKind::MACRO_DEF,
|
||||
SyntaxKind::STRUCT,
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::fmt;
|
|||
use either::Either;
|
||||
use hir::{
|
||||
symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay,
|
||||
InFile, ModuleSource, Semantics,
|
||||
InFile, LocalSource, ModuleSource, Semantics,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::{FileId, FileRange},
|
||||
|
@ -192,6 +192,7 @@ impl TryToNav for Definition {
|
|||
Definition::Const(it) => it.try_to_nav(db),
|
||||
Definition::Static(it) => it.try_to_nav(db),
|
||||
Definition::Trait(it) => it.try_to_nav(db),
|
||||
Definition::TraitAlias(it) => it.try_to_nav(db),
|
||||
Definition::TypeAlias(it) => it.try_to_nav(db),
|
||||
Definition::BuiltinType(_) => None,
|
||||
Definition::ToolModule(_) => None,
|
||||
|
@ -212,6 +213,7 @@ impl TryToNav for hir::ModuleDef {
|
|||
hir::ModuleDef::Const(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::Static(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::Trait(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::TraitAlias(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::Macro(it) => it.try_to_nav(db),
|
||||
hir::ModuleDef::BuiltinType(_) => None,
|
||||
|
@ -249,6 +251,9 @@ impl ToNavFromAst for hir::TypeAlias {
|
|||
impl ToNavFromAst for hir::Trait {
|
||||
const KIND: SymbolKind = SymbolKind::Trait;
|
||||
}
|
||||
impl ToNavFromAst for hir::TraitAlias {
|
||||
const KIND: SymbolKind = SymbolKind::TraitAlias;
|
||||
}
|
||||
|
||||
impl<D> TryToNav for D
|
||||
where
|
||||
|
@ -382,9 +387,11 @@ impl TryToNav for hir::GenericParam {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToNav for hir::Local {
|
||||
impl ToNav for LocalSource {
|
||||
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||
let InFile { file_id, value } = self.source(db);
|
||||
let InFile { file_id, value } = &self.source;
|
||||
let file_id = *file_id;
|
||||
let local = self.local;
|
||||
let (node, name) = match &value {
|
||||
Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()),
|
||||
Either::Right(it) => (it.syntax(), it.name()),
|
||||
|
@ -393,10 +400,10 @@ impl ToNav for hir::Local {
|
|||
let FileRange { file_id, range: full_range } =
|
||||
InFile::new(file_id, node).original_file_range(db);
|
||||
|
||||
let name = self.name(db).to_smol_str();
|
||||
let kind = if self.is_self(db) {
|
||||
let name = local.name(db).to_smol_str();
|
||||
let kind = if local.is_self(db) {
|
||||
SymbolKind::SelfParam
|
||||
} else if self.is_param(db) {
|
||||
} else if local.is_param(db) {
|
||||
SymbolKind::ValueParam
|
||||
} else {
|
||||
SymbolKind::Local
|
||||
|
@ -414,6 +421,12 @@ impl ToNav for hir::Local {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToNav for hir::Local {
|
||||
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||
self.primary_source(db).to_nav(db)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToNav for hir::Label {
|
||||
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||
let InFile { file_id, value } = self.source(db);
|
||||
|
@ -544,6 +557,7 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) ->
|
|||
ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::TraitAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
|
||||
|
|
|
@ -1355,6 +1355,38 @@ impl Foo {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trait_alias() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo {}
|
||||
trait Bar$0 = Foo where Self: ;
|
||||
fn foo<T: Bar>(_: impl Bar, _: &dyn Bar) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Bar TraitAlias FileId(0) 13..42 19..22
|
||||
|
||||
FileId(0) 53..56
|
||||
FileId(0) 66..69
|
||||
FileId(0) 79..82
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trait_alias_self() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo = where Self$0: ;
|
||||
"#,
|
||||
expect![[r#"
|
||||
Self TypeParam FileId(0) 6..9 6..9
|
||||
|
||||
FileId(0) 18..22
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attr_differs_from_fn_with_same_name() {
|
||||
check(
|
||||
|
|
|
@ -353,6 +353,11 @@ mod tests {
|
|||
fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
let ra_fixture_after = &trim_indent(ra_fixture_after);
|
||||
let (analysis, position) = fixture::position(ra_fixture_before);
|
||||
if !ra_fixture_after.starts_with("error: ") {
|
||||
if let Err(err) = analysis.prepare_rename(position).unwrap() {
|
||||
panic!("Prepare rename to '{new_name}' was failed: {err}")
|
||||
}
|
||||
}
|
||||
let rename_result = analysis
|
||||
.rename(position, new_name)
|
||||
.unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}"));
|
||||
|
@ -1709,6 +1714,23 @@ fn foo(bar: i32) -> Foo {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_local_simple() {
|
||||
check(
|
||||
"i",
|
||||
r#"
|
||||
fn foo(bar$0: i32) -> i32 {
|
||||
bar
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn foo(i: i32) -> i32 {
|
||||
i
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_local_put_init_shorthand() {
|
||||
cov_mark::check!(test_rename_local_put_init_shorthand);
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
|
||||
use ast::HasName;
|
||||
use cfg::CfgExpr;
|
||||
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
|
||||
use hir::{AsAssocItem, HasAttrs, HasSource, Semantics};
|
||||
use ide_assists::utils::test_related_attribute;
|
||||
use ide_db::{
|
||||
base_db::{FilePosition, FileRange},
|
||||
|
@ -195,14 +195,13 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
|
|||
//
|
||||
// Provides a sneak peek of all tests where the current item is used.
|
||||
//
|
||||
// The simplest way to use this feature is via the context menu:
|
||||
// - Right-click on the selected item. The context menu opens.
|
||||
// - Select **Peek related tests**
|
||||
// The simplest way to use this feature is via the context menu. Right-click on
|
||||
// the selected item. The context menu opens. Select **Peek Related Tests**.
|
||||
//
|
||||
// |===
|
||||
// | Editor | Action Name
|
||||
//
|
||||
// | VS Code | **rust-analyzer: Peek related tests**
|
||||
// | VS Code | **rust-analyzer: Peek Related Tests**
|
||||
// |===
|
||||
pub(crate) fn related_tests(
|
||||
db: &RootDatabase,
|
||||
|
@ -371,9 +370,9 @@ pub(crate) fn runnable_impl(
|
|||
let nav = def.try_to_nav(sema.db)?;
|
||||
let ty = def.self_ty(sema.db);
|
||||
let adt_name = ty.as_adt()?.name(sema.db);
|
||||
let mut ty_args = ty.type_arguments().peekable();
|
||||
let mut ty_args = ty.generic_parameters(sema.db).peekable();
|
||||
let params = if ty_args.peek().is_some() {
|
||||
format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db))))
|
||||
format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
@ -417,6 +416,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
|
|||
Definition::Const(it) => it.attrs(db),
|
||||
Definition::Static(it) => it.attrs(db),
|
||||
Definition::Trait(it) => it.attrs(db),
|
||||
Definition::TraitAlias(it) => it.attrs(db),
|
||||
Definition::TypeAlias(it) => it.attrs(db),
|
||||
Definition::Macro(it) => it.attrs(db),
|
||||
Definition::SelfType(it) => it.attrs(db),
|
||||
|
@ -437,14 +437,10 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
|
|||
let ty = imp.self_ty(db);
|
||||
if let Some(adt) = ty.as_adt() {
|
||||
let name = adt.name(db);
|
||||
let mut ty_args = ty.type_arguments().peekable();
|
||||
let mut ty_args = ty.generic_parameters(db).peekable();
|
||||
format_to!(path, "{}", name);
|
||||
if ty_args.peek().is_some() {
|
||||
format_to!(
|
||||
path,
|
||||
"<{}>",
|
||||
ty_args.format_with(",", |ty, cb| cb(&ty.display(db)))
|
||||
);
|
||||
format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)));
|
||||
}
|
||||
format_to!(path, "::{}", def_name);
|
||||
path.retain(|c| c != ' ');
|
||||
|
@ -1000,6 +996,221 @@ impl Data {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_doc_test_in_impl_with_lifetime() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
$0
|
||||
fn main() {}
|
||||
|
||||
struct Data<'a>;
|
||||
impl Data<'a> {
|
||||
/// ```
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
&[Bin, DocTest],
|
||||
expect![[r#"
|
||||
[
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 1..13,
|
||||
focus_range: 4..8,
|
||||
name: "main",
|
||||
kind: Function,
|
||||
},
|
||||
kind: Bin,
|
||||
cfg: None,
|
||||
},
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 52..106,
|
||||
name: "foo",
|
||||
},
|
||||
kind: DocTest {
|
||||
test_id: Path(
|
||||
"Data<'a>::foo",
|
||||
),
|
||||
},
|
||||
cfg: None,
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_doc_test_in_impl_with_lifetime_and_types() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
$0
|
||||
fn main() {}
|
||||
|
||||
struct Data<'a, T, U>;
|
||||
impl<T, U> Data<'a, T, U> {
|
||||
/// ```
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
&[Bin, DocTest],
|
||||
expect![[r#"
|
||||
[
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 1..13,
|
||||
focus_range: 4..8,
|
||||
name: "main",
|
||||
kind: Function,
|
||||
},
|
||||
kind: Bin,
|
||||
cfg: None,
|
||||
},
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 70..124,
|
||||
name: "foo",
|
||||
},
|
||||
kind: DocTest {
|
||||
test_id: Path(
|
||||
"Data<'a,T,U>::foo",
|
||||
),
|
||||
},
|
||||
cfg: None,
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_doc_test_in_impl_with_const() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
$0
|
||||
fn main() {}
|
||||
|
||||
struct Data<const N: usize>;
|
||||
impl<const N: usize> Data<N> {
|
||||
/// ```
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
&[Bin, DocTest],
|
||||
expect![[r#"
|
||||
[
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 1..13,
|
||||
focus_range: 4..8,
|
||||
name: "main",
|
||||
kind: Function,
|
||||
},
|
||||
kind: Bin,
|
||||
cfg: None,
|
||||
},
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 79..133,
|
||||
name: "foo",
|
||||
},
|
||||
kind: DocTest {
|
||||
test_id: Path(
|
||||
"Data<N>::foo",
|
||||
),
|
||||
},
|
||||
cfg: None,
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_doc_test_in_impl_with_lifetime_types_and_const() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
$0
|
||||
fn main() {}
|
||||
|
||||
struct Data<'a, T, const N: usize>;
|
||||
impl<'a, T, const N: usize> Data<'a, T, N> {
|
||||
/// ```
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
&[Bin, DocTest],
|
||||
expect![[r#"
|
||||
[
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 1..13,
|
||||
focus_range: 4..8,
|
||||
name: "main",
|
||||
kind: Function,
|
||||
},
|
||||
kind: Bin,
|
||||
cfg: None,
|
||||
},
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 100..154,
|
||||
name: "foo",
|
||||
},
|
||||
kind: DocTest {
|
||||
test_id: Path(
|
||||
"Data<'a,T,N>::foo",
|
||||
),
|
||||
},
|
||||
cfg: None,
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_runnables_module() {
|
||||
check(
|
||||
|
@ -2062,6 +2273,59 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_doc_test_in_impl_with_lifetime_type_const_value() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
$0
|
||||
fn main() {}
|
||||
|
||||
struct Data<'a, A, const B: usize, C, const D: u32>;
|
||||
impl<A, C, const D: u32> Data<'a, A, 12, C, D> {
|
||||
/// ```
|
||||
/// ```
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
&[Bin, DocTest],
|
||||
expect![[r#"
|
||||
[
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 1..13,
|
||||
focus_range: 4..8,
|
||||
name: "main",
|
||||
kind: Function,
|
||||
},
|
||||
kind: Bin,
|
||||
cfg: None,
|
||||
},
|
||||
Runnable {
|
||||
use_name_in_title: false,
|
||||
nav: NavigationTarget {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
full_range: 121..156,
|
||||
name: "foo",
|
||||
},
|
||||
kind: DocTest {
|
||||
test_id: Path(
|
||||
"Data<'a,A,12,C,D>::foo",
|
||||
),
|
||||
},
|
||||
cfg: None,
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doc_test_type_params() {
|
||||
check(
|
||||
|
|
|
@ -172,7 +172,7 @@ fn signature_help_for_call(
|
|||
|
||||
res.signature.push('(');
|
||||
{
|
||||
if let Some(self_param) = callable.receiver_param(db) {
|
||||
if let Some((self_param, _)) = callable.receiver_param(db) {
|
||||
format_to!(res.signature, "{}", self_param)
|
||||
}
|
||||
let mut buf = String::new();
|
||||
|
@ -252,6 +252,10 @@ fn signature_help_for_generics(
|
|||
res.doc = it.docs(db).map(|it| it.into());
|
||||
format_to!(res.signature, "trait {}", it.name(db));
|
||||
}
|
||||
hir::GenericDef::TraitAlias(it) => {
|
||||
res.doc = it.docs(db).map(|it| it.into());
|
||||
format_to!(res.signature, "trait {}", it.name(db));
|
||||
}
|
||||
hir::GenericDef::TypeAlias(it) => {
|
||||
res.doc = it.docs(db).map(|it| it.into());
|
||||
format_to!(res.signature, "type {}", it.name(db));
|
||||
|
|
|
@ -139,6 +139,7 @@ impl StaticIndex<'_> {
|
|||
documentation: true,
|
||||
keywords: true,
|
||||
format: crate::HoverDocFormat::Markdown,
|
||||
interpret_tests: false,
|
||||
};
|
||||
let tokens = tokens.filter(|token| {
|
||||
matches!(
|
||||
|
|
|
@ -217,7 +217,9 @@ fn highlight_name_ref(
|
|||
// to anything when used.
|
||||
// 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) => {
|
||||
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) =>
|
||||
{
|
||||
return HlTag::Symbol(SymbolKind::Attribute).into();
|
||||
}
|
||||
None => return HlTag::UnresolvedReference.into(),
|
||||
|
@ -410,6 +412,7 @@ fn highlight_def(
|
|||
h
|
||||
}
|
||||
Definition::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)),
|
||||
Definition::TraitAlias(_) => Highlight::new(HlTag::Symbol(SymbolKind::TraitAlias)),
|
||||
Definition::TypeAlias(type_) => {
|
||||
let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
|
||||
|
||||
|
|
|
@ -274,6 +274,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
|
|||
Definition::Const(_) => SymbolKind::Const,
|
||||
Definition::Static(_) => SymbolKind::Static,
|
||||
Definition::Trait(_) => SymbolKind::Trait,
|
||||
Definition::TraitAlias(_) => SymbolKind::TraitAlias,
|
||||
Definition::TypeAlias(_) => SymbolKind::TypeAlias,
|
||||
Definition::BuiltinType(_) => return HlTag::BuiltinType,
|
||||
Definition::Macro(_) => SymbolKind::Macro,
|
||||
|
|
|
@ -150,6 +150,7 @@ impl HlTag {
|
|||
SymbolKind::Struct => "struct",
|
||||
SymbolKind::ToolModule => "tool_module",
|
||||
SymbolKind::Trait => "trait",
|
||||
SymbolKind::TraitAlias => "trait_alias",
|
||||
SymbolKind::TypeAlias => "type_alias",
|
||||
SymbolKind::TypeParam => "type_param",
|
||||
SymbolKind::Union => "union",
|
||||
|
|
|
@ -53,6 +53,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="comment">// This is another normal comment</span>
|
||||
<span class="comment documentation">/// This is another doc comment</span>
|
||||
<span class="comment">// This is another normal comment</span>
|
||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</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="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</span><span class="comma attribute">,</span> <span class="unresolved_reference attribute">Unresolved</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
|
||||
<span class="comment">// The reason for these being here is to test AttrIds</span>
|
||||
<span class="keyword">struct</span> <span class="struct declaration">Foo</span><span class="semicolon">;</span></code></pre>
|
|
@ -34,7 +34,7 @@ fn attributes() {
|
|||
// This is another normal comment
|
||||
/// This is another doc comment
|
||||
// This is another normal comment
|
||||
#[derive(Copy)]
|
||||
#[derive(Copy, Unresolved)]
|
||||
// The reason for these being here is to test AttrIds
|
||||
struct Foo;
|
||||
"#,
|
||||
|
|
29
crates/ide/src/view_mir.rs
Normal file
29
crates/ide/src/view_mir.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use hir::{DefWithBody, Semantics};
|
||||
use ide_db::base_db::FilePosition;
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{algo::find_node_at_offset, ast, AstNode};
|
||||
|
||||
// Feature: View Mir
|
||||
//
|
||||
// |===
|
||||
// | Editor | Action Name
|
||||
//
|
||||
// | VS Code | **rust-analyzer: View Mir**
|
||||
// |===
|
||||
pub(crate) fn view_mir(db: &RootDatabase, position: FilePosition) -> String {
|
||||
body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
|
||||
}
|
||||
|
||||
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 def: DefWithBody = match item {
|
||||
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
|
||||
ast::Item::Const(it) => sema.to_def(&it)?.into(),
|
||||
ast::Item::Static(it) => sema.to_def(&it)?.into(),
|
||||
_ => return None,
|
||||
};
|
||||
Some(def.debug_mir(db))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue