mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 05:08:52 +00:00
Auto merge of #134681 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
commit
485f5e80e6
113 changed files with 3098 additions and 2167 deletions
83
Cargo.lock
generated
83
Cargo.lock
generated
|
@ -1008,18 +1008,6 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lsp-server"
|
||||
version = "0.7.7"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"ctrlc",
|
||||
"log",
|
||||
"lsp-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsp-server"
|
||||
version = "0.7.7"
|
||||
|
@ -1032,6 +1020,19 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsp-server"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"ctrlc",
|
||||
"log",
|
||||
"lsp-types",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsp-types"
|
||||
version = "0.95.0"
|
||||
|
@ -1289,7 +1290,6 @@ name = "paths"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1352,12 +1352,12 @@ dependencies = [
|
|||
name = "proc-macro-api"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"base-db",
|
||||
"indexmap",
|
||||
"intern",
|
||||
"paths",
|
||||
"rustc-hash 2.0.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"span",
|
||||
"stdx",
|
||||
|
@ -1369,7 +1369,6 @@ dependencies = [
|
|||
name = "proc-macro-srv"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"base-db",
|
||||
"expect-test",
|
||||
"intern",
|
||||
"libloading",
|
||||
|
@ -1448,6 +1447,7 @@ dependencies = [
|
|||
"rustc-hash 2.0.0",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"span",
|
||||
"stdx",
|
||||
|
@ -1507,9 +1507,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_abi"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af462c3a2d524b84a51b6848b439787f01b35c6c1086d3e3086a5f5eea92ed9a"
|
||||
checksum = "28b782af0a7a8df16ddf43cd70da9f17bc3b1ce712c9e4992b6edb16f5f53632"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"ra-ap-rustc_index",
|
||||
|
@ -1518,9 +1518,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be6bb8cb0ab78d94a222f1ffd3e87254cdfb57413382b8d6ebe26a85482f99d1"
|
||||
checksum = "ce5742f134960482f543b35ecebec3cacc6d79a9a685713518b4d8d70c5f9aa8"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index_macros",
|
||||
"smallvec",
|
||||
|
@ -1528,9 +1528,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index_macros"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c24b1641455b46e87435b7321219672077066e678963d239a4a2904732979b16"
|
||||
checksum = "d7ea011fcf68309a8835ad01d91c032cb18444617b00e2cab21d45b208164441"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1539,9 +1539,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_lexer"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94daa86974417981fed2f12bd8fb00158dfa6fee561152bed689278c846d0272"
|
||||
checksum = "eb76f0a4d4c20859e41f0a23bff0f37ab9ca9171c214a6c7dd72ea69434865dc"
|
||||
dependencies = [
|
||||
"unicode-properties",
|
||||
"unicode-xid",
|
||||
|
@ -1549,9 +1549,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_parse_format"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc07f6bd581746f358e39c4b6bfe8d455b3d6ad1a857821016d0d42eeb5e1e3e"
|
||||
checksum = "06080bd35078305421a62da77f3c128482d8d44441b6da8ce9d146d1cd9cdb5b"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index",
|
||||
"ra-ap-rustc_lexer",
|
||||
|
@ -1559,9 +1559,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_pattern_analysis"
|
||||
version = "0.85.0"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f49b86e1276c1c3c72898410def29b699415f4e7d1dfb3531daf79794694372"
|
||||
checksum = "68a3154fe4c20c177d7b3c678a2d3a97aba0cca156ddef88959915041889daf0"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index",
|
||||
"rustc-hash 2.0.0",
|
||||
|
@ -1676,7 +1676,7 @@ dependencies = [
|
|||
"intern",
|
||||
"itertools",
|
||||
"load-cargo",
|
||||
"lsp-server 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lsp-server 0.7.7",
|
||||
"lsp-types",
|
||||
"memchr",
|
||||
"mimalloc",
|
||||
|
@ -1695,6 +1695,7 @@ dependencies = [
|
|||
"scip",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"stdx",
|
||||
"syntax",
|
||||
|
@ -1822,18 +1823,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.206"
|
||||
version = "1.0.216"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
|
||||
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.206"
|
||||
version = "1.0.216"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
|
||||
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1924,12 +1925,6 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "stdx"
|
||||
version = "0.0.0"
|
||||
|
@ -1946,9 +1941,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.74"
|
||||
version = "2.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
|
||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2264,13 +2259,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "triomphe"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85"
|
||||
|
||||
[[package]]
|
||||
name = "tt"
|
||||
|
|
15
Cargo.toml
15
Cargo.toml
|
@ -85,11 +85,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
|||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||
edition = { path = "./crates/edition", version = "0.0.0" }
|
||||
|
||||
ra-ap-rustc_lexer = { version = "0.85", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.85", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.85", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.85", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.85", default-features = false }
|
||||
ra-ap-rustc_lexer = { version = "0.87", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.87", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.87", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.87", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.87", default-features = false }
|
||||
|
||||
# local crates that aren't published to crates.io. These should not have versions.
|
||||
test-fixture = { path = "./crates/test-fixture" }
|
||||
|
@ -138,7 +138,8 @@ pulldown-cmark = { version = "0.9.0", default-features = false }
|
|||
rayon = "1.8.0"
|
||||
rustc-hash = "2.0.0"
|
||||
semver = "1.0.14"
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
serde = { version = "1.0.192" }
|
||||
serde_derive = { version = "1.0.192" }
|
||||
serde_json = "1.0.108"
|
||||
smallvec = { version = "1.10.0", features = [
|
||||
"const_new",
|
||||
|
@ -157,7 +158,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features =
|
|||
"time",
|
||||
"tracing-log",
|
||||
] }
|
||||
triomphe = { version = "0.1.10", default-features = false, features = ["std"] }
|
||||
triomphe = { version = "0.1.14", default-features = false, features = ["std"] }
|
||||
url = "2.3.1"
|
||||
xshell = "0.2.5"
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use smallvec::SmallVec;
|
|||
use span::{Edition, MacroFileId};
|
||||
use syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||
use triomphe::Arc;
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
|
@ -143,15 +144,7 @@ pub struct BodySourceMap {
|
|||
|
||||
pub types: TypesSourceMap,
|
||||
|
||||
// FIXME: Make this a sane struct.
|
||||
template_map: Option<
|
||||
Box<(
|
||||
// format_args!
|
||||
FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
|
||||
// asm!
|
||||
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
|
||||
)>,
|
||||
>,
|
||||
template_map: Option<Box<FormatTemplate>>,
|
||||
|
||||
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
|
||||
|
||||
|
@ -160,6 +153,20 @@ pub struct BodySourceMap {
|
|||
diagnostics: Vec<BodyDiagnostic>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
struct FormatTemplate {
|
||||
/// A map from `format_args!()` expressions to their captures.
|
||||
format_args_to_captures: FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
|
||||
/// A map from `asm!()` expressions to their captures.
|
||||
asm_to_captures: FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
|
||||
/// A map from desugared expressions of implicit captures to their source.
|
||||
///
|
||||
/// The value stored for each capture is its template literal and offset inside it. The template literal
|
||||
/// is from the `format_args[_nl]!()` macro and so needs to be mapped up once to go to the user-written
|
||||
/// template.
|
||||
implicit_capture_to_source: FxHashMap<ExprId, InFile<(AstPtr<ast::Expr>, TextRange)>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum BodyDiagnostic {
|
||||
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
|
||||
|
@ -798,18 +805,29 @@ impl BodySourceMap {
|
|||
node: InFile<&ast::FormatArgsExpr>,
|
||||
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
|
||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||
let (hygiene, names) =
|
||||
self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
|
||||
let (hygiene, names) = self
|
||||
.template_map
|
||||
.as_ref()?
|
||||
.format_args_to_captures
|
||||
.get(&self.expr_map.get(&src)?.as_expr()?)?;
|
||||
Some((*hygiene, &**names))
|
||||
}
|
||||
|
||||
pub fn format_args_implicit_capture(
|
||||
&self,
|
||||
capture_expr: ExprId,
|
||||
) -> Option<InFile<(AstPtr<ast::Expr>, TextRange)>> {
|
||||
self.template_map.as_ref()?.implicit_capture_to_source.get(&capture_expr).copied()
|
||||
}
|
||||
|
||||
pub fn asm_template_args(
|
||||
&self,
|
||||
node: InFile<&ast::AsmExpr>,
|
||||
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
|
||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||
let expr = self.expr_map.get(&src)?.as_expr()?;
|
||||
Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
|
||||
Some(expr)
|
||||
.zip(self.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref))
|
||||
}
|
||||
|
||||
/// Get a reference to the body source map's diagnostics.
|
||||
|
@ -835,8 +853,14 @@ impl BodySourceMap {
|
|||
types,
|
||||
} = self;
|
||||
if let Some(template_map) = template_map {
|
||||
template_map.0.shrink_to_fit();
|
||||
template_map.1.shrink_to_fit();
|
||||
let FormatTemplate {
|
||||
format_args_to_captures,
|
||||
asm_to_captures,
|
||||
implicit_capture_to_source,
|
||||
} = &mut **template_map;
|
||||
format_args_to_captures.shrink_to_fit();
|
||||
asm_to_captures.shrink_to_fit();
|
||||
implicit_capture_to_source.shrink_to_fit();
|
||||
}
|
||||
expr_map.shrink_to_fit();
|
||||
expr_map_back.shrink_to_fit();
|
||||
|
|
|
@ -1957,8 +1957,10 @@ impl ExprCollector<'_> {
|
|||
_ => None,
|
||||
});
|
||||
let mut mappings = vec![];
|
||||
let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) {
|
||||
Some((s, is_direct_literal)) => {
|
||||
let (fmt, hygiene) = match template.and_then(|template| {
|
||||
self.expand_macros_to_string(template.clone()).map(|it| (it, template))
|
||||
}) {
|
||||
Some(((s, is_direct_literal), template)) => {
|
||||
let call_ctx = self.expander.syntax_context();
|
||||
let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
|
||||
let fmt = format_args::parse(
|
||||
|
@ -1966,8 +1968,18 @@ impl ExprCollector<'_> {
|
|||
fmt_snippet,
|
||||
args,
|
||||
is_direct_literal,
|
||||
|name| {
|
||||
|name, range| {
|
||||
let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
|
||||
if let Some(range) = range {
|
||||
self.source_map
|
||||
.template_map
|
||||
.get_or_insert_with(Default::default)
|
||||
.implicit_capture_to_source
|
||||
.insert(
|
||||
expr_id,
|
||||
self.expander.in_file((AstPtr::new(&template), range)),
|
||||
);
|
||||
}
|
||||
if !hygiene.is_root() {
|
||||
self.body.expr_hygiene.insert(expr_id, hygiene);
|
||||
}
|
||||
|
@ -2139,7 +2151,7 @@ impl ExprCollector<'_> {
|
|||
self.source_map
|
||||
.template_map
|
||||
.get_or_insert_with(Default::default)
|
||||
.0
|
||||
.format_args_to_captures
|
||||
.insert(idx, (hygiene, mappings));
|
||||
idx
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use syntax::{
|
|||
ast::{self, HasName, IsString},
|
||||
AstNode, AstPtr, AstToken, T,
|
||||
};
|
||||
use tt::{TextRange, TextSize};
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
body::lower::{ExprCollector, FxIndexSet},
|
||||
|
@ -224,7 +224,7 @@ impl ExprCollector<'_> {
|
|||
TextRange::new(
|
||||
inner_span.start.try_into().unwrap(),
|
||||
inner_span.end.try_into().unwrap(),
|
||||
) - TextSize::from(str_style.map(|it| it + 1).unwrap_or(0) as u32 + 1)
|
||||
)
|
||||
})
|
||||
};
|
||||
for piece in unverified_pieces {
|
||||
|
@ -268,7 +268,11 @@ impl ExprCollector<'_> {
|
|||
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
|
||||
syntax_ptr,
|
||||
);
|
||||
self.source_map.template_map.get_or_insert_with(Default::default).1.insert(idx, mappings);
|
||||
self.source_map
|
||||
.template_map
|
||||
.get_or_insert_with(Default::default)
|
||||
.asm_to_captures
|
||||
.insert(idx, mappings);
|
||||
idx
|
||||
}
|
||||
}
|
||||
|
|
|
@ -685,6 +685,7 @@ impl Printer<'_> {
|
|||
self.print_binding(*id);
|
||||
if let Some(pat) = subpat {
|
||||
self.whitespace();
|
||||
w!(self, "@ ");
|
||||
self.print_pat(*pat);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,3 +426,21 @@ fn f() {
|
|||
"should have a binding for `B`",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_pretty_print_bind_pat() {
|
||||
let (db, body, owner) = lower(
|
||||
r#"
|
||||
fn foo() {
|
||||
let v @ u = 123;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let printed = body.pretty_print(&db, owner, Edition::CURRENT);
|
||||
assert_eq!(
|
||||
printed,
|
||||
r#"fn foo() -> () {
|
||||
let v @ u = 123;
|
||||
}"#
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Parses `format_args` input.
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::name::Name;
|
||||
use intern::Symbol;
|
||||
use rustc_parse_format as parse;
|
||||
|
@ -7,7 +8,7 @@ use span::SyntaxContextId;
|
|||
use stdx::TupleExt;
|
||||
use syntax::{
|
||||
ast::{self, IsString},
|
||||
TextRange, TextSize,
|
||||
TextRange,
|
||||
};
|
||||
|
||||
use crate::hir::ExprId;
|
||||
|
@ -33,7 +34,7 @@ pub enum FormatArgsPiece {
|
|||
Placeholder(FormatPlaceholder),
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FormatPlaceholder {
|
||||
/// Index into [`FormatArgs::arguments`].
|
||||
pub argument: FormatArgPosition,
|
||||
|
@ -45,11 +46,11 @@ pub struct FormatPlaceholder {
|
|||
pub format_options: FormatOptions,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FormatArgPosition {
|
||||
/// Which argument this position refers to (Ok),
|
||||
/// or would've referred to if it existed (Err).
|
||||
pub index: Result<usize, usize>,
|
||||
pub index: Result<usize, Either<usize, Name>>,
|
||||
/// What kind of position this is. See [`FormatArgPositionKind`].
|
||||
pub kind: FormatArgPositionKind,
|
||||
/// The span of the name or number.
|
||||
|
@ -88,7 +89,7 @@ pub enum FormatTrait {
|
|||
UpperHex,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Default, Debug, PartialEq, Eq)]
|
||||
pub struct FormatOptions {
|
||||
/// The width. E.g. `{:5}` or `{:width$}`.
|
||||
pub width: Option<FormatCount>,
|
||||
|
@ -133,7 +134,7 @@ pub enum FormatAlignment {
|
|||
Center,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FormatCount {
|
||||
/// `{:5}` or `{:.5}`
|
||||
Literal(usize),
|
||||
|
@ -173,7 +174,7 @@ pub(crate) fn parse(
|
|||
fmt_snippet: Option<String>,
|
||||
mut args: FormatArgumentsCollector,
|
||||
is_direct_literal: bool,
|
||||
mut synth: impl FnMut(Name) -> ExprId,
|
||||
mut synth: impl FnMut(Name, Option<TextRange>) -> ExprId,
|
||||
mut record_usage: impl FnMut(Name, Option<TextRange>),
|
||||
call_ctx: SyntaxContextId,
|
||||
) -> FormatArgs {
|
||||
|
@ -192,7 +193,6 @@ pub(crate) fn parse(
|
|||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut parser =
|
||||
parse::Parser::new(&text, str_style, fmt_snippet, false, parse::ParseMode::Format);
|
||||
|
||||
|
@ -217,7 +217,6 @@ pub(crate) fn parse(
|
|||
let to_span = |inner_span: parse::InnerSpan| {
|
||||
is_source_literal.then(|| {
|
||||
TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
|
||||
- TextSize::from(str_style.map(|it| it + 1).unwrap_or(0) as u32 + 1)
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -245,8 +244,8 @@ pub(crate) fn parse(
|
|||
Ok(index)
|
||||
} else {
|
||||
// Doesn't exist as an explicit argument.
|
||||
invalid_refs.push((index, span, used_as, kind));
|
||||
Err(index)
|
||||
invalid_refs.push((Either::Left(index), span, used_as, kind));
|
||||
Err(Either::Left(index))
|
||||
}
|
||||
}
|
||||
ArgRef::Name(name, span) => {
|
||||
|
@ -265,14 +264,17 @@ pub(crate) fn parse(
|
|||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
// FIXME: Diagnose
|
||||
invalid_refs.push((Either::Right(name.clone()), span, used_as, kind));
|
||||
Err(Either::Right(name))
|
||||
} else {
|
||||
record_usage(name.clone(), span);
|
||||
Ok(args.add(FormatArgument {
|
||||
kind: FormatArgumentKind::Captured(name.clone()),
|
||||
// FIXME: This is problematic, we might want to synthesize a dummy
|
||||
// expression proper and/or desugar these.
|
||||
expr: synth(name, span),
|
||||
}))
|
||||
}
|
||||
record_usage(name.clone(), span);
|
||||
Ok(args.add(FormatArgument {
|
||||
kind: FormatArgumentKind::Captured(name.clone()),
|
||||
// FIXME: This is problematic, we might want to synthesize a dummy
|
||||
// expression proper and/or desugar these.
|
||||
expr: synth(name),
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ use syntax::ast;
|
|||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
per_ns::PerNs,
|
||||
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
|
||||
visibility::{Visibility, VisibilityExplicitness},
|
||||
AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
|
||||
Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
|
||||
|
@ -80,9 +80,9 @@ pub struct ItemScope {
|
|||
/// Defs visible in this scope. This includes `declarations`, but also
|
||||
/// imports. The imports belong to this module and can be resolved by using them on
|
||||
/// the `use_imports_*` fields.
|
||||
types: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
||||
values: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
|
||||
macros: FxIndexMap<Name, (MacroId, Visibility, Option<ImportId>)>,
|
||||
types: FxIndexMap<Name, TypesItem>,
|
||||
values: FxIndexMap<Name, ValuesItem>,
|
||||
macros: FxIndexMap<Name, MacrosItem>,
|
||||
unresolved: FxHashSet<Name>,
|
||||
|
||||
/// The defs declared in this scope. Each def has a single scope where it is
|
||||
|
@ -92,7 +92,7 @@ pub struct ItemScope {
|
|||
impls: Vec<ImplId>,
|
||||
unnamed_consts: Vec<ConstId>,
|
||||
/// Traits imported via `use Trait as _;`.
|
||||
unnamed_trait_imports: FxHashMap<TraitId, (Visibility, Option<ImportId>)>,
|
||||
unnamed_trait_imports: FxHashMap<TraitId, Item<()>>,
|
||||
|
||||
// the resolutions of the imports of this scope
|
||||
use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
|
||||
|
@ -187,7 +187,7 @@ impl ItemScope {
|
|||
import = i;
|
||||
}
|
||||
ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
|
||||
res.macros = Some((def, Visibility::Public, None));
|
||||
res.macros = Some(Item { def, vis: Visibility::Public, import: None });
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
|
@ -203,7 +203,7 @@ impl ItemScope {
|
|||
import = i;
|
||||
}
|
||||
ImportOrDef::Def(def) => {
|
||||
res.types = Some((def, Visibility::Public, None));
|
||||
res.types = Some(Item { def, vis: Visibility::Public, import: None });
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
|
@ -219,7 +219,7 @@ impl ItemScope {
|
|||
import = i;
|
||||
}
|
||||
ImportOrDef::Def(def) => {
|
||||
res.values = Some((def, Visibility::Public, None));
|
||||
res.values = Some(Item { def, vis: Visibility::Public, import: None });
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
|
@ -253,8 +253,8 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
|
||||
self.types.values().copied().filter_map(|(def, vis, _)| match def {
|
||||
ModuleDefId::ModuleId(module) => Some((module, vis)),
|
||||
self.types.values().filter_map(|ns| match ns.def {
|
||||
ModuleDefId::ModuleId(module) => Some((module, ns.vis)),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -283,20 +283,20 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
|
||||
self.types.get(name).copied().map(|(a, b, _)| (a, b))
|
||||
self.types.get(name).map(|item| (item.def, item.vis))
|
||||
}
|
||||
|
||||
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
|
||||
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
|
||||
match item {
|
||||
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
|
||||
}),
|
||||
ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
ItemInNs::Types(def) => self.types.iter().find_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
|
||||
}),
|
||||
ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
ItemInNs::Values(def) => self.values.iter().find_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -311,22 +311,34 @@ impl ItemScope {
|
|||
ItemInNs::Macros(def) => self
|
||||
.macros
|
||||
.iter()
|
||||
.filter_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
.filter_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((
|
||||
name,
|
||||
other_def.vis,
|
||||
other_def.import.is_none(),
|
||||
))
|
||||
})
|
||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||
ItemInNs::Types(def) => self
|
||||
.types
|
||||
.iter()
|
||||
.filter_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
.filter_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((
|
||||
name,
|
||||
other_def.vis,
|
||||
other_def.import.is_none(),
|
||||
))
|
||||
})
|
||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||
ItemInNs::Values(def) => self
|
||||
.values
|
||||
.iter()
|
||||
.filter_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
.filter_map(|(name, other_def)| {
|
||||
(other_def.def == def).then_some((
|
||||
name,
|
||||
other_def.vis,
|
||||
other_def.import.is_none(),
|
||||
))
|
||||
})
|
||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||
}
|
||||
|
@ -335,7 +347,7 @@ impl ItemScope {
|
|||
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
|
||||
self.types
|
||||
.values()
|
||||
.filter_map(|&(def, _, _)| match def {
|
||||
.filter_map(|def| match def.def {
|
||||
ModuleDefId::TraitId(t) => Some(t),
|
||||
_ => None,
|
||||
})
|
||||
|
@ -344,13 +356,13 @@ impl ItemScope {
|
|||
|
||||
pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
|
||||
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
|
||||
self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| {
|
||||
self.unnamed_trait_imports.iter().map(|(tr, trait_)| {
|
||||
(
|
||||
None,
|
||||
PerNs::types(
|
||||
ModuleDefId::TraitId(*tr),
|
||||
*vis,
|
||||
i.map(ImportOrExternCrate::Import),
|
||||
trait_.vis,
|
||||
trait_.import.map(ImportOrExternCrate::Import),
|
||||
),
|
||||
)
|
||||
}),
|
||||
|
@ -464,12 +476,12 @@ impl ItemScope {
|
|||
|
||||
// FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
|
||||
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
|
||||
self.unnamed_trait_imports.get(&tr).copied().map(|(a, _)| a)
|
||||
self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
|
||||
}
|
||||
|
||||
pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
|
||||
// FIXME: import
|
||||
self.unnamed_trait_imports.insert(tr, (vis, None));
|
||||
self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import: None });
|
||||
}
|
||||
|
||||
pub(crate) fn push_res_with_import(
|
||||
|
@ -502,7 +514,7 @@ impl ItemScope {
|
|||
}
|
||||
None | Some(ImportType::Glob(_)) => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_types.insert(
|
||||
import,
|
||||
|
@ -513,7 +525,7 @@ impl ItemScope {
|
|||
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
||||
ImportOrDef::ExternCrate(import)
|
||||
}
|
||||
None => ImportOrDef::Def(fld.0),
|
||||
None => ImportOrDef::Def(fld.def),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -540,7 +552,7 @@ impl ItemScope {
|
|||
}
|
||||
None | Some(ImportType::Glob(_)) => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_types.insert(
|
||||
import,
|
||||
|
@ -551,7 +563,7 @@ impl ItemScope {
|
|||
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
||||
ImportOrDef::ExternCrate(import)
|
||||
}
|
||||
None => ImportOrDef::Def(fld.0),
|
||||
None => ImportOrDef::Def(fld.def),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -579,13 +591,13 @@ impl ItemScope {
|
|||
Some(ImportType::Import(import)) => Some(import),
|
||||
_ => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_values.insert(
|
||||
import,
|
||||
match prev {
|
||||
Some(import) => ImportOrDef::Import(import),
|
||||
None => ImportOrDef::Def(fld.0),
|
||||
None => ImportOrDef::Def(fld.def),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -599,13 +611,13 @@ impl ItemScope {
|
|||
Some(ImportType::Import(import)) => Some(import),
|
||||
_ => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_values.insert(
|
||||
import,
|
||||
match prev {
|
||||
Some(import) => ImportOrDef::Import(import),
|
||||
None => ImportOrDef::Def(fld.0),
|
||||
None => ImportOrDef::Def(fld.def),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -631,13 +643,13 @@ impl ItemScope {
|
|||
Some(ImportType::Import(import)) => Some(import),
|
||||
_ => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_macros.insert(
|
||||
import,
|
||||
match prev {
|
||||
Some(import) => ImportOrDef::Import(import),
|
||||
None => ImportOrDef::Def(fld.0.into()),
|
||||
None => ImportOrDef::Def(fld.def.into()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -651,13 +663,13 @@ impl ItemScope {
|
|||
Some(ImportType::Import(import)) => Some(import),
|
||||
_ => None,
|
||||
};
|
||||
let prev = std::mem::replace(&mut fld.2, import);
|
||||
let prev = std::mem::replace(&mut fld.import, import);
|
||||
if let Some(import) = import {
|
||||
self.use_imports_macros.insert(
|
||||
import,
|
||||
match prev {
|
||||
Some(import) => ImportOrDef::Import(import),
|
||||
None => ImportOrDef::Def(fld.0.into()),
|
||||
None => ImportOrDef::Def(fld.def.into()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -680,19 +692,19 @@ impl ItemScope {
|
|||
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
||||
self.types
|
||||
.values_mut()
|
||||
.map(|(_, vis, _)| vis)
|
||||
.chain(self.values.values_mut().map(|(_, vis, _)| vis))
|
||||
.chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
|
||||
.map(|def| &mut def.vis)
|
||||
.chain(self.values.values_mut().map(|def| &mut def.vis))
|
||||
.chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
|
||||
.for_each(|vis| {
|
||||
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
|
||||
});
|
||||
|
||||
for (mac, vis, import) in self.macros.values_mut() {
|
||||
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
|
||||
for mac in self.macros.values_mut() {
|
||||
if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit);
|
||||
mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -707,23 +719,23 @@ impl ItemScope {
|
|||
name.map_or("_".to_owned(), |name| name.display(db, Edition::LATEST).to_string())
|
||||
);
|
||||
|
||||
if let Some((.., i)) = def.types {
|
||||
if let Some(Item { import, .. }) = def.types {
|
||||
buf.push_str(" t");
|
||||
match i {
|
||||
match import {
|
||||
Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
|
||||
Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
if let Some((.., i)) = def.values {
|
||||
if let Some(Item { import, .. }) = def.values {
|
||||
buf.push_str(" v");
|
||||
if i.is_some() {
|
||||
if import.is_some() {
|
||||
buf.push('i');
|
||||
}
|
||||
}
|
||||
if let Some((.., i)) = def.macros {
|
||||
if let Some(Item { import, .. }) = def.macros {
|
||||
buf.push_str(" m");
|
||||
if i.is_some() {
|
||||
if import.is_some() {
|
||||
buf.push('i');
|
||||
}
|
||||
}
|
||||
|
@ -781,19 +793,19 @@ impl ItemScope {
|
|||
pub(crate) fn update_visibility_types(&mut self, name: &Name, vis: Visibility) {
|
||||
let res =
|
||||
self.types.get_mut(name).expect("tried to update visibility of non-existent type");
|
||||
res.1 = vis;
|
||||
res.vis = vis;
|
||||
}
|
||||
|
||||
pub(crate) fn update_visibility_values(&mut self, name: &Name, vis: Visibility) {
|
||||
let res =
|
||||
self.values.get_mut(name).expect("tried to update visibility of non-existent value");
|
||||
res.1 = vis;
|
||||
res.vis = vis;
|
||||
}
|
||||
|
||||
pub(crate) fn update_visibility_macros(&mut self, name: &Name, vis: Visibility) {
|
||||
let res =
|
||||
self.macros.get_mut(name).expect("tried to update visibility of non-existent macro");
|
||||
res.1 = vis;
|
||||
res.vis = vis;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ use crate::{
|
|||
ResolveMode,
|
||||
},
|
||||
path::{ImportAlias, ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
per_ns::{Item, PerNs},
|
||||
tt,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
|
||||
|
@ -523,7 +523,7 @@ impl DefCollector<'_> {
|
|||
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
|
||||
|
||||
match per_ns.types {
|
||||
Some((ModuleDefId::ModuleId(m), _, import)) => {
|
||||
Some(Item { def: ModuleDefId::ModuleId(m), import, .. }) => {
|
||||
// FIXME: This should specifically look for a glob import somehow and record that here
|
||||
self.def_map.prelude = Some((
|
||||
m,
|
||||
|
@ -1069,9 +1069,9 @@ impl DefCollector<'_> {
|
|||
//
|
||||
// This has been historically allowed, but may be not allowed in future
|
||||
// https://github.com/rust-lang/rust/issues/127909
|
||||
if let Some((_, v, it)) = defs.types.as_mut() {
|
||||
if let Some(def) = defs.types.as_mut() {
|
||||
let is_extern_crate_reimport_without_prefix = || {
|
||||
let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
|
||||
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
|
||||
return false;
|
||||
};
|
||||
let Some(ImportType::Import(id)) = def_import_type else {
|
||||
|
@ -1086,16 +1086,16 @@ impl DefCollector<'_> {
|
|||
path.segments().len() < 2
|
||||
};
|
||||
if is_extern_crate_reimport_without_prefix() {
|
||||
*v = vis;
|
||||
def.vis = vis;
|
||||
} else {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
}
|
||||
if let Some((_, v, _)) = defs.values.as_mut() {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
if let Some(def) = defs.values.as_mut() {
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
if let Some((_, v, _)) = defs.macros.as_mut() {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
if let Some(def) = defs.macros.as_mut() {
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
|
||||
let mut changed = false;
|
||||
|
@ -1106,12 +1106,12 @@ impl DefCollector<'_> {
|
|||
// Multiple globs may import the same item and they may override visibility from
|
||||
// previously resolved globs. Handle overrides here and leave the rest to
|
||||
// `ItemScope::push_res_with_import()`.
|
||||
if let Some((def, def_vis, _)) = defs.types {
|
||||
if let Some((prev_def, prev_vis, _)) = prev_defs.types {
|
||||
if def == prev_def
|
||||
if let Some(def) = defs.types {
|
||||
if let Some(prev_def) = prev_defs.types {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_type(module_id, name.clone())
|
||||
&& def_vis != prev_vis
|
||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// This import is being handled here, don't pass it down to
|
||||
|
@ -1119,41 +1119,41 @@ impl DefCollector<'_> {
|
|||
defs.types = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_types(name, def_vis);
|
||||
.update_visibility_types(name, def.vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((def, def_vis, _)) = defs.values {
|
||||
if let Some((prev_def, prev_vis, _)) = prev_defs.values {
|
||||
if def == prev_def
|
||||
if let Some(def) = defs.values {
|
||||
if let Some(prev_def) = prev_defs.values {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_value(module_id, name.clone())
|
||||
&& def_vis != prev_vis
|
||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.values = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_values(name, def_vis);
|
||||
.update_visibility_values(name, def.vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((def, def_vis, _)) = defs.macros {
|
||||
if let Some((prev_def, prev_vis, _)) = prev_defs.macros {
|
||||
if def == prev_def
|
||||
if let Some(def) = defs.macros {
|
||||
if let Some(prev_def) = prev_defs.macros {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_macro(module_id, name.clone())
|
||||
&& def_vis != prev_vis
|
||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.macros = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_macros(name, def_vis);
|
||||
.update_visibility_macros(name, def.vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ impl PerNs {
|
|||
db: &dyn DefDatabase,
|
||||
expected: Option<MacroSubNs>,
|
||||
) -> Self {
|
||||
self.macros = self.macros.filter(|&(id, _, _)| {
|
||||
let this = MacroSubNs::from_id(db, id);
|
||||
self.macros = self.macros.filter(|def| {
|
||||
let this = MacroSubNs::from_id(db, def.def);
|
||||
sub_namespace_match(Some(this), expected)
|
||||
});
|
||||
|
||||
|
@ -411,7 +411,7 @@ impl DefMap {
|
|||
original_module: LocalModuleId,
|
||||
) -> ResolvePathResult {
|
||||
for (i, segment) in segments {
|
||||
let (curr, vis, imp) = match curr_per_ns.take_types_full() {
|
||||
let curr = match curr_per_ns.take_types_full() {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// we still have path segments left, but the path so far
|
||||
|
@ -424,7 +424,7 @@ impl DefMap {
|
|||
};
|
||||
// resolve segment in curr
|
||||
|
||||
curr_per_ns = match curr {
|
||||
curr_per_ns = match curr.def {
|
||||
ModuleDefId::ModuleId(module) => {
|
||||
if module.krate != self.krate {
|
||||
let path = ModPath::from_segments(
|
||||
|
@ -492,7 +492,7 @@ impl DefMap {
|
|||
Some(res) => res,
|
||||
None => {
|
||||
return ResolvePathResult::new(
|
||||
PerNs::types(e.into(), vis, imp),
|
||||
PerNs::types(e.into(), curr.vis, curr.import),
|
||||
ReachedFixedPoint::Yes,
|
||||
Some(i),
|
||||
false,
|
||||
|
@ -510,7 +510,7 @@ impl DefMap {
|
|||
);
|
||||
|
||||
return ResolvePathResult::new(
|
||||
PerNs::types(s, vis, imp),
|
||||
PerNs::types(s, curr.vis, curr.import),
|
||||
ReachedFixedPoint::Yes,
|
||||
Some(i),
|
||||
false,
|
||||
|
|
|
@ -331,7 +331,7 @@ pub type Ty = ();
|
|||
}
|
||||
|
||||
for (_, res) in module_data.scope.resolutions() {
|
||||
match res.values.map(|(a, _, _)| a).or(res.types.map(|(a, _, _)| a)).unwrap() {
|
||||
match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() {
|
||||
ModuleDefId::FunctionId(f) => _ = db.function_data(f),
|
||||
ModuleDefId::AdtId(adt) => match adt {
|
||||
AdtId::StructId(it) => _ = db.struct_data(it),
|
||||
|
|
|
@ -28,11 +28,22 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Item<Def, Import = ImportId> {
|
||||
pub def: Def,
|
||||
pub vis: Visibility,
|
||||
pub import: Option<Import>,
|
||||
}
|
||||
|
||||
pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
|
||||
pub type ValuesItem = Item<ModuleDefId>;
|
||||
pub type MacrosItem = Item<MacroId>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct PerNs {
|
||||
pub types: Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
||||
pub values: Option<(ModuleDefId, Visibility, Option<ImportId>)>,
|
||||
pub macros: Option<(MacroId, Visibility, Option<ImportId>)>,
|
||||
pub types: Option<TypesItem>,
|
||||
pub values: Option<ValuesItem>,
|
||||
pub macros: Option<MacrosItem>,
|
||||
}
|
||||
|
||||
impl PerNs {
|
||||
|
@ -48,29 +59,33 @@ impl PerNs {
|
|||
PerNs { types: None, values: None, macros: None }
|
||||
}
|
||||
|
||||
pub fn values(t: ModuleDefId, v: Visibility, i: Option<ImportId>) -> PerNs {
|
||||
PerNs { types: None, values: Some((t, v, i)), macros: None }
|
||||
pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportId>) -> PerNs {
|
||||
PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
|
||||
}
|
||||
|
||||
pub fn types(t: ModuleDefId, v: Visibility, i: Option<ImportOrExternCrate>) -> PerNs {
|
||||
PerNs { types: Some((t, v, i)), values: None, macros: None }
|
||||
pub fn types(def: ModuleDefId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
|
||||
PerNs { types: Some(Item { def, vis, import }), values: None, macros: None }
|
||||
}
|
||||
|
||||
pub fn both(
|
||||
types: ModuleDefId,
|
||||
values: ModuleDefId,
|
||||
v: Visibility,
|
||||
i: Option<ImportOrExternCrate>,
|
||||
vis: Visibility,
|
||||
import: Option<ImportOrExternCrate>,
|
||||
) -> PerNs {
|
||||
PerNs {
|
||||
types: Some((types, v, i)),
|
||||
values: Some((values, v, i.and_then(ImportOrExternCrate::into_import))),
|
||||
types: Some(Item { def: types, vis, import }),
|
||||
values: Some(Item {
|
||||
def: values,
|
||||
vis,
|
||||
import: import.and_then(ImportOrExternCrate::into_import),
|
||||
}),
|
||||
macros: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn macros(macro_: MacroId, v: Visibility, i: Option<ImportId>) -> PerNs {
|
||||
PerNs { types: None, values: None, macros: Some((macro_, v, i)) }
|
||||
pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportId>) -> PerNs {
|
||||
PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
|
@ -82,43 +97,43 @@ impl PerNs {
|
|||
}
|
||||
|
||||
pub fn take_types(self) -> Option<ModuleDefId> {
|
||||
self.types.map(|it| it.0)
|
||||
self.types.map(|it| it.def)
|
||||
}
|
||||
|
||||
pub fn take_types_full(self) -> Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)> {
|
||||
pub fn take_types_full(self) -> Option<TypesItem> {
|
||||
self.types
|
||||
}
|
||||
|
||||
pub fn take_values(self) -> Option<ModuleDefId> {
|
||||
self.values.map(|it| it.0)
|
||||
self.values.map(|it| it.def)
|
||||
}
|
||||
|
||||
pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportId>)> {
|
||||
self.values.map(|it| (it.0, it.2))
|
||||
self.values.map(|it| (it.def, it.import))
|
||||
}
|
||||
|
||||
pub fn take_macros(self) -> Option<MacroId> {
|
||||
self.macros.map(|it| it.0)
|
||||
self.macros.map(|it| it.def)
|
||||
}
|
||||
|
||||
pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportId>)> {
|
||||
self.macros.map(|it| (it.0, it.2))
|
||||
self.macros.map(|it| (it.def, it.import))
|
||||
}
|
||||
|
||||
pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
|
||||
let _p = tracing::info_span!("PerNs::filter_visibility").entered();
|
||||
PerNs {
|
||||
types: self.types.filter(|&(_, v, _)| f(v)),
|
||||
values: self.values.filter(|&(_, v, _)| f(v)),
|
||||
macros: self.macros.filter(|&(_, v, _)| f(v)),
|
||||
types: self.types.filter(|def| f(def.vis)),
|
||||
values: self.values.filter(|def| f(def.vis)),
|
||||
macros: self.macros.filter(|def| f(def.vis)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_visibility(self, vis: Visibility) -> PerNs {
|
||||
PerNs {
|
||||
types: self.types.map(|(it, _, c)| (it, vis, c)),
|
||||
values: self.values.map(|(it, _, c)| (it, vis, c)),
|
||||
macros: self.macros.map(|(it, _, import)| (it, vis, import)),
|
||||
types: self.types.map(|def| Item { vis, ..def }),
|
||||
values: self.values.map(|def| Item { vis, ..def }),
|
||||
macros: self.macros.map(|def| Item { vis, ..def }),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,15 +156,17 @@ impl PerNs {
|
|||
pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
|
||||
let _p = tracing::info_span!("PerNs::iter_items").entered();
|
||||
self.types
|
||||
.map(|it| (ItemInNs::Types(it.0), it.2))
|
||||
.map(|it| (ItemInNs::Types(it.def), it.import))
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.values
|
||||
.map(|it| (ItemInNs::Values(it.0), it.2.map(ImportOrExternCrate::Import))),
|
||||
self.values.map(|it| {
|
||||
(ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::Import))
|
||||
}),
|
||||
)
|
||||
.chain(
|
||||
self.macros
|
||||
.map(|it| (ItemInNs::Macros(it.0), it.2.map(ImportOrExternCrate::Import))),
|
||||
self.macros.map(|it| {
|
||||
(ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::Import))
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -933,8 +933,8 @@ impl ModuleItemMap {
|
|||
Some(ResolveValueResult::ValueNs(value, import))
|
||||
}
|
||||
Some(idx) => {
|
||||
let (def, _, import) = module_def.take_types_full()?;
|
||||
let ty = match def {
|
||||
let def = module_def.take_types_full()?;
|
||||
let ty = match def.def {
|
||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
|
||||
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
|
||||
|
@ -948,7 +948,7 @@ impl ModuleItemMap {
|
|||
| ModuleDefId::MacroId(_)
|
||||
| ModuleDefId::StaticId(_) => return None,
|
||||
};
|
||||
Some(ResolveValueResult::Partial(ty, idx, import))
|
||||
Some(ResolveValueResult::Partial(ty, idx, def.import))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -986,8 +986,8 @@ fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportId>)> {
|
|||
}
|
||||
|
||||
fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
|
||||
let (def, _, import) = per_ns.take_types_full()?;
|
||||
let res = match def {
|
||||
let def = per_ns.take_types_full()?;
|
||||
let res = match def.def {
|
||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
|
||||
|
||||
|
@ -1003,7 +1003,7 @@ fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
|
|||
| ModuleDefId::StaticId(_)
|
||||
| ModuleDefId::ModuleId(_) => return None,
|
||||
};
|
||||
Some((res, import))
|
||||
Some((res, def.import))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -1019,14 +1019,14 @@ impl ScopeNames {
|
|||
}
|
||||
}
|
||||
fn add_per_ns(&mut self, name: &Name, def: PerNs) {
|
||||
if let &Some((ty, _, _)) = &def.types {
|
||||
self.add(name, ScopeDef::ModuleDef(ty))
|
||||
if let Some(ty) = &def.types {
|
||||
self.add(name, ScopeDef::ModuleDef(ty.def))
|
||||
}
|
||||
if let &Some((def, _, _)) = &def.values {
|
||||
self.add(name, ScopeDef::ModuleDef(def))
|
||||
if let Some(def) = &def.values {
|
||||
self.add(name, ScopeDef::ModuleDef(def.def))
|
||||
}
|
||||
if let &Some((mac, _, _)) = &def.macros {
|
||||
self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)))
|
||||
if let Some(mac) = &def.macros {
|
||||
self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac.def)))
|
||||
}
|
||||
if def.is_none() {
|
||||
self.add(name, ScopeDef::Unknown)
|
||||
|
|
|
@ -153,13 +153,13 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId {
|
|||
/// This expands the given macro call, but with different arguments. This is
|
||||
/// used for completion, where we want to see what 'would happen' if we insert a
|
||||
/// token. The `token_to_map` mapped down into the expansion, with the mapped
|
||||
/// token returned.
|
||||
/// token(s) returned with their priority.
|
||||
pub fn expand_speculative(
|
||||
db: &dyn ExpandDatabase,
|
||||
actual_macro_call: MacroCallId,
|
||||
speculative_args: &SyntaxNode,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||
let loc = db.lookup_intern_macro_call(actual_macro_call);
|
||||
let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
|
||||
|
||||
|
@ -303,17 +303,19 @@ pub fn expand_speculative(
|
|||
token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition);
|
||||
|
||||
let syntax_node = node.syntax_node();
|
||||
let (token, _) = rev_tmap
|
||||
let token = rev_tmap
|
||||
.ranges_with_span(span_map.span_for_range(token_to_map.text_range()))
|
||||
.filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx)))
|
||||
.min_by_key(|(t, ctx)| {
|
||||
.map(|(t, ctx)| {
|
||||
// prefer tokens of the same kind and text, as well as non opaque marked ones
|
||||
// Note the inversion of the score here, as we want to prefer the first token in case
|
||||
// of all tokens having the same score
|
||||
ctx.is_opaque(db) as u8
|
||||
let ranking = ctx.is_opaque(db) as u8
|
||||
+ 2 * (t.kind() != token_to_map.kind()) as u8
|
||||
+ 4 * ((t.text() != token_to_map.text()) as u8)
|
||||
})?;
|
||||
+ 4 * ((t.text() != token_to_map.text()) as u8);
|
||||
(t, ranking)
|
||||
})
|
||||
.collect();
|
||||
Some((node.syntax_node(), token))
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ use hir_def::{
|
|||
|
||||
use crate::{
|
||||
db::{HirDatabase, InternedCoroutine},
|
||||
display::HirDisplay,
|
||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
|
||||
generics::generics,
|
||||
make_binders, make_single_type_binders,
|
||||
|
@ -823,13 +822,12 @@ pub(crate) fn impl_datum_query(
|
|||
let _p = tracing::info_span!("impl_datum_query").entered();
|
||||
debug!("impl_datum {:?}", impl_id);
|
||||
let impl_: hir_def::ImplId = from_chalk(db, impl_id);
|
||||
impl_def_datum(db, krate, impl_id, impl_)
|
||||
impl_def_datum(db, krate, impl_)
|
||||
}
|
||||
|
||||
fn impl_def_datum(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
chalk_id: ImplId,
|
||||
impl_id: hir_def::ImplId,
|
||||
) -> Arc<ImplDatum> {
|
||||
let trait_ref = db
|
||||
|
@ -850,13 +848,6 @@ fn impl_def_datum(
|
|||
};
|
||||
let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars);
|
||||
let negative = impl_data.is_negative;
|
||||
debug!(
|
||||
"impl {:?}: {}{} where {:?}",
|
||||
chalk_id,
|
||||
if negative { "!" } else { "" },
|
||||
trait_ref.display(db, db.crate_graph()[krate].edition),
|
||||
where_clauses
|
||||
);
|
||||
|
||||
let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
|
||||
|
||||
|
|
|
@ -193,10 +193,19 @@ impl<'a> UnsafeVisitor<'a> {
|
|||
self.resolver.reset_to_guard(guard);
|
||||
}
|
||||
Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
|
||||
if let Expr::Path(_) = self.body.exprs[*expr] {
|
||||
match self.body.exprs[*expr] {
|
||||
// Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
|
||||
// see https://github.com/rust-lang/rust/pull/125834.
|
||||
return;
|
||||
Expr::Path(_) => return,
|
||||
// https://github.com/rust-lang/rust/pull/129248
|
||||
// Taking a raw ref to a deref place expr is always safe.
|
||||
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
|
||||
self.body
|
||||
.walk_child_exprs_without_pats(expr, |child| self.walk_expr(child));
|
||||
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Expr::MethodCall { .. } => {
|
||||
|
|
|
@ -262,7 +262,7 @@ pub struct UnresolvedAssocItem {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct UnresolvedIdent {
|
||||
pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
|
||||
pub node: InFile<(AstPtr<Either<ast::Expr, ast::Pat>>, Option<TextRange>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -550,11 +550,10 @@ impl AnyDiagnostic {
|
|||
source_map: &hir_def::body::BodySourceMap,
|
||||
) -> Option<AnyDiagnostic> {
|
||||
let expr_syntax = |expr| {
|
||||
source_map.expr_syntax(expr).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
|
||||
};
|
||||
let pat_syntax = |pat| {
|
||||
source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
|
||||
source_map.expr_syntax(expr).inspect_err(|_| stdx::never!("synthetic syntax")).ok()
|
||||
};
|
||||
let pat_syntax =
|
||||
|pat| source_map.pat_syntax(pat).inspect_err(|_| stdx::never!("synthetic syntax")).ok();
|
||||
let expr_or_pat_syntax = |id| match id {
|
||||
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
|
||||
ExprOrPatId::PatId(pat) => pat_syntax(pat),
|
||||
|
@ -626,8 +625,16 @@ impl AnyDiagnostic {
|
|||
UnresolvedAssocItem { expr_or_pat }.into()
|
||||
}
|
||||
&InferenceDiagnostic::UnresolvedIdent { id } => {
|
||||
let expr_or_pat = expr_or_pat_syntax(id)?;
|
||||
UnresolvedIdent { expr_or_pat }.into()
|
||||
let node = match id {
|
||||
ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) {
|
||||
Ok(syntax) => syntax.map(|it| (it.wrap_left(), None)),
|
||||
Err(SyntheticSyntax) => source_map
|
||||
.format_args_implicit_capture(id)?
|
||||
.map(|(node, range)| (node.wrap_left(), Some(range))),
|
||||
},
|
||||
ExprOrPatId::PatId(id) => pat_syntax(id)?.map(|it| (it, None)),
|
||||
};
|
||||
UnresolvedIdent { node }.into()
|
||||
}
|
||||
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
|
||||
let expr = expr_syntax(expr)?;
|
||||
|
|
|
@ -3105,10 +3105,10 @@ impl From<ModuleDef> for ItemInNs {
|
|||
}
|
||||
|
||||
impl ItemInNs {
|
||||
pub fn as_module_def(self) -> Option<ModuleDef> {
|
||||
pub fn into_module_def(self) -> ModuleDef {
|
||||
match self {
|
||||
ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
|
||||
ItemInNs::Macros(_) => None,
|
||||
ItemInNs::Types(id) | ItemInNs::Values(id) => id,
|
||||
ItemInNs::Macros(id) => ModuleDef::Macro(id),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId};
|
|||
use stdx::TupleExt;
|
||||
use syntax::{
|
||||
algo::skip_trivia_token,
|
||||
ast::{self, HasAttrs as _, HasGenericParams, IsString as _},
|
||||
AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
|
||||
TextSize,
|
||||
ast::{self, HasAttrs as _, HasGenericParams},
|
||||
AstNode, AstToken, Direction, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken,
|
||||
TextRange, TextSize,
|
||||
};
|
||||
use triomphe::Arc;
|
||||
|
||||
|
@ -571,7 +571,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
actual_macro_call: &ast::MacroCall,
|
||||
speculative_args: &ast::TokenTree,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||
let SourceAnalyzer { file_id, resolver, .. } =
|
||||
self.analyze_no_infer(actual_macro_call.syntax())?;
|
||||
let macro_call = InFile::new(file_id, actual_macro_call);
|
||||
|
@ -592,7 +592,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
macro_file: MacroFileId,
|
||||
speculative_args: &SyntaxNode,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||
hir_expand::db::expand_speculative(
|
||||
self.db.upcast(),
|
||||
macro_file.macro_call_id,
|
||||
|
@ -608,7 +608,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
actual_macro_call: &ast::Item,
|
||||
speculative_args: &ast::Item,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||
let macro_call = self.wrap_node_infile(actual_macro_call.clone());
|
||||
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?;
|
||||
hir_expand::db::expand_speculative(
|
||||
|
@ -624,7 +624,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
actual_macro_call: &ast::Attr,
|
||||
speculative_args: &ast::Attr,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||
let attr = self.wrap_node_infile(actual_macro_call.clone());
|
||||
let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
|
||||
let macro_call_id = self.with_ctx(|ctx| {
|
||||
|
@ -643,8 +643,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
&self,
|
||||
string: &ast::String,
|
||||
) -> Option<Vec<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)>> {
|
||||
let quote = string.open_quote_text_range()?;
|
||||
|
||||
let string_start = string.syntax().text_range().start();
|
||||
let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?;
|
||||
self.descend_into_macros_breakable(token, |token, _| {
|
||||
(|| {
|
||||
|
@ -658,7 +657,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
let format_args = self.wrap_node_infile(format_args);
|
||||
let res = source_analyzer
|
||||
.as_format_args_parts(self.db, format_args.as_ref())?
|
||||
.map(|(range, res)| (range + quote.end(), res.map(Either::Left)))
|
||||
.map(|(range, res)| (range + string_start, res.map(Either::Left)))
|
||||
.collect();
|
||||
Some(res)
|
||||
} else {
|
||||
|
@ -672,7 +671,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
.iter()
|
||||
.map(|&(range, index)| {
|
||||
(
|
||||
range + quote.end(),
|
||||
range + string_start,
|
||||
Some(Either::Right(InlineAsmOperand { owner, expr, index })),
|
||||
)
|
||||
})
|
||||
|
@ -690,17 +689,16 @@ impl<'db> SemanticsImpl<'db> {
|
|||
original_token: SyntaxToken,
|
||||
offset: TextSize,
|
||||
) -> Option<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)> {
|
||||
let original_string = ast::String::cast(original_token.clone())?;
|
||||
let string_start = original_token.text_range().start();
|
||||
let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?;
|
||||
let quote = original_string.open_quote_text_range()?;
|
||||
self.descend_into_macros_breakable(original_token, |token, _| {
|
||||
(|| {
|
||||
let token = token.value;
|
||||
self.resolve_offset_in_format_args(
|
||||
ast::String::cast(token)?,
|
||||
offset.checked_sub(quote.end())?,
|
||||
offset.checked_sub(string_start)?,
|
||||
)
|
||||
.map(|(range, res)| (range + quote.end(), res))
|
||||
.map(|(range, res)| (range + string_start, res))
|
||||
})()
|
||||
.map_or(ControlFlow::Continue(()), ControlFlow::Break)
|
||||
})
|
||||
|
@ -1542,6 +1540,21 @@ impl<'db> SemanticsImpl<'db> {
|
|||
Some(items.iter_items().map(|(item, _)| item.into()))
|
||||
}
|
||||
|
||||
pub fn resolve_mod_path_relative(
|
||||
&self,
|
||||
to: Module,
|
||||
segments: impl IntoIterator<Item = SmolStr>,
|
||||
) -> Option<impl Iterator<Item = ItemInNs>> {
|
||||
let items = to.id.resolver(self.db.upcast()).resolve_module_path_in_items(
|
||||
self.db.upcast(),
|
||||
&ModPath::from_segments(
|
||||
hir_def::path::PathKind::Plain,
|
||||
segments.into_iter().map(|it| Name::new(&it, SyntaxContextId::ROOT)),
|
||||
),
|
||||
);
|
||||
Some(items.iter_items().map(|(item, _)| item.into()))
|
||||
}
|
||||
|
||||
fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
|
||||
self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use hir::{FileRange, Semantics};
|
||||
use ide_db::EditionedFileId;
|
||||
use ide_db::{label::Label, FileId, RootDatabase};
|
||||
use syntax::Edition;
|
||||
use syntax::{
|
||||
algo::{self, find_node_at_offset, find_node_at_range},
|
||||
AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange,
|
||||
|
@ -94,6 +95,10 @@ impl<'a> AssistContext<'a> {
|
|||
self.frange.file_id
|
||||
}
|
||||
|
||||
pub(crate) fn edition(&self) -> Edition {
|
||||
self.frange.file_id.edition()
|
||||
}
|
||||
|
||||
pub(crate) fn has_empty_selection(&self) -> bool {
|
||||
self.trimmed_range.is_empty()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use ide_db::text_edit::TextRange;
|
||||
use ide_db::{
|
||||
assists::{AssistId, AssistKind},
|
||||
defs::Definition,
|
||||
search::{FileReference, SearchScope, UsageSearchResult},
|
||||
search::{FileReference, SearchScope},
|
||||
syntax_helpers::suggest_name,
|
||||
text_edit::TextRange,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use syntax::SmolStr;
|
||||
use syntax::{
|
||||
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
|
||||
ted,
|
||||
|
@ -122,33 +124,43 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
|
|||
return None;
|
||||
}
|
||||
|
||||
let name = ident_pat.name()?.to_string();
|
||||
|
||||
let usages = ctx.sema.to_def(&ident_pat).map(|def| {
|
||||
let usages = ctx.sema.to_def(&ident_pat).and_then(|def| {
|
||||
Definition::Local(def)
|
||||
.usages(&ctx.sema)
|
||||
.in_scope(&SearchScope::single_file(ctx.file_id()))
|
||||
.all()
|
||||
.iter()
|
||||
.next()
|
||||
.map(|(_, refs)| refs.to_vec())
|
||||
});
|
||||
|
||||
let field_names = (0..field_types.len())
|
||||
.map(|i| generate_name(ctx, i, &name, &ident_pat, &usages))
|
||||
let mut name_generator = {
|
||||
let mut names = vec![];
|
||||
if let Some(scope) = ctx.sema.scope(ident_pat.syntax()) {
|
||||
scope.process_all_names(&mut |name, scope| {
|
||||
if let hir::ScopeDef::Local(_) = scope {
|
||||
names.push(name.as_str().into())
|
||||
}
|
||||
})
|
||||
}
|
||||
suggest_name::NameGenerator::new_with_names(names.iter().map(|s: &SmolStr| s.as_str()))
|
||||
};
|
||||
|
||||
let field_names = field_types
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, ty)| {
|
||||
match name_generator.for_type(&ty, ctx.db(), ctx.edition()) {
|
||||
Some(name) => name,
|
||||
None => name_generator.suggest_name(&format!("_{}", id)),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Some(TupleData { ident_pat, ref_type, field_names, usages })
|
||||
}
|
||||
|
||||
fn generate_name(
|
||||
_ctx: &AssistContext<'_>,
|
||||
index: usize,
|
||||
_tuple_name: &str,
|
||||
_ident_pat: &IdentPat,
|
||||
_usages: &Option<UsageSearchResult>,
|
||||
) -> String {
|
||||
// FIXME: detect if name already used
|
||||
format!("_{index}")
|
||||
}
|
||||
|
||||
enum RefType {
|
||||
ReadOnly,
|
||||
Mutable,
|
||||
|
@ -157,7 +169,7 @@ struct TupleData {
|
|||
ident_pat: IdentPat,
|
||||
ref_type: Option<RefType>,
|
||||
field_names: Vec<String>,
|
||||
usages: Option<UsageSearchResult>,
|
||||
usages: Option<Vec<FileReference>>,
|
||||
}
|
||||
fn edit_tuple_assignment(
|
||||
ctx: &AssistContext<'_>,
|
||||
|
@ -213,42 +225,23 @@ fn edit_tuple_usages(
|
|||
ctx: &AssistContext<'_>,
|
||||
in_sub_pattern: bool,
|
||||
) -> Option<Vec<EditTupleUsage>> {
|
||||
let mut current_file_usages = None;
|
||||
// We need to collect edits first before actually applying them
|
||||
// as mapping nodes to their mutable node versions requires an
|
||||
// unmodified syntax tree.
|
||||
//
|
||||
// We also defer editing usages in the current file first since
|
||||
// tree mutation in the same file breaks when `builder.edit_file`
|
||||
// is called
|
||||
|
||||
if let Some(usages) = data.usages.as_ref() {
|
||||
// We need to collect edits first before actually applying them
|
||||
// as mapping nodes to their mutable node versions requires an
|
||||
// unmodified syntax tree.
|
||||
//
|
||||
// We also defer editing usages in the current file first since
|
||||
// tree mutation in the same file breaks when `builder.edit_file`
|
||||
// is called
|
||||
let edits = data
|
||||
.usages
|
||||
.as_ref()?
|
||||
.as_slice()
|
||||
.iter()
|
||||
.filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern))
|
||||
.collect_vec();
|
||||
|
||||
if let Some((_, refs)) = usages.iter().find(|(file_id, _)| *file_id == ctx.file_id()) {
|
||||
current_file_usages = Some(
|
||||
refs.iter()
|
||||
.filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern))
|
||||
.collect_vec(),
|
||||
);
|
||||
}
|
||||
|
||||
for (file_id, refs) in usages.iter() {
|
||||
if file_id == ctx.file_id() {
|
||||
continue;
|
||||
}
|
||||
|
||||
edit.edit_file(file_id.file_id());
|
||||
|
||||
let tuple_edits = refs
|
||||
.iter()
|
||||
.filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern))
|
||||
.collect_vec();
|
||||
|
||||
tuple_edits.into_iter().for_each(|tuple_edit| tuple_edit.apply(edit))
|
||||
}
|
||||
}
|
||||
|
||||
current_file_usages
|
||||
Some(edits)
|
||||
}
|
||||
fn edit_tuple_usage(
|
||||
ctx: &AssistContext<'_>,
|
||||
|
@ -1769,14 +1762,14 @@ struct S4 {
|
|||
}
|
||||
|
||||
fn foo() -> Option<()> {
|
||||
let ($0_0, _1, _2, _3, _4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
|
||||
let ($0_0, _1, _2, _3, s4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
|
||||
let v: i32 = *_0; // deref, no parens
|
||||
let v: &i32 = _0; // no deref, no parens, remove `&`
|
||||
f1(*_0); // deref, no parens
|
||||
f2(_0); // `&*` -> cancel out -> no deref, no parens
|
||||
// https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
|
||||
// let v: i32 = t.1.0; // no deref, no parens
|
||||
let v: i32 = _4.value; // no deref, no parens
|
||||
let v: i32 = s4.value; // no deref, no parens
|
||||
(*_0).do_stuff(); // deref, parens
|
||||
let v: i32 = (*_2)?; // deref, parens
|
||||
let v: i32 = _3[0]; // no deref, no parens
|
||||
|
@ -1815,8 +1808,8 @@ impl S {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,2);
|
||||
let s = _0.f();
|
||||
let ($0s, _1) = &(S,2);
|
||||
let s = s.f();
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -1845,8 +1838,8 @@ impl S {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,2);
|
||||
let s = (*_0).f();
|
||||
let ($0s, _1) = &(S,2);
|
||||
let s = (*s).f();
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -1882,8 +1875,8 @@ impl T for &S {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,2);
|
||||
let s = (*_0).f();
|
||||
let ($0s, _1) = &(S,2);
|
||||
let s = (*s).f();
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -1923,8 +1916,8 @@ impl T for &S {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,2);
|
||||
let s = (*_0).f();
|
||||
let ($0s, _1) = &(S,2);
|
||||
let s = (*s).f();
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -1951,8 +1944,8 @@ impl S {
|
|||
fn do_stuff(&self) -> i32 { 42 }
|
||||
}
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,&S);
|
||||
let v = _0.do_stuff();
|
||||
let ($0s, s1) = &(S,&S);
|
||||
let v = s.do_stuff();
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
@ -1973,7 +1966,7 @@ fn main() {
|
|||
// `t.0` gets auto-refed -> no deref needed -> no parens
|
||||
let v = t.0.do_stuff(); // no deref, no parens
|
||||
let v = &t.0.do_stuff(); // `&` is for result -> no deref, no parens
|
||||
// deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
|
||||
// deref: `s1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
|
||||
let v = t.1.do_stuff(); // deref, parens
|
||||
}
|
||||
"#,
|
||||
|
@ -1984,13 +1977,13 @@ impl S {
|
|||
fn do_stuff(&self) -> i32 { 42 }
|
||||
}
|
||||
fn main() {
|
||||
let ($0_0, _1) = &(S,&S);
|
||||
let v = _0.do_stuff(); // no deref, remove parens
|
||||
let ($0s, s1) = &(S,&S);
|
||||
let v = s.do_stuff(); // no deref, remove parens
|
||||
// `t.0` gets auto-refed -> no deref needed -> no parens
|
||||
let v = _0.do_stuff(); // no deref, no parens
|
||||
let v = &_0.do_stuff(); // `&` is for result -> no deref, no parens
|
||||
// deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
|
||||
let v = (*_1).do_stuff(); // deref, parens
|
||||
let v = s.do_stuff(); // no deref, no parens
|
||||
let v = &s.do_stuff(); // `&` is for result -> no deref, no parens
|
||||
// deref: `s1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
|
||||
let v = (*s1).do_stuff(); // deref, parens
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use hir::{HirDisplay, TypeInfo};
|
||||
use ide_db::{assists::GroupLabel, syntax_helpers::suggest_name};
|
||||
use ide_db::{
|
||||
assists::GroupLabel,
|
||||
syntax_helpers::{suggest_name, LexedStr},
|
||||
};
|
||||
use syntax::{
|
||||
ast::{
|
||||
self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory,
|
||||
|
@ -320,24 +323,58 @@ impl ExtractionKind {
|
|||
ctx: &AssistContext<'_>,
|
||||
to_extract: &ast::Expr,
|
||||
) -> (String, SyntaxNode) {
|
||||
let field_shorthand = to_extract
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordExprField::cast)
|
||||
.filter(|field| field.name_ref().is_some());
|
||||
let (var_name, expr_replace) = match field_shorthand {
|
||||
Some(field) => (field.to_string(), field.syntax().clone()),
|
||||
None => {
|
||||
(suggest_name::for_variable(to_extract, &ctx.sema), to_extract.syntax().clone())
|
||||
// We only do this sort of extraction for fields because they should have lowercase names
|
||||
if let ExtractionKind::Variable = self {
|
||||
let field_shorthand = to_extract
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordExprField::cast)
|
||||
.filter(|field| field.name_ref().is_some());
|
||||
|
||||
if let Some(field) = field_shorthand {
|
||||
return (field.to_string(), field.syntax().clone());
|
||||
}
|
||||
}
|
||||
|
||||
let var_name = if let Some(literal_name) = get_literal_name(ctx, to_extract) {
|
||||
literal_name
|
||||
} else {
|
||||
suggest_name::for_variable(to_extract, &ctx.sema)
|
||||
};
|
||||
|
||||
let var_name = match self {
|
||||
ExtractionKind::Variable => var_name,
|
||||
ExtractionKind::Variable => var_name.to_lowercase(),
|
||||
ExtractionKind::Constant | ExtractionKind::Static => var_name.to_uppercase(),
|
||||
};
|
||||
|
||||
(var_name, expr_replace)
|
||||
(var_name, to_extract.syntax().clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_literal_name(ctx: &AssistContext<'_>, expr: &ast::Expr) -> Option<String> {
|
||||
let literal = match expr {
|
||||
ast::Expr::Literal(literal) => literal,
|
||||
_ => return None,
|
||||
};
|
||||
let inner = match literal.kind() {
|
||||
ast::LiteralKind::String(string) => string.value().ok()?.into_owned(),
|
||||
ast::LiteralKind::ByteString(byte_string) => {
|
||||
String::from_utf8(byte_string.value().ok()?.into_owned()).ok()?
|
||||
}
|
||||
ast::LiteralKind::CString(cstring) => {
|
||||
String::from_utf8(cstring.value().ok()?.into_owned()).ok()?
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Entirely arbitrary
|
||||
if inner.len() > 32 {
|
||||
return None;
|
||||
}
|
||||
|
||||
match LexedStr::single_token(ctx.file_id().edition(), &inner) {
|
||||
Some((SyntaxKind::IDENT, None)) => Some(inner),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,7 +530,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let $0var_name = "hello";
|
||||
let $0hello = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
|
@ -588,7 +625,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
const $0VAR_NAME: &str = "hello";
|
||||
const $0HELLO: &str = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
|
@ -683,7 +720,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
static $0VAR_NAME: &str = "hello";
|
||||
static $0HELLO: &str = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
|
@ -2479,4 +2516,120 @@ fn foo() {
|
|||
"Extract into variable",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extract_string_literal() {
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let $0hello = "Hello";
|
||||
let entry = Entry(hello);
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
const $0HELLO: &str = "Hello";
|
||||
let entry = Entry(HELLO);
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
static $0HELLO: &str = "Hello";
|
||||
let entry = Entry(HELLO);
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extract_variable_string_literal_use_field_shorthand() {
|
||||
// When field shorthand is available, it should
|
||||
// only be used when extracting into a variable
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let $0message = "Hello";
|
||||
let entry = Entry { message };
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
const $0HELLO: &str = "Hello";
|
||||
let entry = Entry { message: HELLO };
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
static $0HELLO: &str = "Hello";
|
||||
let entry = Entry { message: HELLO };
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ fn item_for_path_search(db: &dyn HirDatabase, item: ItemInNs) -> Option<ItemInNs
|
|||
}
|
||||
|
||||
fn item_as_assoc(db: &dyn HirDatabase, item: ItemInNs) -> Option<AssocItem> {
|
||||
item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
|
||||
item.into_module_def().as_assoc_item(db)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
|||
let candidate = import_assets.import_candidate();
|
||||
let qualify_candidate = match syntax_under_caret.clone() {
|
||||
NodeOrToken::Node(syntax_under_caret) => match candidate {
|
||||
ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
|
||||
ImportCandidate::Path(candidate) if !candidate.qualifier.is_empty() => {
|
||||
cov_mark::hit!(qualify_path_qualifier_start);
|
||||
let path = ast::Path::cast(syntax_under_caret)?;
|
||||
let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
|
||||
|
@ -219,11 +219,9 @@ fn find_trait_method(
|
|||
}
|
||||
|
||||
fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
|
||||
let item_module_def = item.as_module_def()?;
|
||||
|
||||
match item_module_def {
|
||||
match item.into_module_def() {
|
||||
hir::ModuleDef::Trait(trait_) => Some(trait_),
|
||||
_ => item_module_def.as_assoc_item(db)?.container_trait(db),
|
||||
item_module_def => item_module_def.as_assoc_item(db)?.container_trait(db),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +245,7 @@ fn label(
|
|||
let import_path = &import.import_path;
|
||||
|
||||
match candidate {
|
||||
ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
|
||||
ImportCandidate::Path(candidate) if candidate.qualifier.is_empty() => {
|
||||
format!("Qualify as `{}`", import_path.display(db, edition))
|
||||
}
|
||||
_ => format!("Qualify with `{}`", import_path.display(db, edition)),
|
||||
|
|
|
@ -78,7 +78,7 @@ pub(crate) fn replace_derive_with_manual_impl(
|
|||
NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
|
||||
items_locator::AssocSearchMode::Exclude,
|
||||
)
|
||||
.filter_map(|item| match item.as_module_def()? {
|
||||
.filter_map(|item| match item.into_module_def() {
|
||||
ModuleDef::Trait(trait_) => Some(trait_),
|
||||
_ => None,
|
||||
})
|
||||
|
|
|
@ -12,13 +12,15 @@ use syntax::{
|
|||
|
||||
use crate::{AssistContext, Assists};
|
||||
|
||||
// FIXME: This ought to be a diagnostic lint.
|
||||
|
||||
// Assist: unnecessary_async
|
||||
//
|
||||
// Removes the `async` mark from functions which have no `.await` in their body.
|
||||
// Looks for calls to the functions and removes the `.await` on the call site.
|
||||
//
|
||||
// ```
|
||||
// pub async f$0n foo() {}
|
||||
// pub asy$0nc fn foo() {}
|
||||
// pub async fn bar() { foo().await }
|
||||
// ```
|
||||
// ->
|
||||
|
@ -29,15 +31,11 @@ use crate::{AssistContext, Assists};
|
|||
pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let function: ast::Fn = ctx.find_node_at_offset()?;
|
||||
|
||||
// Do nothing if the cursor is not on the prototype. This is so that the check does not pollute
|
||||
// when the user asks us for assists when in the middle of the function body.
|
||||
// We consider the prototype to be anything that is before the body of the function.
|
||||
let cursor_position = ctx.offset();
|
||||
if cursor_position >= function.body()?.syntax().text_range().start() {
|
||||
// Do nothing if the cursor isn't on the async token.
|
||||
let async_token = function.async_token()?;
|
||||
if !async_token.text_range().contains_inclusive(ctx.offset()) {
|
||||
return None;
|
||||
}
|
||||
// Do nothing if the function isn't async.
|
||||
function.async_token()?;
|
||||
// Do nothing if the function has an `await` expression in its body.
|
||||
if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() {
|
||||
return None;
|
||||
|
@ -138,27 +136,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn applies_on_empty_function() {
|
||||
check_assist(unnecessary_async, "pub async f$0n f() {}", "pub fn f() {}")
|
||||
check_assist(unnecessary_async, "pub asy$0nc fn f() {}", "pub fn f() {}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn applies_and_removes_whitespace() {
|
||||
check_assist(unnecessary_async, "pub async f$0n f() {}", "pub fn f() {}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_apply_on_non_async_function() {
|
||||
check_assist_not_applicable(unnecessary_async, "pub f$0n f() {}")
|
||||
check_assist(unnecessary_async, "pub async$0 fn f() {}", "pub fn f() {}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn applies_on_function_with_a_non_await_expr() {
|
||||
check_assist(unnecessary_async, "pub async f$0n f() { f2() }", "pub fn f() { f2() }")
|
||||
check_assist(unnecessary_async, "pub asy$0nc fn f() { f2() }", "pub fn f() { f2() }")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_apply_on_function_with_an_await_expr() {
|
||||
check_assist_not_applicable(unnecessary_async, "pub async f$0n f() { f2().await }")
|
||||
check_assist_not_applicable(unnecessary_async, "pub asy$0nc fn f() { f2().await }")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -167,7 +160,7 @@ mod tests {
|
|||
unnecessary_async,
|
||||
r#"
|
||||
pub async fn f4() { }
|
||||
pub async f$0n f2() { }
|
||||
pub asy$0nc fn f2() { }
|
||||
pub async fn f() { f2().await }
|
||||
pub async fn f3() { f2().await }"#,
|
||||
r#"
|
||||
|
@ -184,7 +177,7 @@ pub async fn f3() { f2() }"#,
|
|||
unnecessary_async,
|
||||
r#"
|
||||
pub async fn f4() { }
|
||||
mod a { pub async f$0n f2() { } }
|
||||
mod a { pub asy$0nc fn f2() { } }
|
||||
pub async fn f() { a::f2().await }
|
||||
pub async fn f3() { a::f2().await }"#,
|
||||
r#"
|
||||
|
@ -202,7 +195,7 @@ pub async fn f3() { a::f2() }"#,
|
|||
// Ensure that it is the first await on the 3rd line that is removed
|
||||
r#"
|
||||
pub async fn f() { f2().await }
|
||||
pub async f$0n f2() -> i32 { 1 }
|
||||
pub asy$0nc fn f2() -> i32 { 1 }
|
||||
pub async fn f3() { f4(f2().await).await }
|
||||
pub async fn f4(i: i32) { }"#,
|
||||
r#"
|
||||
|
@ -220,7 +213,7 @@ pub async fn f4(i: i32) { }"#,
|
|||
// Ensure that it is the second await on the 3rd line that is removed
|
||||
r#"
|
||||
pub async fn f() { f2().await }
|
||||
pub async f$0n f2(i: i32) { }
|
||||
pub async$0 fn f2(i: i32) { }
|
||||
pub async fn f3() { f2(f4().await).await }
|
||||
pub async fn f4() -> i32 { 1 }"#,
|
||||
r#"
|
||||
|
@ -237,7 +230,7 @@ pub async fn f4() -> i32 { 1 }"#,
|
|||
unnecessary_async,
|
||||
r#"
|
||||
pub struct S { }
|
||||
impl S { pub async f$0n f2(&self) { } }
|
||||
impl S { pub async$0 fn f2(&self) { } }
|
||||
pub async fn f(s: &S) { s.f2().await }"#,
|
||||
r#"
|
||||
pub struct S { }
|
||||
|
@ -250,13 +243,13 @@ pub async fn f(s: &S) { s.f2() }"#,
|
|||
fn does_not_apply_on_function_with_a_nested_await_expr() {
|
||||
check_assist_not_applicable(
|
||||
unnecessary_async,
|
||||
"async f$0n f() { if true { loop { f2().await } } }",
|
||||
"async$0 fn f() { if true { loop { f2().await } } }",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_apply_when_not_on_prototype() {
|
||||
check_assist_not_applicable(unnecessary_async, "pub async fn f() { $0f2() }")
|
||||
fn does_not_apply_when_not_on_async_token() {
|
||||
check_assist_not_applicable(unnecessary_async, "pub async fn$0 f() { f2() }")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -198,7 +198,7 @@ fn wrapper_alias(
|
|||
);
|
||||
|
||||
ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| {
|
||||
def.filter_map(|def| match def.as_module_def()? {
|
||||
def.filter_map(|def| match def.into_module_def() {
|
||||
hir::ModuleDef::TypeAlias(alias) => {
|
||||
let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
|
||||
(&enum_ty == core_wrapper).then_some(alias)
|
||||
|
|
|
@ -3280,7 +3280,7 @@ fn doctest_unnecessary_async() {
|
|||
check_doc_test(
|
||||
"unnecessary_async",
|
||||
r#####"
|
||||
pub async f$0n foo() {}
|
||||
pub asy$0nc fn foo() {}
|
||||
pub async fn bar() { foo().await }
|
||||
"#####,
|
||||
r#####"
|
||||
|
|
|
@ -205,7 +205,7 @@ impl S {
|
|||
fn foo(s: S) { s.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd foo u32
|
||||
fd foo u32
|
||||
me bar() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
@ -259,7 +259,7 @@ impl S {
|
|||
"#,
|
||||
expect![[r#"
|
||||
fd the_field (u32,)
|
||||
me foo() fn(self)
|
||||
me foo() fn(self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ impl A {
|
|||
"#,
|
||||
expect![[r#"
|
||||
fd the_field (u32, i32)
|
||||
me foo() fn(&self)
|
||||
me foo() fn(&self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -536,7 +536,7 @@ impl A {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd pub_field u32
|
||||
fd pub_field u32
|
||||
me pub_method() fn(&self)
|
||||
"#]],
|
||||
)
|
||||
|
@ -550,7 +550,7 @@ union U { field: u8, other: u16 }
|
|||
fn foo(u: U) { u.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd field u8
|
||||
fd field u8
|
||||
fd other u16
|
||||
"#]],
|
||||
);
|
||||
|
@ -725,8 +725,8 @@ fn test(a: A) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd another u32
|
||||
fd field u8
|
||||
fd another u32
|
||||
fd field u8
|
||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||
"#]],
|
||||
);
|
||||
|
@ -748,8 +748,8 @@ fn test(a: A) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd 0 u8
|
||||
fd 1 u32
|
||||
fd 0 u8
|
||||
fd 1 u32
|
||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||
"#]],
|
||||
);
|
||||
|
@ -770,8 +770,8 @@ fn test(a: A) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd 0 u8
|
||||
fd 1 u32
|
||||
fd 0 u8
|
||||
fd 1 u32
|
||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||
"#]],
|
||||
);
|
||||
|
@ -964,12 +964,12 @@ struct Foo { field: i32 }
|
|||
|
||||
impl Foo { fn foo(&self) { $0 } }"#,
|
||||
expect![[r#"
|
||||
fd self.field i32
|
||||
fd self.field i32
|
||||
me self.foo() fn(&self)
|
||||
lc self &Foo
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
lc self &Foo
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
|
@ -978,12 +978,12 @@ struct Foo(i32);
|
|||
|
||||
impl Foo { fn foo(&mut self) { $0 } }"#,
|
||||
expect![[r#"
|
||||
fd self.0 i32
|
||||
fd self.0 i32
|
||||
me self.foo() fn(&mut self)
|
||||
lc self &mut Foo
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
lc self &mut Foo
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1106,7 +1106,7 @@ fn test(a: A) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd 0 u8
|
||||
fd 0 u8
|
||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||
"#]],
|
||||
);
|
||||
|
@ -1162,7 +1162,7 @@ impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd foo &u8
|
||||
fd foo &u8
|
||||
me foobar() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
@ -1199,8 +1199,8 @@ impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd foo &u8
|
||||
"#]],
|
||||
fd foo &u8
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -537,10 +537,10 @@ impl Test for T {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
sp Self T
|
||||
st T T
|
||||
sp Self T
|
||||
st T T
|
||||
tt Test
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -646,10 +646,10 @@ impl Test for T {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
sp Self T
|
||||
st T T
|
||||
sp Self T
|
||||
st T T
|
||||
tt Test
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -663,10 +663,10 @@ impl Test for T {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
sp Self T
|
||||
st T T
|
||||
sp Self T
|
||||
st T T
|
||||
tt Test
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -682,10 +682,10 @@ impl Test for T {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
sp Self T
|
||||
st T T
|
||||
sp Self T
|
||||
st T T
|
||||
tt Test
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -730,10 +730,10 @@ impl Test for T {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
sp Self T
|
||||
st T T
|
||||
sp Self T
|
||||
st T T
|
||||
tt Test
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
|
|
@ -78,19 +78,19 @@ fn foo(a: A) { a.$0 }
|
|||
"#,
|
||||
expect![[r#"
|
||||
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -105,19 +105,19 @@ fn foo() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -134,19 +134,19 @@ fn foo(a: A) { a.$0 }
|
|||
"#,
|
||||
expect![[r#"
|
||||
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
kw await expr.await
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -423,21 +423,21 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -456,19 +456,19 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -483,18 +483,18 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -509,21 +509,21 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -718,7 +718,7 @@ impl<'a> CompletionContext<'a> {
|
|||
expected: (expected_type, expected_name),
|
||||
qualifier_ctx,
|
||||
token,
|
||||
offset,
|
||||
original_offset,
|
||||
} = expand_and_analyze(
|
||||
&sema,
|
||||
original_file.syntax().clone(),
|
||||
|
@ -728,7 +728,7 @@ impl<'a> CompletionContext<'a> {
|
|||
)?;
|
||||
|
||||
// adjust for macro input, this still fails if there is no token written yet
|
||||
let scope = sema.scope_at_offset(&token.parent()?, offset)?;
|
||||
let scope = sema.scope_at_offset(&token.parent()?, original_offset)?;
|
||||
|
||||
let krate = scope.krate();
|
||||
let module = scope.module();
|
||||
|
|
|
@ -22,10 +22,14 @@ use crate::context::{
|
|||
COMPLETION_MARKER,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExpansionResult {
|
||||
original_file: SyntaxNode,
|
||||
speculative_file: SyntaxNode,
|
||||
offset: TextSize,
|
||||
/// The offset in the original file.
|
||||
original_offset: TextSize,
|
||||
/// The offset in the speculatively expanded file.
|
||||
speculative_offset: TextSize,
|
||||
fake_ident_token: SyntaxToken,
|
||||
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
|
||||
}
|
||||
|
@ -36,7 +40,8 @@ pub(super) struct AnalysisResult {
|
|||
pub(super) qualifier_ctx: QualifierCtx,
|
||||
/// the original token of the expanded file
|
||||
pub(super) token: SyntaxToken,
|
||||
pub(super) offset: TextSize,
|
||||
/// The offset in the original file.
|
||||
pub(super) original_offset: TextSize,
|
||||
}
|
||||
|
||||
pub(super) fn expand_and_analyze(
|
||||
|
@ -54,226 +59,344 @@ pub(super) fn expand_and_analyze(
|
|||
// make the offset point to the start of the original token, as that is what the
|
||||
// intermediate offsets calculated in expansion always points to
|
||||
let offset = offset - relative_offset;
|
||||
let expansion =
|
||||
expand(sema, original_file, speculative_file, offset, fake_ident_token, relative_offset);
|
||||
let expansion = expand(
|
||||
sema,
|
||||
original_file.clone(),
|
||||
speculative_file.clone(),
|
||||
offset,
|
||||
fake_ident_token.clone(),
|
||||
relative_offset,
|
||||
)
|
||||
.unwrap_or(ExpansionResult {
|
||||
original_file,
|
||||
speculative_file,
|
||||
original_offset: offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
fake_ident_token,
|
||||
derive_ctx: None,
|
||||
});
|
||||
|
||||
// add the relative offset back, so that left_biased finds the proper token
|
||||
let offset = expansion.offset + relative_offset;
|
||||
let token = expansion.original_file.token_at_offset(offset).left_biased()?;
|
||||
let original_offset = expansion.original_offset + relative_offset;
|
||||
let token = expansion.original_file.token_at_offset(original_offset).left_biased()?;
|
||||
|
||||
analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
|
||||
AnalysisResult { analysis, expected, qualifier_ctx, token, offset }
|
||||
AnalysisResult { analysis, expected, qualifier_ctx, token, original_offset }
|
||||
})
|
||||
}
|
||||
|
||||
/// Expand attributes and macro calls at the current cursor position for both the original file
|
||||
/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
|
||||
/// and speculative states stay in sync.
|
||||
///
|
||||
/// We do this by recursively expanding all macros and picking the best possible match. We cannot just
|
||||
/// choose the first expansion each time because macros can expand to something that does not include
|
||||
/// our completion marker, e.g.:
|
||||
/// ```
|
||||
/// macro_rules! helper { ($v:ident) => {} }
|
||||
/// macro_rules! my_macro {
|
||||
/// ($v:ident) => {
|
||||
/// helper!($v);
|
||||
/// $v
|
||||
/// };
|
||||
/// }
|
||||
///
|
||||
/// my_macro!(complete_me_here)
|
||||
/// ```
|
||||
/// If we would expand the first thing we encounter only (which in fact this method used to do), we would
|
||||
/// be unable to complete here, because we would be walking directly into the void. So we instead try
|
||||
/// *every* possible path.
|
||||
///
|
||||
/// This can also creates discrepancies between the speculative and real expansions: because we insert
|
||||
/// tokens, we insert characters, which means if we try the second occurrence it may not be at the same
|
||||
/// position in the original and speculative file. We take an educated guess here, and for each token
|
||||
/// that we check, we subtract `COMPLETION_MARKER.len()`. This may not be accurate because proc macros
|
||||
/// can insert the text of the completion marker in other places while removing the span, but this is
|
||||
/// the best we can do.
|
||||
fn expand(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
mut original_file: SyntaxNode,
|
||||
mut speculative_file: SyntaxNode,
|
||||
mut offset: TextSize,
|
||||
mut fake_ident_token: SyntaxToken,
|
||||
original_file: SyntaxNode,
|
||||
speculative_file: SyntaxNode,
|
||||
original_offset: TextSize,
|
||||
fake_ident_token: SyntaxToken,
|
||||
relative_offset: TextSize,
|
||||
) -> ExpansionResult {
|
||||
) -> Option<ExpansionResult> {
|
||||
let _p = tracing::info_span!("CompletionContext::expand").entered();
|
||||
let mut derive_ctx = None;
|
||||
|
||||
'expansion: loop {
|
||||
let parent_item =
|
||||
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
|
||||
let ancestor_items = iter::successors(
|
||||
Option::zip(
|
||||
find_node_at_offset::<ast::Item>(&original_file, offset),
|
||||
find_node_at_offset::<ast::Item>(&speculative_file, offset),
|
||||
if !sema.might_be_inside_macro_call(&fake_ident_token)
|
||||
&& original_file
|
||||
.token_at_offset(original_offset + relative_offset)
|
||||
.right_biased()
|
||||
.is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
|
||||
{
|
||||
// Recursion base case.
|
||||
return Some(ExpansionResult {
|
||||
original_file,
|
||||
speculative_file,
|
||||
original_offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
fake_ident_token,
|
||||
derive_ctx: None,
|
||||
});
|
||||
}
|
||||
|
||||
let parent_item =
|
||||
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
|
||||
let ancestor_items = iter::successors(
|
||||
Option::zip(
|
||||
find_node_at_offset::<ast::Item>(&original_file, original_offset),
|
||||
find_node_at_offset::<ast::Item>(
|
||||
&speculative_file,
|
||||
fake_ident_token.text_range().start(),
|
||||
),
|
||||
|(a, b)| parent_item(a).zip(parent_item(b)),
|
||||
);
|
||||
),
|
||||
|(a, b)| parent_item(a).zip(parent_item(b)),
|
||||
);
|
||||
|
||||
// first try to expand attributes as these are always the outermost macro calls
|
||||
'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
|
||||
match (
|
||||
sema.expand_attr_macro(&actual_item),
|
||||
sema.speculative_expand_attr_macro(
|
||||
&actual_item,
|
||||
&item_with_fake_ident,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
// maybe parent items have attributes, so continue walking the ancestors
|
||||
(None, None) => continue 'ancestors,
|
||||
// successful expansions
|
||||
(
|
||||
Some(ExpandResult { value: actual_expansion, err: _ }),
|
||||
Some((fake_expansion, fake_mapped_token)),
|
||||
) => {
|
||||
let new_offset = fake_mapped_token.text_range().start();
|
||||
if new_offset + relative_offset > actual_expansion.text_range().end() {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
break 'expansion;
|
||||
}
|
||||
original_file = actual_expansion;
|
||||
speculative_file = fake_expansion;
|
||||
fake_ident_token = fake_mapped_token;
|
||||
offset = new_offset;
|
||||
continue 'expansion;
|
||||
// first try to expand attributes as these are always the outermost macro calls
|
||||
'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
|
||||
match (
|
||||
sema.expand_attr_macro(&actual_item),
|
||||
sema.speculative_expand_attr_macro(
|
||||
&actual_item,
|
||||
&item_with_fake_ident,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
// maybe parent items have attributes, so continue walking the ancestors
|
||||
(None, None) => continue 'ancestors,
|
||||
// successful expansions
|
||||
(
|
||||
Some(ExpandResult { value: actual_expansion, err: _ }),
|
||||
Some((fake_expansion, fake_mapped_tokens)),
|
||||
) => {
|
||||
let mut accumulated_offset_from_fake_tokens = 0;
|
||||
let actual_range = actual_expansion.text_range().end();
|
||||
let result = fake_mapped_tokens
|
||||
.into_iter()
|
||||
.filter_map(|(fake_mapped_token, rank)| {
|
||||
let accumulated_offset = accumulated_offset_from_fake_tokens;
|
||||
if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
|
||||
// Proc macros can make the same span with different text, we don't
|
||||
// want them to participate in completion because the macro author probably
|
||||
// didn't intend them to.
|
||||
return None;
|
||||
}
|
||||
accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
|
||||
|
||||
let new_offset = fake_mapped_token.text_range().start()
|
||||
- TextSize::new(accumulated_offset as u32);
|
||||
if new_offset + relative_offset > actual_range {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
return None;
|
||||
}
|
||||
let result = expand(
|
||||
sema,
|
||||
actual_expansion.clone(),
|
||||
fake_expansion.clone(),
|
||||
new_offset,
|
||||
fake_mapped_token,
|
||||
relative_offset,
|
||||
)?;
|
||||
Some((result, rank))
|
||||
})
|
||||
.min_by_key(|(_, rank)| *rank)
|
||||
.map(|(result, _)| result);
|
||||
if result.is_some() {
|
||||
return result;
|
||||
}
|
||||
// exactly one expansion failed, inconsistent state so stop expanding completely
|
||||
_ => break 'expansion,
|
||||
}
|
||||
// exactly one expansion failed, inconsistent state so stop expanding completely
|
||||
_ => break 'ancestors,
|
||||
}
|
||||
}
|
||||
|
||||
// No attributes have been expanded, so look for macro_call! token trees or derive token trees
|
||||
let orig_tt = ancestors_at_offset(&original_file, original_offset)
|
||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||
.last()?;
|
||||
let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start())
|
||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||
.last()?;
|
||||
|
||||
let (tts, attrs) = match (orig_tt, spec_tt) {
|
||||
(Either::Left(orig_tt), Either::Left(spec_tt)) => {
|
||||
let attrs = orig_tt
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::Meta::cast)
|
||||
.and_then(|it| it.parent_attr())
|
||||
.zip(
|
||||
spec_tt
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::Meta::cast)
|
||||
.and_then(|it| it.parent_attr()),
|
||||
);
|
||||
(Some((orig_tt, spec_tt)), attrs)
|
||||
}
|
||||
(Either::Right(orig_path), Either::Right(spec_path)) => {
|
||||
(None, orig_path.parent_attr().zip(spec_path.parent_attr()))
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Expand pseudo-derive expansion aka `derive(Debug$0)`
|
||||
if let Some((orig_attr, spec_attr)) = attrs {
|
||||
if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) = (
|
||||
sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
|
||||
sema.speculative_expand_derive_as_pseudo_attr_macro(
|
||||
&orig_attr,
|
||||
&spec_attr,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
if let Some((fake_mapped_token, _)) =
|
||||
fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank)
|
||||
{
|
||||
return Some(ExpansionResult {
|
||||
original_file,
|
||||
speculative_file,
|
||||
original_offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
fake_ident_token,
|
||||
derive_ctx: Some((
|
||||
actual_expansion,
|
||||
fake_expansion,
|
||||
fake_mapped_token.text_range().start(),
|
||||
orig_attr,
|
||||
)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// No attributes have been expanded, so look for macro_call! token trees or derive token trees
|
||||
let orig_tt = match ancestors_at_offset(&original_file, offset)
|
||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||
.last()
|
||||
if let Some(spec_adt) =
|
||||
spec_attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
|
||||
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
|
||||
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
|
||||
ast::Item::Union(it) => Some(ast::Adt::Union(it)),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
Some(it) => it,
|
||||
None => break 'expansion,
|
||||
};
|
||||
let spec_tt = match ancestors_at_offset(&speculative_file, offset)
|
||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||
.last()
|
||||
{
|
||||
Some(it) => it,
|
||||
None => break 'expansion,
|
||||
};
|
||||
// might be the path of derive helper or a token tree inside of one
|
||||
if let Some(helpers) = sema.derive_helper(&orig_attr) {
|
||||
for (_mac, file) in helpers {
|
||||
if let Some((fake_expansion, fake_mapped_tokens)) = sema.speculative_expand_raw(
|
||||
file,
|
||||
spec_adt.syntax(),
|
||||
fake_ident_token.clone(),
|
||||
) {
|
||||
// we are inside a derive helper token tree, treat this as being inside
|
||||
// the derive expansion
|
||||
let actual_expansion = sema.parse_or_expand(file.into());
|
||||
let mut accumulated_offset_from_fake_tokens = 0;
|
||||
let actual_range = actual_expansion.text_range().end();
|
||||
let result = fake_mapped_tokens
|
||||
.into_iter()
|
||||
.filter_map(|(fake_mapped_token, rank)| {
|
||||
let accumulated_offset = accumulated_offset_from_fake_tokens;
|
||||
if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
|
||||
// Proc macros can make the same span with different text, we don't
|
||||
// want them to participate in completion because the macro author probably
|
||||
// didn't intend them to.
|
||||
return None;
|
||||
}
|
||||
accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
|
||||
|
||||
let (tts, attrs) = match (orig_tt, spec_tt) {
|
||||
(Either::Left(orig_tt), Either::Left(spec_tt)) => {
|
||||
let attrs = orig_tt
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::Meta::cast)
|
||||
.and_then(|it| it.parent_attr())
|
||||
.zip(
|
||||
spec_tt
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::Meta::cast)
|
||||
.and_then(|it| it.parent_attr()),
|
||||
);
|
||||
(Some((orig_tt, spec_tt)), attrs)
|
||||
}
|
||||
(Either::Right(orig_path), Either::Right(spec_path)) => {
|
||||
(None, orig_path.parent_attr().zip(spec_path.parent_attr()))
|
||||
}
|
||||
_ => break 'expansion,
|
||||
};
|
||||
|
||||
// Expand pseudo-derive expansion aka `derive(Debug$0)`
|
||||
if let Some((orig_attr, spec_attr)) = attrs {
|
||||
if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
|
||||
sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
|
||||
sema.speculative_expand_derive_as_pseudo_attr_macro(
|
||||
&orig_attr,
|
||||
&spec_attr,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
derive_ctx = Some((
|
||||
actual_expansion,
|
||||
fake_expansion,
|
||||
fake_mapped_token.text_range().start(),
|
||||
orig_attr,
|
||||
));
|
||||
break 'expansion;
|
||||
}
|
||||
|
||||
if let Some(spec_adt) =
|
||||
spec_attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
|
||||
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
|
||||
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
|
||||
ast::Item::Union(it) => Some(ast::Adt::Union(it)),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
// might be the path of derive helper or a token tree inside of one
|
||||
if let Some(helpers) = sema.derive_helper(&orig_attr) {
|
||||
for (_mac, file) in helpers {
|
||||
if let Some((fake_expansion, fake_mapped_token)) = sema
|
||||
.speculative_expand_raw(
|
||||
file,
|
||||
spec_adt.syntax(),
|
||||
fake_ident_token.clone(),
|
||||
)
|
||||
{
|
||||
// we are inside a derive helper token tree, treat this as being inside
|
||||
// the derive expansion
|
||||
let actual_expansion = sema.parse_or_expand(file.into());
|
||||
let new_offset = fake_mapped_token.text_range().start();
|
||||
if new_offset + relative_offset > actual_expansion.text_range().end() {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
break 'expansion;
|
||||
}
|
||||
original_file = actual_expansion;
|
||||
speculative_file = fake_expansion;
|
||||
fake_ident_token = fake_mapped_token;
|
||||
offset = new_offset;
|
||||
continue 'expansion;
|
||||
let new_offset = fake_mapped_token.text_range().start()
|
||||
- TextSize::new(accumulated_offset as u32);
|
||||
if new_offset + relative_offset > actual_range {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
return None;
|
||||
}
|
||||
let result = expand(
|
||||
sema,
|
||||
actual_expansion.clone(),
|
||||
fake_expansion.clone(),
|
||||
new_offset,
|
||||
fake_mapped_token,
|
||||
relative_offset,
|
||||
)?;
|
||||
Some((result, rank))
|
||||
})
|
||||
.min_by_key(|(_, rank)| *rank)
|
||||
.map(|(result, _)| result);
|
||||
if result.is_some() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// at this point we won't have any more successful expansions, so stop
|
||||
break 'expansion;
|
||||
}
|
||||
|
||||
// Expand fn-like macro calls
|
||||
let Some((orig_tt, spec_tt)) = tts else { break 'expansion };
|
||||
if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
|
||||
orig_tt.syntax().parent().and_then(ast::MacroCall::cast),
|
||||
spec_tt.syntax().parent().and_then(ast::MacroCall::cast),
|
||||
) {
|
||||
let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
|
||||
let mac_call_path1 =
|
||||
macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
|
||||
|
||||
// inconsistent state, stop expanding
|
||||
if mac_call_path0 != mac_call_path1 {
|
||||
break 'expansion;
|
||||
}
|
||||
let speculative_args = match macro_call_with_fake_ident.token_tree() {
|
||||
Some(tt) => tt,
|
||||
None => break 'expansion,
|
||||
};
|
||||
|
||||
match (
|
||||
sema.expand_macro_call(&actual_macro_call),
|
||||
sema.speculative_expand_macro_call(
|
||||
&actual_macro_call,
|
||||
&speculative_args,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
// successful expansions
|
||||
(Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
|
||||
let new_offset = fake_mapped_token.text_range().start();
|
||||
if new_offset + relative_offset > actual_expansion.text_range().end() {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
break 'expansion;
|
||||
}
|
||||
original_file = actual_expansion;
|
||||
speculative_file = fake_expansion;
|
||||
fake_ident_token = fake_mapped_token;
|
||||
offset = new_offset;
|
||||
continue 'expansion;
|
||||
}
|
||||
// at least on expansion failed, we won't have anything to expand from this point
|
||||
// onwards so break out
|
||||
_ => break 'expansion,
|
||||
}
|
||||
}
|
||||
|
||||
// none of our states have changed so stop the loop
|
||||
break 'expansion;
|
||||
// at this point we won't have any more successful expansions, so stop
|
||||
return None;
|
||||
}
|
||||
|
||||
ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx }
|
||||
// Expand fn-like macro calls
|
||||
let (orig_tt, spec_tt) = tts?;
|
||||
let (actual_macro_call, macro_call_with_fake_ident) = (
|
||||
orig_tt.syntax().parent().and_then(ast::MacroCall::cast)?,
|
||||
spec_tt.syntax().parent().and_then(ast::MacroCall::cast)?,
|
||||
);
|
||||
let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
|
||||
let mac_call_path1 = macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
|
||||
|
||||
// inconsistent state, stop expanding
|
||||
if mac_call_path0 != mac_call_path1 {
|
||||
return None;
|
||||
}
|
||||
let speculative_args = macro_call_with_fake_ident.token_tree()?;
|
||||
|
||||
match (
|
||||
sema.expand_macro_call(&actual_macro_call),
|
||||
sema.speculative_expand_macro_call(
|
||||
&actual_macro_call,
|
||||
&speculative_args,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
// successful expansions
|
||||
(Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) => {
|
||||
let mut accumulated_offset_from_fake_tokens = 0;
|
||||
let actual_range = actual_expansion.text_range().end();
|
||||
fake_mapped_tokens
|
||||
.into_iter()
|
||||
.filter_map(|(fake_mapped_token, rank)| {
|
||||
let accumulated_offset = accumulated_offset_from_fake_tokens;
|
||||
if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
|
||||
// Proc macros can make the same span with different text, we don't
|
||||
// want them to participate in completion because the macro author probably
|
||||
// didn't intend them to.
|
||||
return None;
|
||||
}
|
||||
accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
|
||||
|
||||
let new_offset = fake_mapped_token.text_range().start()
|
||||
- TextSize::new(accumulated_offset as u32);
|
||||
if new_offset + relative_offset > actual_range {
|
||||
// offset outside of bounds from the original expansion,
|
||||
// stop here to prevent problems from happening
|
||||
return None;
|
||||
}
|
||||
let result = expand(
|
||||
sema,
|
||||
actual_expansion.clone(),
|
||||
fake_expansion.clone(),
|
||||
new_offset,
|
||||
fake_mapped_token,
|
||||
relative_offset,
|
||||
)?;
|
||||
Some((result, rank))
|
||||
})
|
||||
.min_by_key(|(_, rank)| *rank)
|
||||
.map(|(result, _)| result)
|
||||
}
|
||||
// at least one expansion failed, we won't have anything to expand from this point
|
||||
// onwards so break out
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the completion context, this is what does semantic reasoning about the surrounding context
|
||||
|
@ -285,8 +408,14 @@ fn analyze(
|
|||
self_token: &SyntaxToken,
|
||||
) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
|
||||
let _p = tracing::info_span!("CompletionContext::analyze").entered();
|
||||
let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } =
|
||||
expansion_result;
|
||||
let ExpansionResult {
|
||||
original_file,
|
||||
speculative_file,
|
||||
original_offset: _,
|
||||
speculative_offset,
|
||||
fake_ident_token,
|
||||
derive_ctx,
|
||||
} = expansion_result;
|
||||
|
||||
// Overwrite the path kind for derives
|
||||
if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
|
||||
|
@ -294,7 +423,8 @@ fn analyze(
|
|||
find_node_at_offset(&file_with_fake_ident, offset)
|
||||
{
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
let (mut nameref_ctx, _) = classify_name_ref(sema, &original_file, name_ref, parent)?;
|
||||
let (mut nameref_ctx, _) =
|
||||
classify_name_ref(sema, &original_file, name_ref, offset, parent)?;
|
||||
if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
|
||||
path_ctx.kind = PathKind::Derive {
|
||||
existing_derives: sema
|
||||
|
@ -314,7 +444,7 @@ fn analyze(
|
|||
return None;
|
||||
}
|
||||
|
||||
let Some(name_like) = find_node_at_offset(&speculative_file, offset) else {
|
||||
let Some(name_like) = find_node_at_offset(&speculative_file, speculative_offset) else {
|
||||
let analysis = if let Some(original) = ast::String::cast(original_token.clone()) {
|
||||
CompletionAnalysis::String { original, expanded: ast::String::cast(self_token.clone()) }
|
||||
} else {
|
||||
|
@ -350,8 +480,13 @@ fn analyze(
|
|||
}
|
||||
ast::NameLike::NameRef(name_ref) => {
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
let (nameref_ctx, qualifier_ctx) =
|
||||
classify_name_ref(sema, &original_file, name_ref, parent)?;
|
||||
let (nameref_ctx, qualifier_ctx) = classify_name_ref(
|
||||
sema,
|
||||
&original_file,
|
||||
name_ref,
|
||||
expansion_result.original_offset,
|
||||
parent,
|
||||
)?;
|
||||
|
||||
if let NameRefContext {
|
||||
kind:
|
||||
|
@ -636,9 +771,10 @@ fn classify_name_ref(
|
|||
sema: &Semantics<'_, RootDatabase>,
|
||||
original_file: &SyntaxNode,
|
||||
name_ref: ast::NameRef,
|
||||
original_offset: TextSize,
|
||||
parent: SyntaxNode,
|
||||
) -> Option<(NameRefContext, QualifierCtx)> {
|
||||
let nameref = find_node_at_offset(original_file, name_ref.syntax().text_range().start());
|
||||
let nameref = find_node_at_offset(original_file, original_offset);
|
||||
|
||||
let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
|
||||
|
||||
|
@ -760,7 +896,7 @@ fn classify_name_ref(
|
|||
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
|
||||
// ex. trait Foo $0 {}
|
||||
// in these cases parser recovery usually kicks in for our inserted identifier, causing it
|
||||
// to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block
|
||||
// to either be parsed as an ExprStmt or a ItemRecovery, depending on whether it is in a block
|
||||
// expression or an item list.
|
||||
// The following code checks if the body is missing, if it is we either cut off the body
|
||||
// from the item or it was missing in the first place
|
||||
|
@ -1088,15 +1224,10 @@ fn classify_name_ref(
|
|||
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
|
||||
};
|
||||
|
||||
let mut kind_macro_call = |it: ast::MacroCall| {
|
||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||
let parent = it.syntax().parent()?;
|
||||
// Any path in an item list will be treated as a macro call by the parser
|
||||
let kind_item = |it: &SyntaxNode| {
|
||||
let parent = it.parent()?;
|
||||
let kind = match_ast! {
|
||||
match parent {
|
||||
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
|
||||
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
|
||||
ast::MacroType(ty) => make_path_kind_type(ty.into()),
|
||||
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
|
||||
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
||||
Some(it) => match_ast! {
|
||||
|
@ -1126,6 +1257,23 @@ fn classify_name_ref(
|
|||
};
|
||||
Some(kind)
|
||||
};
|
||||
|
||||
let mut kind_macro_call = |it: ast::MacroCall| {
|
||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||
let parent = it.syntax().parent()?;
|
||||
if let Some(kind) = kind_item(it.syntax()) {
|
||||
return Some(kind);
|
||||
}
|
||||
let kind = match_ast! {
|
||||
match parent {
|
||||
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
|
||||
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
|
||||
ast::MacroType(ty) => make_path_kind_type(ty.into()),
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
Some(kind)
|
||||
};
|
||||
let make_path_kind_attr = |meta: ast::Meta| {
|
||||
let attr = meta.parent_attr()?;
|
||||
let kind = attr.kind();
|
||||
|
@ -1153,94 +1301,98 @@ fn classify_name_ref(
|
|||
|
||||
// Infer the path kind
|
||||
let parent = path.syntax().parent()?;
|
||||
let kind = match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
if let Some(p) = it.syntax().parent() {
|
||||
let p_kind = p.kind();
|
||||
// The syntax node of interest, for which we want to check whether
|
||||
// it is sandwiched between an item decl signature and its body.
|
||||
let probe = if ast::ExprStmt::can_cast(p_kind) {
|
||||
Some(p)
|
||||
} else if ast::StmtList::can_cast(p_kind) {
|
||||
Some(it.syntax().clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
|
||||
let kind = 'find_kind: {
|
||||
if parent.kind() == SyntaxKind::ERROR {
|
||||
if let Some(kind) = inbetween_body_and_decl_check(parent.clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
|
||||
break 'find_kind kind_item(&parent)?;
|
||||
}
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
if let Some(p) = it.syntax().parent() {
|
||||
let p_kind = p.kind();
|
||||
// The syntax node of interest, for which we want to check whether
|
||||
// it is sandwiched between an item decl signature and its body.
|
||||
let probe = if ast::ExprStmt::can_cast(p_kind) {
|
||||
Some(p)
|
||||
} else if ast::StmtList::can_cast(p_kind) {
|
||||
Some(it.syntax().clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
}
|
||||
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
// completing inside a qualifier
|
||||
ast::Path(parent) => {
|
||||
path_ctx.parent = Some(parent.clone());
|
||||
let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::RecordExpr(it) => {
|
||||
// A record expression in this position is usually a result of parsing recovery, so check that
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
}
|
||||
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
// A macro call in this position is usually a result of parsing recovery, so check that
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
// completing inside a qualifier
|
||||
ast::Path(parent) => {
|
||||
path_ctx.parent = Some(parent.clone());
|
||||
let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::RecordExpr(it) => {
|
||||
// A record expression in this position is usually a result of parsing recovery, so check that
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
_ => return None,
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1320,9 +1472,7 @@ fn classify_name_ref(
|
|||
}
|
||||
})
|
||||
}
|
||||
PathKind::Item { .. } => {
|
||||
parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
|
||||
}
|
||||
PathKind::Item { .. } => parent.ancestors().find(|it| it.kind() == SyntaxKind::ERROR),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(top) = top_node {
|
||||
|
|
|
@ -10,7 +10,7 @@ use ide_db::{
|
|||
};
|
||||
use itertools::Itertools;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::{impl_from, never};
|
||||
use stdx::{format_to, impl_from, never};
|
||||
use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
|
||||
|
||||
use crate::{
|
||||
|
@ -27,10 +27,7 @@ use crate::{
|
|||
#[non_exhaustive]
|
||||
pub struct CompletionItem {
|
||||
/// Label in the completion pop up which identifies completion.
|
||||
pub label: SmolStr,
|
||||
/// Additional label details in the completion pop up that are
|
||||
/// displayed and aligned on the right side after the label.
|
||||
pub label_detail: Option<SmolStr>,
|
||||
pub label: CompletionItemLabel,
|
||||
|
||||
/// Range of identifier that is being completed.
|
||||
///
|
||||
|
@ -89,11 +86,23 @@ pub struct CompletionItem {
|
|||
pub import_to_add: SmallVec<[(String, String); 1]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct CompletionItemLabel {
|
||||
/// The primary label for the completion item.
|
||||
pub primary: SmolStr,
|
||||
/// The left detail for the completion item, usually rendered right next to the primary label.
|
||||
pub detail_left: Option<String>,
|
||||
/// The right detail for the completion item, usually rendered right aligned at the end of the completion item.
|
||||
pub detail_right: Option<String>,
|
||||
}
|
||||
// We use custom debug for CompletionItem to make snapshot tests more readable.
|
||||
impl fmt::Debug for CompletionItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut s = f.debug_struct("CompletionItem");
|
||||
s.field("label", &self.label).field("source_range", &self.source_range);
|
||||
s.field("label", &self.label.primary)
|
||||
.field("detail_left", &self.label.detail_left)
|
||||
.field("detail_right", &self.label.detail_right)
|
||||
.field("source_range", &self.source_range);
|
||||
if self.text_edit.len() == 1 {
|
||||
let atom = self.text_edit.iter().next().unwrap();
|
||||
s.field("delete", &atom.delete);
|
||||
|
@ -102,7 +111,7 @@ impl fmt::Debug for CompletionItem {
|
|||
s.field("text_edit", &self.text_edit);
|
||||
}
|
||||
s.field("kind", &self.kind);
|
||||
if self.lookup() != self.label {
|
||||
if self.lookup() != self.label.primary {
|
||||
s.field("lookup", &self.lookup());
|
||||
}
|
||||
if let Some(detail) = &self.detail {
|
||||
|
@ -434,7 +443,7 @@ impl CompletionItem {
|
|||
|
||||
self.ref_match.map(|(mutability, offset)| {
|
||||
(
|
||||
format!("&{}{}", mutability.as_keyword_for_ref(), self.label),
|
||||
format!("&{}{}", mutability.as_keyword_for_ref(), self.label.primary),
|
||||
ide_db::text_edit::Indel::insert(
|
||||
offset,
|
||||
format!("&{}", mutability.as_keyword_for_ref()),
|
||||
|
@ -488,13 +497,13 @@ impl Builder {
|
|||
let _p = tracing::info_span!("item::Builder::build").entered();
|
||||
|
||||
let label = self.label;
|
||||
let mut label_detail = None;
|
||||
let mut lookup = self.lookup.unwrap_or_else(|| label.clone());
|
||||
let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
|
||||
|
||||
let mut detail_left = None;
|
||||
if !self.doc_aliases.is_empty() {
|
||||
let doc_aliases = self.doc_aliases.iter().join(", ");
|
||||
label_detail.replace(format_smolstr!(" (alias {doc_aliases})"));
|
||||
detail_left = Some(format!("(alias {doc_aliases})"));
|
||||
let lookup_doc_aliases = self
|
||||
.doc_aliases
|
||||
.iter()
|
||||
|
@ -516,16 +525,20 @@ impl Builder {
|
|||
}
|
||||
if let [import_edit] = &*self.imports_to_add {
|
||||
// snippets can have multiple imports, but normal completions only have up to one
|
||||
label_detail.replace(format_smolstr!(
|
||||
"{} (use {})",
|
||||
label_detail.as_deref().unwrap_or_default(),
|
||||
let detail_left = detail_left.get_or_insert_with(String::new);
|
||||
format_to!(
|
||||
detail_left,
|
||||
"{}(use {})",
|
||||
if detail_left.is_empty() { "" } else { " " },
|
||||
import_edit.import_path.display(db, self.edition)
|
||||
));
|
||||
);
|
||||
} else if let Some(trait_name) = self.trait_name {
|
||||
label_detail.replace(format_smolstr!(
|
||||
"{} (as {trait_name})",
|
||||
label_detail.as_deref().unwrap_or_default(),
|
||||
));
|
||||
let detail_left = detail_left.get_or_insert_with(String::new);
|
||||
format_to!(
|
||||
detail_left,
|
||||
"{}(as {trait_name})",
|
||||
if detail_left.is_empty() { "" } else { " " },
|
||||
);
|
||||
}
|
||||
|
||||
let text_edit = match self.text_edit {
|
||||
|
@ -546,8 +559,11 @@ impl Builder {
|
|||
|
||||
CompletionItem {
|
||||
source_range: self.source_range,
|
||||
label,
|
||||
label_detail,
|
||||
label: CompletionItemLabel {
|
||||
primary: label,
|
||||
detail_left,
|
||||
detail_right: self.detail.clone(),
|
||||
},
|
||||
text_edit,
|
||||
is_snippet: self.is_snippet,
|
||||
detail: self.detail,
|
||||
|
|
|
@ -748,9 +748,9 @@ mod tests {
|
|||
let tag = it.kind.tag();
|
||||
let relevance = display_relevance(it.relevance);
|
||||
items.push(format!(
|
||||
"{tag} {}{} {relevance}\n",
|
||||
it.label,
|
||||
it.label_detail.clone().unwrap_or_default(),
|
||||
"{tag} {} {} {relevance}\n",
|
||||
it.label.primary,
|
||||
it.label.detail_right.clone().unwrap_or_default(),
|
||||
));
|
||||
|
||||
if let Some((label, _indel, relevance)) = it.ref_match() {
|
||||
|
@ -812,13 +812,13 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st dep::test_mod_b::Struct {…} [type_could_unify]
|
||||
ex dep::test_mod_b::Struct { } [type_could_unify]
|
||||
st Struct (use dep::test_mod_b::Struct) [type_could_unify+requires_import]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
st Struct (use dep::test_mod_a::Struct) [requires_import]
|
||||
st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type_could_unify]
|
||||
ex dep::test_mod_b::Struct { } [type_could_unify]
|
||||
st Struct Struct [type_could_unify+requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(Struct) []
|
||||
md dep []
|
||||
st Struct Struct [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -852,11 +852,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
un Union (use dep::test_mod_b::Union) [type_could_unify+requires_import]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
en Union (use dep::test_mod_a::Union) [requires_import]
|
||||
un Union Union [type_could_unify+requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(Union) []
|
||||
md dep []
|
||||
en Union Union [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -888,13 +888,13 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev dep::test_mod_b::Enum::variant [type_could_unify]
|
||||
ex dep::test_mod_b::Enum::variant [type_could_unify]
|
||||
en Enum (use dep::test_mod_b::Enum) [type_could_unify+requires_import]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
en Enum (use dep::test_mod_a::Enum) [requires_import]
|
||||
ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify]
|
||||
ex dep::test_mod_b::Enum::variant [type_could_unify]
|
||||
en Enum Enum [type_could_unify+requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(Enum) []
|
||||
md dep []
|
||||
en Enum Enum [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -926,11 +926,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev dep::test_mod_b::Enum::Variant [type_could_unify]
|
||||
ex dep::test_mod_b::Enum::Variant [type_could_unify]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify]
|
||||
ex dep::test_mod_b::Enum::Variant [type_could_unify]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(Enum) []
|
||||
md dep []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -958,11 +958,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
fn function (use dep::test_mod_a::function) [requires_import]
|
||||
fn function(…) (use dep::test_mod_b::function) [requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(fn(usize) -> i32) []
|
||||
md dep []
|
||||
fn function fn(usize) -> i32 [requires_import]
|
||||
fn function(…) fn(isize) -> i32 [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -990,11 +990,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST (use dep::test_mod_b::CONST) [type_could_unify+requires_import]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
ct CONST (use dep::test_mod_a::CONST) [requires_import]
|
||||
ct CONST i32 [type_could_unify+requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(i32) []
|
||||
md dep []
|
||||
ct CONST i64 [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1022,11 +1022,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sc STATIC (use dep::test_mod_b::STATIC) [type_could_unify+requires_import]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
md dep []
|
||||
sc STATIC (use dep::test_mod_a::STATIC) [requires_import]
|
||||
sc STATIC i32 [type_could_unify+requires_import]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(i32) []
|
||||
md dep []
|
||||
sc STATIC i64 [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ fn main() {
|
|||
|
||||
"#,
|
||||
expect![[r#"
|
||||
me Function []
|
||||
me Function fn(&self, i32) -> bool []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1081,14 +1081,14 @@ fn func(input: Struct) { }
|
|||
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Struct [type]
|
||||
st Self [type]
|
||||
sp Self [type]
|
||||
st Struct [type]
|
||||
ex Struct [type]
|
||||
lc self [local]
|
||||
fn func(…) []
|
||||
me self.test() []
|
||||
st Struct Struct [type]
|
||||
st Self Self [type]
|
||||
sp Self Struct [type]
|
||||
st Struct Struct [type]
|
||||
ex Struct [type]
|
||||
lc self &Struct [local]
|
||||
fn func(…) fn(Struct) []
|
||||
me self.test() fn(&self) []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1109,13 +1109,13 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc input [type+name+local]
|
||||
ex input [type]
|
||||
ex true [type]
|
||||
ex false [type]
|
||||
lc inputbad [local]
|
||||
fn main() []
|
||||
fn test(…) []
|
||||
lc input bool [type+name+local]
|
||||
ex input [type]
|
||||
ex true [type]
|
||||
ex false [type]
|
||||
lc inputbad i32 [local]
|
||||
fn main() fn() []
|
||||
fn test(…) fn(bool) []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1133,6 +1133,10 @@ fn main() { Foo::Fo$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "Foo {…}",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"Foo { x: i32, y: i32 }",
|
||||
),
|
||||
source_range: 54..56,
|
||||
delete: 54..56,
|
||||
insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
|
||||
|
@ -1161,6 +1165,10 @@ fn main() { Foo::Fo$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "Foo(…)",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"Foo(i32, i32)",
|
||||
),
|
||||
source_range: 46..48,
|
||||
delete: 46..48,
|
||||
insert: "Foo(${1:()}, ${2:()})$0",
|
||||
|
@ -1189,6 +1197,10 @@ fn main() { fo$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "foo(…)",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn(u32, u32, T) -> (u32, T)",
|
||||
),
|
||||
source_range: 68..70,
|
||||
delete: 68..70,
|
||||
insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
|
||||
|
@ -1201,6 +1213,10 @@ fn main() { fo$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "main()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 68..70,
|
||||
delete: 68..70,
|
||||
insert: "main();$0",
|
||||
|
@ -1228,6 +1244,10 @@ fn main() { Foo::Fo$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "Foo",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"Foo",
|
||||
),
|
||||
source_range: 35..37,
|
||||
delete: 35..37,
|
||||
insert: "Foo$0",
|
||||
|
@ -1260,6 +1280,10 @@ fn main() { let _: m::Spam = S$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "main()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 75..76,
|
||||
delete: 75..76,
|
||||
insert: "main();$0",
|
||||
|
@ -1271,6 +1295,8 @@ fn main() { let _: m::Spam = S$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "m",
|
||||
detail_left: None,
|
||||
detail_right: None,
|
||||
source_range: 75..76,
|
||||
delete: 75..76,
|
||||
insert: "m",
|
||||
|
@ -1280,6 +1306,10 @@ fn main() { let _: m::Spam = S$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "m::Spam::Bar(…)",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"m::Spam::Bar(i32)",
|
||||
),
|
||||
source_range: 75..76,
|
||||
delete: 75..76,
|
||||
insert: "m::Spam::Bar(${1:()})$0",
|
||||
|
@ -1305,6 +1335,10 @@ fn main() { let _: m::Spam = S$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "m::Spam::Foo",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"m::Spam::Foo",
|
||||
),
|
||||
source_range: 75..76,
|
||||
delete: 75..76,
|
||||
insert: "m::Spam::Foo$0",
|
||||
|
@ -1347,6 +1381,10 @@ fn main() { som$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "main()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 56..59,
|
||||
delete: 56..59,
|
||||
insert: "main();$0",
|
||||
|
@ -1358,6 +1396,10 @@ fn main() { som$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "something_deprecated()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 56..59,
|
||||
delete: 56..59,
|
||||
insert: "something_deprecated();$0",
|
||||
|
@ -1382,6 +1424,10 @@ fn foo() { A { the$0 } }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "the_field",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"u32",
|
||||
),
|
||||
source_range: 57..60,
|
||||
delete: 57..60,
|
||||
insert: "the_field",
|
||||
|
@ -1429,6 +1475,10 @@ impl S {
|
|||
[
|
||||
CompletionItem {
|
||||
label: "bar()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn(self)",
|
||||
),
|
||||
source_range: 94..94,
|
||||
delete: 94..94,
|
||||
insert: "bar();$0",
|
||||
|
@ -1460,6 +1510,10 @@ impl S {
|
|||
},
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"{unknown}",
|
||||
),
|
||||
source_range: 94..94,
|
||||
delete: 94..94,
|
||||
insert: "foo",
|
||||
|
@ -1498,6 +1552,8 @@ use self::E::*;
|
|||
[
|
||||
CompletionItem {
|
||||
label: "my",
|
||||
detail_left: None,
|
||||
detail_right: None,
|
||||
source_range: 10..12,
|
||||
delete: 10..12,
|
||||
insert: "my",
|
||||
|
@ -1510,6 +1566,10 @@ use self::E::*;
|
|||
},
|
||||
CompletionItem {
|
||||
label: "V",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"V",
|
||||
),
|
||||
source_range: 10..12,
|
||||
delete: 10..12,
|
||||
insert: "V$0",
|
||||
|
@ -1524,6 +1584,10 @@ use self::E::*;
|
|||
},
|
||||
CompletionItem {
|
||||
label: "E",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"E",
|
||||
),
|
||||
source_range: 10..12,
|
||||
delete: 10..12,
|
||||
insert: "E",
|
||||
|
@ -1556,6 +1620,10 @@ fn foo(s: S) { s.$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "the_method()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn(&self)",
|
||||
),
|
||||
source_range: 81..81,
|
||||
delete: 81..81,
|
||||
insert: "the_method();$0",
|
||||
|
@ -1729,9 +1797,9 @@ fn test(bar: u32) { }
|
|||
fn foo(s: S) { test(s.$0) }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd bar [type+name]
|
||||
fd baz [type]
|
||||
fd foo []
|
||||
fd bar u32 [type+name]
|
||||
fd baz u32 [type]
|
||||
fd foo i64 []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1745,9 +1813,9 @@ struct B { x: (), y: f32, bar: u32 }
|
|||
fn foo(a: A) { B { bar: a.$0 }; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd bar [type+name]
|
||||
fd baz [type]
|
||||
fd foo []
|
||||
fd bar u32 [type+name]
|
||||
fd baz u32 [type]
|
||||
fd foo i64 []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -1768,6 +1836,10 @@ fn f() -> i32 {
|
|||
[
|
||||
CompletionItem {
|
||||
label: "0",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"i32",
|
||||
),
|
||||
source_range: 56..57,
|
||||
delete: 56..57,
|
||||
insert: "0",
|
||||
|
@ -1804,9 +1876,9 @@ fn f(foo: i64) { }
|
|||
fn foo(a: A) { B { bar: f(a.$0) }; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd foo [type+name]
|
||||
fd bar []
|
||||
fd baz []
|
||||
fd foo i64 [type+name]
|
||||
fd bar u32 []
|
||||
fd baz u32 []
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -1817,9 +1889,9 @@ fn f(foo: i64) { }
|
|||
fn foo(a: A) { f(B { bar: a.$0 }); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd bar [type+name]
|
||||
fd baz [type]
|
||||
fd foo []
|
||||
fd bar u32 [type+name]
|
||||
fd baz u32 [type]
|
||||
fd foo i64 []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1832,13 +1904,13 @@ struct WorldSnapshot { _f: () };
|
|||
fn go(world: &WorldSnapshot) { go(w$0) }
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc world [type+name+local]
|
||||
ex world [type]
|
||||
st WorldSnapshot {…} []
|
||||
lc world &WorldSnapshot [type+name+local]
|
||||
ex world [type]
|
||||
st WorldSnapshot {…} WorldSnapshot { _f: () } []
|
||||
st &WorldSnapshot {…} [type]
|
||||
st WorldSnapshot []
|
||||
st WorldSnapshot WorldSnapshot []
|
||||
st &WorldSnapshot [type]
|
||||
fn go(…) []
|
||||
fn go(…) fn(&WorldSnapshot) []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1852,9 +1924,9 @@ struct Foo;
|
|||
fn f(foo: &Foo) { f(foo, w$0) }
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc foo [local]
|
||||
st Foo []
|
||||
fn f(…) []
|
||||
lc foo &Foo [local]
|
||||
st Foo Foo []
|
||||
fn f(…) fn(&Foo) []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1869,12 +1941,12 @@ fn bar() -> u8 { 0 }
|
|||
fn f() { A { bar: b$0 }; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar() [type+name]
|
||||
fn baz() [type]
|
||||
ex bar() [type]
|
||||
ex baz() [type]
|
||||
st A []
|
||||
fn f() []
|
||||
fn bar() fn() -> u8 [type+name]
|
||||
fn baz() fn() -> u8 [type]
|
||||
ex bar() [type]
|
||||
ex baz() [type]
|
||||
st A A []
|
||||
fn f() fn() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1895,9 +1967,9 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me aaa() [type+name]
|
||||
me bbb() [type]
|
||||
me ccc() []
|
||||
me aaa() fn(&self) -> u32 [type+name]
|
||||
me bbb() fn(&self) -> u32 [type]
|
||||
me ccc() fn(&self) -> u64 []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1916,7 +1988,7 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me aaa() [name]
|
||||
me aaa() fn(&self) -> u64 [name]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1934,14 +2006,14 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc s [name+local]
|
||||
lc s S [name+local]
|
||||
lc &mut s [type+name+local]
|
||||
st S []
|
||||
st S S []
|
||||
st &mut S [type]
|
||||
st S []
|
||||
st S S []
|
||||
st &mut S [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
fn foo(…) fn(&mut S) []
|
||||
fn main() fn() []
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -1954,13 +2026,13 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc s [type+name+local]
|
||||
st S [type]
|
||||
st S [type]
|
||||
ex s [type]
|
||||
ex S [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
lc s S [type+name+local]
|
||||
st S S [type]
|
||||
st S S [type]
|
||||
ex s [type]
|
||||
ex S [type]
|
||||
fn foo(…) fn(&mut S) []
|
||||
fn main() fn() []
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -1973,13 +2045,13 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc ssss [type+local]
|
||||
st S [type]
|
||||
st S [type]
|
||||
ex ssss [type]
|
||||
ex S [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
lc ssss S [type+local]
|
||||
st S S [type]
|
||||
st S S [type]
|
||||
ex ssss [type]
|
||||
ex S [type]
|
||||
fn foo(…) fn(&mut S) []
|
||||
fn main() fn() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2010,19 +2082,19 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
|
||||
lc m [local]
|
||||
lc t [local]
|
||||
ex core::ops::Deref::deref(&t) [type_could_unify]
|
||||
lc m i32 [local]
|
||||
lc t T [local]
|
||||
lc &t [type+local]
|
||||
st S []
|
||||
st S S []
|
||||
st &S [type]
|
||||
st S []
|
||||
st S S []
|
||||
st &S [type]
|
||||
st T []
|
||||
st T T []
|
||||
st &T [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
fn foo(…) fn(&S) []
|
||||
fn main() fn() []
|
||||
md core []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -2059,19 +2131,19 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
|
||||
lc m [local]
|
||||
lc t [local]
|
||||
ex core::ops::DerefMut::deref_mut(&mut t) [type_could_unify]
|
||||
lc m i32 [local]
|
||||
lc t T [local]
|
||||
lc &mut t [type+local]
|
||||
st S []
|
||||
st S S []
|
||||
st &mut S [type]
|
||||
st S []
|
||||
st S S []
|
||||
st &mut S [type]
|
||||
st T []
|
||||
st T T []
|
||||
st &mut T [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
fn foo(…) fn(&mut S) []
|
||||
fn main() fn() []
|
||||
md core []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -2087,9 +2159,9 @@ fn foo(bar: u32) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc baz [local]
|
||||
lc bar [local]
|
||||
fn foo(…) []
|
||||
lc baz i32 [local]
|
||||
lc bar u32 [local]
|
||||
fn foo(…) fn(u32) []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2105,13 +2177,13 @@ fn foo() {
|
|||
fn bar(t: Foo) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Foo::A [type]
|
||||
ev Foo::B [type]
|
||||
en Foo [type]
|
||||
ex Foo::A [type]
|
||||
ex Foo::B [type]
|
||||
fn bar(…) []
|
||||
fn foo() []
|
||||
ev Foo::A Foo::A [type]
|
||||
ev Foo::B Foo::B [type]
|
||||
en Foo Foo [type]
|
||||
ex Foo::A [type]
|
||||
ex Foo::B [type]
|
||||
fn bar(…) fn(Foo) []
|
||||
fn foo() fn() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2127,14 +2199,14 @@ fn foo() {
|
|||
fn bar(t: &Foo) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Foo::A []
|
||||
ev Foo::A Foo::A []
|
||||
ev &Foo::A [type]
|
||||
ev Foo::B []
|
||||
ev Foo::B Foo::B []
|
||||
ev &Foo::B [type]
|
||||
en Foo []
|
||||
en Foo Foo []
|
||||
en &Foo [type]
|
||||
fn bar(…) []
|
||||
fn foo() []
|
||||
fn bar(…) fn(&Foo) []
|
||||
fn foo() fn() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2163,18 +2235,18 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify]
|
||||
st S []
|
||||
ex core::ops::Deref::deref(&bar()) [type_could_unify]
|
||||
st S S []
|
||||
st &S [type]
|
||||
st S []
|
||||
st S S []
|
||||
st &S [type]
|
||||
st T []
|
||||
st T T []
|
||||
st &T [type]
|
||||
fn bar() []
|
||||
fn bar() fn() -> T []
|
||||
fn &bar() [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
fn foo(…) fn(&S) []
|
||||
fn main() fn() []
|
||||
md core []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -2191,7 +2263,7 @@ impl Sub for u32 {}
|
|||
fn foo(a: u32) { a.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
me sub(…) (as Sub) [op_method]
|
||||
me sub(…) fn(self, Self) -> Self [op_method]
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -2212,9 +2284,9 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn new() []
|
||||
me eq(…) (as PartialEq) [op_method]
|
||||
me ne(…) (as PartialEq) [op_method]
|
||||
fn new() fn() -> Foo []
|
||||
me eq(…) fn(&self, &Rhs) -> bool [op_method]
|
||||
me ne(…) fn(&self, &Rhs) -> bool [op_method]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2238,9 +2310,9 @@ fn test() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn fn_ctr() [type_could_unify]
|
||||
fn fn_ctr_self() [type_could_unify]
|
||||
fn fn_another(…) [type_could_unify]
|
||||
fn fn_ctr() fn() -> Foo [type_could_unify]
|
||||
fn fn_ctr_self() fn() -> Option<Foo> [type_could_unify]
|
||||
fn fn_another(…) fn(u32) -> Other [type_could_unify]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2384,12 +2456,12 @@ fn test() {
|
|||
// Constructor
|
||||
// Others
|
||||
expect![[r#"
|
||||
fn fn_direct_ctr() [type_could_unify]
|
||||
fn fn_ctr_with_args(…) [type_could_unify]
|
||||
fn fn_builder() [type_could_unify]
|
||||
fn fn_ctr() [type_could_unify]
|
||||
me fn_no_ret(…) [type_could_unify]
|
||||
fn fn_other() [type_could_unify]
|
||||
fn fn_direct_ctr() fn() -> Foo [type_could_unify]
|
||||
fn fn_ctr_with_args(…) fn(u32) -> Foo [type_could_unify]
|
||||
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||
fn fn_ctr() fn() -> Result<Foo> [type_could_unify]
|
||||
me fn_no_ret(…) fn(&self) [type_could_unify]
|
||||
fn fn_other() fn() -> Result<u32> [type_could_unify]
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -2420,14 +2492,14 @@ fn test() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn fn_direct_ctr() [type_could_unify]
|
||||
fn fn_ctr_with_args(…) [type_could_unify]
|
||||
fn fn_builder() [type_could_unify]
|
||||
fn fn_ctr_wrapped() [type_could_unify]
|
||||
fn fn_ctr_wrapped_2() [type_could_unify]
|
||||
me fn_returns_unit(…) [type_could_unify]
|
||||
fn fn_other() [type_could_unify]
|
||||
"#]],
|
||||
fn fn_direct_ctr() fn() -> Foo<T> [type_could_unify]
|
||||
fn fn_ctr_with_args(…) fn(T) -> Foo<T> [type_could_unify]
|
||||
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||
fn fn_ctr_wrapped() fn() -> Option<Foo<T>> [type_could_unify]
|
||||
fn fn_ctr_wrapped_2() fn() -> Result<Foo<T>, u32> [type_could_unify]
|
||||
me fn_returns_unit(…) fn(&self) [type_could_unify]
|
||||
fn fn_other() fn() -> Option<u32> [type_could_unify]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2456,13 +2528,13 @@ fn test() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn fn_direct_ctr() [type_could_unify]
|
||||
fn fn_ctr_with_args(…) [type_could_unify]
|
||||
fn fn_builder() [type_could_unify]
|
||||
fn fn_ctr() [type_could_unify]
|
||||
fn fn_ctr2() [type_could_unify]
|
||||
me fn_no_ret(…) [type_could_unify]
|
||||
fn fn_other() [type_could_unify]
|
||||
fn fn_direct_ctr() fn() -> Foo<T> [type_could_unify]
|
||||
fn fn_ctr_with_args(…) fn(T) -> Foo<T> [type_could_unify]
|
||||
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||
fn fn_ctr() fn() -> Option<Foo<T>> [type_could_unify]
|
||||
fn fn_ctr2() fn() -> Result<Foo<T>, u32> [type_could_unify]
|
||||
me fn_no_ret(…) fn(&self) [type_could_unify]
|
||||
fn fn_other() fn() -> Option<u32> [type_could_unify]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2484,6 +2556,10 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
|
|||
[
|
||||
CompletionItem {
|
||||
label: "baz()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn(&self) -> u32",
|
||||
),
|
||||
source_range: 109..110,
|
||||
delete: 109..110,
|
||||
insert: "baz()$0",
|
||||
|
@ -2513,6 +2589,10 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "bar",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"u32",
|
||||
),
|
||||
source_range: 109..110,
|
||||
delete: 109..110,
|
||||
insert: "bar",
|
||||
|
@ -2524,6 +2604,10 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
|
|||
},
|
||||
CompletionItem {
|
||||
label: "qux",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 109..110,
|
||||
text_edit: TextEdit {
|
||||
indels: [
|
||||
|
@ -2562,6 +2646,10 @@ fn foo() {
|
|||
[
|
||||
CompletionItem {
|
||||
label: "field",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn()",
|
||||
),
|
||||
source_range: 76..78,
|
||||
delete: 76..78,
|
||||
insert: "field",
|
||||
|
@ -2610,6 +2698,10 @@ fn main() {
|
|||
[
|
||||
CompletionItem {
|
||||
label: "foo()",
|
||||
detail_left: None,
|
||||
detail_right: Some(
|
||||
"fn() -> S",
|
||||
),
|
||||
source_range: 95..95,
|
||||
delete: 95..95,
|
||||
insert: "foo()$0",
|
||||
|
@ -2661,15 +2753,15 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc foo [type+local]
|
||||
ex foo [type]
|
||||
ex Foo::B [type]
|
||||
ev Foo::A(…) [type_could_unify]
|
||||
ev Foo::B [type_could_unify]
|
||||
en Foo [type_could_unify]
|
||||
fn foo() []
|
||||
fn bar() []
|
||||
fn baz() []
|
||||
lc foo Foo<u32> [type+local]
|
||||
ex foo [type]
|
||||
ex Foo::B [type]
|
||||
ev Foo::A(…) Foo::A(T) [type_could_unify]
|
||||
ev Foo::B Foo::B [type_could_unify]
|
||||
en Foo Foo<{unknown}> [type_could_unify]
|
||||
fn foo() fn() []
|
||||
fn bar() fn() -> Foo<u8> []
|
||||
fn baz() fn() -> Foo<T> []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2697,20 +2789,20 @@ fn main() {
|
|||
"#,
|
||||
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
||||
expect![[r#"
|
||||
sn not [snippet]
|
||||
me not() (use ops::Not) [type_could_unify+requires_import]
|
||||
sn if []
|
||||
sn while []
|
||||
sn ref []
|
||||
sn refm []
|
||||
sn deref []
|
||||
sn unsafe []
|
||||
sn match []
|
||||
sn box []
|
||||
sn dbg []
|
||||
sn dbgr []
|
||||
sn call []
|
||||
sn return []
|
||||
sn not !expr [snippet]
|
||||
me not() fn(self) -> <Self as Not>::Output [type_could_unify+requires_import]
|
||||
sn if if expr {} []
|
||||
sn while while expr {} []
|
||||
sn ref &expr []
|
||||
sn refm &mut expr []
|
||||
sn deref *expr []
|
||||
sn unsafe unsafe {} []
|
||||
sn match match expr {} []
|
||||
sn box Box::new(expr) []
|
||||
sn dbg dbg!(expr) []
|
||||
sn dbgr dbg!(&expr) []
|
||||
sn call function(expr) []
|
||||
sn return return expr []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2730,19 +2822,19 @@ fn main() {
|
|||
"#,
|
||||
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
||||
expect![[r#"
|
||||
me f() []
|
||||
sn ref []
|
||||
sn refm []
|
||||
sn deref []
|
||||
sn unsafe []
|
||||
sn match []
|
||||
sn box []
|
||||
sn dbg []
|
||||
sn dbgr []
|
||||
sn call []
|
||||
sn let []
|
||||
sn letm []
|
||||
sn return []
|
||||
me f() fn(&self) []
|
||||
sn ref &expr []
|
||||
sn refm &mut expr []
|
||||
sn deref *expr []
|
||||
sn unsafe unsafe {} []
|
||||
sn match match expr {} []
|
||||
sn box Box::new(expr) []
|
||||
sn dbg dbg!(expr) []
|
||||
sn dbgr dbg!(&expr) []
|
||||
sn call function(expr) []
|
||||
sn let let []
|
||||
sn letm let mut []
|
||||
sn return return expr []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2765,12 +2857,12 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Buffer []
|
||||
fn f() []
|
||||
md std []
|
||||
tt BufRead (use std::io::BufRead) [requires_import]
|
||||
st BufReader (use std::io::BufReader) [requires_import]
|
||||
st BufWriter (use std::io::BufWriter) [requires_import]
|
||||
st Buffer Buffer []
|
||||
fn f() fn() []
|
||||
md std []
|
||||
tt BufRead [requires_import]
|
||||
st BufReader BufReader [requires_import]
|
||||
st BufWriter BufWriter [requires_import]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2979,6 +3071,12 @@ fn main() {
|
|||
[
|
||||
CompletionItem {
|
||||
label: "flush()",
|
||||
detail_left: Some(
|
||||
"(as Write)",
|
||||
),
|
||||
detail_right: Some(
|
||||
"fn(&self)",
|
||||
),
|
||||
source_range: 193..193,
|
||||
delete: 193..193,
|
||||
insert: "flush();$0",
|
||||
|
@ -3006,6 +3104,12 @@ fn main() {
|
|||
},
|
||||
CompletionItem {
|
||||
label: "write()",
|
||||
detail_left: Some(
|
||||
"(as Write)",
|
||||
),
|
||||
detail_right: Some(
|
||||
"fn(&self)",
|
||||
),
|
||||
source_range: 193..193,
|
||||
delete: 193..193,
|
||||
insert: "write();$0",
|
||||
|
|
|
@ -118,10 +118,16 @@ fn completion_list_with_config_raw(
|
|||
let items = get_all_items(config, ra_fixture, trigger_character);
|
||||
items
|
||||
.into_iter()
|
||||
.filter(|it| it.kind != CompletionItemKind::BuiltinType || it.label == "u32")
|
||||
.filter(|it| it.kind != CompletionItemKind::BuiltinType || it.label.primary == "u32")
|
||||
.filter(|it| include_keywords || it.kind != CompletionItemKind::Keyword)
|
||||
.filter(|it| include_keywords || it.kind != CompletionItemKind::Snippet)
|
||||
.sorted_by_key(|it| (it.kind, it.label.clone(), it.detail.as_ref().map(ToOwned::to_owned)))
|
||||
.sorted_by_key(|it| {
|
||||
(
|
||||
it.kind,
|
||||
it.label.primary.clone(),
|
||||
it.label.detail_left.as_ref().map(ToOwned::to_owned),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -173,27 +179,30 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
|
|||
let label_width = completions
|
||||
.iter()
|
||||
.map(|it| {
|
||||
monospace_width(&it.label)
|
||||
+ monospace_width(it.label_detail.as_deref().unwrap_or_default())
|
||||
monospace_width(&it.label.primary)
|
||||
+ monospace_width(it.label.detail_left.as_deref().unwrap_or_default())
|
||||
+ monospace_width(it.label.detail_right.as_deref().unwrap_or_default())
|
||||
+ it.label.detail_left.is_some() as usize
|
||||
+ it.label.detail_right.is_some() as usize
|
||||
})
|
||||
.max()
|
||||
.unwrap_or_default()
|
||||
.min(22);
|
||||
.unwrap_or_default();
|
||||
completions
|
||||
.into_iter()
|
||||
.map(|it| {
|
||||
let tag = it.kind.tag();
|
||||
let var_name = format!("{tag} {}", it.label);
|
||||
let mut buf = var_name;
|
||||
if let Some(ref label_detail) = it.label_detail {
|
||||
format_to!(buf, "{label_detail}");
|
||||
let mut buf = format!("{tag} {}", it.label.primary);
|
||||
if let Some(label_detail) = &it.label.detail_left {
|
||||
format_to!(buf, " {label_detail}");
|
||||
}
|
||||
if let Some(detail) = it.detail {
|
||||
let width = label_width.saturating_sub(
|
||||
monospace_width(&it.label)
|
||||
+ monospace_width(&it.label_detail.unwrap_or_default()),
|
||||
if let Some(detail_right) = it.label.detail_right {
|
||||
let pad_with = label_width.saturating_sub(
|
||||
monospace_width(&it.label.primary)
|
||||
+ monospace_width(it.label.detail_left.as_deref().unwrap_or_default())
|
||||
+ monospace_width(&detail_right)
|
||||
+ it.label.detail_left.is_some() as usize,
|
||||
);
|
||||
format_to!(buf, "{:width$} {}", "", detail, width = width);
|
||||
format_to!(buf, "{:pad_with$}{detail_right}", "",);
|
||||
}
|
||||
if it.deprecated {
|
||||
format_to!(buf, " DEPRECATED");
|
||||
|
|
|
@ -33,7 +33,7 @@ pub struct Foo(#[m$0] i32);
|
|||
at cold
|
||||
at deny(…)
|
||||
at deprecated
|
||||
at derive macro derive
|
||||
at derive macro derive
|
||||
at derive(…)
|
||||
at doc = "…"
|
||||
at doc(alias = "…")
|
||||
|
@ -367,9 +367,9 @@ struct Foo;
|
|||
at cfg_attr(…)
|
||||
at deny(…)
|
||||
at deprecated
|
||||
at derive macro derive
|
||||
at derive macro derive
|
||||
at derive(…)
|
||||
at derive_const macro derive_const
|
||||
at derive_const macro derive_const
|
||||
at doc = "…"
|
||||
at doc(alias = "…")
|
||||
at doc(hidden)
|
||||
|
@ -790,10 +790,10 @@ mod derive {
|
|||
#[derive($0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Clone macro Clone
|
||||
de Clone macro Clone
|
||||
de Clone, Copy
|
||||
de Default macro Default
|
||||
de PartialEq macro PartialEq
|
||||
de Default macro Default
|
||||
de PartialEq macro PartialEq
|
||||
de PartialEq, Eq
|
||||
de PartialEq, Eq, PartialOrd, Ord
|
||||
de PartialEq, PartialOrd
|
||||
|
@ -812,9 +812,9 @@ mod derive {
|
|||
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Clone macro Clone
|
||||
de Clone macro Clone
|
||||
de Clone, Copy
|
||||
de Default macro Default
|
||||
de Default macro Default
|
||||
de Eq
|
||||
de Eq, PartialOrd, Ord
|
||||
de PartialOrd
|
||||
|
@ -833,9 +833,9 @@ mod derive {
|
|||
#[derive($0 serde::Serialize, PartialEq)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Clone macro Clone
|
||||
de Clone macro Clone
|
||||
de Clone, Copy
|
||||
de Default macro Default
|
||||
de Default macro Default
|
||||
de Eq
|
||||
de Eq, PartialOrd, Ord
|
||||
de PartialOrd
|
||||
|
@ -854,9 +854,9 @@ mod derive {
|
|||
#[derive(PartialEq, Eq, Or$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Clone macro Clone
|
||||
de Clone macro Clone
|
||||
de Clone, Copy
|
||||
de Default macro Default
|
||||
de Default macro Default
|
||||
de PartialOrd
|
||||
de PartialOrd, Ord
|
||||
md core
|
||||
|
|
|
@ -26,22 +26,22 @@ fn baz() {
|
|||
"#,
|
||||
// This should not contain `FooDesc {…}`.
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
en Enum Enum
|
||||
fn baz() fn()
|
||||
fn create_foo(…) fn(&FooDesc)
|
||||
fn function() fn()
|
||||
ma makro!(…) macro_rules! makro
|
||||
ct CONST Unit
|
||||
en Enum Enum
|
||||
fn baz() fn()
|
||||
fn create_foo(…) fn(&FooDesc)
|
||||
fn function() fn()
|
||||
ma makro!(…) macro_rules! makro
|
||||
md _69latrick
|
||||
md module
|
||||
sc STATIC Unit
|
||||
st FooDesc FooDesc
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32 u32
|
||||
sc STATIC Unit
|
||||
st FooDesc FooDesc
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -76,14 +76,14 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn func(…) fn((i32, i32))
|
||||
lc ifletlocal i32
|
||||
lc letlocal i32
|
||||
lc matcharm i32
|
||||
lc param0 (i32, i32)
|
||||
lc param1 i32
|
||||
lc param2 i32
|
||||
bt u32 u32
|
||||
fn func(…) fn((i32, i32))
|
||||
lc ifletlocal i32
|
||||
lc letlocal i32
|
||||
lc matcharm i32
|
||||
lc param0 (i32, i32)
|
||||
lc param1 i32
|
||||
lc param2 i32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -122,25 +122,25 @@ impl Unit {
|
|||
"#,
|
||||
// `self` is in here twice, once as the module, once as the local
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct CONST Unit
|
||||
cp CONST_PARAM
|
||||
en Enum Enum
|
||||
fn function() fn()
|
||||
fn local_func() fn()
|
||||
me self.foo() fn(self)
|
||||
lc self Unit
|
||||
ma makro!(…) macro_rules! makro
|
||||
en Enum Enum
|
||||
fn function() fn()
|
||||
fn local_func() fn()
|
||||
me self.foo() fn(self)
|
||||
lc self Unit
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
md qualified
|
||||
sp Self Unit
|
||||
sc STATIC Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self Unit
|
||||
sc STATIC Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tp TypeParam
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -187,19 +187,19 @@ impl Unit {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
en Enum Enum
|
||||
fn function() fn()
|
||||
ma makro!(…) macro_rules! makro
|
||||
ct CONST Unit
|
||||
en Enum Enum
|
||||
fn function() fn()
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
md qualified
|
||||
sc STATIC Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sc STATIC Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
?? Unresolved
|
||||
"#]],
|
||||
);
|
||||
|
@ -216,8 +216,8 @@ fn complete_in_block() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -264,8 +264,8 @@ fn complete_after_if_expr() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -313,8 +313,8 @@ fn complete_in_match_arm() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -337,8 +337,8 @@ fn completes_in_loop_ctx() {
|
|||
check_empty(
|
||||
r"fn my() { loop { $0 } }",
|
||||
expect![[r#"
|
||||
fn my() fn()
|
||||
bt u32 u32
|
||||
fn my() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw break
|
||||
kw const
|
||||
|
@ -376,22 +376,22 @@ fn completes_in_loop_ctx() {
|
|||
check_empty(
|
||||
r"fn my() { loop { foo.$0 } }",
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn break break expr
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
sn box Box::new(expr)
|
||||
sn break break expr
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -401,8 +401,8 @@ fn completes_in_let_initializer() {
|
|||
check_empty(
|
||||
r#"fn main() { let _ = $0 }"#,
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
bt u32 u32
|
||||
fn main() fn()
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -434,9 +434,9 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -469,9 +469,9 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
lc bar i32
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
lc bar i32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -499,10 +499,10 @@ fn quux(x: i32) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -526,10 +526,10 @@ fn quux(x: i32) {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -554,11 +554,11 @@ fn quux(x: i32) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
lc y i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
fn quux(…) fn(i32)
|
||||
lc x i32
|
||||
lc y i32
|
||||
ma m!(…) macro_rules! m
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -590,12 +590,12 @@ fn func() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||
fn assoc_fn() fn()
|
||||
ta AssocType type AssocType = ()
|
||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||
fn assoc_fn() fn()
|
||||
ta AssocType type AssocType = ()
|
||||
ev RecordV {…} RecordV { field: u32 }
|
||||
ev TupleV(…) TupleV(u32)
|
||||
ev UnitV UnitV
|
||||
ev TupleV(…) TupleV(u32)
|
||||
ev UnitV UnitV
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -633,7 +633,7 @@ fn func() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
fn variant fn() -> Enum
|
||||
ev Variant Variant
|
||||
ev Variant Variant
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -650,8 +650,8 @@ fn main() {
|
|||
}
|
||||
",
|
||||
expect![[r#"
|
||||
fn foo() fn() -> impl Trait<U>
|
||||
fn main() fn()
|
||||
fn foo() fn() -> impl Trait<U>
|
||||
fn main() fn()
|
||||
tt Trait
|
||||
"#]],
|
||||
);
|
||||
|
@ -670,9 +670,9 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar() async fn() -> impl Trait<U>
|
||||
fn foo() async fn() -> u8
|
||||
fn main() fn()
|
||||
fn bar() async fn() -> impl Trait<U>
|
||||
fn foo() async fn() -> u8
|
||||
fn main() fn()
|
||||
tt Trait
|
||||
"#]],
|
||||
);
|
||||
|
@ -692,9 +692,9 @@ fn main() {
|
|||
Foo::$0
|
||||
}
|
||||
",
|
||||
expect![[r"
|
||||
expect![[r#"
|
||||
fn bar(…) fn(impl Trait<U>)
|
||||
"]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -712,7 +712,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn test() fn() -> Zulu
|
||||
fn test() fn() -> Zulu
|
||||
ex Zulu
|
||||
ex Zulu::test()
|
||||
"#]],
|
||||
|
@ -736,11 +736,11 @@ fn brr() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en HH HH
|
||||
fn brr() fn()
|
||||
st YoloVariant YoloVariant
|
||||
en HH HH
|
||||
fn brr() fn()
|
||||
st YoloVariant YoloVariant
|
||||
st YoloVariant {…} YoloVariant { f: usize }
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -801,8 +801,8 @@ fn else_completion_after_if() {
|
|||
fn foo() { if foo {} $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -842,8 +842,8 @@ fn foo() { if foo {} $0 }
|
|||
fn foo() { if foo {} el$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -883,8 +883,8 @@ fn foo() { if foo {} el$0 }
|
|||
fn foo() { bar(if foo {} $0) }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw else
|
||||
kw else if
|
||||
|
@ -907,8 +907,8 @@ fn foo() { bar(if foo {} $0) }
|
|||
fn foo() { bar(if foo {} el$0) }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw else
|
||||
kw else if
|
||||
|
@ -931,8 +931,8 @@ fn foo() { bar(if foo {} el$0) }
|
|||
fn foo() { if foo {} $0 let x = 92; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -972,8 +972,8 @@ fn foo() { if foo {} $0 let x = 92; }
|
|||
fn foo() { if foo {} el$0 let x = 92; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1013,8 +1013,8 @@ fn foo() { if foo {} el$0 let x = 92; }
|
|||
fn foo() { if foo {} el$0 { let x = 92; } }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1065,9 +1065,9 @@ fn main() {
|
|||
pub struct UnstableThisShouldNotBeListed;
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
fn main() fn()
|
||||
md std
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1117,10 +1117,10 @@ fn main() {
|
|||
pub struct UnstableButWeAreOnNightlyAnyway;
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
fn main() fn()
|
||||
md std
|
||||
st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1170,17 +1170,17 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
|
@ -1196,17 +1196,17 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1226,17 +1226,17 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
|
@ -1252,17 +1252,17 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
|
@ -1278,17 +1278,17 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
|
@ -1304,19 +1304,89 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn if if expr {}
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_that_ignores_completion_marker() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! helper {
|
||||
($v:ident) => {};
|
||||
}
|
||||
|
||||
macro_rules! m {
|
||||
($v:ident) => {{
|
||||
helper!($v);
|
||||
$v
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let variable = "test";
|
||||
m!(v$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
en Enum Enum
|
||||
fn function() fn()
|
||||
fn main() fn()
|
||||
lc variable &str
|
||||
ma helper!(…) macro_rules! helper
|
||||
ma m!(…) macro_rules! m
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sc STATIC Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
un Union Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
kw enum
|
||||
kw extern
|
||||
kw false
|
||||
kw fn
|
||||
kw for
|
||||
kw if
|
||||
kw if let
|
||||
kw impl
|
||||
kw let
|
||||
kw loop
|
||||
kw match
|
||||
kw mod
|
||||
kw self::
|
||||
kw static
|
||||
kw struct
|
||||
kw trait
|
||||
kw true
|
||||
kw type
|
||||
kw union
|
||||
kw unsafe
|
||||
kw use
|
||||
kw while
|
||||
kw while let
|
||||
sn macro_rules
|
||||
sn pd
|
||||
sn ppd
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -139,9 +139,9 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Rc (use dep::Rc) Rc
|
||||
st Rcar (use dep::Rcar) Rcar
|
||||
st Rc (use dep::some_module::Rc) Rc
|
||||
st Rc (use dep::Rc) Rc
|
||||
st Rcar (use dep::Rcar) Rcar
|
||||
st Rc (use dep::some_module::Rc) Rc
|
||||
st Rcar (use dep::some_module::Rcar) Rcar
|
||||
"#]],
|
||||
);
|
||||
|
@ -165,11 +165,11 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct RC (use dep::RC) ()
|
||||
st Rc (use dep::Rc) Rc
|
||||
st Rcar (use dep::Rcar) Rcar
|
||||
ct RC (use dep::some_module::RC) ()
|
||||
st Rc (use dep::some_module::Rc) Rc
|
||||
ct RC (use dep::RC) ()
|
||||
st Rc (use dep::Rc) Rc
|
||||
st Rcar (use dep::Rcar) Rcar
|
||||
ct RC (use dep::some_module::RC) ()
|
||||
st Rc (use dep::some_module::Rc) Rc
|
||||
st Rcar (use dep::some_module::Rcar) Rcar
|
||||
"#]],
|
||||
);
|
||||
|
@ -193,7 +193,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct RC (use dep::RC) ()
|
||||
ct RC (use dep::RC) ()
|
||||
ct RC (use dep::some_module::RC) ()
|
||||
"#]],
|
||||
);
|
||||
|
@ -227,7 +227,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st ThirdStruct (use dep::some_module::ThirdStruct) ThirdStruct
|
||||
st ThirdStruct (use dep::some_module::ThirdStruct) ThirdStruct
|
||||
st AfterThirdStruct (use dep::some_module::AfterThirdStruct) AfterThirdStruct
|
||||
st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) ThiiiiiirdStruct
|
||||
"#]],
|
||||
|
@ -263,8 +263,8 @@ fn trait_function_fuzzy_completion() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn()
|
||||
"#]],
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn()
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -356,8 +356,8 @@ fn trait_method_fuzzy_completion() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me random_method() (use dep::test_mod::TestTrait) fn(&self)
|
||||
"#]],
|
||||
me random_method() (use dep::test_mod::TestTrait) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -401,8 +401,8 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me some_method() (use foo::TestTrait) fn(&self)
|
||||
"#]],
|
||||
me some_method() (use foo::TestTrait) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -448,8 +448,8 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me some_method() (use foo::TestTrait) fn(&self)
|
||||
"#]],
|
||||
me some_method() (use foo::TestTrait) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -496,8 +496,8 @@ fn completion<T: Wrapper>(whatever: T) {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me not_in_scope() (use foo::NotInScope) fn(&self)
|
||||
"#]],
|
||||
me not_in_scope() (use foo::NotInScope) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -539,8 +539,8 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me into() (use test_trait::TestInto) fn(self) -> T
|
||||
"#]],
|
||||
me into() (use test_trait::TestInto) fn(self) -> T
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -568,8 +568,8 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
fn random_method() (use dep::test_mod::TestTrait) fn()
|
||||
"#]],
|
||||
fn random_method() (use dep::test_mod::TestTrait) fn()
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_edit(
|
||||
|
@ -737,8 +737,8 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||
"#]],
|
||||
me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
|
@ -767,8 +767,8 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
|
@ -1117,7 +1117,7 @@ fn main() {
|
|||
tes$0
|
||||
}"#,
|
||||
expect![[r#"
|
||||
ct TEST_CONST (use foo::TEST_CONST) usize
|
||||
ct TEST_CONST (use foo::TEST_CONST) usize
|
||||
fn test_function() (use foo::test_function) fn() -> i32
|
||||
"#]],
|
||||
);
|
||||
|
@ -1175,8 +1175,8 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn some_fn() (use m::some_fn) fn() -> i32
|
||||
"#]],
|
||||
fn some_fn() (use m::some_fn) fn() -> i32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1691,7 +1691,7 @@ fn function() {
|
|||
expect![[r#"
|
||||
st FooStruct (use outer::FooStruct) BarStruct
|
||||
md foo (use outer::foo)
|
||||
fn foo_fun() (use outer::foo_fun) fn()
|
||||
fn foo_fun() (use outer::foo_fun) fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1720,3 +1720,45 @@ fn function() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intrinsics() {
|
||||
check(
|
||||
r#"
|
||||
//- /core.rs crate:core
|
||||
pub mod intrinsics {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn transmute<Src, Dst>(src: Src) -> Dst;
|
||||
}
|
||||
}
|
||||
pub mod mem {
|
||||
pub use crate::intrinsics::transmute;
|
||||
}
|
||||
//- /main.rs crate:main deps:core
|
||||
fn function() {
|
||||
transmute$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn transmute(…) (use core::mem::transmute) unsafe fn(Src) -> Dst
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
//- /core.rs crate:core
|
||||
pub mod intrinsics {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn transmute<Src, Dst>(src: Src) -> Dst;
|
||||
}
|
||||
}
|
||||
pub mod mem {
|
||||
pub use crate::intrinsics::transmute;
|
||||
}
|
||||
//- /main.rs crate:main deps:core
|
||||
fn function() {
|
||||
mem::transmute$0
|
||||
}
|
||||
"#,
|
||||
expect![""],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ fn foo2($0) {}
|
|||
expect![[r#"
|
||||
st Bar
|
||||
bn Bar { bar }: Bar
|
||||
bn Bar {…} Bar { bar$1 }: Bar$0
|
||||
bn Bar {…} Bar { bar$1 }: Bar$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
|
|
@ -20,15 +20,15 @@ fn target_type_or_trait_in_impl_block() {
|
|||
impl Tra$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -42,15 +42,15 @@ fn target_type_in_trait_impl_block() {
|
|||
impl Trait for Str$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
|
|
@ -13,7 +13,7 @@ fn in_mod_item_list() {
|
|||
check(
|
||||
r#"mod tests { $0 }"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -46,7 +46,7 @@ fn in_source_file_item_list() {
|
|||
check(
|
||||
r#"$0"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw async
|
||||
kw const
|
||||
|
@ -79,7 +79,7 @@ fn in_item_list_after_attr() {
|
|||
check(
|
||||
r#"#[attr] $0"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw async
|
||||
kw const
|
||||
|
@ -182,7 +182,7 @@ fn in_impl_assoc_item_list() {
|
|||
check(
|
||||
r#"impl Struct { $0 }"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw async
|
||||
kw const
|
||||
|
@ -202,7 +202,7 @@ fn in_impl_assoc_item_list_after_attr() {
|
|||
check(
|
||||
r#"impl Struct { #[attr] $0 }"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw async
|
||||
kw const
|
||||
|
@ -315,7 +315,7 @@ impl Test for () {
|
|||
fn async fn function2()
|
||||
fn fn function1()
|
||||
fn fn function2()
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
ta type Type1 =
|
||||
kw crate::
|
||||
|
@ -381,7 +381,7 @@ fn after_unit_struct() {
|
|||
check(
|
||||
r#"struct S; f$0"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw async
|
||||
kw const
|
||||
|
@ -503,7 +503,7 @@ fn inside_extern_blocks() {
|
|||
check(
|
||||
r#"extern { $0 }"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw crate::
|
||||
kw fn
|
||||
|
@ -520,7 +520,7 @@ fn inside_extern_blocks() {
|
|||
check(
|
||||
r#"unsafe extern { $0 }"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
kw crate::
|
||||
kw fn
|
||||
|
|
|
@ -122,15 +122,15 @@ fn foo() {
|
|||
expect![[r#"
|
||||
ct CONST
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
ev TupleV
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -151,15 +151,15 @@ fn foo() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
en SingleVariantEnum
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
ev Variant
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn Variant Variant$0
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn Variant Variant$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -174,13 +174,13 @@ fn foo(a$0) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
bn Record {…} Record { field$1 }: Record$0
|
||||
bn Tuple(…) Tuple($1): Tuple$0
|
||||
bn Tuple(…) Tuple($1): Tuple$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -191,13 +191,13 @@ fn foo(a$0: Tuple) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn tuple
|
||||
kw mut
|
||||
kw ref
|
||||
|
@ -240,7 +240,7 @@ fn foo() {
|
|||
expect![[r#"
|
||||
en E
|
||||
ma m!(…) macro_rules! m
|
||||
bn E::X E::X$0
|
||||
bn E::X E::X$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -268,7 +268,7 @@ fn outer() {
|
|||
st Record
|
||||
st Tuple
|
||||
bn Record {…} Record { field$1, .. }$0
|
||||
bn Tuple(…) Tuple($1, ..)$0
|
||||
bn Tuple(…) Tuple($1, ..)$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -291,7 +291,7 @@ impl Foo {
|
|||
expect![[r#"
|
||||
sp Self
|
||||
st Foo
|
||||
bn Foo(…) Foo($1)$0
|
||||
bn Foo(…) Foo($1)$0
|
||||
bn Self(…) Self($1)$0
|
||||
kw mut
|
||||
kw ref
|
||||
|
@ -315,8 +315,8 @@ fn func() {
|
|||
expect![[r#"
|
||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||
bn RecordV {…} RecordV { field$1 }$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
bn UnitV UnitV$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
bn UnitV UnitV$0
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ fn outer(Foo { bar: $0 }: Foo) {}
|
|||
expect![[r#"
|
||||
st Bar
|
||||
st Foo
|
||||
bn Bar(…) Bar($1)$0
|
||||
bn Bar(…) Bar($1)$0
|
||||
bn Foo {…} Foo { bar$1 }$0
|
||||
kw mut
|
||||
kw ref
|
||||
|
@ -395,7 +395,7 @@ fn foo($0) {}
|
|||
expect![[r#"
|
||||
st Bar
|
||||
st Foo
|
||||
bn Bar(…) Bar($1): Bar$0
|
||||
bn Bar(…) Bar($1): Bar$0
|
||||
bn Foo {…} Foo { bar$1 }: Foo$0
|
||||
kw mut
|
||||
kw ref
|
||||
|
@ -416,7 +416,7 @@ fn foo() {
|
|||
expect![[r#"
|
||||
st Bar
|
||||
st Foo
|
||||
bn Bar(…) Bar($1)$0
|
||||
bn Bar(…) Bar($1)$0
|
||||
bn Foo {…} Foo { bar$1 }$0
|
||||
kw mut
|
||||
kw ref
|
||||
|
@ -436,7 +436,7 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Bar Bar
|
||||
st Bar Bar
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -451,7 +451,7 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Foo Foo
|
||||
st Foo Foo
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -535,10 +535,10 @@ fn foo() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
en Enum
|
||||
bn Enum::A Enum::A$0
|
||||
bn Enum::B {…} Enum::B { r#type$1 }$0
|
||||
bn Enum::A Enum::A$0
|
||||
bn Enum::B {…} Enum::B { r#type$1 }$0
|
||||
bn Enum::struct {…} Enum::r#struct { r#type$1 }$0
|
||||
bn Enum::type Enum::r#type$0
|
||||
bn Enum::type Enum::r#type$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -559,10 +559,10 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn A A$0
|
||||
bn B {…} B { r#type$1 }$0
|
||||
bn A A$0
|
||||
bn B {…} B { r#type$1 }$0
|
||||
bn struct {…} r#struct { r#type$1 }$0
|
||||
bn type r#type$0
|
||||
bn type r#type$0
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -672,8 +672,8 @@ impl Ty {
|
|||
st Ty
|
||||
bn &mut self
|
||||
bn &self
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn mut self
|
||||
bn self
|
||||
kw mut
|
||||
|
@ -693,8 +693,8 @@ impl Ty {
|
|||
st Ty
|
||||
bn &mut self
|
||||
bn &self
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn mut self
|
||||
bn self
|
||||
kw mut
|
||||
|
@ -714,8 +714,8 @@ impl Ty {
|
|||
st Ty
|
||||
bn &mut self
|
||||
bn &self
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn mut self
|
||||
bn self
|
||||
kw mut
|
||||
|
@ -734,7 +734,7 @@ impl Ty {
|
|||
sp Self
|
||||
st Ty
|
||||
bn Self(…) Self($1): Self$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
bn Ty(…) Ty($1): Ty$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -763,7 +763,7 @@ fn f(x: EnumAlias<u8>) {
|
|||
"#,
|
||||
expect![[r#"
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn Unit Unit$0
|
||||
bn Unit Unit$0
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,16 +16,16 @@ fn predicate_start() {
|
|||
struct Foo<'lt, T, const C: usize> where $0 {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -89,16 +89,16 @@ fn param_list_for_for_pred() {
|
|||
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -114,16 +114,16 @@ impl Record {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sp Self Record
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self Record
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
|
|
@ -24,19 +24,19 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -57,19 +57,19 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -92,19 +92,19 @@ impl Foo {
|
|||
fn main() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -127,19 +127,19 @@ impl Foo {
|
|||
fn main() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -70,8 +70,8 @@ fn foo(baz: Baz) {
|
|||
ev Ok
|
||||
bn Baz::Bar Baz::Bar$0
|
||||
bn Baz::Foo Baz::Foo$0
|
||||
bn Err(…) Err($1)$0
|
||||
bn Ok(…) Ok($1)$0
|
||||
bn Err(…) Err($1)$0
|
||||
bn Ok(…) Ok($1)$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
|
@ -91,20 +91,20 @@ fn foo(baz: Baz) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Baz
|
||||
en Result
|
||||
md core
|
||||
ev Bar
|
||||
ev Err
|
||||
ev Foo
|
||||
ev Ok
|
||||
bn Bar Bar$0
|
||||
bn Err(…) Err($1)$0
|
||||
bn Foo Foo$0
|
||||
bn Ok(…) Ok($1)$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
en Baz
|
||||
en Result
|
||||
md core
|
||||
ev Bar
|
||||
ev Err
|
||||
ev Foo
|
||||
ev Ok
|
||||
bn Bar Bar$0
|
||||
bn Err(…) Err($1)$0
|
||||
bn Foo Foo$0
|
||||
bn Ok(…) Ok($1)$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -184,14 +184,14 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
fd ..Default::default()
|
||||
fn main() fn()
|
||||
lc foo Foo
|
||||
lc thing i32
|
||||
fn main() fn()
|
||||
lc foo Foo
|
||||
lc thing i32
|
||||
md core
|
||||
st Foo Foo
|
||||
st Foo {…} Foo { foo1: u32, foo2: u32 }
|
||||
st Foo Foo
|
||||
st Foo {…} Foo { foo1: u32, foo2: u32 }
|
||||
tt Default
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
ex Foo::default()
|
||||
|
@ -238,8 +238,8 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
fd ..Default::default()
|
||||
fd foo1 u32
|
||||
fd foo2 u32
|
||||
fd foo1 u32
|
||||
fd foo2 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ pub mod prelude {
|
|||
expect![[r#"
|
||||
md std
|
||||
st Option Option
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -113,10 +113,10 @@ mod macros {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn f() fn()
|
||||
fn f() fn()
|
||||
ma concat!(…) macro_rules! concat
|
||||
md std
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ pub mod prelude {
|
|||
md core
|
||||
md std
|
||||
st String String
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ pub mod prelude {
|
|||
expect![[r#"
|
||||
fn f() fn()
|
||||
md std
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -226,9 +226,9 @@ impl S {
|
|||
fn foo() { let _ = lib::S::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct PUBLIC_CONST pub const PUBLIC_CONST: u32
|
||||
fn public_method() fn()
|
||||
ta PublicType pub type PublicType = u32
|
||||
ct PUBLIC_CONST pub const PUBLIC_CONST: u32
|
||||
fn public_method() fn()
|
||||
ta PublicType pub type PublicType = u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -317,14 +317,14 @@ trait Sub: Super {
|
|||
fn foo<T: Sub>() { T::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct C2 (as Sub) const C2: ()
|
||||
ct CONST (as Super) const CONST: u8
|
||||
fn func() (as Super) fn()
|
||||
fn subfunc() (as Sub) fn()
|
||||
me method(…) (as Super) fn(&self)
|
||||
me submethod(…) (as Sub) fn(&self)
|
||||
ct C2 (as Sub) const C2: ()
|
||||
ct CONST (as Super) const CONST: u8
|
||||
fn func() (as Super) fn()
|
||||
fn subfunc() (as Sub) fn()
|
||||
me method(…) (as Super) fn(&self)
|
||||
me submethod(…) (as Sub) fn(&self)
|
||||
ta SubTy (as Sub) type SubTy
|
||||
ta Ty (as Super) type Ty
|
||||
ta Ty (as Super) type Ty
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -357,14 +357,14 @@ impl<T> Sub for Wrap<T> {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct C2 (as Sub) const C2: ()
|
||||
ct CONST (as Super) const CONST: u8
|
||||
fn func() (as Super) fn()
|
||||
fn subfunc() (as Sub) fn()
|
||||
me method(…) (as Super) fn(&self)
|
||||
me submethod(…) (as Sub) fn(&self)
|
||||
ct C2 (as Sub) const C2: ()
|
||||
ct CONST (as Super) const CONST: u8
|
||||
fn func() (as Super) fn()
|
||||
fn subfunc() (as Sub) fn()
|
||||
me method(…) (as Super) fn(&self)
|
||||
me submethod(…) (as Sub) fn(&self)
|
||||
ta SubTy (as Sub) type SubTy
|
||||
ta Ty (as Super) type Ty
|
||||
ta Ty (as Super) type Ty
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -381,9 +381,9 @@ impl T { fn bar() {} }
|
|||
fn main() { T::$0; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar() fn()
|
||||
fn foo() fn()
|
||||
"#]],
|
||||
fn bar() fn()
|
||||
fn foo() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ macro_rules! foo { () => {} }
|
|||
fn main() { let _ = crate::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
fn main() fn()
|
||||
ma foo!(…) macro_rules! foo
|
||||
"#]],
|
||||
);
|
||||
|
@ -447,9 +447,9 @@ mod p {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct RIGHT_CONST u32
|
||||
fn right_fn() fn()
|
||||
st RightType WrongType
|
||||
ct RIGHT_CONST u32
|
||||
fn right_fn() fn()
|
||||
st RightType WrongType
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -495,9 +495,9 @@ fn main() { m!(self::f$0); }
|
|||
fn foo() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
fn main() fn()
|
||||
"#]],
|
||||
fn foo() fn()
|
||||
fn main() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -513,9 +513,9 @@ mod m {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn z() fn()
|
||||
md z
|
||||
"#]],
|
||||
fn z() fn()
|
||||
md z
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -534,8 +534,8 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn new() fn() -> HashMap<K, V, RandomState>
|
||||
"#]],
|
||||
fn new() fn() -> HashMap<K, V, RandomState>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -557,8 +557,8 @@ impl Foo {
|
|||
"#,
|
||||
expect![[r#"
|
||||
me foo(…) fn(self)
|
||||
ev Bar Bar
|
||||
ev Baz Baz
|
||||
ev Bar Bar
|
||||
ev Baz Baz
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -578,9 +578,9 @@ fn foo(self) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Bar Bar
|
||||
ev Baz Baz
|
||||
"#]],
|
||||
ev Bar Bar
|
||||
ev Baz Baz
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_no_kw(
|
||||
|
@ -598,8 +598,8 @@ enum Foo {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Baz Baz
|
||||
"#]],
|
||||
ev Baz Baz
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -623,9 +623,9 @@ impl u8 {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct MAX pub const MAX: Self
|
||||
me func(…) fn(self)
|
||||
"#]],
|
||||
ct MAX pub const MAX: Self
|
||||
me func(…) fn(self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -643,8 +643,8 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Bar Bar
|
||||
"#]],
|
||||
ev Bar Bar
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -723,7 +723,7 @@ fn bar() -> Bar {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar() fn()
|
||||
fn bar() fn()
|
||||
fn foo() (as Foo) fn() -> Self
|
||||
ex Bar
|
||||
ex bar()
|
||||
|
@ -787,7 +787,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me by_macro() (as MyTrait) fn(&self)
|
||||
me by_macro() (as MyTrait) fn(&self)
|
||||
me not_by_macro() (as MyTrait) fn(&self)
|
||||
"#]],
|
||||
)
|
||||
|
@ -827,7 +827,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me by_macro() (as MyTrait) fn(&self)
|
||||
me by_macro() (as MyTrait) fn(&self)
|
||||
me not_by_macro() (as MyTrait) fn(&self)
|
||||
"#]],
|
||||
)
|
||||
|
@ -885,10 +885,10 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
lc foobar i32
|
||||
ma x!(…) macro_rules! x
|
||||
bt u32 u32
|
||||
fn main() fn()
|
||||
lc foobar i32
|
||||
ma x!(…) macro_rules! x
|
||||
bt u32 u32
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -1014,7 +1014,7 @@ fn here_we_go() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn here_we_go() fn()
|
||||
fn here_we_go() fn()
|
||||
st Foo (alias Bar) Foo
|
||||
bt u32 u32
|
||||
kw async
|
||||
|
@ -1064,9 +1064,9 @@ fn here_we_go() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn here_we_go() fn()
|
||||
fn here_we_go() fn()
|
||||
st Foo (alias Bar, Qux, Baz) Foo
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1160,20 +1160,20 @@ fn here_we_go() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd bar u8
|
||||
fd bar u8
|
||||
me baz() (alias qux) fn(&self) -> u8
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn let let
|
||||
sn letm let mut
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1189,7 +1189,7 @@ fn bar() { qu$0 }
|
|||
expect![[r#"
|
||||
fn bar() fn()
|
||||
fn foo() (alias qux) fn()
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1277,10 +1277,10 @@ fn here_we_go() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn here_we_go() fn()
|
||||
fn here_we_go() fn()
|
||||
md foo
|
||||
st Bar (alias Qux) (use foo::Bar) Bar
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw false
|
||||
kw for
|
||||
|
@ -1315,10 +1315,9 @@ use krate::e;
|
|||
fn main() {
|
||||
e::$0
|
||||
}"#,
|
||||
expect![
|
||||
"fn i_am_public() fn()
|
||||
"
|
||||
],
|
||||
expect![[r#"
|
||||
fn i_am_public() fn()
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1444,8 +1443,8 @@ fn foo() {
|
|||
"#,
|
||||
Some('_'),
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
fn foo() fn()
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
|
@ -1498,7 +1497,7 @@ fn foo(_: a_$0) { }
|
|||
"#,
|
||||
Some('_'),
|
||||
expect![[r#"
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -1512,7 +1511,7 @@ fn foo<T>() {
|
|||
Some('_'),
|
||||
expect![[r#"
|
||||
tp T
|
||||
bt u32 u32
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
|
|
@ -17,18 +17,18 @@ struct Foo<'lt, T, const C: usize> {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sp Self Foo<'_, {unknown}, _>
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self Foo<'_, {unknown}, _>
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -42,18 +42,18 @@ fn tuple_struct_field() {
|
|||
struct Foo<'lt, T, const C: usize>(f$0);
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sp Self Foo<'_, {unknown}, _>
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self Foo<'_, {unknown}, _>
|
||||
st Foo<…> Foo<'_, {unknown}, _>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw pub
|
||||
kw pub(crate)
|
||||
|
@ -70,16 +70,16 @@ fn fn_return_type() {
|
|||
fn x<'lt, T, const C: usize>() -> $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -100,15 +100,15 @@ fn foo() -> B$0 {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it ()
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -124,16 +124,16 @@ struct Foo<T>(T);
|
|||
const FOO: $0 = Foo(2);
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo<…> Foo<{unknown}>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo<…> Foo<{unknown}>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it Foo<i32>
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -151,15 +151,15 @@ fn f2() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it i32
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -179,15 +179,15 @@ fn f2() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it u64
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -204,15 +204,15 @@ fn f2(x: u64) -> $0 {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it u64
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -230,15 +230,15 @@ fn f2(x: $0) {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it i32
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -262,17 +262,17 @@ fn foo<'lt, T, const C: usize>() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md a
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it a::Foo<a::Foo<i32>>
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -291,17 +291,17 @@ fn foo<'lt, T, const C: usize>() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo<…> Foo<{unknown}>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo<…> Foo<{unknown}>
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
it Foo<i32>
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -319,16 +319,16 @@ fn foo<'lt, T, const C: usize>() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -341,14 +341,14 @@ fn foo<'lt, T, const C: usize>() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
un Union Union
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ trait Trait2: Trait1 {
|
|||
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ta Foo = (as Trait2) type Foo
|
||||
ta Foo = (as Trait2) type Foo
|
||||
ta Super = (as Trait1) type Super
|
||||
"#]],
|
||||
);
|
||||
|
@ -384,18 +384,18 @@ trait Trait2<T>: Trait1 {
|
|||
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tt Trait1
|
||||
tt Trait2
|
||||
tp T
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -409,15 +409,15 @@ trait Trait2<T> {
|
|||
fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
tt Trait2
|
||||
un Union Union
|
||||
un Union Union
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -434,18 +434,18 @@ trait Tr<T> {
|
|||
impl Tr<$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sp Self dyn Tr<{unknown}>
|
||||
st Record Record
|
||||
st S S
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self dyn Tr<{unknown}>
|
||||
st Record Record
|
||||
st S S
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Tr
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -481,16 +481,16 @@ trait MyTrait<T, U> {
|
|||
fn f(t: impl MyTrait<u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -506,16 +506,16 @@ trait MyTrait<T, U> {
|
|||
fn f(t: impl MyTrait<u8, u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -549,16 +549,16 @@ trait MyTrait<T, U = u8> {
|
|||
fn f(t: impl MyTrait<u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -574,18 +574,18 @@ trait MyTrait<T, U = u8> {
|
|||
fn f(t: impl MyTrait<u8, u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
ta Item1 = (as MyTrait) type Item1
|
||||
ta Item2 = (as MyTrait) type Item2
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -619,16 +619,16 @@ trait MyTrait {
|
|||
fn f(t: impl MyTrait<Item1 = $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -644,16 +644,16 @@ trait MyTrait {
|
|||
fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -668,7 +668,7 @@ trait MyTrait {
|
|||
fn f(t: impl MyTrait<C = $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct CONST Unit
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -691,9 +691,9 @@ pub struct S;
|
|||
"#,
|
||||
expect![[r#"
|
||||
md std
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -716,10 +716,10 @@ pub struct S;
|
|||
"#,
|
||||
expect![[r#"
|
||||
md std
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
st S S
|
||||
bt u32 u32
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
st S S
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -739,16 +739,16 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -766,8 +766,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -785,16 +785,16 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -809,8 +809,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -828,17 +828,17 @@ fn completes_const_and_type_generics_separately() {
|
|||
fn foo(_: impl Bar<Baz<F$0, 0> = ()>) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
st Foo Foo
|
||||
st Record Record
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Bar
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -853,8 +853,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
fn foo<T: Bar<Baz<(), $0> = ()>>() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -871,8 +871,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -890,8 +890,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -908,8 +908,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -924,8 +924,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
impl Foo<(), $0> for () {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -942,8 +942,8 @@ fn completes_const_and_type_generics_separately() {
|
|||
fn foo<T: Bar<X$0, ()>>() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ct CONST Unit
|
||||
ct X usize
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -957,7 +957,7 @@ struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>);
|
|||
fn foo<'a>() { S::<F$0, _>; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct CONST Unit
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
@ -970,7 +970,7 @@ struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>);
|
|||
fn foo<'a>() { S::<'static, 'static, F$0, _>; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST Unit
|
||||
ct CONST Unit
|
||||
ma makro!(…) macro_rules! makro
|
||||
kw crate::
|
||||
kw self::
|
||||
|
|
|
@ -92,7 +92,7 @@ use self::{foo::*, bar$0};
|
|||
"#,
|
||||
expect![[r#"
|
||||
md foo
|
||||
st S S
|
||||
st S S
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ struct Bar;
|
|||
"#,
|
||||
expect![[r#"
|
||||
ma foo macro_rules! foo_
|
||||
st Foo Foo
|
||||
st Foo Foo
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -203,8 +203,8 @@ impl Foo {
|
|||
"#,
|
||||
expect![[r#"
|
||||
ev RecordVariant RecordVariant
|
||||
ev TupleVariant TupleVariant
|
||||
ev UnitVariant UnitVariant
|
||||
ev TupleVariant TupleVariant
|
||||
ev UnitVariant UnitVariant
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ mod a {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct A usize
|
||||
ct A usize
|
||||
md b
|
||||
kw super::
|
||||
"#]],
|
||||
|
@ -450,9 +450,9 @@ pub fn foo() {}
|
|||
marco_rules! m { () => {} }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo fn()
|
||||
fn foo fn()
|
||||
md simd
|
||||
st S S
|
||||
st S S
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
use hir::{
|
||||
db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
|
||||
ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
|
||||
ItemInNs, ModPath, Module, ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics,
|
||||
SemanticsScope, Trait, TyFingerprint, Type,
|
||||
};
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::{
|
||||
ast::{self, make, HasName},
|
||||
|
@ -13,7 +13,6 @@ use syntax::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
helpers::item_name,
|
||||
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||
FxIndexSet, RootDatabase,
|
||||
};
|
||||
|
@ -52,7 +51,7 @@ pub struct TraitImportCandidate {
|
|||
#[derive(Debug)]
|
||||
pub struct PathImportCandidate {
|
||||
/// Optional qualifier before name.
|
||||
pub qualifier: Option<Vec<SmolStr>>,
|
||||
pub qualifier: Vec<SmolStr>,
|
||||
/// The name the item (struct, trait, enum, etc.) should have.
|
||||
pub name: NameToImport,
|
||||
}
|
||||
|
@ -264,7 +263,6 @@ impl ImportAssets {
|
|||
Some(it) => it,
|
||||
None => return <FxIndexSet<_>>::default().into_iter(),
|
||||
};
|
||||
|
||||
let krate = self.module_with_candidate.krate();
|
||||
let scope_definitions = self.scope_definitions(sema);
|
||||
let mod_path = |item| {
|
||||
|
@ -279,11 +277,14 @@ impl ImportAssets {
|
|||
};
|
||||
|
||||
match &self.import_candidate {
|
||||
ImportCandidate::Path(path_candidate) => {
|
||||
path_applicable_imports(sema, krate, path_candidate, mod_path, |item_to_import| {
|
||||
!scope_definitions.contains(&ScopeDef::from(item_to_import))
|
||||
})
|
||||
}
|
||||
ImportCandidate::Path(path_candidate) => path_applicable_imports(
|
||||
sema,
|
||||
&scope,
|
||||
krate,
|
||||
path_candidate,
|
||||
mod_path,
|
||||
|item_to_import| !scope_definitions.contains(&ScopeDef::from(item_to_import)),
|
||||
),
|
||||
ImportCandidate::TraitAssocItem(trait_candidate)
|
||||
| ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
|
||||
sema,
|
||||
|
@ -315,6 +316,7 @@ impl ImportAssets {
|
|||
|
||||
fn path_applicable_imports(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
scope: &SemanticsScope<'_>,
|
||||
current_crate: Crate,
|
||||
path_candidate: &PathImportCandidate,
|
||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
|
||||
|
@ -322,8 +324,8 @@ fn path_applicable_imports(
|
|||
) -> FxIndexSet<LocatedImport> {
|
||||
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
|
||||
|
||||
match &path_candidate.qualifier {
|
||||
None => {
|
||||
match &*path_candidate.qualifier {
|
||||
[] => {
|
||||
items_locator::items_with_name(
|
||||
sema,
|
||||
current_crate,
|
||||
|
@ -348,89 +350,107 @@ fn path_applicable_imports(
|
|||
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
|
||||
.collect()
|
||||
}
|
||||
Some(qualifier) => items_locator::items_with_name(
|
||||
[first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name(
|
||||
sema,
|
||||
current_crate,
|
||||
path_candidate.name.clone(),
|
||||
AssocSearchMode::Include,
|
||||
NameToImport::Exact(first_qsegment.to_string(), true),
|
||||
AssocSearchMode::Exclude,
|
||||
)
|
||||
.filter_map(|item| import_for_item(sema.db, mod_path, qualifier, item, scope_filter))
|
||||
.filter_map(|item| {
|
||||
import_for_item(
|
||||
sema,
|
||||
scope,
|
||||
mod_path,
|
||||
&path_candidate.name,
|
||||
item,
|
||||
qualifier_rest,
|
||||
scope_filter,
|
||||
)
|
||||
})
|
||||
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_for_item(
|
||||
db: &RootDatabase,
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
scope: &SemanticsScope<'_>,
|
||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
||||
candidate: &NameToImport,
|
||||
resolved_qualifier: ItemInNs,
|
||||
unresolved_qualifier: &[SmolStr],
|
||||
original_item: ItemInNs,
|
||||
scope_filter: impl Fn(ItemInNs) -> bool,
|
||||
) -> Option<LocatedImport> {
|
||||
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
|
||||
let [first_segment, ..] = unresolved_qualifier else { return None };
|
||||
|
||||
let item_as_assoc = item_as_assoc(db, original_item);
|
||||
|
||||
let (original_item_candidate, trait_item_to_import) = match item_as_assoc {
|
||||
Some(assoc_item) => match assoc_item.container(db) {
|
||||
AssocItemContainer::Trait(trait_) => {
|
||||
let trait_ = ItemInNs::from(ModuleDef::from(trait_));
|
||||
(trait_, Some(trait_))
|
||||
let qualifier = {
|
||||
let mut adjusted_resolved_qualifier = resolved_qualifier;
|
||||
if !unresolved_qualifier.is_empty() {
|
||||
match resolved_qualifier {
|
||||
ItemInNs::Types(ModuleDef::Module(module)) => {
|
||||
adjusted_resolved_qualifier = sema
|
||||
.resolve_mod_path_relative(module, unresolved_qualifier.iter().cloned())?
|
||||
.next()?;
|
||||
}
|
||||
// can't resolve multiple segments for non-module item path bases
|
||||
_ => return None,
|
||||
}
|
||||
AssocItemContainer::Impl(impl_) => {
|
||||
(ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)), None)
|
||||
}
|
||||
},
|
||||
None => (original_item, None),
|
||||
}
|
||||
|
||||
match adjusted_resolved_qualifier {
|
||||
ItemInNs::Types(def) => def,
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
let import_path_candidate = mod_path(original_item_candidate)?;
|
||||
|
||||
let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev();
|
||||
let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it {
|
||||
// segments match, check next one
|
||||
EitherOrBoth::Both(a, b) if b.as_str() == &**a => None,
|
||||
// segments mismatch / qualifier is longer than the path, bail out
|
||||
EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false),
|
||||
// all segments match and we have exhausted the qualifier, proceed
|
||||
EitherOrBoth::Right(_) => Some(true),
|
||||
};
|
||||
if item_as_assoc.is_none() {
|
||||
let item_name = item_name(db, original_item)?;
|
||||
let last_segment = import_path_candidate_segments.next()?;
|
||||
if *last_segment != item_name {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let ends_with = unresolved_qualifier
|
||||
.iter()
|
||||
.rev()
|
||||
.zip_longest(import_path_candidate_segments)
|
||||
.find_map(predicate)
|
||||
.unwrap_or(true);
|
||||
if !ends_with {
|
||||
return None;
|
||||
}
|
||||
|
||||
let segment_import = find_import_for_segment(db, original_item_candidate, first_segment)?;
|
||||
|
||||
Some(match (segment_import == original_item_candidate, trait_item_to_import) {
|
||||
(true, Some(_)) => {
|
||||
// FIXME we should be able to import both the trait and the segment,
|
||||
// but it's unclear what to do with overlapping edits (merge imports?)
|
||||
// especially in case of lazy completion edit resolutions.
|
||||
return None;
|
||||
}
|
||||
(false, Some(trait_to_import)) if scope_filter(trait_to_import) => {
|
||||
LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item)
|
||||
}
|
||||
(true, None) if scope_filter(original_item_candidate) => {
|
||||
LocatedImport::new(import_path_candidate, original_item_candidate, original_item)
|
||||
}
|
||||
(false, None) if scope_filter(segment_import) => {
|
||||
LocatedImport::new(mod_path(segment_import)?, segment_import, original_item)
|
||||
let import_path_candidate = mod_path(resolved_qualifier)?;
|
||||
let ty = match qualifier {
|
||||
ModuleDef::Module(module) => {
|
||||
return items_locator::items_with_name_in_module(
|
||||
sema,
|
||||
module,
|
||||
candidate.clone(),
|
||||
AssocSearchMode::Exclude,
|
||||
)
|
||||
.find(|&it| scope_filter(it))
|
||||
.map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item))
|
||||
}
|
||||
// FIXME
|
||||
ModuleDef::Trait(_) => return None,
|
||||
// FIXME
|
||||
ModuleDef::TraitAlias(_) => return None,
|
||||
ModuleDef::TypeAlias(alias) => alias.ty(sema.db),
|
||||
ModuleDef::BuiltinType(builtin) => builtin.ty(sema.db),
|
||||
ModuleDef::Adt(adt) => adt.ty(sema.db),
|
||||
_ => return None,
|
||||
};
|
||||
ty.iterate_path_candidates(sema.db, scope, &FxHashSet::default(), None, None, |assoc| {
|
||||
// FIXME: Support extra trait imports
|
||||
if assoc.container_or_implemented_trait(sema.db).is_some() {
|
||||
return None;
|
||||
}
|
||||
let name = assoc.name(sema.db)?;
|
||||
let is_match = match candidate {
|
||||
NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
|
||||
NameToImport::Prefix(text, false) => {
|
||||
name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
|
||||
name_char.eq_ignore_ascii_case(&candidate_char)
|
||||
})
|
||||
}
|
||||
NameToImport::Exact(text, true) => name.as_str() == text,
|
||||
NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
|
||||
NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
|
||||
NameToImport::Fuzzy(text, false) => text
|
||||
.chars()
|
||||
.all(|c| name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))),
|
||||
};
|
||||
if !is_match {
|
||||
return None;
|
||||
}
|
||||
Some(LocatedImport::new(
|
||||
import_path_candidate.clone(),
|
||||
resolved_qualifier,
|
||||
assoc_to_item(assoc),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -453,45 +473,6 @@ fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Optio
|
|||
})
|
||||
}
|
||||
|
||||
fn find_import_for_segment(
|
||||
db: &RootDatabase,
|
||||
original_item: ItemInNs,
|
||||
unresolved_first_segment: &str,
|
||||
) -> Option<ItemInNs> {
|
||||
let segment_is_name = item_name(db, original_item)
|
||||
.map(|name| name.eq_ident(unresolved_first_segment))
|
||||
.unwrap_or(false);
|
||||
|
||||
Some(if segment_is_name {
|
||||
original_item
|
||||
} else {
|
||||
let matching_module =
|
||||
module_with_segment_name(db, unresolved_first_segment, original_item)?;
|
||||
ItemInNs::from(ModuleDef::from(matching_module))
|
||||
})
|
||||
}
|
||||
|
||||
fn module_with_segment_name(
|
||||
db: &RootDatabase,
|
||||
segment_name: &str,
|
||||
candidate: ItemInNs,
|
||||
) -> Option<Module> {
|
||||
let mut current_module = match candidate {
|
||||
ItemInNs::Types(module_def_id) => module_def_id.module(db),
|
||||
ItemInNs::Values(module_def_id) => module_def_id.module(db),
|
||||
ItemInNs::Macros(macro_def_id) => ModuleDef::from(macro_def_id).module(db),
|
||||
};
|
||||
while let Some(module) = current_module {
|
||||
if let Some(module_name) = module.name(db) {
|
||||
if module_name.eq_ident(segment_name) {
|
||||
return Some(module);
|
||||
}
|
||||
}
|
||||
current_module = module.parent(db);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn trait_applicable_items(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
current_crate: Crate,
|
||||
|
@ -703,7 +684,7 @@ impl ImportCandidate {
|
|||
return None;
|
||||
}
|
||||
Some(ImportCandidate::Path(PathImportCandidate {
|
||||
qualifier: None,
|
||||
qualifier: vec![],
|
||||
name: NameToImport::exact_case_sensitive(name.to_string()),
|
||||
}))
|
||||
}
|
||||
|
@ -730,7 +711,7 @@ fn path_import_candidate(
|
|||
.segments()
|
||||
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
||||
ImportCandidate::Path(PathImportCandidate { qualifier, name })
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
@ -754,10 +735,10 @@ fn path_import_candidate(
|
|||
}
|
||||
Some(_) => return None,
|
||||
},
|
||||
None => ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
|
||||
None => ImportCandidate::Path(PathImportCandidate { qualifier: vec![], name }),
|
||||
})
|
||||
}
|
||||
|
||||
fn item_as_assoc(db: &RootDatabase, item: ItemInNs) -> Option<AssocItem> {
|
||||
item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
|
||||
item.into_module_def().as_assoc_item(db)
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
//! The main reason for this module to exist is the fact that project's items and dependencies' items
|
||||
//! are located in different caches, with different APIs.
|
||||
use either::Either;
|
||||
use hir::{import_map, Crate, ItemInNs, Semantics};
|
||||
use hir::{import_map, Crate, ItemInNs, Module, Semantics};
|
||||
use limit::Limit;
|
||||
|
||||
use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase};
|
||||
use crate::{
|
||||
imports::import_assets::NameToImport,
|
||||
symbol_index::{self, SymbolsDatabase as _},
|
||||
RootDatabase,
|
||||
};
|
||||
|
||||
/// A value to use, when uncertain which limit to pick.
|
||||
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
|
||||
|
@ -20,8 +24,7 @@ pub fn items_with_name<'a>(
|
|||
name: NameToImport,
|
||||
assoc_item_search: AssocSearchMode,
|
||||
) -> impl Iterator<Item = ItemInNs> + 'a {
|
||||
let krate_name = krate.display_name(sema.db).map(|name| name.to_string());
|
||||
let _p = tracing::info_span!("items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate_name)
|
||||
let _p = tracing::info_span!("items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate.display_name(sema.db).map(|name| name.to_string()))
|
||||
.entered();
|
||||
|
||||
let prefix = matches!(name, NameToImport::Prefix(..));
|
||||
|
@ -66,6 +69,54 @@ pub fn items_with_name<'a>(
|
|||
find_items(sema, krate, local_query, external_query)
|
||||
}
|
||||
|
||||
/// Searches for importable items with the given name in the crate and its dependencies.
|
||||
pub fn items_with_name_in_module<'a>(
|
||||
sema: &'a Semantics<'_, RootDatabase>,
|
||||
module: Module,
|
||||
name: NameToImport,
|
||||
assoc_item_search: AssocSearchMode,
|
||||
) -> impl Iterator<Item = ItemInNs> + 'a {
|
||||
let _p = tracing::info_span!("items_with_name_in", name = name.text(), assoc_item_search = ?assoc_item_search, ?module)
|
||||
.entered();
|
||||
|
||||
let prefix = matches!(name, NameToImport::Prefix(..));
|
||||
let local_query = match name {
|
||||
NameToImport::Prefix(exact_name, case_sensitive)
|
||||
| NameToImport::Exact(exact_name, case_sensitive) => {
|
||||
let mut local_query = symbol_index::Query::new(exact_name.clone());
|
||||
local_query.assoc_search_mode(assoc_item_search);
|
||||
if prefix {
|
||||
local_query.prefix();
|
||||
} else {
|
||||
local_query.exact();
|
||||
}
|
||||
if case_sensitive {
|
||||
local_query.case_sensitive();
|
||||
}
|
||||
local_query
|
||||
}
|
||||
NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => {
|
||||
let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
|
||||
local_query.fuzzy();
|
||||
local_query.assoc_search_mode(assoc_item_search);
|
||||
|
||||
if case_sensitive {
|
||||
local_query.case_sensitive();
|
||||
}
|
||||
|
||||
local_query
|
||||
}
|
||||
};
|
||||
let mut local_results = Vec::new();
|
||||
local_query.search(&[sema.db.module_symbols(module)], |local_candidate| {
|
||||
local_results.push(match local_candidate.def {
|
||||
hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
|
||||
def => ItemInNs::from(def),
|
||||
})
|
||||
});
|
||||
local_results.into_iter()
|
||||
}
|
||||
|
||||
fn find_items<'a>(
|
||||
sema: &'a Semantics<'_, RootDatabase>,
|
||||
krate: Crate,
|
||||
|
|
|
@ -377,6 +377,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
|
|||
return None;
|
||||
}
|
||||
name
|
||||
} else if let Some(inner_ty) = ty.remove_ref() {
|
||||
return name_of_type(&inner_ty, db, edition);
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
|
|
@ -778,4 +778,20 @@ fn bar(mut v: Union2) {
|
|||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raw_ref_reborrow_is_safe() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
fn main() {
|
||||
let ptr: *mut i32;
|
||||
let _addr = &raw const *ptr;
|
||||
|
||||
let local = 1;
|
||||
let ptr = &local as *const i32;
|
||||
let _addr = &raw const *ptr;
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,9 @@ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<A
|
|||
make::ty("()")
|
||||
};
|
||||
|
||||
if !is_editable_crate(target_module.krate(), ctx.sema.db) {
|
||||
if !is_editable_crate(target_module.krate(), ctx.sema.db)
|
||||
|| SyntaxKind::from_keyword(field_name, ctx.edition).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -501,4 +503,19 @@ fn main() {}
|
|||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_18683() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn f(self) {
|
||||
self.self
|
||||
// ^^^^ error: no field `self` on type `S`
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,20 +7,19 @@ pub(crate) fn unresolved_ident(
|
|||
ctx: &DiagnosticsContext<'_>,
|
||||
d: &hir::UnresolvedIdent,
|
||||
) -> Diagnostic {
|
||||
Diagnostic::new_with_syntax_node_ptr(
|
||||
ctx,
|
||||
DiagnosticCode::RustcHardError("E0425"),
|
||||
"no such value in this scope",
|
||||
d.expr_or_pat.map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
let mut range =
|
||||
ctx.sema.diagnostics_display_range(d.node.map(|(node, _)| node.syntax_node_ptr()));
|
||||
if let Some(in_node_range) = d.node.value.1 {
|
||||
range.range = in_node_range + range.range.start();
|
||||
}
|
||||
Diagnostic::new(DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", range)
|
||||
.experimental()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::check_diagnostics;
|
||||
|
||||
// FIXME: This should show a diagnostic
|
||||
#[test]
|
||||
fn feature() {
|
||||
check_diagnostics(
|
||||
|
@ -28,6 +27,7 @@ mod tests {
|
|||
//- minicore: fmt
|
||||
fn main() {
|
||||
format_args!("{unresolved}");
|
||||
// ^^^^^^^^^^ error: no such value in this scope
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@ use ide_db::{
|
|||
};
|
||||
use itertools::Itertools;
|
||||
use span::{Edition, TextSize};
|
||||
use stdx::{always, format_to};
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
SmolStr, SyntaxNode, ToSmolStr,
|
||||
|
@ -130,14 +130,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
|
|||
// In case an expansion creates multiple runnables we want to name them to avoid emitting a bunch of equally named runnables.
|
||||
let mut in_macro_expansion = FxHashMap::<hir::HirFileId, Vec<Runnable>>::default();
|
||||
let mut add_opt = |runnable: Option<Runnable>, def| {
|
||||
if let Some(runnable) = runnable.filter(|runnable| {
|
||||
always!(
|
||||
runnable.nav.file_id == file_id,
|
||||
"tried adding a runnable pointing to a different file: {:?} for {:?}",
|
||||
runnable.kind,
|
||||
file_id
|
||||
)
|
||||
}) {
|
||||
if let Some(runnable) = runnable.filter(|runnable| runnable.nav.file_id == file_id) {
|
||||
if let Some(def) = def {
|
||||
let file_id = match def {
|
||||
Definition::Module(it) => {
|
||||
|
@ -161,13 +154,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
|
|||
Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
|
||||
_ => None,
|
||||
};
|
||||
add_opt(
|
||||
runnable
|
||||
.or_else(|| module_def_doctest(sema.db, def))
|
||||
// #[macro_export] mbe macros are declared in the root, while their definition may reside in a different module
|
||||
.filter(|it| it.nav.file_id == file_id),
|
||||
Some(def),
|
||||
);
|
||||
add_opt(runnable.or_else(|| module_def_doctest(sema.db, def)), Some(def));
|
||||
if let Definition::SelfType(impl_) = def {
|
||||
impl_.items(db).into_iter().for_each(|assoc| {
|
||||
let runnable = match assoc {
|
||||
|
|
|
@ -174,6 +174,9 @@ fn on_delimited_node_typed(
|
|||
kinds: &[fn(SyntaxKind) -> bool],
|
||||
) -> Option<TextEdit> {
|
||||
let t = reparsed.syntax().token_at_offset(offset).right_biased()?;
|
||||
if t.prev_token().map_or(false, |t| t.kind().is_any_identifier()) {
|
||||
return None;
|
||||
}
|
||||
let (filter, node) = t
|
||||
.parent_ancestors()
|
||||
.take_while(|n| n.text_range().start() == offset)
|
||||
|
@ -1091,6 +1094,22 @@ fn f() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preceding_whitespace_is_significant_for_closing_brackets() {
|
||||
type_char_noop(
|
||||
'(',
|
||||
r#"
|
||||
fn f() { a.b$0if true {} }
|
||||
"#,
|
||||
);
|
||||
type_char_noop(
|
||||
'(',
|
||||
r#"
|
||||
fn f() { foo$0{} }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adds_closing_parenthesis_for_pat() {
|
||||
type_char(
|
||||
|
|
|
@ -487,7 +487,7 @@ impl ProcMacroExpander for Expander {
|
|||
match self.0.expand(
|
||||
subtree,
|
||||
attrs,
|
||||
env.clone(),
|
||||
env.clone().into(),
|
||||
def_site,
|
||||
call_site,
|
||||
mixed_site,
|
||||
|
|
|
@ -72,8 +72,19 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool, is_in_ext
|
|||
// macro_rules! ()
|
||||
// macro_rules! []
|
||||
if paths::is_use_path_start(p) {
|
||||
macro_call(p, m);
|
||||
return;
|
||||
paths::use_path(p);
|
||||
// Do not create a MACRO_CALL node here if this isn't a macro call, this causes problems with completion.
|
||||
|
||||
// test_err path_item_without_excl
|
||||
// foo
|
||||
if p.at(T![!]) {
|
||||
macro_call(p, m);
|
||||
return;
|
||||
} else {
|
||||
m.complete(p, ERROR);
|
||||
p.error("expected an item");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m.abandon(p);
|
||||
|
@ -410,8 +421,7 @@ fn fn_(p: &mut Parser<'_>, m: Marker) {
|
|||
}
|
||||
|
||||
fn macro_call(p: &mut Parser<'_>, m: Marker) {
|
||||
assert!(paths::is_use_path_start(p));
|
||||
paths::use_path(p);
|
||||
assert!(p.at(T![!]));
|
||||
match macro_call_after_excl(p) {
|
||||
BlockLike::Block => (),
|
||||
BlockLike::NotBlock => {
|
||||
|
|
|
@ -30,22 +30,20 @@ fn source_file() {
|
|||
TopEntryPoint::SourceFile,
|
||||
"@error@",
|
||||
expect![[r#"
|
||||
SOURCE_FILE
|
||||
ERROR
|
||||
AT "@"
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "error"
|
||||
ERROR
|
||||
AT "@"
|
||||
error 0: expected an item
|
||||
error 6: expected BANG
|
||||
error 6: expected `{`, `[`, `(`
|
||||
error 6: expected SEMICOLON
|
||||
error 6: expected an item
|
||||
"#]],
|
||||
SOURCE_FILE
|
||||
ERROR
|
||||
AT "@"
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "error"
|
||||
ERROR
|
||||
AT "@"
|
||||
error 0: expected an item
|
||||
error 6: expected an item
|
||||
error 6: expected an item
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -775,6 +775,10 @@ mod err {
|
|||
run_and_expect_errors("test_data/parser/inline/err/missing_fn_param_type.rs");
|
||||
}
|
||||
#[test]
|
||||
fn path_item_without_excl() {
|
||||
run_and_expect_errors("test_data/parser/inline/err/path_item_without_excl.rs");
|
||||
}
|
||||
#[test]
|
||||
fn pointer_type_no_mutability() {
|
||||
run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
|
||||
}
|
||||
|
|
|
@ -10,20 +10,20 @@ SOURCE_FILE
|
|||
USE_KW "use"
|
||||
ERROR
|
||||
SLASH "/"
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bin"
|
||||
ERROR
|
||||
SLASH "/"
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "env"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
|
@ -33,13 +33,7 @@ error 23: expected `[`
|
|||
error 23: expected an item
|
||||
error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
|
||||
error 28: expected SEMICOLON
|
||||
error 31: expected BANG
|
||||
error 31: expected `{`, `[`, `(`
|
||||
error 31: expected SEMICOLON
|
||||
error 31: expected an item
|
||||
error 35: expected BANG
|
||||
error 35: expected `{`, `[`, `(`
|
||||
error 35: expected SEMICOLON
|
||||
error 41: expected BANG
|
||||
error 41: expected `{`, `[`, `(`
|
||||
error 41: expected SEMICOLON
|
||||
error 31: expected an item
|
||||
error 35: expected an item
|
||||
error 41: expected an item
|
||||
|
|
|
@ -14,14 +14,15 @@ SOURCE_FILE
|
|||
WHITESPACE "\n"
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n\n"
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
TOKEN_TREE
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
ERROR
|
||||
L_PAREN "("
|
||||
ERROR
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
ERROR
|
||||
L_CURLY "{"
|
||||
|
@ -75,6 +76,7 @@ SOURCE_FILE
|
|||
WHITESPACE "\n"
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
error 17: expected BANG
|
||||
error 19: expected SEMICOLON
|
||||
error 17: expected an item
|
||||
error 17: expected an item
|
||||
error 18: expected an item
|
||||
error 20: expected an item
|
||||
|
|
|
@ -46,7 +46,7 @@ SOURCE_FILE
|
|||
ERROR
|
||||
AT "@"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
|
@ -72,9 +72,7 @@ error 67: expected R_ANGLE
|
|||
error 67: expected R_PAREN
|
||||
error 67: expected SEMICOLON
|
||||
error 67: expected an item
|
||||
error 72: expected BANG
|
||||
error 72: expected `{`, `[`, `(`
|
||||
error 72: expected SEMICOLON
|
||||
error 72: expected an item
|
||||
error 72: expected an item
|
||||
error 73: expected an item
|
||||
error 79: expected an item
|
||||
|
|
|
@ -26,14 +26,15 @@ SOURCE_FILE
|
|||
ERROR
|
||||
FN_KW "fn"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
TOKEN_TREE
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
ERROR
|
||||
L_PAREN "("
|
||||
ERROR
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
ERROR
|
||||
L_CURLY "{"
|
||||
|
@ -43,6 +44,7 @@ error 6: expected fn, trait or impl
|
|||
error 38: expected a name
|
||||
error 40: missing type for `const` or `static`
|
||||
error 40: expected SEMICOLON
|
||||
error 44: expected BANG
|
||||
error 46: expected SEMICOLON
|
||||
error 44: expected an item
|
||||
error 44: expected an item
|
||||
error 45: expected an item
|
||||
error 47: expected an item
|
||||
|
|
|
@ -12,15 +12,16 @@ SOURCE_FILE
|
|||
ERROR
|
||||
USE_KW "use"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "std"
|
||||
ERROR
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n"
|
||||
error 8: expected R_ANGLE
|
||||
error 8: expected type
|
||||
error 11: expected `{`
|
||||
error 15: expected BANG
|
||||
error 15: expected `{`, `[`, `(`
|
||||
error 15: expected an item
|
||||
error 15: expected an item
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SOURCE_FILE
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
|
@ -22,7 +22,7 @@ SOURCE_FILE
|
|||
ERROR
|
||||
ASYNC_KW "async"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
|
@ -42,10 +42,6 @@ SOURCE_FILE
|
|||
L_CURLY "{"
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
error 3: expected BANG
|
||||
error 3: expected `{`, `[`, `(`
|
||||
error 3: expected SEMICOLON
|
||||
error 3: expected an item
|
||||
error 24: expected fn, trait or impl
|
||||
error 28: expected BANG
|
||||
error 28: expected `{`, `[`, `(`
|
||||
error 28: expected SEMICOLON
|
||||
error 28: expected an item
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
SOURCE_FILE
|
||||
ERROR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "foo"
|
||||
WHITESPACE "\n"
|
||||
error 3: expected an item
|
|
@ -0,0 +1 @@
|
|||
foo
|
|
@ -14,10 +14,9 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
camino.workspace = true
|
||||
serde = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
serde1 = ["camino/serde1", "dep:serde"]
|
||||
serde1 = ["camino/serde1"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -14,6 +14,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
serde_json = { workspace = true, features = ["unbounded_depth"] }
|
||||
tracing.workspace = true
|
||||
rustc-hash.workspace = true
|
||||
|
@ -23,11 +24,9 @@ indexmap.workspace = true
|
|||
paths = { workspace = true, features = ["serde1"] }
|
||||
tt.workspace = true
|
||||
stdx.workspace = true
|
||||
# Ideally this crate would not depend on salsa things, but we need span information here which wraps
|
||||
# InternIds for the syntax context
|
||||
span.workspace = true
|
||||
# only here due to the `Env` newtype :/
|
||||
base-db.workspace = true
|
||||
# span = {workspace = true, default-features = false} does not work
|
||||
span = { path = "../span", version = "0.0.0", default-features = false}
|
||||
|
||||
intern.workspace = true
|
||||
|
||||
[lints]
|
||||
|
|
|
@ -9,7 +9,6 @@ pub mod json;
|
|||
pub mod msg;
|
||||
mod process;
|
||||
|
||||
use base_db::Env;
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use span::Span;
|
||||
use std::{fmt, io, sync::Arc};
|
||||
|
@ -148,7 +147,7 @@ impl ProcMacro {
|
|||
&self,
|
||||
subtree: &tt::Subtree<Span>,
|
||||
attr: Option<&tt::Subtree<Span>>,
|
||||
env: Env,
|
||||
env: Vec<(String, String)>,
|
||||
def_site: Span,
|
||||
call_site: Span,
|
||||
mixed_site: Span,
|
||||
|
@ -179,7 +178,7 @@ impl ProcMacro {
|
|||
},
|
||||
},
|
||||
lib: self.dylib_path.to_path_buf().into(),
|
||||
env: env.into(),
|
||||
env,
|
||||
current_dir,
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ pub(crate) mod flat;
|
|||
use std::io::{self, BufRead, Write};
|
||||
|
||||
use paths::Utf8PathBuf;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::ProcMacroKind;
|
||||
|
||||
|
@ -123,7 +124,7 @@ impl ExpnGlobals {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Message: Serialize + DeserializeOwned {
|
||||
pub trait Message: serde::Serialize + DeserializeOwned {
|
||||
fn read<R: BufRead>(
|
||||
from_proto: ProtocolRead<R>,
|
||||
inp: &mut R,
|
||||
|
|
|
@ -39,10 +39,10 @@ use std::collections::VecDeque;
|
|||
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use span::{EditionedFileId, ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange};
|
||||
|
||||
use crate::msg::EXTENDED_LEAF_DATA;
|
||||
use crate::msg::{ENCODE_CLOSE_SPAN_VERSION, EXTENDED_LEAF_DATA};
|
||||
|
||||
pub type SpanDataIndexMap =
|
||||
indexmap::IndexSet<Span, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||
|
@ -145,7 +145,11 @@ impl FlatTree {
|
|||
w.write(subtree);
|
||||
|
||||
FlatTree {
|
||||
subtree: write_vec(w.subtree, SubtreeRepr::write),
|
||||
subtree: if version >= ENCODE_CLOSE_SPAN_VERSION {
|
||||
write_vec(w.subtree, SubtreeRepr::write_with_close_span)
|
||||
} else {
|
||||
write_vec(w.subtree, SubtreeRepr::write)
|
||||
},
|
||||
literal: if version >= EXTENDED_LEAF_DATA {
|
||||
write_vec(w.literal, LiteralRepr::write_with_kind)
|
||||
} else {
|
||||
|
@ -179,7 +183,11 @@ impl FlatTree {
|
|||
w.write(subtree);
|
||||
|
||||
FlatTree {
|
||||
subtree: write_vec(w.subtree, SubtreeRepr::write),
|
||||
subtree: if version >= ENCODE_CLOSE_SPAN_VERSION {
|
||||
write_vec(w.subtree, SubtreeRepr::write_with_close_span)
|
||||
} else {
|
||||
write_vec(w.subtree, SubtreeRepr::write)
|
||||
},
|
||||
literal: if version >= EXTENDED_LEAF_DATA {
|
||||
write_vec(w.literal, LiteralRepr::write_with_kind)
|
||||
} else {
|
||||
|
@ -202,7 +210,11 @@ impl FlatTree {
|
|||
span_data_table: &SpanDataIndexMap,
|
||||
) -> tt::Subtree<Span> {
|
||||
Reader {
|
||||
subtree: read_vec(self.subtree, SubtreeRepr::read),
|
||||
subtree: if version >= ENCODE_CLOSE_SPAN_VERSION {
|
||||
read_vec(self.subtree, SubtreeRepr::read_with_close_span)
|
||||
} else {
|
||||
read_vec(self.subtree, SubtreeRepr::read)
|
||||
},
|
||||
literal: if version >= EXTENDED_LEAF_DATA {
|
||||
read_vec(self.literal, LiteralRepr::read_with_kind)
|
||||
} else {
|
||||
|
@ -224,7 +236,11 @@ impl FlatTree {
|
|||
|
||||
pub fn to_subtree_unresolved(self, version: u32) -> tt::Subtree<TokenId> {
|
||||
Reader {
|
||||
subtree: read_vec(self.subtree, SubtreeRepr::read),
|
||||
subtree: if version >= ENCODE_CLOSE_SPAN_VERSION {
|
||||
read_vec(self.subtree, SubtreeRepr::read_with_close_span)
|
||||
} else {
|
||||
read_vec(self.subtree, SubtreeRepr::read)
|
||||
},
|
||||
literal: if version >= EXTENDED_LEAF_DATA {
|
||||
read_vec(self.literal, LiteralRepr::read_with_kind)
|
||||
} else {
|
||||
|
@ -257,7 +273,26 @@ fn write_vec<T, F: Fn(T) -> [u32; N], const N: usize>(xs: Vec<T>, f: F) -> Vec<u
|
|||
}
|
||||
|
||||
impl SubtreeRepr {
|
||||
fn write(self) -> [u32; 5] {
|
||||
fn write(self) -> [u32; 4] {
|
||||
let kind = match self.kind {
|
||||
tt::DelimiterKind::Invisible => 0,
|
||||
tt::DelimiterKind::Parenthesis => 1,
|
||||
tt::DelimiterKind::Brace => 2,
|
||||
tt::DelimiterKind::Bracket => 3,
|
||||
};
|
||||
[self.open.0, kind, self.tt[0], self.tt[1]]
|
||||
}
|
||||
fn read([open, kind, lo, len]: [u32; 4]) -> SubtreeRepr {
|
||||
let kind = match kind {
|
||||
0 => tt::DelimiterKind::Invisible,
|
||||
1 => tt::DelimiterKind::Parenthesis,
|
||||
2 => tt::DelimiterKind::Brace,
|
||||
3 => tt::DelimiterKind::Bracket,
|
||||
other => panic!("bad kind {other}"),
|
||||
};
|
||||
SubtreeRepr { open: TokenId(open), close: TokenId(!0), kind, tt: [lo, len] }
|
||||
}
|
||||
fn write_with_close_span(self) -> [u32; 5] {
|
||||
let kind = match self.kind {
|
||||
tt::DelimiterKind::Invisible => 0,
|
||||
tt::DelimiterKind::Parenthesis => 1,
|
||||
|
@ -266,7 +301,7 @@ impl SubtreeRepr {
|
|||
};
|
||||
[self.open.0, self.close.0, kind, self.tt[0], self.tt[1]]
|
||||
}
|
||||
fn read([open, close, kind, lo, len]: [u32; 5]) -> SubtreeRepr {
|
||||
fn read_with_close_span([open, close, kind, lo, len]: [u32; 5]) -> SubtreeRepr {
|
||||
let kind = match kind {
|
||||
0 => tt::DelimiterKind::Invisible,
|
||||
1 => tt::DelimiterKind::Parenthesis,
|
||||
|
|
|
@ -56,25 +56,8 @@ impl ProcMacroProcessSrv {
|
|||
match srv.version_check() {
|
||||
Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"The version of the proc-macro server ({v}) in your Rust toolchain \
|
||||
is newer than the version supported by your rust-analyzer ({CURRENT_API_VERSION}).
|
||||
\
|
||||
This will prevent proc-macro expansion from working. \
|
||||
Please consider updating your rust-analyzer to ensure compatibility with your \
|
||||
current toolchain."
|
||||
),
|
||||
)),
|
||||
Ok(v) if v < RUST_ANALYZER_SPAN_SUPPORT => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"The version of the proc-macro server ({v}) in your Rust toolchain \
|
||||
is too old and no longer supported by your rust-analyzer which requires\
|
||||
version {RUST_ANALYZER_SPAN_SUPPORT} or higher.
|
||||
\
|
||||
This will prevent proc-macro expansion from working. \
|
||||
Please consider updating your toolchain or downgrading your rust-analyzer \
|
||||
to ensure compatibility with your current toolchain."
|
||||
format!( "The version of the proc-macro server ({v}) in your Rust toolchain is newer than the version supported by your rust-analyzer ({CURRENT_API_VERSION}).
|
||||
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain."
|
||||
),
|
||||
)),
|
||||
Ok(v) => {
|
||||
|
@ -89,10 +72,10 @@ impl ProcMacroProcessSrv {
|
|||
tracing::info!("Proc-macro server span mode: {:?}", srv.mode);
|
||||
Ok(srv)
|
||||
}
|
||||
Err(e) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to fetch proc-macro server version: {e}"),
|
||||
)),
|
||||
Err(e) => {
|
||||
tracing::info!(%e, "proc-macro version check failed, restarting and assuming version 0");
|
||||
create_srv(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ stdx.workspace = true
|
|||
tt.workspace = true
|
||||
syntax-bridge.workspace = true
|
||||
paths.workspace = true
|
||||
base-db.workspace = true
|
||||
span.workspace = true
|
||||
# span = {workspace = true, default-features = false} does not work
|
||||
span = { path = "../span", version = "0.0.0", default-features = false}
|
||||
proc-macro-api.workspace = true
|
||||
intern.workspace = true
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ rustc-hash.workspace = true
|
|||
semver.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
tracing.workspace = true
|
||||
triomphe.workspace = true
|
||||
la-arena.workspace = true
|
||||
|
|
|
@ -15,7 +15,7 @@ use itertools::Itertools;
|
|||
use la_arena::ArenaMap;
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::Deserialize;
|
||||
use serde::Deserialize as _;
|
||||
use toolchain::Tool;
|
||||
|
||||
use crate::{
|
||||
|
|
|
@ -8,7 +8,7 @@ use cargo_metadata::{CargoOpt, MetadataCommand};
|
|||
use la_arena::{Arena, Idx};
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::Deserialize;
|
||||
use serde_derive::Deserialize;
|
||||
use serde_json::from_value;
|
||||
use span::Edition;
|
||||
use toolchain::Tool;
|
||||
|
|
|
@ -20,7 +20,7 @@ parking_lot = "0.12.1"
|
|||
rustc-hash = "2.0.0"
|
||||
smallvec = "1.0.0"
|
||||
oorandom = "11"
|
||||
triomphe = "0.1.11"
|
||||
triomphe.workspace = true
|
||||
itertools.workspace = true
|
||||
|
||||
ra-salsa-macros = { version = "0.0.0", path = "ra-salsa-macros", package = "salsa-macros" }
|
||||
|
|
|
@ -36,6 +36,7 @@ rayon.workspace = true
|
|||
rustc-hash.workspace = true
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
tenthash = "0.4.0"
|
||||
num_cpus = "1.15.0"
|
||||
mimalloc = { version = "0.1.30", default-features = false, optional = true }
|
||||
|
|
|
@ -644,7 +644,8 @@ config_data! {
|
|||
/// Aliased as `"checkOnSave.targets"`.
|
||||
check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = None,
|
||||
/// Whether `--workspace` should be passed to `cargo check`.
|
||||
/// If false, `-p <package>` will be passed instead.
|
||||
/// If false, `-p <package>` will be passed instead if applicable. In case it is not, no
|
||||
/// check will be performed.
|
||||
check_workspace: bool = true,
|
||||
|
||||
/// These proc-macros will be ignored when trying to expand them.
|
||||
|
|
|
@ -3,6 +3,7 @@ pub(crate) mod to_proto;
|
|||
|
||||
use std::mem;
|
||||
|
||||
use cargo_metadata::PackageId;
|
||||
use ide::FileId;
|
||||
use ide_db::FxHashMap;
|
||||
use itertools::Itertools;
|
||||
|
@ -13,7 +14,8 @@ use triomphe::Arc;
|
|||
|
||||
use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext, main_loop::DiagnosticsTaskKind};
|
||||
|
||||
pub(crate) type CheckFixes = Arc<IntMap<usize, IntMap<FileId, Vec<Fix>>>>;
|
||||
pub(crate) type CheckFixes =
|
||||
Arc<IntMap<usize, FxHashMap<Option<Arc<PackageId>>, IntMap<FileId, Vec<Fix>>>>>;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct DiagnosticsMapConfig {
|
||||
|
@ -31,7 +33,10 @@ pub(crate) struct DiagnosticCollection {
|
|||
pub(crate) native_syntax: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
|
||||
pub(crate) native_semantic: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
|
||||
// FIXME: should be Vec<flycheck::Diagnostic>
|
||||
pub(crate) check: IntMap<usize, IntMap<FileId, Vec<lsp_types::Diagnostic>>>,
|
||||
pub(crate) check: IntMap<
|
||||
usize,
|
||||
FxHashMap<Option<Arc<PackageId>>, IntMap<FileId, Vec<lsp_types::Diagnostic>>>,
|
||||
>,
|
||||
pub(crate) check_fixes: CheckFixes,
|
||||
changes: IntSet<FileId>,
|
||||
/// Counter for supplying a new generation number for diagnostics.
|
||||
|
@ -50,18 +55,37 @@ pub(crate) struct Fix {
|
|||
|
||||
impl DiagnosticCollection {
|
||||
pub(crate) fn clear_check(&mut self, flycheck_id: usize) {
|
||||
if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) {
|
||||
it.clear();
|
||||
}
|
||||
if let Some(it) = self.check.get_mut(&flycheck_id) {
|
||||
self.changes.extend(it.drain().map(|(key, _value)| key));
|
||||
let Some(check) = self.check.get_mut(&flycheck_id) else {
|
||||
return;
|
||||
};
|
||||
self.changes.extend(check.drain().flat_map(|(_, v)| v.into_keys()));
|
||||
if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) {
|
||||
fixes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clear_check_all(&mut self) {
|
||||
Arc::make_mut(&mut self.check_fixes).clear();
|
||||
self.changes
|
||||
.extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key)))
|
||||
self.changes.extend(
|
||||
self.check.values_mut().flat_map(|it| it.drain().flat_map(|(_, v)| v.into_keys())),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn clear_check_for_package(
|
||||
&mut self,
|
||||
flycheck_id: usize,
|
||||
package_id: Arc<PackageId>,
|
||||
) {
|
||||
let Some(check) = self.check.get_mut(&flycheck_id) else {
|
||||
return;
|
||||
};
|
||||
let package_id = Some(package_id);
|
||||
if let Some(checks) = check.remove(&package_id) {
|
||||
self.changes.extend(checks.into_keys());
|
||||
}
|
||||
if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) {
|
||||
fixes.remove(&package_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
|
||||
|
@ -73,11 +97,19 @@ impl DiagnosticCollection {
|
|||
pub(crate) fn add_check_diagnostic(
|
||||
&mut self,
|
||||
flycheck_id: usize,
|
||||
package_id: &Option<Arc<PackageId>>,
|
||||
file_id: FileId,
|
||||
diagnostic: lsp_types::Diagnostic,
|
||||
fix: Option<Box<Fix>>,
|
||||
) {
|
||||
let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default();
|
||||
let diagnostics = self
|
||||
.check
|
||||
.entry(flycheck_id)
|
||||
.or_default()
|
||||
.entry(package_id.clone())
|
||||
.or_default()
|
||||
.entry(file_id)
|
||||
.or_default();
|
||||
for existing_diagnostic in diagnostics.iter() {
|
||||
if are_diagnostics_equal(existing_diagnostic, &diagnostic) {
|
||||
return;
|
||||
|
@ -86,7 +118,14 @@ impl DiagnosticCollection {
|
|||
|
||||
if let Some(fix) = fix {
|
||||
let check_fixes = Arc::make_mut(&mut self.check_fixes);
|
||||
check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().push(*fix);
|
||||
check_fixes
|
||||
.entry(flycheck_id)
|
||||
.or_default()
|
||||
.entry(package_id.clone())
|
||||
.or_default()
|
||||
.entry(file_id)
|
||||
.or_default()
|
||||
.push(*fix);
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
self.changes.insert(file_id);
|
||||
|
@ -135,7 +174,12 @@ impl DiagnosticCollection {
|
|||
) -> impl Iterator<Item = &lsp_types::Diagnostic> {
|
||||
let native_syntax = self.native_syntax.get(&file_id).into_iter().flat_map(|(_, d)| d);
|
||||
let native_semantic = self.native_semantic.get(&file_id).into_iter().flat_map(|(_, d)| d);
|
||||
let check = self.check.values().filter_map(move |it| it.get(&file_id)).flatten();
|
||||
let check = self
|
||||
.check
|
||||
.values()
|
||||
.flat_map(|it| it.values())
|
||||
.filter_map(move |it| it.get(&file_id))
|
||||
.flatten();
|
||||
native_syntax.chain(native_semantic).chain(check)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
//! Flycheck provides the functionality needed to run `cargo check` to provide
|
||||
//! LSP diagnostics based on the output of the command.
|
||||
|
||||
use std::{fmt, io, process::Command, time::Duration};
|
||||
use std::{fmt, io, mem, process::Command, time::Duration};
|
||||
|
||||
use cargo_metadata::PackageId;
|
||||
use crossbeam_channel::{select_biased, unbounded, Receiver, Sender};
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize;
|
||||
use serde::Deserialize as _;
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
pub(crate) use cargo_metadata::diagnostic::{
|
||||
Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
|
||||
};
|
||||
use toolchain::Tool;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::command::{CommandHandle, ParseFromLine};
|
||||
|
||||
|
@ -150,10 +153,19 @@ impl FlycheckHandle {
|
|||
|
||||
pub(crate) enum FlycheckMessage {
|
||||
/// Request adding a diagnostic with fixes included to a file
|
||||
AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
|
||||
AddDiagnostic {
|
||||
id: usize,
|
||||
workspace_root: Arc<AbsPathBuf>,
|
||||
diagnostic: Diagnostic,
|
||||
package_id: Option<Arc<PackageId>>,
|
||||
},
|
||||
|
||||
/// Request clearing all previous diagnostics
|
||||
ClearDiagnostics { id: usize },
|
||||
/// Request clearing all outdated diagnostics.
|
||||
ClearDiagnostics {
|
||||
id: usize,
|
||||
/// The package whose diagnostics to clear, or if unspecified, all diagnostics.
|
||||
package_id: Option<Arc<PackageId>>,
|
||||
},
|
||||
|
||||
/// Request check progress notification to client
|
||||
Progress {
|
||||
|
@ -166,15 +178,18 @@ pub(crate) enum FlycheckMessage {
|
|||
impl fmt::Debug for FlycheckMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => f
|
||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => f
|
||||
.debug_struct("AddDiagnostic")
|
||||
.field("id", id)
|
||||
.field("workspace_root", workspace_root)
|
||||
.field("package_id", package_id)
|
||||
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
|
||||
.finish(),
|
||||
FlycheckMessage::ClearDiagnostics { id } => {
|
||||
f.debug_struct("ClearDiagnostics").field("id", id).finish()
|
||||
}
|
||||
FlycheckMessage::ClearDiagnostics { id, package_id } => f
|
||||
.debug_struct("ClearDiagnostics")
|
||||
.field("id", id)
|
||||
.field("package_id", package_id)
|
||||
.finish(),
|
||||
FlycheckMessage::Progress { id, progress } => {
|
||||
f.debug_struct("Progress").field("id", id).field("progress", progress).finish()
|
||||
}
|
||||
|
@ -200,12 +215,13 @@ enum StateChange {
|
|||
struct FlycheckActor {
|
||||
/// The workspace id of this flycheck instance.
|
||||
id: usize,
|
||||
|
||||
sender: Sender<FlycheckMessage>,
|
||||
config: FlycheckConfig,
|
||||
manifest_path: Option<AbsPathBuf>,
|
||||
/// Either the workspace root of the workspace we are flychecking,
|
||||
/// or the project root of the project.
|
||||
root: AbsPathBuf,
|
||||
root: Arc<AbsPathBuf>,
|
||||
sysroot_root: Option<AbsPathBuf>,
|
||||
/// CargoHandle exists to wrap around the communication needed to be able to
|
||||
/// run `cargo check` without blocking. Currently the Rust standard library
|
||||
|
@ -215,8 +231,13 @@ struct FlycheckActor {
|
|||
command_handle: Option<CommandHandle<CargoCheckMessage>>,
|
||||
/// The receiver side of the channel mentioned above.
|
||||
command_receiver: Option<Receiver<CargoCheckMessage>>,
|
||||
package_status: FxHashMap<Arc<PackageId>, DiagnosticReceived>,
|
||||
}
|
||||
|
||||
status: FlycheckStatus,
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
enum DiagnosticReceived {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
|
@ -225,13 +246,6 @@ enum Event {
|
|||
CheckEvent(Option<CargoCheckMessage>),
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum FlycheckStatus {
|
||||
Started,
|
||||
DiagnosticSent,
|
||||
Finished,
|
||||
}
|
||||
|
||||
pub(crate) const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
|
||||
|
||||
impl FlycheckActor {
|
||||
|
@ -249,11 +263,11 @@ impl FlycheckActor {
|
|||
sender,
|
||||
config,
|
||||
sysroot_root,
|
||||
root: workspace_root,
|
||||
root: Arc::new(workspace_root),
|
||||
manifest_path,
|
||||
command_handle: None,
|
||||
command_receiver: None,
|
||||
status: FlycheckStatus::Finished,
|
||||
package_status: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,13 +320,11 @@ impl FlycheckActor {
|
|||
self.command_handle = Some(command_handle);
|
||||
self.command_receiver = Some(receiver);
|
||||
self.report_progress(Progress::DidStart);
|
||||
self.status = FlycheckStatus::Started;
|
||||
}
|
||||
Err(error) => {
|
||||
self.report_progress(Progress::DidFailToRestart(format!(
|
||||
"Failed to run the following command: {formatted_command} error={error}"
|
||||
)));
|
||||
self.status = FlycheckStatus::Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,37 +344,62 @@ impl FlycheckActor {
|
|||
error
|
||||
);
|
||||
}
|
||||
if self.status == FlycheckStatus::Started {
|
||||
self.send(FlycheckMessage::ClearDiagnostics { id: self.id });
|
||||
if self.package_status.is_empty() {
|
||||
// We finished without receiving any diagnostics.
|
||||
// That means all of them are stale.
|
||||
self.send(FlycheckMessage::ClearDiagnostics {
|
||||
id: self.id,
|
||||
package_id: None,
|
||||
});
|
||||
} else {
|
||||
for (package_id, status) in mem::take(&mut self.package_status) {
|
||||
if let DiagnosticReceived::No = status {
|
||||
self.send(FlycheckMessage::ClearDiagnostics {
|
||||
id: self.id,
|
||||
package_id: Some(package_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.report_progress(Progress::DidFinish(res));
|
||||
self.status = FlycheckStatus::Finished;
|
||||
}
|
||||
Event::CheckEvent(Some(message)) => match message {
|
||||
CargoCheckMessage::CompilerArtifact(msg) => {
|
||||
tracing::trace!(
|
||||
flycheck_id = self.id,
|
||||
artifact = msg.target.name,
|
||||
package_id = msg.package_id.repr,
|
||||
"artifact received"
|
||||
);
|
||||
self.report_progress(Progress::DidCheckCrate(msg.target.name));
|
||||
self.package_status
|
||||
.entry(Arc::new(msg.package_id))
|
||||
.or_insert(DiagnosticReceived::No);
|
||||
}
|
||||
|
||||
CargoCheckMessage::Diagnostic(msg) => {
|
||||
CargoCheckMessage::Diagnostic { diagnostic, package_id } => {
|
||||
tracing::trace!(
|
||||
flycheck_id = self.id,
|
||||
message = msg.message,
|
||||
message = diagnostic.message,
|
||||
package_id = package_id.as_ref().map(|it| &it.repr),
|
||||
"diagnostic received"
|
||||
);
|
||||
if self.status == FlycheckStatus::Started {
|
||||
self.send(FlycheckMessage::ClearDiagnostics { id: self.id });
|
||||
if let Some(package_id) = &package_id {
|
||||
if !self.package_status.contains_key(package_id) {
|
||||
self.package_status
|
||||
.insert(package_id.clone(), DiagnosticReceived::Yes);
|
||||
self.send(FlycheckMessage::ClearDiagnostics {
|
||||
id: self.id,
|
||||
package_id: Some(package_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
self.send(FlycheckMessage::AddDiagnostic {
|
||||
id: self.id,
|
||||
package_id,
|
||||
workspace_root: self.root.clone(),
|
||||
diagnostic: msg,
|
||||
diagnostic,
|
||||
});
|
||||
self.status = FlycheckStatus::DiagnosticSent;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -380,7 +417,7 @@ impl FlycheckActor {
|
|||
command_handle.cancel();
|
||||
self.command_receiver.take();
|
||||
self.report_progress(Progress::DidCancel);
|
||||
self.status = FlycheckStatus::Finished;
|
||||
self.package_status.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,7 +437,7 @@ impl FlycheckActor {
|
|||
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
|
||||
}
|
||||
cmd.arg(command);
|
||||
cmd.current_dir(&self.root);
|
||||
cmd.current_dir(&*self.root);
|
||||
|
||||
match package {
|
||||
Some(pkg) => cmd.arg("-p").arg(pkg),
|
||||
|
@ -442,11 +479,11 @@ impl FlycheckActor {
|
|||
|
||||
match invocation_strategy {
|
||||
InvocationStrategy::Once => {
|
||||
cmd.current_dir(&self.root);
|
||||
cmd.current_dir(&*self.root);
|
||||
}
|
||||
InvocationStrategy::PerWorkspace => {
|
||||
// FIXME: cmd.current_dir(&affected_workspace);
|
||||
cmd.current_dir(&self.root);
|
||||
cmd.current_dir(&*self.root);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,7 +523,7 @@ impl FlycheckActor {
|
|||
#[allow(clippy::large_enum_variant)]
|
||||
enum CargoCheckMessage {
|
||||
CompilerArtifact(cargo_metadata::Artifact),
|
||||
Diagnostic(Diagnostic),
|
||||
Diagnostic { diagnostic: Diagnostic, package_id: Option<Arc<PackageId>> },
|
||||
}
|
||||
|
||||
impl ParseFromLine for CargoCheckMessage {
|
||||
|
@ -501,11 +538,16 @@ impl ParseFromLine for CargoCheckMessage {
|
|||
Some(CargoCheckMessage::CompilerArtifact(artifact))
|
||||
}
|
||||
cargo_metadata::Message::CompilerMessage(msg) => {
|
||||
Some(CargoCheckMessage::Diagnostic(msg.message))
|
||||
Some(CargoCheckMessage::Diagnostic {
|
||||
diagnostic: msg.message,
|
||||
package_id: Some(Arc::new(msg.package_id)),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
JsonMessage::Rustc(message) => Some(CargoCheckMessage::Diagnostic(message)),
|
||||
JsonMessage::Rustc(message) => {
|
||||
Some(CargoCheckMessage::Diagnostic { diagnostic: message, package_id: None })
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ pub(crate) struct GlobalState {
|
|||
|
||||
// status
|
||||
pub(crate) shutdown_requested: bool,
|
||||
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
|
||||
pub(crate) last_reported_status: lsp_ext::ServerStatusParams,
|
||||
|
||||
// proc macros
|
||||
pub(crate) proc_macro_clients: Arc<[anyhow::Result<ProcMacroServer>]>,
|
||||
|
@ -238,7 +238,11 @@ impl GlobalState {
|
|||
mem_docs: MemDocs::default(),
|
||||
semantic_tokens_cache: Arc::new(Default::default()),
|
||||
shutdown_requested: false,
|
||||
last_reported_status: None,
|
||||
last_reported_status: lsp_ext::ServerStatusParams {
|
||||
health: lsp_ext::Health::Ok,
|
||||
quiescent: true,
|
||||
message: None,
|
||||
},
|
||||
source_root_config: SourceRootConfig::default(),
|
||||
local_roots_parent_map: Arc::new(FxHashMap::default()),
|
||||
config_errors: Default::default(),
|
||||
|
|
|
@ -126,7 +126,7 @@ impl RequestDispatcher<'_> {
|
|||
|
||||
/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
|
||||
/// ready this will return a `default` constructed [`R::Result`].
|
||||
pub(crate) fn on_with<R>(
|
||||
pub(crate) fn on_with_vfs_default<R>(
|
||||
&mut self,
|
||||
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
|
||||
default: impl FnOnce() -> R::Result,
|
||||
|
|
|
@ -189,7 +189,7 @@ pub(crate) fn handle_did_save_text_document(
|
|||
if !state.config.check_on_save(Some(sr)) || run_flycheck(state, vfs_path) {
|
||||
return Ok(());
|
||||
}
|
||||
} else if state.config.check_on_save(None) {
|
||||
} else if state.config.check_on_save(None) && state.config.flycheck_workspace(None) {
|
||||
// No specific flycheck was triggered, so let's trigger all of them.
|
||||
for flycheck in state.flycheck.iter() {
|
||||
flycheck.restart_workspace(None);
|
||||
|
@ -293,7 +293,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
|
|||
let file_id = state.vfs.read().0.file_id(&vfs_path);
|
||||
if let Some(file_id) = file_id {
|
||||
let world = state.snapshot();
|
||||
let source_root_id = world.analysis.source_root_id(file_id).ok();
|
||||
let may_flycheck_workspace = state.config.flycheck_workspace(None);
|
||||
let mut updated = false;
|
||||
let task = move || -> std::result::Result<(), ide::Cancelled> {
|
||||
// Is the target binary? If so we let flycheck run only for the workspace that contains the crate.
|
||||
|
@ -375,21 +375,22 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
|
|||
let saved_file = vfs_path.as_path().map(|p| p.to_owned());
|
||||
|
||||
// Find and trigger corresponding flychecks
|
||||
for flycheck in world.flycheck.iter() {
|
||||
'flychecks: for flycheck in world.flycheck.iter() {
|
||||
for (id, package) in workspace_ids.clone() {
|
||||
if id == flycheck.id() {
|
||||
updated = true;
|
||||
match package.filter(|_| !world.config.flycheck_workspace(source_root_id)) {
|
||||
Some(package) => flycheck
|
||||
.restart_for_package(package, target.clone().map(TupleExt::head)),
|
||||
None => flycheck.restart_workspace(saved_file.clone()),
|
||||
if may_flycheck_workspace {
|
||||
flycheck.restart_workspace(saved_file.clone())
|
||||
} else if let Some(package) = package {
|
||||
flycheck
|
||||
.restart_for_package(package, target.clone().map(TupleExt::head))
|
||||
}
|
||||
continue;
|
||||
continue 'flychecks;
|
||||
}
|
||||
}
|
||||
}
|
||||
// No specific flycheck was triggered, so let's trigger all of them.
|
||||
if !updated {
|
||||
if !updated && may_flycheck_workspace {
|
||||
for flycheck in world.flycheck.iter() {
|
||||
flycheck.restart_workspace(saved_file.clone());
|
||||
}
|
||||
|
@ -432,8 +433,10 @@ pub(crate) fn handle_run_flycheck(
|
|||
}
|
||||
}
|
||||
// No specific flycheck was triggered, so let's trigger all of them.
|
||||
for flycheck in state.flycheck.iter() {
|
||||
flycheck.restart_workspace(None);
|
||||
if state.config.flycheck_workspace(None) {
|
||||
for flycheck in state.flycheck.iter() {
|
||||
flycheck.restart_workspace(None);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -481,27 +481,28 @@ pub(crate) fn handle_document_diagnostics(
|
|||
snap: GlobalStateSnapshot,
|
||||
params: lsp_types::DocumentDiagnosticParams,
|
||||
) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
|
||||
const EMPTY: lsp_types::DocumentDiagnosticReportResult =
|
||||
let empty = || {
|
||||
lsp_types::DocumentDiagnosticReportResult::Report(
|
||||
lsp_types::DocumentDiagnosticReport::Full(
|
||||
lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||
related_documents: None,
|
||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||
result_id: None,
|
||||
result_id: Some("rust-analyzer".to_owned()),
|
||||
items: vec![],
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?;
|
||||
let source_root = snap.analysis.source_root_id(file_id)?;
|
||||
if !snap.analysis.is_local_source_root(source_root)? {
|
||||
return Ok(EMPTY);
|
||||
return Ok(empty());
|
||||
}
|
||||
let config = snap.config.diagnostics(Some(source_root));
|
||||
if !config.enabled {
|
||||
return Ok(EMPTY);
|
||||
return Ok(empty());
|
||||
}
|
||||
let line_index = snap.file_line_index(file_id)?;
|
||||
let supports_related = snap.config.text_document_diagnostic_related_document_support();
|
||||
|
@ -529,7 +530,7 @@ pub(crate) fn handle_document_diagnostics(
|
|||
Ok(lsp_types::DocumentDiagnosticReportResult::Report(
|
||||
lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||
result_id: None,
|
||||
result_id: Some("rust-analyzer".to_owned()),
|
||||
items: diagnostics.collect(),
|
||||
},
|
||||
related_documents: related_documents.is_empty().not().then(|| {
|
||||
|
@ -539,7 +540,10 @@ pub(crate) fn handle_document_diagnostics(
|
|||
(
|
||||
to_proto::url(&snap, id),
|
||||
lsp_types::DocumentDiagnosticReportKind::Full(
|
||||
lsp_types::FullDocumentDiagnosticReport { result_id: None, items },
|
||||
lsp_types::FullDocumentDiagnosticReport {
|
||||
result_id: Some("rust-analyzer".to_owned()),
|
||||
items,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
|
@ -1144,7 +1148,7 @@ pub(crate) fn handle_completion_resolve(
|
|||
let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
|
||||
// Avoid computing hashes for items that obviously do not match
|
||||
// r-a might append a detail-based suffix to the label, so we cannot check for equality
|
||||
original_completion.label.starts_with(completion_item.label.as_str())
|
||||
original_completion.label.starts_with(completion_item.label.primary.as_str())
|
||||
&& resolve_data_hash == completion_item_hash(completion_item, resolve_data.for_ref)
|
||||
}) else {
|
||||
return Ok(original_completion);
|
||||
|
@ -1441,7 +1445,13 @@ pub(crate) fn handle_code_action(
|
|||
}
|
||||
|
||||
// Fixes from `cargo check`.
|
||||
for fix in snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).flatten() {
|
||||
for fix in snap
|
||||
.check_fixes
|
||||
.values()
|
||||
.flat_map(|it| it.values())
|
||||
.filter_map(|it| it.get(&frange.file_id))
|
||||
.flatten()
|
||||
{
|
||||
// FIXME: this mapping is awkward and shouldn't exist. Refactor
|
||||
// `snap.check_fixes` to not convert to LSP prematurely.
|
||||
let intersect_fix_range = fix
|
||||
|
|
|
@ -114,8 +114,11 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
|
|||
u8::from(item.deprecated),
|
||||
u8::from(item.trigger_call_info),
|
||||
]);
|
||||
hasher.update(&item.label);
|
||||
if let Some(label_detail) = &item.label_detail {
|
||||
hasher.update(&item.label.primary);
|
||||
if let Some(label_detail) = &item.label.detail_left {
|
||||
hasher.update(label_detail);
|
||||
}
|
||||
if let Some(label_detail) = &item.label.detail_right {
|
||||
hasher.update(label_detail);
|
||||
}
|
||||
// NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
|
||||
|
|
|
@ -823,8 +823,11 @@ impl Request for OnTypeFormatting {
|
|||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CompletionResolveData {
|
||||
pub position: lsp_types::TextDocumentPositionParams,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub imports: Vec<CompletionImport>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub version: Option<i32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub trigger_character: Option<char>,
|
||||
pub for_ref: bool,
|
||||
pub hash: String,
|
||||
|
@ -836,6 +839,7 @@ pub struct InlayHintResolveData {
|
|||
// This is a string instead of a u64 as javascript can't represent u64 fully
|
||||
pub hash: String,
|
||||
pub resolve_range: lsp_types::Range,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub version: Option<i32>,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
use std::{
|
||||
iter::once,
|
||||
mem,
|
||||
ops::Not as _,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
|
@ -353,14 +354,17 @@ fn completion_item(
|
|||
};
|
||||
|
||||
let mut lsp_item = lsp_types::CompletionItem {
|
||||
label: item.label.to_string(),
|
||||
label: item.label.primary.to_string(),
|
||||
detail,
|
||||
filter_text,
|
||||
kind: Some(completion_item_kind(item.kind)),
|
||||
text_edit,
|
||||
additional_text_edits: Some(additional_text_edits),
|
||||
additional_text_edits: additional_text_edits
|
||||
.is_empty()
|
||||
.not()
|
||||
.then_some(additional_text_edits),
|
||||
documentation,
|
||||
deprecated: Some(item.deprecated),
|
||||
deprecated: item.deprecated.then_some(item.deprecated),
|
||||
tags,
|
||||
command,
|
||||
insert_text_format,
|
||||
|
@ -368,15 +372,17 @@ fn completion_item(
|
|||
};
|
||||
|
||||
if config.completion_label_details_support() {
|
||||
let has_label_details =
|
||||
item.label.detail_left.is_some() || item.label.detail_right.is_some();
|
||||
if fields_to_resolve.resolve_label_details {
|
||||
something_to_resolve |= true;
|
||||
} else {
|
||||
something_to_resolve |= has_label_details;
|
||||
} else if has_label_details {
|
||||
lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
|
||||
detail: item.label_detail.as_ref().map(ToString::to_string),
|
||||
description: item.detail.clone(),
|
||||
detail: item.label.detail_left.clone(),
|
||||
description: item.label.detail_right.clone(),
|
||||
});
|
||||
}
|
||||
} else if let Some(label_detail) = &item.label_detail {
|
||||
} else if let Some(label_detail) = &item.label.detail_left {
|
||||
lsp_item.label.push_str(label_detail.as_str());
|
||||
}
|
||||
|
||||
|
@ -1578,22 +1584,26 @@ pub(crate) fn code_lens(
|
|||
};
|
||||
|
||||
let lens_config = snap.config.lens();
|
||||
if lens_config.run && client_commands_config.run_single && has_root {
|
||||
let command = command::run_single(&r, &title);
|
||||
acc.push(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command: Some(command),
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
if lens_config.debug && can_debug && client_commands_config.debug_single {
|
||||
let command = command::debug_single(&r);
|
||||
acc.push(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command: Some(command),
|
||||
data: None,
|
||||
})
|
||||
|
||||
if has_root {
|
||||
if lens_config.run && client_commands_config.run_single {
|
||||
let command = command::run_single(&r, &title);
|
||||
acc.push(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command: Some(command),
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
if lens_config.debug && can_debug && client_commands_config.debug_single {
|
||||
let command = command::debug_single(&r);
|
||||
acc.push(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command: Some(command),
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if lens_config.interpret {
|
||||
let command = command::interpret_single(&r);
|
||||
acc.push(lsp_types::CodeLens {
|
||||
|
|
|
@ -408,7 +408,10 @@ impl GlobalState {
|
|||
if self.is_quiescent() {
|
||||
let became_quiescent = !was_quiescent;
|
||||
if became_quiescent {
|
||||
if self.config.check_on_save(None) {
|
||||
if self.config.check_on_save(None)
|
||||
&& self.config.flycheck_workspace(None)
|
||||
&& !self.fetch_build_data_queue.op_requested()
|
||||
{
|
||||
// Project has loaded properly, kick off initial flycheck
|
||||
self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
|
||||
}
|
||||
|
@ -656,8 +659,8 @@ impl GlobalState {
|
|||
|
||||
fn update_status_or_notify(&mut self) {
|
||||
let status = self.current_status();
|
||||
if self.last_reported_status.as_ref() != Some(&status) {
|
||||
self.last_reported_status = Some(status.clone());
|
||||
if self.last_reported_status != status {
|
||||
self.last_reported_status = status.clone();
|
||||
|
||||
if self.config.server_status_notification() {
|
||||
self.send_notification::<lsp_ext::ServerStatusNotification>(status);
|
||||
|
@ -715,6 +718,7 @@ impl GlobalState {
|
|||
error!("FetchWorkspaceError: {e}");
|
||||
}
|
||||
self.wants_to_switch = Some("fetched workspace".to_owned());
|
||||
self.diagnostics.clear_check_all();
|
||||
(Progress::End, None)
|
||||
}
|
||||
};
|
||||
|
@ -956,7 +960,7 @@ impl GlobalState {
|
|||
|
||||
fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
|
||||
match message {
|
||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => {
|
||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => {
|
||||
let snap = self.snapshot();
|
||||
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
|
||||
&self.config.diagnostics_map(None),
|
||||
|
@ -968,6 +972,7 @@ impl GlobalState {
|
|||
match url_to_file_id(&self.vfs.read().0, &diag.url) {
|
||||
Ok(file_id) => self.diagnostics.add_check_diagnostic(
|
||||
id,
|
||||
&package_id,
|
||||
file_id,
|
||||
diag.diagnostic,
|
||||
diag.fix,
|
||||
|
@ -981,9 +986,12 @@ impl GlobalState {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
FlycheckMessage::ClearDiagnostics { id } => self.diagnostics.clear_check(id),
|
||||
|
||||
FlycheckMessage::ClearDiagnostics { id, package_id: None } => {
|
||||
self.diagnostics.clear_check(id)
|
||||
}
|
||||
FlycheckMessage::ClearDiagnostics { id, package_id: Some(package_id) } => {
|
||||
self.diagnostics.clear_check_for_package(id, package_id)
|
||||
}
|
||||
FlycheckMessage::Progress { id, progress } => {
|
||||
let (state, message) = match progress {
|
||||
flycheck::Progress::DidStart => (Progress::Begin, None),
|
||||
|
@ -1090,12 +1098,12 @@ impl GlobalState {
|
|||
.on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
|
||||
// FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
|
||||
// All other request handlers
|
||||
.on_with::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
|
||||
.on_with_vfs_default::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
|
||||
lsp_types::DocumentDiagnosticReport::Full(
|
||||
lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||
related_documents: None,
|
||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||
result_id: None,
|
||||
result_id: Some("rust-analyzer".to_owned()),
|
||||
items: vec![],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -70,7 +70,6 @@ impl GlobalState {
|
|||
/// are ready to do semantic work.
|
||||
pub(crate) fn is_quiescent(&self) -> bool {
|
||||
self.vfs_done
|
||||
&& self.last_reported_status.is_some()
|
||||
&& !self.fetch_workspaces_queue.op_in_progress()
|
||||
&& !self.fetch_build_data_queue.op_in_progress()
|
||||
&& !self.fetch_proc_macros_queue.op_in_progress()
|
||||
|
|
|
@ -5,7 +5,8 @@ use std::process::Command;
|
|||
|
||||
use crossbeam_channel::Sender;
|
||||
use paths::AbsPath;
|
||||
use serde::Deserialize;
|
||||
use serde::Deserialize as _;
|
||||
use serde_derive::Deserialize;
|
||||
use toolchain::Tool;
|
||||
|
||||
use crate::{
|
||||
|
|
|
@ -54,7 +54,7 @@ where
|
|||
fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {}
|
||||
|
||||
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde_derive::Serialize)]
|
||||
struct JsonDataInner {
|
||||
name: &'static str,
|
||||
elapsed_ms: u128,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
env, fs,
|
||||
sync::{Once, OnceLock},
|
||||
sync::Once,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
|
@ -141,34 +141,15 @@ impl Project<'_> {
|
|||
/// file in the config dir after server is run, something where our naive approach comes short.
|
||||
/// Using a `prelock` allows us to force a lock when we know we need it.
|
||||
pub(crate) fn server_with_lock(self, config_lock: bool) -> Server {
|
||||
static CONFIG_DIR_LOCK: OnceLock<(Utf8PathBuf, Mutex<()>)> = OnceLock::new();
|
||||
static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
let config_dir_guard = if config_lock {
|
||||
Some({
|
||||
let (path, mutex) = CONFIG_DIR_LOCK.get_or_init(|| {
|
||||
let value = TestDir::new().keep().path().to_owned();
|
||||
env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
|
||||
(value, Mutex::new(()))
|
||||
});
|
||||
#[allow(dyn_drop)]
|
||||
(mutex.lock(), {
|
||||
Box::new({
|
||||
struct Dropper(Utf8PathBuf);
|
||||
impl Drop for Dropper {
|
||||
fn drop(&mut self) {
|
||||
for entry in fs::read_dir(&self.0).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
if path.is_file() {
|
||||
fs::remove_file(path).unwrap();
|
||||
} else if path.is_dir() {
|
||||
fs::remove_dir_all(path).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Dropper(path.clone())
|
||||
}) as Box<dyn Drop>
|
||||
})
|
||||
let guard = CONFIG_DIR_LOCK.lock();
|
||||
let test_dir = TestDir::new();
|
||||
let value = test_dir.path().to_owned();
|
||||
env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
|
||||
(guard, test_dir)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -311,14 +292,12 @@ pub(crate) struct Server {
|
|||
client: Connection,
|
||||
/// XXX: remove the tempdir last
|
||||
dir: TestDir,
|
||||
#[allow(dyn_drop)]
|
||||
_config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>,
|
||||
_config_dir_guard: Option<(MutexGuard<'static, ()>, TestDir)>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
#[allow(dyn_drop)]
|
||||
fn new(
|
||||
config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>,
|
||||
config_dir_guard: Option<(MutexGuard<'static, ()>, TestDir)>,
|
||||
dir: TestDir,
|
||||
config: Config,
|
||||
) -> Server {
|
||||
|
|
|
@ -12,7 +12,7 @@ authors.workspace = true
|
|||
|
||||
[dependencies]
|
||||
la-arena.workspace = true
|
||||
ra-salsa.workspace = true
|
||||
ra-salsa = { workspace = true, optional = true }
|
||||
rustc-hash.workspace = true
|
||||
hashbrown.workspace = true
|
||||
text-size.workspace = true
|
||||
|
@ -22,5 +22,8 @@ vfs.workspace = true
|
|||
syntax.workspace = true
|
||||
stdx.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["ra-salsa"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(not(feature = "ra-salsa"))]
|
||||
use crate::InternId;
|
||||
#[cfg(feature = "ra-salsa")]
|
||||
use ra_salsa::{InternId, InternValue};
|
||||
|
||||
use crate::MacroCallId;
|
||||
|
@ -39,6 +42,7 @@ impl fmt::Debug for SyntaxContextId {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ra-salsa")]
|
||||
impl ra_salsa::InternKey for SyntaxContextId {
|
||||
fn from_intern_id(v: ra_salsa::InternId) -> Self {
|
||||
SyntaxContextId(v)
|
||||
|
@ -92,6 +96,7 @@ pub struct SyntaxContextData {
|
|||
pub opaque_and_semitransparent: SyntaxContextId,
|
||||
}
|
||||
|
||||
#[cfg(feature = "ra-salsa")]
|
||||
impl InternValue for SyntaxContextData {
|
||||
type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue