mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-26 03:45:04 +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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lsp-server"
|
|
||||||
version = "0.7.7"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"ctrlc",
|
|
||||||
"log",
|
|
||||||
"lsp-types",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsp-server"
|
name = "lsp-server"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
|
@ -1032,6 +1020,19 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lsp-server"
|
||||||
|
version = "0.7.8"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"ctrlc",
|
||||||
|
"log",
|
||||||
|
"lsp-types",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsp-types"
|
name = "lsp-types"
|
||||||
version = "0.95.0"
|
version = "0.95.0"
|
||||||
|
@ -1289,7 +1290,6 @@ name = "paths"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"camino",
|
"camino",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1352,12 +1352,12 @@ dependencies = [
|
||||||
name = "proc-macro-api"
|
name = "proc-macro-api"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base-db",
|
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"intern",
|
"intern",
|
||||||
"paths",
|
"paths",
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"span",
|
"span",
|
||||||
"stdx",
|
"stdx",
|
||||||
|
@ -1369,7 +1369,6 @@ dependencies = [
|
||||||
name = "proc-macro-srv"
|
name = "proc-macro-srv"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base-db",
|
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"intern",
|
"intern",
|
||||||
"libloading",
|
"libloading",
|
||||||
|
@ -1448,6 +1447,7 @@ dependencies = [
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"span",
|
"span",
|
||||||
"stdx",
|
"stdx",
|
||||||
|
@ -1507,9 +1507,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_abi"
|
name = "ra-ap-rustc_abi"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af462c3a2d524b84a51b6848b439787f01b35c6c1086d3e3086a5f5eea92ed9a"
|
checksum = "28b782af0a7a8df16ddf43cd70da9f17bc3b1ce712c9e4992b6edb16f5f53632"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"ra-ap-rustc_index",
|
"ra-ap-rustc_index",
|
||||||
|
@ -1518,9 +1518,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_index"
|
name = "ra-ap-rustc_index"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be6bb8cb0ab78d94a222f1ffd3e87254cdfb57413382b8d6ebe26a85482f99d1"
|
checksum = "ce5742f134960482f543b35ecebec3cacc6d79a9a685713518b4d8d70c5f9aa8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ra-ap-rustc_index_macros",
|
"ra-ap-rustc_index_macros",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
@ -1528,9 +1528,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_index_macros"
|
name = "ra-ap-rustc_index_macros"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c24b1641455b46e87435b7321219672077066e678963d239a4a2904732979b16"
|
checksum = "d7ea011fcf68309a8835ad01d91c032cb18444617b00e2cab21d45b208164441"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1539,9 +1539,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_lexer"
|
name = "ra-ap-rustc_lexer"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94daa86974417981fed2f12bd8fb00158dfa6fee561152bed689278c846d0272"
|
checksum = "eb76f0a4d4c20859e41f0a23bff0f37ab9ca9171c214a6c7dd72ea69434865dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-properties",
|
"unicode-properties",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
|
@ -1549,9 +1549,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_parse_format"
|
name = "ra-ap-rustc_parse_format"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc07f6bd581746f358e39c4b6bfe8d455b3d6ad1a857821016d0d42eeb5e1e3e"
|
checksum = "06080bd35078305421a62da77f3c128482d8d44441b6da8ce9d146d1cd9cdb5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ra-ap-rustc_index",
|
"ra-ap-rustc_index",
|
||||||
"ra-ap-rustc_lexer",
|
"ra-ap-rustc_lexer",
|
||||||
|
@ -1559,9 +1559,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra-ap-rustc_pattern_analysis"
|
name = "ra-ap-rustc_pattern_analysis"
|
||||||
version = "0.85.0"
|
version = "0.87.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f49b86e1276c1c3c72898410def29b699415f4e7d1dfb3531daf79794694372"
|
checksum = "68a3154fe4c20c177d7b3c678a2d3a97aba0cca156ddef88959915041889daf0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ra-ap-rustc_index",
|
"ra-ap-rustc_index",
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
|
@ -1676,7 +1676,7 @@ dependencies = [
|
||||||
"intern",
|
"intern",
|
||||||
"itertools",
|
"itertools",
|
||||||
"load-cargo",
|
"load-cargo",
|
||||||
"lsp-server 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lsp-server 0.7.7",
|
||||||
"lsp-types",
|
"lsp-types",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
|
@ -1695,6 +1695,7 @@ dependencies = [
|
||||||
"scip",
|
"scip",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"stdx",
|
"stdx",
|
||||||
"syntax",
|
"syntax",
|
||||||
|
@ -1822,18 +1823,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.206"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
|
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.206"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
|
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1924,12 +1925,6 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
|
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stable_deref_trait"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stdx"
|
name = "stdx"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -1946,9 +1941,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.74"
|
version = "2.0.87"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
|
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2264,13 +2259,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.13"
|
version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369"
|
checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"stable_deref_trait",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tt"
|
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" }
|
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||||
edition = { path = "./crates/edition", 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_lexer = { version = "0.87", default-features = false }
|
||||||
ra-ap-rustc_parse_format = { version = "0.85", default-features = false }
|
ra-ap-rustc_parse_format = { version = "0.87", default-features = false }
|
||||||
ra-ap-rustc_index = { version = "0.85", default-features = false }
|
ra-ap-rustc_index = { version = "0.87", default-features = false }
|
||||||
ra-ap-rustc_abi = { version = "0.85", default-features = false }
|
ra-ap-rustc_abi = { version = "0.87", default-features = false }
|
||||||
ra-ap-rustc_pattern_analysis = { version = "0.85", 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.
|
# local crates that aren't published to crates.io. These should not have versions.
|
||||||
test-fixture = { path = "./crates/test-fixture" }
|
test-fixture = { path = "./crates/test-fixture" }
|
||||||
|
@ -138,7 +138,8 @@ pulldown-cmark = { version = "0.9.0", default-features = false }
|
||||||
rayon = "1.8.0"
|
rayon = "1.8.0"
|
||||||
rustc-hash = "2.0.0"
|
rustc-hash = "2.0.0"
|
||||||
semver = "1.0.14"
|
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"
|
serde_json = "1.0.108"
|
||||||
smallvec = { version = "1.10.0", features = [
|
smallvec = { version = "1.10.0", features = [
|
||||||
"const_new",
|
"const_new",
|
||||||
|
@ -157,7 +158,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features =
|
||||||
"time",
|
"time",
|
||||||
"tracing-log",
|
"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"
|
url = "2.3.1"
|
||||||
xshell = "0.2.5"
|
xshell = "0.2.5"
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ use smallvec::SmallVec;
|
||||||
use span::{Edition, MacroFileId};
|
use span::{Edition, MacroFileId};
|
||||||
use syntax::{ast, AstPtr, SyntaxNodePtr};
|
use syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
use tt::TextRange;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
@ -143,15 +144,7 @@ pub struct BodySourceMap {
|
||||||
|
|
||||||
pub types: TypesSourceMap,
|
pub types: TypesSourceMap,
|
||||||
|
|
||||||
// FIXME: Make this a sane struct.
|
template_map: Option<Box<FormatTemplate>>,
|
||||||
template_map: Option<
|
|
||||||
Box<(
|
|
||||||
// format_args!
|
|
||||||
FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
|
|
||||||
// asm!
|
|
||||||
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
|
|
||||||
)>,
|
|
||||||
>,
|
|
||||||
|
|
||||||
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
|
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
|
||||||
|
|
||||||
|
@ -160,6 +153,20 @@ pub struct BodySourceMap {
|
||||||
diagnostics: Vec<BodyDiagnostic>,
|
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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum BodyDiagnostic {
|
pub enum BodyDiagnostic {
|
||||||
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
|
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
|
||||||
|
@ -798,18 +805,29 @@ impl BodySourceMap {
|
||||||
node: InFile<&ast::FormatArgsExpr>,
|
node: InFile<&ast::FormatArgsExpr>,
|
||||||
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
|
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
|
||||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||||
let (hygiene, names) =
|
let (hygiene, names) = self
|
||||||
self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
|
.template_map
|
||||||
|
.as_ref()?
|
||||||
|
.format_args_to_captures
|
||||||
|
.get(&self.expr_map.get(&src)?.as_expr()?)?;
|
||||||
Some((*hygiene, &**names))
|
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(
|
pub fn asm_template_args(
|
||||||
&self,
|
&self,
|
||||||
node: InFile<&ast::AsmExpr>,
|
node: InFile<&ast::AsmExpr>,
|
||||||
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
|
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
|
||||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||||
let expr = self.expr_map.get(&src)?.as_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.
|
/// Get a reference to the body source map's diagnostics.
|
||||||
|
@ -835,8 +853,14 @@ impl BodySourceMap {
|
||||||
types,
|
types,
|
||||||
} = self;
|
} = self;
|
||||||
if let Some(template_map) = template_map {
|
if let Some(template_map) = template_map {
|
||||||
template_map.0.shrink_to_fit();
|
let FormatTemplate {
|
||||||
template_map.1.shrink_to_fit();
|
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.shrink_to_fit();
|
||||||
expr_map_back.shrink_to_fit();
|
expr_map_back.shrink_to_fit();
|
||||||
|
|
|
@ -1957,8 +1957,10 @@ impl ExprCollector<'_> {
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let mut mappings = vec![];
|
let mut mappings = vec![];
|
||||||
let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) {
|
let (fmt, hygiene) = match template.and_then(|template| {
|
||||||
Some((s, is_direct_literal)) => {
|
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 call_ctx = self.expander.syntax_context();
|
||||||
let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
|
let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
|
||||||
let fmt = format_args::parse(
|
let fmt = format_args::parse(
|
||||||
|
@ -1966,8 +1968,18 @@ impl ExprCollector<'_> {
|
||||||
fmt_snippet,
|
fmt_snippet,
|
||||||
args,
|
args,
|
||||||
is_direct_literal,
|
is_direct_literal,
|
||||||
|name| {
|
|name, range| {
|
||||||
let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
|
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() {
|
if !hygiene.is_root() {
|
||||||
self.body.expr_hygiene.insert(expr_id, hygiene);
|
self.body.expr_hygiene.insert(expr_id, hygiene);
|
||||||
}
|
}
|
||||||
|
@ -2139,7 +2151,7 @@ impl ExprCollector<'_> {
|
||||||
self.source_map
|
self.source_map
|
||||||
.template_map
|
.template_map
|
||||||
.get_or_insert_with(Default::default)
|
.get_or_insert_with(Default::default)
|
||||||
.0
|
.format_args_to_captures
|
||||||
.insert(idx, (hygiene, mappings));
|
.insert(idx, (hygiene, mappings));
|
||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use syntax::{
|
||||||
ast::{self, HasName, IsString},
|
ast::{self, HasName, IsString},
|
||||||
AstNode, AstPtr, AstToken, T,
|
AstNode, AstPtr, AstToken, T,
|
||||||
};
|
};
|
||||||
use tt::{TextRange, TextSize};
|
use tt::TextRange;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::lower::{ExprCollector, FxIndexSet},
|
body::lower::{ExprCollector, FxIndexSet},
|
||||||
|
@ -224,7 +224,7 @@ impl ExprCollector<'_> {
|
||||||
TextRange::new(
|
TextRange::new(
|
||||||
inner_span.start.try_into().unwrap(),
|
inner_span.start.try_into().unwrap(),
|
||||||
inner_span.end.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 {
|
for piece in unverified_pieces {
|
||||||
|
@ -268,7 +268,11 @@ impl ExprCollector<'_> {
|
||||||
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
|
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
|
||||||
syntax_ptr,
|
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
|
idx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -685,6 +685,7 @@ impl Printer<'_> {
|
||||||
self.print_binding(*id);
|
self.print_binding(*id);
|
||||||
if let Some(pat) = subpat {
|
if let Some(pat) = subpat {
|
||||||
self.whitespace();
|
self.whitespace();
|
||||||
|
w!(self, "@ ");
|
||||||
self.print_pat(*pat);
|
self.print_pat(*pat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,3 +426,21 @@ fn f() {
|
||||||
"should have a binding for `B`",
|
"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.
|
//! Parses `format_args` input.
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use intern::Symbol;
|
use intern::Symbol;
|
||||||
use rustc_parse_format as parse;
|
use rustc_parse_format as parse;
|
||||||
|
@ -7,7 +8,7 @@ use span::SyntaxContextId;
|
||||||
use stdx::TupleExt;
|
use stdx::TupleExt;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, IsString},
|
ast::{self, IsString},
|
||||||
TextRange, TextSize,
|
TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::hir::ExprId;
|
use crate::hir::ExprId;
|
||||||
|
@ -33,7 +34,7 @@ pub enum FormatArgsPiece {
|
||||||
Placeholder(FormatPlaceholder),
|
Placeholder(FormatPlaceholder),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FormatPlaceholder {
|
pub struct FormatPlaceholder {
|
||||||
/// Index into [`FormatArgs::arguments`].
|
/// Index into [`FormatArgs::arguments`].
|
||||||
pub argument: FormatArgPosition,
|
pub argument: FormatArgPosition,
|
||||||
|
@ -45,11 +46,11 @@ pub struct FormatPlaceholder {
|
||||||
pub format_options: FormatOptions,
|
pub format_options: FormatOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FormatArgPosition {
|
pub struct FormatArgPosition {
|
||||||
/// Which argument this position refers to (Ok),
|
/// Which argument this position refers to (Ok),
|
||||||
/// or would've referred to if it existed (Err).
|
/// 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`].
|
/// What kind of position this is. See [`FormatArgPositionKind`].
|
||||||
pub kind: FormatArgPositionKind,
|
pub kind: FormatArgPositionKind,
|
||||||
/// The span of the name or number.
|
/// The span of the name or number.
|
||||||
|
@ -88,7 +89,7 @@ pub enum FormatTrait {
|
||||||
UpperHex,
|
UpperHex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
#[derive(Clone, Default, Debug, PartialEq, Eq)]
|
||||||
pub struct FormatOptions {
|
pub struct FormatOptions {
|
||||||
/// The width. E.g. `{:5}` or `{:width$}`.
|
/// The width. E.g. `{:5}` or `{:width$}`.
|
||||||
pub width: Option<FormatCount>,
|
pub width: Option<FormatCount>,
|
||||||
|
@ -133,7 +134,7 @@ pub enum FormatAlignment {
|
||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum FormatCount {
|
pub enum FormatCount {
|
||||||
/// `{:5}` or `{:.5}`
|
/// `{:5}` or `{:.5}`
|
||||||
Literal(usize),
|
Literal(usize),
|
||||||
|
@ -173,7 +174,7 @@ pub(crate) fn parse(
|
||||||
fmt_snippet: Option<String>,
|
fmt_snippet: Option<String>,
|
||||||
mut args: FormatArgumentsCollector,
|
mut args: FormatArgumentsCollector,
|
||||||
is_direct_literal: bool,
|
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>),
|
mut record_usage: impl FnMut(Name, Option<TextRange>),
|
||||||
call_ctx: SyntaxContextId,
|
call_ctx: SyntaxContextId,
|
||||||
) -> FormatArgs {
|
) -> FormatArgs {
|
||||||
|
@ -192,7 +193,6 @@ pub(crate) fn parse(
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut parser =
|
let mut parser =
|
||||||
parse::Parser::new(&text, str_style, fmt_snippet, false, parse::ParseMode::Format);
|
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| {
|
let to_span = |inner_span: parse::InnerSpan| {
|
||||||
is_source_literal.then(|| {
|
is_source_literal.then(|| {
|
||||||
TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
|
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)
|
Ok(index)
|
||||||
} else {
|
} else {
|
||||||
// Doesn't exist as an explicit argument.
|
// Doesn't exist as an explicit argument.
|
||||||
invalid_refs.push((index, span, used_as, kind));
|
invalid_refs.push((Either::Left(index), span, used_as, kind));
|
||||||
Err(index)
|
Err(Either::Left(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgRef::Name(name, span) => {
|
ArgRef::Name(name, span) => {
|
||||||
|
@ -265,14 +264,17 @@ pub(crate) fn parse(
|
||||||
// For the moment capturing variables from format strings expanded from macros is
|
// For the moment capturing variables from format strings expanded from macros is
|
||||||
// disabled (see RFC #2795)
|
// disabled (see RFC #2795)
|
||||||
// FIXME: Diagnose
|
// 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::{
|
use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
per_ns::PerNs,
|
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
|
||||||
visibility::{Visibility, VisibilityExplicitness},
|
visibility::{Visibility, VisibilityExplicitness},
|
||||||
AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
|
AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
|
||||||
Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
|
Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
|
||||||
|
@ -80,9 +80,9 @@ pub struct ItemScope {
|
||||||
/// Defs visible in this scope. This includes `declarations`, but also
|
/// 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
|
/// imports. The imports belong to this module and can be resolved by using them on
|
||||||
/// the `use_imports_*` fields.
|
/// the `use_imports_*` fields.
|
||||||
types: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
types: FxIndexMap<Name, TypesItem>,
|
||||||
values: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
|
values: FxIndexMap<Name, ValuesItem>,
|
||||||
macros: FxIndexMap<Name, (MacroId, Visibility, Option<ImportId>)>,
|
macros: FxIndexMap<Name, MacrosItem>,
|
||||||
unresolved: FxHashSet<Name>,
|
unresolved: FxHashSet<Name>,
|
||||||
|
|
||||||
/// The defs declared in this scope. Each def has a single scope where it is
|
/// 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>,
|
impls: Vec<ImplId>,
|
||||||
unnamed_consts: Vec<ConstId>,
|
unnamed_consts: Vec<ConstId>,
|
||||||
/// Traits imported via `use Trait as _;`.
|
/// 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
|
// the resolutions of the imports of this scope
|
||||||
use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
|
use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
|
||||||
|
@ -187,7 +187,7 @@ impl ItemScope {
|
||||||
import = i;
|
import = i;
|
||||||
}
|
}
|
||||||
ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
|
ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
|
||||||
res.macros = Some((def, Visibility::Public, None));
|
res.macros = Some(Item { def, vis: Visibility::Public, import: None });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
|
@ -203,7 +203,7 @@ impl ItemScope {
|
||||||
import = i;
|
import = i;
|
||||||
}
|
}
|
||||||
ImportOrDef::Def(def) => {
|
ImportOrDef::Def(def) => {
|
||||||
res.types = Some((def, Visibility::Public, None));
|
res.types = Some(Item { def, vis: Visibility::Public, import: None });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
|
@ -219,7 +219,7 @@ impl ItemScope {
|
||||||
import = i;
|
import = i;
|
||||||
}
|
}
|
||||||
ImportOrDef::Def(def) => {
|
ImportOrDef::Def(def) => {
|
||||||
res.values = Some((def, Visibility::Public, None));
|
res.values = Some(Item { def, vis: Visibility::Public, import: None });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
|
@ -253,8 +253,8 @@ impl ItemScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
|
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
|
||||||
self.types.values().copied().filter_map(|(def, vis, _)| match def {
|
self.types.values().filter_map(|ns| match ns.def {
|
||||||
ModuleDefId::ModuleId(module) => Some((module, vis)),
|
ModuleDefId::ModuleId(module) => Some((module, ns.vis)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -283,20 +283,20 @@ impl ItemScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
|
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.
|
/// 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)> {
|
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
|
||||||
match item {
|
match item {
|
||||||
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| {
|
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(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))| {
|
ItemInNs::Types(def) => self.types.iter().find_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(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))| {
|
ItemInNs::Values(def) => self.values.iter().find_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(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
|
ItemInNs::Macros(def) => self
|
||||||
.macros
|
.macros
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, &(other_def, vis, i))| {
|
.filter_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(other_def.def == def).then_some((
|
||||||
|
name,
|
||||||
|
other_def.vis,
|
||||||
|
other_def.import.is_none(),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||||
ItemInNs::Types(def) => self
|
ItemInNs::Types(def) => self
|
||||||
.types
|
.types
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, &(other_def, vis, i))| {
|
.filter_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(other_def.def == def).then_some((
|
||||||
|
name,
|
||||||
|
other_def.vis,
|
||||||
|
other_def.import.is_none(),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||||
ItemInNs::Values(def) => self
|
ItemInNs::Values(def) => self
|
||||||
.values
|
.values
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, &(other_def, vis, i))| {
|
.filter_map(|(name, other_def)| {
|
||||||
(other_def == def).then_some((name, vis, i.is_none()))
|
(other_def.def == def).then_some((
|
||||||
|
name,
|
||||||
|
other_def.vis,
|
||||||
|
other_def.import.is_none(),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.find_map(|(a, b, c)| cb(a, b, c)),
|
.find_map(|(a, b, c)| cb(a, b, c)),
|
||||||
}
|
}
|
||||||
|
@ -335,7 +347,7 @@ impl ItemScope {
|
||||||
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
|
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
|
||||||
self.types
|
self.types
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|&(def, _, _)| match def {
|
.filter_map(|def| match def.def {
|
||||||
ModuleDefId::TraitId(t) => Some(t),
|
ModuleDefId::TraitId(t) => Some(t),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
@ -344,13 +356,13 @@ impl ItemScope {
|
||||||
|
|
||||||
pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
|
pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
|
||||||
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
|
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,
|
None,
|
||||||
PerNs::types(
|
PerNs::types(
|
||||||
ModuleDefId::TraitId(*tr),
|
ModuleDefId::TraitId(*tr),
|
||||||
*vis,
|
trait_.vis,
|
||||||
i.map(ImportOrExternCrate::Import),
|
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
|
// 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> {
|
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) {
|
pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
|
||||||
// FIXME: import
|
// 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(
|
pub(crate) fn push_res_with_import(
|
||||||
|
@ -502,7 +514,7 @@ impl ItemScope {
|
||||||
}
|
}
|
||||||
None | Some(ImportType::Glob(_)) => None,
|
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 {
|
if let Some(import) = import {
|
||||||
self.use_imports_types.insert(
|
self.use_imports_types.insert(
|
||||||
import,
|
import,
|
||||||
|
@ -513,7 +525,7 @@ impl ItemScope {
|
||||||
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
||||||
ImportOrDef::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,
|
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 {
|
if let Some(import) = import {
|
||||||
self.use_imports_types.insert(
|
self.use_imports_types.insert(
|
||||||
import,
|
import,
|
||||||
|
@ -551,7 +563,7 @@ impl ItemScope {
|
||||||
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
Some(ImportOrExternCrate::ExternCrate(import)) => {
|
||||||
ImportOrDef::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),
|
Some(ImportType::Import(import)) => Some(import),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let prev = std::mem::replace(&mut fld.2, import);
|
let prev = std::mem::replace(&mut fld.import, import);
|
||||||
if let Some(import) = import {
|
if let Some(import) = import {
|
||||||
self.use_imports_values.insert(
|
self.use_imports_values.insert(
|
||||||
import,
|
import,
|
||||||
match prev {
|
match prev {
|
||||||
Some(import) => ImportOrDef::Import(import),
|
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),
|
Some(ImportType::Import(import)) => Some(import),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let prev = std::mem::replace(&mut fld.2, import);
|
let prev = std::mem::replace(&mut fld.import, import);
|
||||||
if let Some(import) = import {
|
if let Some(import) = import {
|
||||||
self.use_imports_values.insert(
|
self.use_imports_values.insert(
|
||||||
import,
|
import,
|
||||||
match prev {
|
match prev {
|
||||||
Some(import) => ImportOrDef::Import(import),
|
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),
|
Some(ImportType::Import(import)) => Some(import),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let prev = std::mem::replace(&mut fld.2, import);
|
let prev = std::mem::replace(&mut fld.import, import);
|
||||||
if let Some(import) = import {
|
if let Some(import) = import {
|
||||||
self.use_imports_macros.insert(
|
self.use_imports_macros.insert(
|
||||||
import,
|
import,
|
||||||
match prev {
|
match prev {
|
||||||
Some(import) => ImportOrDef::Import(import),
|
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),
|
Some(ImportType::Import(import)) => Some(import),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let prev = std::mem::replace(&mut fld.2, import);
|
let prev = std::mem::replace(&mut fld.import, import);
|
||||||
if let Some(import) = import {
|
if let Some(import) = import {
|
||||||
self.use_imports_macros.insert(
|
self.use_imports_macros.insert(
|
||||||
import,
|
import,
|
||||||
match prev {
|
match prev {
|
||||||
Some(import) => ImportOrDef::Import(import),
|
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) {
|
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
||||||
self.types
|
self.types
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.map(|(_, vis, _)| vis)
|
.map(|def| &mut def.vis)
|
||||||
.chain(self.values.values_mut().map(|(_, vis, _)| vis))
|
.chain(self.values.values_mut().map(|def| &mut def.vis))
|
||||||
.chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
|
.chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
|
||||||
.for_each(|vis| {
|
.for_each(|vis| {
|
||||||
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
|
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (mac, vis, import) in self.macros.values_mut() {
|
for mac in self.macros.values_mut() {
|
||||||
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
|
if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
|
||||||
continue;
|
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())
|
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");
|
buf.push_str(" t");
|
||||||
match i {
|
match import {
|
||||||
Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
|
Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
|
||||||
Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
|
Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((.., i)) = def.values {
|
if let Some(Item { import, .. }) = def.values {
|
||||||
buf.push_str(" v");
|
buf.push_str(" v");
|
||||||
if i.is_some() {
|
if import.is_some() {
|
||||||
buf.push('i');
|
buf.push('i');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((.., i)) = def.macros {
|
if let Some(Item { import, .. }) = def.macros {
|
||||||
buf.push_str(" m");
|
buf.push_str(" m");
|
||||||
if i.is_some() {
|
if import.is_some() {
|
||||||
buf.push('i');
|
buf.push('i');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,19 +793,19 @@ impl ItemScope {
|
||||||
pub(crate) fn update_visibility_types(&mut self, name: &Name, vis: Visibility) {
|
pub(crate) fn update_visibility_types(&mut self, name: &Name, vis: Visibility) {
|
||||||
let res =
|
let res =
|
||||||
self.types.get_mut(name).expect("tried to update visibility of non-existent type");
|
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) {
|
pub(crate) fn update_visibility_values(&mut self, name: &Name, vis: Visibility) {
|
||||||
let res =
|
let res =
|
||||||
self.values.get_mut(name).expect("tried to update visibility of non-existent value");
|
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) {
|
pub(crate) fn update_visibility_macros(&mut self, name: &Name, vis: Visibility) {
|
||||||
let res =
|
let res =
|
||||||
self.macros.get_mut(name).expect("tried to update visibility of non-existent macro");
|
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,
|
ResolveMode,
|
||||||
},
|
},
|
||||||
path::{ImportAlias, ModPath, PathKind},
|
path::{ImportAlias, ModPath, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::{Item, PerNs},
|
||||||
tt,
|
tt,
|
||||||
visibility::{RawVisibility, Visibility},
|
visibility::{RawVisibility, Visibility},
|
||||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
|
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);
|
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
|
||||||
|
|
||||||
match per_ns.types {
|
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
|
// FIXME: This should specifically look for a glob import somehow and record that here
|
||||||
self.def_map.prelude = Some((
|
self.def_map.prelude = Some((
|
||||||
m,
|
m,
|
||||||
|
@ -1069,9 +1069,9 @@ impl DefCollector<'_> {
|
||||||
//
|
//
|
||||||
// This has been historically allowed, but may be not allowed in future
|
// This has been historically allowed, but may be not allowed in future
|
||||||
// https://github.com/rust-lang/rust/issues/127909
|
// 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 is_extern_crate_reimport_without_prefix = || {
|
||||||
let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
|
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let Some(ImportType::Import(id)) = def_import_type else {
|
let Some(ImportType::Import(id)) = def_import_type else {
|
||||||
|
@ -1086,16 +1086,16 @@ impl DefCollector<'_> {
|
||||||
path.segments().len() < 2
|
path.segments().len() < 2
|
||||||
};
|
};
|
||||||
if is_extern_crate_reimport_without_prefix() {
|
if is_extern_crate_reimport_without_prefix() {
|
||||||
*v = vis;
|
def.vis = vis;
|
||||||
} else {
|
} 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() {
|
if let Some(def) = defs.values.as_mut() {
|
||||||
*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.macros.as_mut() {
|
if let Some(def) = defs.macros.as_mut() {
|
||||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
|
@ -1106,12 +1106,12 @@ impl DefCollector<'_> {
|
||||||
// Multiple globs may import the same item and they may override visibility from
|
// Multiple globs may import the same item and they may override visibility from
|
||||||
// previously resolved globs. Handle overrides here and leave the rest to
|
// previously resolved globs. Handle overrides here and leave the rest to
|
||||||
// `ItemScope::push_res_with_import()`.
|
// `ItemScope::push_res_with_import()`.
|
||||||
if let Some((def, def_vis, _)) = defs.types {
|
if let Some(def) = defs.types {
|
||||||
if let Some((prev_def, prev_vis, _)) = prev_defs.types {
|
if let Some(prev_def) = prev_defs.types {
|
||||||
if def == prev_def
|
if def.def == prev_def.def
|
||||||
&& self.from_glob_import.contains_type(module_id, name.clone())
|
&& self.from_glob_import.contains_type(module_id, name.clone())
|
||||||
&& def_vis != prev_vis
|
&& def.vis != prev_def.vis
|
||||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
// This import is being handled here, don't pass it down to
|
// This import is being handled here, don't pass it down to
|
||||||
|
@ -1119,41 +1119,41 @@ impl DefCollector<'_> {
|
||||||
defs.types = None;
|
defs.types = None;
|
||||||
self.def_map.modules[module_id]
|
self.def_map.modules[module_id]
|
||||||
.scope
|
.scope
|
||||||
.update_visibility_types(name, def_vis);
|
.update_visibility_types(name, def.vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((def, def_vis, _)) = defs.values {
|
if let Some(def) = defs.values {
|
||||||
if let Some((prev_def, prev_vis, _)) = prev_defs.values {
|
if let Some(prev_def) = prev_defs.values {
|
||||||
if def == prev_def
|
if def.def == prev_def.def
|
||||||
&& self.from_glob_import.contains_value(module_id, name.clone())
|
&& self.from_glob_import.contains_value(module_id, name.clone())
|
||||||
&& def_vis != prev_vis
|
&& def.vis != prev_def.vis
|
||||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
// See comment above.
|
// See comment above.
|
||||||
defs.values = None;
|
defs.values = None;
|
||||||
self.def_map.modules[module_id]
|
self.def_map.modules[module_id]
|
||||||
.scope
|
.scope
|
||||||
.update_visibility_values(name, def_vis);
|
.update_visibility_values(name, def.vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((def, def_vis, _)) = defs.macros {
|
if let Some(def) = defs.macros {
|
||||||
if let Some((prev_def, prev_vis, _)) = prev_defs.macros {
|
if let Some(prev_def) = prev_defs.macros {
|
||||||
if def == prev_def
|
if def.def == prev_def.def
|
||||||
&& self.from_glob_import.contains_macro(module_id, name.clone())
|
&& self.from_glob_import.contains_macro(module_id, name.clone())
|
||||||
&& def_vis != prev_vis
|
&& def.vis != prev_def.vis
|
||||||
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
|
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
// See comment above.
|
// See comment above.
|
||||||
defs.macros = None;
|
defs.macros = None;
|
||||||
self.def_map.modules[module_id]
|
self.def_map.modules[module_id]
|
||||||
.scope
|
.scope
|
||||||
.update_visibility_macros(name, def_vis);
|
.update_visibility_macros(name, def.vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,8 @@ impl PerNs {
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
expected: Option<MacroSubNs>,
|
expected: Option<MacroSubNs>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.macros = self.macros.filter(|&(id, _, _)| {
|
self.macros = self.macros.filter(|def| {
|
||||||
let this = MacroSubNs::from_id(db, id);
|
let this = MacroSubNs::from_id(db, def.def);
|
||||||
sub_namespace_match(Some(this), expected)
|
sub_namespace_match(Some(this), expected)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -411,7 +411,7 @@ impl DefMap {
|
||||||
original_module: LocalModuleId,
|
original_module: LocalModuleId,
|
||||||
) -> ResolvePathResult {
|
) -> ResolvePathResult {
|
||||||
for (i, segment) in segments {
|
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,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
// we still have path segments left, but the path so far
|
// we still have path segments left, but the path so far
|
||||||
|
@ -424,7 +424,7 @@ impl DefMap {
|
||||||
};
|
};
|
||||||
// resolve segment in curr
|
// resolve segment in curr
|
||||||
|
|
||||||
curr_per_ns = match curr {
|
curr_per_ns = match curr.def {
|
||||||
ModuleDefId::ModuleId(module) => {
|
ModuleDefId::ModuleId(module) => {
|
||||||
if module.krate != self.krate {
|
if module.krate != self.krate {
|
||||||
let path = ModPath::from_segments(
|
let path = ModPath::from_segments(
|
||||||
|
@ -492,7 +492,7 @@ impl DefMap {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => {
|
None => {
|
||||||
return ResolvePathResult::new(
|
return ResolvePathResult::new(
|
||||||
PerNs::types(e.into(), vis, imp),
|
PerNs::types(e.into(), curr.vis, curr.import),
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
Some(i),
|
||||||
false,
|
false,
|
||||||
|
@ -510,7 +510,7 @@ impl DefMap {
|
||||||
);
|
);
|
||||||
|
|
||||||
return ResolvePathResult::new(
|
return ResolvePathResult::new(
|
||||||
PerNs::types(s, vis, imp),
|
PerNs::types(s, curr.vis, curr.import),
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
Some(i),
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -331,7 +331,7 @@ pub type Ty = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, res) in module_data.scope.resolutions() {
|
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::FunctionId(f) => _ = db.function_data(f),
|
||||||
ModuleDefId::AdtId(adt) => match adt {
|
ModuleDefId::AdtId(adt) => match adt {
|
||||||
AdtId::StructId(it) => _ = db.struct_data(it),
|
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)]
|
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||||
pub struct PerNs {
|
pub struct PerNs {
|
||||||
pub types: Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
pub types: Option<TypesItem>,
|
||||||
pub values: Option<(ModuleDefId, Visibility, Option<ImportId>)>,
|
pub values: Option<ValuesItem>,
|
||||||
pub macros: Option<(MacroId, Visibility, Option<ImportId>)>,
|
pub macros: Option<MacrosItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerNs {
|
impl PerNs {
|
||||||
|
@ -48,29 +59,33 @@ impl PerNs {
|
||||||
PerNs { types: None, values: None, macros: None }
|
PerNs { types: None, values: None, macros: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(t: ModuleDefId, v: Visibility, i: Option<ImportId>) -> PerNs {
|
pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportId>) -> PerNs {
|
||||||
PerNs { types: None, values: Some((t, v, i)), macros: None }
|
PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types(t: ModuleDefId, v: Visibility, i: Option<ImportOrExternCrate>) -> PerNs {
|
pub fn types(def: ModuleDefId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
|
||||||
PerNs { types: Some((t, v, i)), values: None, macros: None }
|
PerNs { types: Some(Item { def, vis, import }), values: None, macros: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn both(
|
pub fn both(
|
||||||
types: ModuleDefId,
|
types: ModuleDefId,
|
||||||
values: ModuleDefId,
|
values: ModuleDefId,
|
||||||
v: Visibility,
|
vis: Visibility,
|
||||||
i: Option<ImportOrExternCrate>,
|
import: Option<ImportOrExternCrate>,
|
||||||
) -> PerNs {
|
) -> PerNs {
|
||||||
PerNs {
|
PerNs {
|
||||||
types: Some((types, v, i)),
|
types: Some(Item { def: types, vis, import }),
|
||||||
values: Some((values, v, i.and_then(ImportOrExternCrate::into_import))),
|
values: Some(Item {
|
||||||
|
def: values,
|
||||||
|
vis,
|
||||||
|
import: import.and_then(ImportOrExternCrate::into_import),
|
||||||
|
}),
|
||||||
macros: None,
|
macros: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macros(macro_: MacroId, v: Visibility, i: Option<ImportId>) -> PerNs {
|
pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportId>) -> PerNs {
|
||||||
PerNs { types: None, values: None, macros: Some((macro_, v, i)) }
|
PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
|
@ -82,43 +97,43 @@ impl PerNs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_types(self) -> Option<ModuleDefId> {
|
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
|
self.types
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_values(self) -> Option<ModuleDefId> {
|
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>)> {
|
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> {
|
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>)> {
|
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 {
|
pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
|
||||||
let _p = tracing::info_span!("PerNs::filter_visibility").entered();
|
let _p = tracing::info_span!("PerNs::filter_visibility").entered();
|
||||||
PerNs {
|
PerNs {
|
||||||
types: self.types.filter(|&(_, v, _)| f(v)),
|
types: self.types.filter(|def| f(def.vis)),
|
||||||
values: self.values.filter(|&(_, v, _)| f(v)),
|
values: self.values.filter(|def| f(def.vis)),
|
||||||
macros: self.macros.filter(|&(_, v, _)| f(v)),
|
macros: self.macros.filter(|def| f(def.vis)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_visibility(self, vis: Visibility) -> PerNs {
|
pub fn with_visibility(self, vis: Visibility) -> PerNs {
|
||||||
PerNs {
|
PerNs {
|
||||||
types: self.types.map(|(it, _, c)| (it, vis, c)),
|
types: self.types.map(|def| Item { vis, ..def }),
|
||||||
values: self.values.map(|(it, _, c)| (it, vis, c)),
|
values: self.values.map(|def| Item { vis, ..def }),
|
||||||
macros: self.macros.map(|(it, _, import)| (it, vis, import)),
|
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>)> {
|
pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
|
||||||
let _p = tracing::info_span!("PerNs::iter_items").entered();
|
let _p = tracing::info_span!("PerNs::iter_items").entered();
|
||||||
self.types
|
self.types
|
||||||
.map(|it| (ItemInNs::Types(it.0), it.2))
|
.map(|it| (ItemInNs::Types(it.def), it.import))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(
|
.chain(
|
||||||
self.values
|
self.values.map(|it| {
|
||||||
.map(|it| (ItemInNs::Values(it.0), it.2.map(ImportOrExternCrate::Import))),
|
(ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::Import))
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
self.macros
|
self.macros.map(|it| {
|
||||||
.map(|it| (ItemInNs::Macros(it.0), it.2.map(ImportOrExternCrate::Import))),
|
(ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::Import))
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -933,8 +933,8 @@ impl ModuleItemMap {
|
||||||
Some(ResolveValueResult::ValueNs(value, import))
|
Some(ResolveValueResult::ValueNs(value, import))
|
||||||
}
|
}
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
let (def, _, import) = module_def.take_types_full()?;
|
let def = module_def.take_types_full()?;
|
||||||
let ty = match def {
|
let ty = match def.def {
|
||||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||||
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
|
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
|
||||||
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
|
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
|
||||||
|
@ -948,7 +948,7 @@ impl ModuleItemMap {
|
||||||
| ModuleDefId::MacroId(_)
|
| ModuleDefId::MacroId(_)
|
||||||
| ModuleDefId::StaticId(_) => return None,
|
| 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>)> {
|
fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
|
||||||
let (def, _, import) = per_ns.take_types_full()?;
|
let def = per_ns.take_types_full()?;
|
||||||
let res = match def {
|
let res = match def.def {
|
||||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||||
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(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::StaticId(_)
|
||||||
| ModuleDefId::ModuleId(_) => return None,
|
| ModuleDefId::ModuleId(_) => return None,
|
||||||
};
|
};
|
||||||
Some((res, import))
|
Some((res, def.import))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -1019,14 +1019,14 @@ impl ScopeNames {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_per_ns(&mut self, name: &Name, def: PerNs) {
|
fn add_per_ns(&mut self, name: &Name, def: PerNs) {
|
||||||
if let &Some((ty, _, _)) = &def.types {
|
if let Some(ty) = &def.types {
|
||||||
self.add(name, ScopeDef::ModuleDef(ty))
|
self.add(name, ScopeDef::ModuleDef(ty.def))
|
||||||
}
|
}
|
||||||
if let &Some((def, _, _)) = &def.values {
|
if let Some(def) = &def.values {
|
||||||
self.add(name, ScopeDef::ModuleDef(def))
|
self.add(name, ScopeDef::ModuleDef(def.def))
|
||||||
}
|
}
|
||||||
if let &Some((mac, _, _)) = &def.macros {
|
if let Some(mac) = &def.macros {
|
||||||
self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)))
|
self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac.def)))
|
||||||
}
|
}
|
||||||
if def.is_none() {
|
if def.is_none() {
|
||||||
self.add(name, ScopeDef::Unknown)
|
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
|
/// 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
|
/// 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. The `token_to_map` mapped down into the expansion, with the mapped
|
||||||
/// token returned.
|
/// token(s) returned with their priority.
|
||||||
pub fn expand_speculative(
|
pub fn expand_speculative(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
actual_macro_call: MacroCallId,
|
actual_macro_call: MacroCallId,
|
||||||
speculative_args: &SyntaxNode,
|
speculative_args: &SyntaxNode,
|
||||||
token_to_map: SyntaxToken,
|
token_to_map: SyntaxToken,
|
||||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||||
let loc = db.lookup_intern_macro_call(actual_macro_call);
|
let loc = db.lookup_intern_macro_call(actual_macro_call);
|
||||||
let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
|
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);
|
token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition);
|
||||||
|
|
||||||
let syntax_node = node.syntax_node();
|
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()))
|
.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)))
|
.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
|
// 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
|
// Note the inversion of the score here, as we want to prefer the first token in case
|
||||||
// of all tokens having the same score
|
// 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
|
+ 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))
|
Some((node.syntax_node(), token))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ use hir_def::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{HirDatabase, InternedCoroutine},
|
db::{HirDatabase, InternedCoroutine},
|
||||||
display::HirDisplay,
|
|
||||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
|
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
|
||||||
generics::generics,
|
generics::generics,
|
||||||
make_binders, make_single_type_binders,
|
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();
|
let _p = tracing::info_span!("impl_datum_query").entered();
|
||||||
debug!("impl_datum {:?}", impl_id);
|
debug!("impl_datum {:?}", impl_id);
|
||||||
let impl_: hir_def::ImplId = from_chalk(db, 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(
|
fn impl_def_datum(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
chalk_id: ImplId,
|
|
||||||
impl_id: hir_def::ImplId,
|
impl_id: hir_def::ImplId,
|
||||||
) -> Arc<ImplDatum> {
|
) -> Arc<ImplDatum> {
|
||||||
let trait_ref = db
|
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 where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars);
|
||||||
let negative = impl_data.is_negative;
|
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 };
|
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);
|
self.resolver.reset_to_guard(guard);
|
||||||
}
|
}
|
||||||
Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
|
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)`,
|
// Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
|
||||||
// see https://github.com/rust-lang/rust/pull/125834.
|
// 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 { .. } => {
|
Expr::MethodCall { .. } => {
|
||||||
|
|
|
@ -262,7 +262,7 @@ pub struct UnresolvedAssocItem {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnresolvedIdent {
|
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)]
|
#[derive(Debug)]
|
||||||
|
@ -550,11 +550,10 @@ impl AnyDiagnostic {
|
||||||
source_map: &hir_def::body::BodySourceMap,
|
source_map: &hir_def::body::BodySourceMap,
|
||||||
) -> Option<AnyDiagnostic> {
|
) -> Option<AnyDiagnostic> {
|
||||||
let expr_syntax = |expr| {
|
let expr_syntax = |expr| {
|
||||||
source_map.expr_syntax(expr).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(|_| tracing::error!("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 {
|
let expr_or_pat_syntax = |id| match id {
|
||||||
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
|
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
|
||||||
ExprOrPatId::PatId(pat) => pat_syntax(pat),
|
ExprOrPatId::PatId(pat) => pat_syntax(pat),
|
||||||
|
@ -626,8 +625,16 @@ impl AnyDiagnostic {
|
||||||
UnresolvedAssocItem { expr_or_pat }.into()
|
UnresolvedAssocItem { expr_or_pat }.into()
|
||||||
}
|
}
|
||||||
&InferenceDiagnostic::UnresolvedIdent { id } => {
|
&InferenceDiagnostic::UnresolvedIdent { id } => {
|
||||||
let expr_or_pat = expr_or_pat_syntax(id)?;
|
let node = match id {
|
||||||
UnresolvedIdent { expr_or_pat }.into()
|
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 } => {
|
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
|
||||||
let expr = expr_syntax(expr)?;
|
let expr = expr_syntax(expr)?;
|
||||||
|
|
|
@ -3105,10 +3105,10 @@ impl From<ModuleDef> for ItemInNs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemInNs {
|
impl ItemInNs {
|
||||||
pub fn as_module_def(self) -> Option<ModuleDef> {
|
pub fn into_module_def(self) -> ModuleDef {
|
||||||
match self {
|
match self {
|
||||||
ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
|
ItemInNs::Types(id) | ItemInNs::Values(id) => id,
|
||||||
ItemInNs::Macros(_) => None,
|
ItemInNs::Macros(id) => ModuleDef::Macro(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,9 @@ use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId};
|
||||||
use stdx::TupleExt;
|
use stdx::TupleExt;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::skip_trivia_token,
|
algo::skip_trivia_token,
|
||||||
ast::{self, HasAttrs as _, HasGenericParams, IsString as _},
|
ast::{self, HasAttrs as _, HasGenericParams},
|
||||||
AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
|
AstNode, AstToken, Direction, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken,
|
||||||
TextSize,
|
TextRange, TextSize,
|
||||||
};
|
};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
actual_macro_call: &ast::MacroCall,
|
actual_macro_call: &ast::MacroCall,
|
||||||
speculative_args: &ast::TokenTree,
|
speculative_args: &ast::TokenTree,
|
||||||
token_to_map: SyntaxToken,
|
token_to_map: SyntaxToken,
|
||||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||||
let SourceAnalyzer { file_id, resolver, .. } =
|
let SourceAnalyzer { file_id, resolver, .. } =
|
||||||
self.analyze_no_infer(actual_macro_call.syntax())?;
|
self.analyze_no_infer(actual_macro_call.syntax())?;
|
||||||
let macro_call = InFile::new(file_id, actual_macro_call);
|
let macro_call = InFile::new(file_id, actual_macro_call);
|
||||||
|
@ -592,7 +592,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
macro_file: MacroFileId,
|
macro_file: MacroFileId,
|
||||||
speculative_args: &SyntaxNode,
|
speculative_args: &SyntaxNode,
|
||||||
token_to_map: SyntaxToken,
|
token_to_map: SyntaxToken,
|
||||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||||
hir_expand::db::expand_speculative(
|
hir_expand::db::expand_speculative(
|
||||||
self.db.upcast(),
|
self.db.upcast(),
|
||||||
macro_file.macro_call_id,
|
macro_file.macro_call_id,
|
||||||
|
@ -608,7 +608,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
actual_macro_call: &ast::Item,
|
actual_macro_call: &ast::Item,
|
||||||
speculative_args: &ast::Item,
|
speculative_args: &ast::Item,
|
||||||
token_to_map: SyntaxToken,
|
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 = 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()))?;
|
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?;
|
||||||
hir_expand::db::expand_speculative(
|
hir_expand::db::expand_speculative(
|
||||||
|
@ -624,7 +624,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
actual_macro_call: &ast::Attr,
|
actual_macro_call: &ast::Attr,
|
||||||
speculative_args: &ast::Attr,
|
speculative_args: &ast::Attr,
|
||||||
token_to_map: SyntaxToken,
|
token_to_map: SyntaxToken,
|
||||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
|
||||||
let attr = self.wrap_node_infile(actual_macro_call.clone());
|
let attr = self.wrap_node_infile(actual_macro_call.clone());
|
||||||
let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
|
let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
|
||||||
let macro_call_id = self.with_ctx(|ctx| {
|
let macro_call_id = self.with_ctx(|ctx| {
|
||||||
|
@ -643,8 +643,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
&self,
|
&self,
|
||||||
string: &ast::String,
|
string: &ast::String,
|
||||||
) -> Option<Vec<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)>> {
|
) -> 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()?;
|
let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?;
|
||||||
self.descend_into_macros_breakable(token, |token, _| {
|
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 format_args = self.wrap_node_infile(format_args);
|
||||||
let res = source_analyzer
|
let res = source_analyzer
|
||||||
.as_format_args_parts(self.db, format_args.as_ref())?
|
.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();
|
.collect();
|
||||||
Some(res)
|
Some(res)
|
||||||
} else {
|
} else {
|
||||||
|
@ -672,7 +671,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(range, index)| {
|
.map(|&(range, index)| {
|
||||||
(
|
(
|
||||||
range + quote.end(),
|
range + string_start,
|
||||||
Some(Either::Right(InlineAsmOperand { owner, expr, index })),
|
Some(Either::Right(InlineAsmOperand { owner, expr, index })),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -690,17 +689,16 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
original_token: SyntaxToken,
|
original_token: SyntaxToken,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
) -> Option<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)> {
|
) -> 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 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, _| {
|
self.descend_into_macros_breakable(original_token, |token, _| {
|
||||||
(|| {
|
(|| {
|
||||||
let token = token.value;
|
let token = token.value;
|
||||||
self.resolve_offset_in_format_args(
|
self.resolve_offset_in_format_args(
|
||||||
ast::String::cast(token)?,
|
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)
|
.map_or(ControlFlow::Continue(()), ControlFlow::Break)
|
||||||
})
|
})
|
||||||
|
@ -1542,6 +1540,21 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
Some(items.iter_items().map(|(item, _)| item.into()))
|
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> {
|
fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
|
||||||
self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
|
self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use hir::{FileRange, Semantics};
|
use hir::{FileRange, Semantics};
|
||||||
use ide_db::EditionedFileId;
|
use ide_db::EditionedFileId;
|
||||||
use ide_db::{label::Label, FileId, RootDatabase};
|
use ide_db::{label::Label, FileId, RootDatabase};
|
||||||
|
use syntax::Edition;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::{self, find_node_at_offset, find_node_at_range},
|
algo::{self, find_node_at_offset, find_node_at_range},
|
||||||
AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange,
|
AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange,
|
||||||
|
@ -94,6 +95,10 @@ impl<'a> AssistContext<'a> {
|
||||||
self.frange.file_id
|
self.frange.file_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn edition(&self) -> Edition {
|
||||||
|
self.frange.file_id.edition()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn has_empty_selection(&self) -> bool {
|
pub(crate) fn has_empty_selection(&self) -> bool {
|
||||||
self.trimmed_range.is_empty()
|
self.trimmed_range.is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use ide_db::text_edit::TextRange;
|
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
assists::{AssistId, AssistKind},
|
assists::{AssistId, AssistKind},
|
||||||
defs::Definition,
|
defs::Definition,
|
||||||
search::{FileReference, SearchScope, UsageSearchResult},
|
search::{FileReference, SearchScope},
|
||||||
|
syntax_helpers::suggest_name,
|
||||||
|
text_edit::TextRange,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use syntax::SmolStr;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
|
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
|
||||||
ted,
|
ted,
|
||||||
|
@ -122,33 +124,43 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = ident_pat.name()?.to_string();
|
let usages = ctx.sema.to_def(&ident_pat).and_then(|def| {
|
||||||
|
|
||||||
let usages = ctx.sema.to_def(&ident_pat).map(|def| {
|
|
||||||
Definition::Local(def)
|
Definition::Local(def)
|
||||||
.usages(&ctx.sema)
|
.usages(&ctx.sema)
|
||||||
.in_scope(&SearchScope::single_file(ctx.file_id()))
|
.in_scope(&SearchScope::single_file(ctx.file_id()))
|
||||||
.all()
|
.all()
|
||||||
|
.iter()
|
||||||
|
.next()
|
||||||
|
.map(|(_, refs)| refs.to_vec())
|
||||||
});
|
});
|
||||||
|
|
||||||
let field_names = (0..field_types.len())
|
let mut name_generator = {
|
||||||
.map(|i| generate_name(ctx, i, &name, &ident_pat, &usages))
|
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<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Some(TupleData { ident_pat, ref_type, field_names, usages })
|
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 {
|
enum RefType {
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
Mutable,
|
Mutable,
|
||||||
|
@ -157,7 +169,7 @@ struct TupleData {
|
||||||
ident_pat: IdentPat,
|
ident_pat: IdentPat,
|
||||||
ref_type: Option<RefType>,
|
ref_type: Option<RefType>,
|
||||||
field_names: Vec<String>,
|
field_names: Vec<String>,
|
||||||
usages: Option<UsageSearchResult>,
|
usages: Option<Vec<FileReference>>,
|
||||||
}
|
}
|
||||||
fn edit_tuple_assignment(
|
fn edit_tuple_assignment(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
|
@ -213,42 +225,23 @@ fn edit_tuple_usages(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
in_sub_pattern: bool,
|
in_sub_pattern: bool,
|
||||||
) -> Option<Vec<EditTupleUsage>> {
|
) -> 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() {
|
let edits = data
|
||||||
// We need to collect edits first before actually applying them
|
.usages
|
||||||
// as mapping nodes to their mutable node versions requires an
|
.as_ref()?
|
||||||
// unmodified syntax tree.
|
.as_slice()
|
||||||
//
|
.iter()
|
||||||
// We also defer editing usages in the current file first since
|
.filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern))
|
||||||
// tree mutation in the same file breaks when `builder.edit_file`
|
.collect_vec();
|
||||||
// is called
|
|
||||||
|
|
||||||
if let Some((_, refs)) = usages.iter().find(|(file_id, _)| *file_id == ctx.file_id()) {
|
Some(edits)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
fn edit_tuple_usage(
|
fn edit_tuple_usage(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
|
@ -1769,14 +1762,14 @@ struct S4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo() -> Option<()> {
|
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; // deref, no parens
|
||||||
let v: &i32 = _0; // no deref, no parens, remove `&`
|
let v: &i32 = _0; // no deref, no parens, remove `&`
|
||||||
f1(*_0); // deref, no parens
|
f1(*_0); // deref, no parens
|
||||||
f2(_0); // `&*` -> cancel out -> no deref, no parens
|
f2(_0); // `&*` -> cancel out -> no deref, no parens
|
||||||
// https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
|
// https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
|
||||||
// let v: i32 = t.1.0; // no deref, no parens
|
// 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
|
(*_0).do_stuff(); // deref, parens
|
||||||
let v: i32 = (*_2)?; // deref, parens
|
let v: i32 = (*_2)?; // deref, parens
|
||||||
let v: i32 = _3[0]; // no deref, no parens
|
let v: i32 = _3[0]; // no deref, no parens
|
||||||
|
@ -1815,8 +1808,8 @@ impl S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,2);
|
let ($0s, _1) = &(S,2);
|
||||||
let s = _0.f();
|
let s = s.f();
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
@ -1845,8 +1838,8 @@ impl S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,2);
|
let ($0s, _1) = &(S,2);
|
||||||
let s = (*_0).f();
|
let s = (*s).f();
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
@ -1882,8 +1875,8 @@ impl T for &S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,2);
|
let ($0s, _1) = &(S,2);
|
||||||
let s = (*_0).f();
|
let s = (*s).f();
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
@ -1923,8 +1916,8 @@ impl T for &S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,2);
|
let ($0s, _1) = &(S,2);
|
||||||
let s = (*_0).f();
|
let s = (*s).f();
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
@ -1951,8 +1944,8 @@ impl S {
|
||||||
fn do_stuff(&self) -> i32 { 42 }
|
fn do_stuff(&self) -> i32 { 42 }
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,&S);
|
let ($0s, s1) = &(S,&S);
|
||||||
let v = _0.do_stuff();
|
let v = s.do_stuff();
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
@ -1973,7 +1966,7 @@ fn main() {
|
||||||
// `t.0` gets auto-refed -> no deref needed -> no parens
|
// `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(); // no deref, no parens
|
||||||
let v = &t.0.do_stuff(); // `&` is for result -> 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
|
let v = t.1.do_stuff(); // deref, parens
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1984,13 +1977,13 @@ impl S {
|
||||||
fn do_stuff(&self) -> i32 { 42 }
|
fn do_stuff(&self) -> i32 { 42 }
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
let ($0_0, _1) = &(S,&S);
|
let ($0s, s1) = &(S,&S);
|
||||||
let v = _0.do_stuff(); // no deref, remove parens
|
let v = s.do_stuff(); // no deref, remove parens
|
||||||
// `t.0` gets auto-refed -> no deref needed -> no parens
|
// `t.0` gets auto-refed -> no deref needed -> no parens
|
||||||
let v = _0.do_stuff(); // no deref, no parens
|
let v = s.do_stuff(); // no deref, no parens
|
||||||
let v = &_0.do_stuff(); // `&` is for result -> no deref, no parens
|
let v = &s.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 = (*_1).do_stuff(); // deref, parens
|
let v = (*s1).do_stuff(); // deref, parens
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use hir::{HirDisplay, TypeInfo};
|
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::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory,
|
self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory,
|
||||||
|
@ -320,24 +323,58 @@ impl ExtractionKind {
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
to_extract: &ast::Expr,
|
to_extract: &ast::Expr,
|
||||||
) -> (String, SyntaxNode) {
|
) -> (String, SyntaxNode) {
|
||||||
let field_shorthand = to_extract
|
// We only do this sort of extraction for fields because they should have lowercase names
|
||||||
.syntax()
|
if let ExtractionKind::Variable = self {
|
||||||
.parent()
|
let field_shorthand = to_extract
|
||||||
.and_then(ast::RecordExprField::cast)
|
.syntax()
|
||||||
.filter(|field| field.name_ref().is_some());
|
.parent()
|
||||||
let (var_name, expr_replace) = match field_shorthand {
|
.and_then(ast::RecordExprField::cast)
|
||||||
Some(field) => (field.to_string(), field.syntax().clone()),
|
.filter(|field| field.name_ref().is_some());
|
||||||
None => {
|
|
||||||
(suggest_name::for_variable(to_extract, &ctx.sema), to_extract.syntax().clone())
|
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 {
|
let var_name = match self {
|
||||||
ExtractionKind::Variable => var_name,
|
ExtractionKind::Variable => var_name.to_lowercase(),
|
||||||
ExtractionKind::Constant | ExtractionKind::Static => var_name.to_uppercase(),
|
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#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
let $0var_name = "hello";
|
let $0hello = "hello";
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
"Extract into variable",
|
"Extract into variable",
|
||||||
|
@ -588,7 +625,7 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
const $0VAR_NAME: &str = "hello";
|
const $0HELLO: &str = "hello";
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
"Extract into constant",
|
"Extract into constant",
|
||||||
|
@ -683,7 +720,7 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
static $0VAR_NAME: &str = "hello";
|
static $0HELLO: &str = "hello";
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
"Extract into static",
|
"Extract into static",
|
||||||
|
@ -2479,4 +2516,120 @@ fn foo() {
|
||||||
"Extract into variable",
|
"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> {
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
||||||
let candidate = import_assets.import_candidate();
|
let candidate = import_assets.import_candidate();
|
||||||
let qualify_candidate = match syntax_under_caret.clone() {
|
let qualify_candidate = match syntax_under_caret.clone() {
|
||||||
NodeOrToken::Node(syntax_under_caret) => match candidate {
|
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);
|
cov_mark::hit!(qualify_path_qualifier_start);
|
||||||
let path = ast::Path::cast(syntax_under_caret)?;
|
let path = ast::Path::cast(syntax_under_caret)?;
|
||||||
let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
|
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> {
|
fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
|
||||||
let item_module_def = item.as_module_def()?;
|
match item.into_module_def() {
|
||||||
|
|
||||||
match item_module_def {
|
|
||||||
hir::ModuleDef::Trait(trait_) => Some(trait_),
|
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;
|
let import_path = &import.import_path;
|
||||||
|
|
||||||
match candidate {
|
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 as `{}`", import_path.display(db, edition))
|
||||||
}
|
}
|
||||||
_ => format!("Qualify with `{}`", 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()),
|
NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
|
||||||
items_locator::AssocSearchMode::Exclude,
|
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_),
|
ModuleDef::Trait(trait_) => Some(trait_),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,13 +12,15 @@ use syntax::{
|
||||||
|
|
||||||
use crate::{AssistContext, Assists};
|
use crate::{AssistContext, Assists};
|
||||||
|
|
||||||
|
// FIXME: This ought to be a diagnostic lint.
|
||||||
|
|
||||||
// Assist: unnecessary_async
|
// Assist: unnecessary_async
|
||||||
//
|
//
|
||||||
// Removes the `async` mark from functions which have no `.await` in their body.
|
// 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.
|
// 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 }
|
// 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<()> {
|
pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
let function: ast::Fn = ctx.find_node_at_offset()?;
|
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
|
// Do nothing if the cursor isn't on the async token.
|
||||||
// when the user asks us for assists when in the middle of the function body.
|
let async_token = function.async_token()?;
|
||||||
// We consider the prototype to be anything that is before the body of the function.
|
if !async_token.text_range().contains_inclusive(ctx.offset()) {
|
||||||
let cursor_position = ctx.offset();
|
|
||||||
if cursor_position >= function.body()?.syntax().text_range().start() {
|
|
||||||
return None;
|
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.
|
// Do nothing if the function has an `await` expression in its body.
|
||||||
if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() {
|
if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -138,27 +136,22 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn applies_on_empty_function() {
|
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]
|
#[test]
|
||||||
fn applies_and_removes_whitespace() {
|
fn applies_and_removes_whitespace() {
|
||||||
check_assist(unnecessary_async, "pub async f$0n f() {}", "pub fn f() {}")
|
check_assist(unnecessary_async, "pub async$0 fn f() {}", "pub fn f() {}")
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_not_apply_on_non_async_function() {
|
|
||||||
check_assist_not_applicable(unnecessary_async, "pub f$0n f() {}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn applies_on_function_with_a_non_await_expr() {
|
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]
|
#[test]
|
||||||
fn does_not_apply_on_function_with_an_await_expr() {
|
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]
|
#[test]
|
||||||
|
@ -167,7 +160,7 @@ mod tests {
|
||||||
unnecessary_async,
|
unnecessary_async,
|
||||||
r#"
|
r#"
|
||||||
pub async fn f4() { }
|
pub async fn f4() { }
|
||||||
pub async f$0n f2() { }
|
pub asy$0nc fn f2() { }
|
||||||
pub async fn f() { f2().await }
|
pub async fn f() { f2().await }
|
||||||
pub async fn f3() { f2().await }"#,
|
pub async fn f3() { f2().await }"#,
|
||||||
r#"
|
r#"
|
||||||
|
@ -184,7 +177,7 @@ pub async fn f3() { f2() }"#,
|
||||||
unnecessary_async,
|
unnecessary_async,
|
||||||
r#"
|
r#"
|
||||||
pub async fn f4() { }
|
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 f() { a::f2().await }
|
||||||
pub async fn f3() { a::f2().await }"#,
|
pub async fn f3() { a::f2().await }"#,
|
||||||
r#"
|
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
|
// Ensure that it is the first await on the 3rd line that is removed
|
||||||
r#"
|
r#"
|
||||||
pub async fn f() { f2().await }
|
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 f3() { f4(f2().await).await }
|
||||||
pub async fn f4(i: i32) { }"#,
|
pub async fn f4(i: i32) { }"#,
|
||||||
r#"
|
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
|
// Ensure that it is the second await on the 3rd line that is removed
|
||||||
r#"
|
r#"
|
||||||
pub async fn f() { f2().await }
|
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 f3() { f2(f4().await).await }
|
||||||
pub async fn f4() -> i32 { 1 }"#,
|
pub async fn f4() -> i32 { 1 }"#,
|
||||||
r#"
|
r#"
|
||||||
|
@ -237,7 +230,7 @@ pub async fn f4() -> i32 { 1 }"#,
|
||||||
unnecessary_async,
|
unnecessary_async,
|
||||||
r#"
|
r#"
|
||||||
pub struct S { }
|
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 }"#,
|
pub async fn f(s: &S) { s.f2().await }"#,
|
||||||
r#"
|
r#"
|
||||||
pub struct S { }
|
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() {
|
fn does_not_apply_on_function_with_a_nested_await_expr() {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
unnecessary_async,
|
unnecessary_async,
|
||||||
"async f$0n f() { if true { loop { f2().await } } }",
|
"async$0 fn f() { if true { loop { f2().await } } }",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_not_apply_when_not_on_prototype() {
|
fn does_not_apply_when_not_on_async_token() {
|
||||||
check_assist_not_applicable(unnecessary_async, "pub async fn f() { $0f2() }")
|
check_assist_not_applicable(unnecessary_async, "pub async fn$0 f() { f2() }")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -198,7 +198,7 @@ fn wrapper_alias(
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| {
|
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) => {
|
hir::ModuleDef::TypeAlias(alias) => {
|
||||||
let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
|
let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
|
||||||
(&enum_ty == core_wrapper).then_some(alias)
|
(&enum_ty == core_wrapper).then_some(alias)
|
||||||
|
|
|
@ -3280,7 +3280,7 @@ fn doctest_unnecessary_async() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
"unnecessary_async",
|
"unnecessary_async",
|
||||||
r#####"
|
r#####"
|
||||||
pub async f$0n foo() {}
|
pub asy$0nc fn foo() {}
|
||||||
pub async fn bar() { foo().await }
|
pub async fn bar() { foo().await }
|
||||||
"#####,
|
"#####,
|
||||||
r#####"
|
r#####"
|
||||||
|
|
|
@ -205,7 +205,7 @@ impl S {
|
||||||
fn foo(s: S) { s.$0 }
|
fn foo(s: S) { s.$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd foo u32
|
fd foo u32
|
||||||
me bar() fn(&self)
|
me bar() fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -259,7 +259,7 @@ impl S {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd the_field (u32,)
|
fd the_field (u32,)
|
||||||
me foo() fn(self)
|
me foo() fn(self)
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ impl A {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd the_field (u32, i32)
|
fd the_field (u32, i32)
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -536,7 +536,7 @@ impl A {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd pub_field u32
|
fd pub_field u32
|
||||||
me pub_method() fn(&self)
|
me pub_method() fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
|
@ -550,7 +550,7 @@ union U { field: u8, other: u16 }
|
||||||
fn foo(u: U) { u.$0 }
|
fn foo(u: U) { u.$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd field u8
|
fd field u8
|
||||||
fd other u16
|
fd other u16
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -725,8 +725,8 @@ fn test(a: A) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd another u32
|
fd another u32
|
||||||
fd field u8
|
fd field u8
|
||||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -748,8 +748,8 @@ fn test(a: A) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd 0 u8
|
fd 0 u8
|
||||||
fd 1 u32
|
fd 1 u32
|
||||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -770,8 +770,8 @@ fn test(a: A) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd 0 u8
|
fd 0 u8
|
||||||
fd 1 u32
|
fd 1 u32
|
||||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
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 } }"#,
|
impl Foo { fn foo(&self) { $0 } }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd self.field i32
|
fd self.field i32
|
||||||
me self.foo() fn(&self)
|
me self.foo() fn(&self)
|
||||||
lc self &Foo
|
lc self &Foo
|
||||||
sp Self Foo
|
sp Self Foo
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
|
@ -978,12 +978,12 @@ struct Foo(i32);
|
||||||
|
|
||||||
impl Foo { fn foo(&mut self) { $0 } }"#,
|
impl Foo { fn foo(&mut self) { $0 } }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd self.0 i32
|
fd self.0 i32
|
||||||
me self.foo() fn(&mut self)
|
me self.foo() fn(&mut self)
|
||||||
lc self &mut Foo
|
lc self &mut Foo
|
||||||
sp Self Foo
|
sp Self Foo
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1106,7 +1106,7 @@ fn test(a: A) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd 0 u8
|
fd 0 u8
|
||||||
me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
|
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#"
|
expect![[r#"
|
||||||
fd foo &u8
|
fd foo &u8
|
||||||
me foobar() fn(&self)
|
me foobar() fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1199,8 +1199,8 @@ impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd foo &u8
|
fd foo &u8
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -537,10 +537,10 @@ impl Test for T {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self T
|
sp Self T
|
||||||
st T T
|
st T T
|
||||||
tt Test
|
tt Test
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -646,10 +646,10 @@ impl Test for T {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self T
|
sp Self T
|
||||||
st T T
|
st T T
|
||||||
tt Test
|
tt Test
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -663,10 +663,10 @@ impl Test for T {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self T
|
sp Self T
|
||||||
st T T
|
st T T
|
||||||
tt Test
|
tt Test
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -682,10 +682,10 @@ impl Test for T {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self T
|
sp Self T
|
||||||
st T T
|
st T T
|
||||||
tt Test
|
tt Test
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -730,10 +730,10 @@ impl Test for T {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self T
|
sp Self T
|
||||||
st T T
|
st T T
|
||||||
tt Test
|
tt Test
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -78,19 +78,19 @@ fn foo(a: A) { a.$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||||
kw await expr.await
|
kw await expr.await
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -105,19 +105,19 @@ fn foo() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||||
kw await expr.await
|
kw await expr.await
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -134,19 +134,19 @@ fn foo(a: A) { a.$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
|
||||||
kw await expr.await
|
kw await expr.await
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,21 +423,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
sn if if expr {}
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
sn not !expr
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
sn while while expr {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -456,19 +456,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
sn if if expr {}
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
sn not !expr
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
sn while while expr {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -483,18 +483,18 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -509,21 +509,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
sn if if expr {}
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
sn not !expr
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
sn while while expr {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,7 +718,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
expected: (expected_type, expected_name),
|
expected: (expected_type, expected_name),
|
||||||
qualifier_ctx,
|
qualifier_ctx,
|
||||||
token,
|
token,
|
||||||
offset,
|
original_offset,
|
||||||
} = expand_and_analyze(
|
} = expand_and_analyze(
|
||||||
&sema,
|
&sema,
|
||||||
original_file.syntax().clone(),
|
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
|
// 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 krate = scope.krate();
|
||||||
let module = scope.module();
|
let module = scope.module();
|
||||||
|
|
|
@ -22,10 +22,14 @@ use crate::context::{
|
||||||
COMPLETION_MARKER,
|
COMPLETION_MARKER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ExpansionResult {
|
struct ExpansionResult {
|
||||||
original_file: SyntaxNode,
|
original_file: SyntaxNode,
|
||||||
speculative_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,
|
fake_ident_token: SyntaxToken,
|
||||||
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
|
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
|
||||||
}
|
}
|
||||||
|
@ -36,7 +40,8 @@ pub(super) struct AnalysisResult {
|
||||||
pub(super) qualifier_ctx: QualifierCtx,
|
pub(super) qualifier_ctx: QualifierCtx,
|
||||||
/// the original token of the expanded file
|
/// the original token of the expanded file
|
||||||
pub(super) token: SyntaxToken,
|
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(
|
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
|
// make the offset point to the start of the original token, as that is what the
|
||||||
// intermediate offsets calculated in expansion always points to
|
// intermediate offsets calculated in expansion always points to
|
||||||
let offset = offset - relative_offset;
|
let offset = offset - relative_offset;
|
||||||
let expansion =
|
let expansion = expand(
|
||||||
expand(sema, original_file, speculative_file, offset, fake_ident_token, relative_offset);
|
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
|
// add the relative offset back, so that left_biased finds the proper token
|
||||||
let offset = expansion.offset + relative_offset;
|
let original_offset = expansion.original_offset + relative_offset;
|
||||||
let token = expansion.original_file.token_at_offset(offset).left_biased()?;
|
let token = expansion.original_file.token_at_offset(original_offset).left_biased()?;
|
||||||
|
|
||||||
analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
|
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
|
/// 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 fake file repeatedly. As soon as one of the two expansions fail we stop so the original
|
||||||
/// and speculative states stay in sync.
|
/// 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(
|
fn expand(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
mut original_file: SyntaxNode,
|
original_file: SyntaxNode,
|
||||||
mut speculative_file: SyntaxNode,
|
speculative_file: SyntaxNode,
|
||||||
mut offset: TextSize,
|
original_offset: TextSize,
|
||||||
mut fake_ident_token: SyntaxToken,
|
fake_ident_token: SyntaxToken,
|
||||||
relative_offset: TextSize,
|
relative_offset: TextSize,
|
||||||
) -> ExpansionResult {
|
) -> Option<ExpansionResult> {
|
||||||
let _p = tracing::info_span!("CompletionContext::expand").entered();
|
let _p = tracing::info_span!("CompletionContext::expand").entered();
|
||||||
let mut derive_ctx = None;
|
|
||||||
|
|
||||||
'expansion: loop {
|
if !sema.might_be_inside_macro_call(&fake_ident_token)
|
||||||
let parent_item =
|
&& original_file
|
||||||
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
|
.token_at_offset(original_offset + relative_offset)
|
||||||
let ancestor_items = iter::successors(
|
.right_biased()
|
||||||
Option::zip(
|
.is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
|
||||||
find_node_at_offset::<ast::Item>(&original_file, offset),
|
{
|
||||||
find_node_at_offset::<ast::Item>(&speculative_file, offset),
|
// 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
|
// first try to expand attributes as these are always the outermost macro calls
|
||||||
'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
|
'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
|
||||||
match (
|
match (
|
||||||
sema.expand_attr_macro(&actual_item),
|
sema.expand_attr_macro(&actual_item),
|
||||||
sema.speculative_expand_attr_macro(
|
sema.speculative_expand_attr_macro(
|
||||||
&actual_item,
|
&actual_item,
|
||||||
&item_with_fake_ident,
|
&item_with_fake_ident,
|
||||||
fake_ident_token.clone(),
|
fake_ident_token.clone(),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
// maybe parent items have attributes, so continue walking the ancestors
|
// maybe parent items have attributes, so continue walking the ancestors
|
||||||
(None, None) => continue 'ancestors,
|
(None, None) => continue 'ancestors,
|
||||||
// successful expansions
|
// successful expansions
|
||||||
(
|
(
|
||||||
Some(ExpandResult { value: actual_expansion, err: _ }),
|
Some(ExpandResult { value: actual_expansion, err: _ }),
|
||||||
Some((fake_expansion, fake_mapped_token)),
|
Some((fake_expansion, fake_mapped_tokens)),
|
||||||
) => {
|
) => {
|
||||||
let new_offset = fake_mapped_token.text_range().start();
|
let mut accumulated_offset_from_fake_tokens = 0;
|
||||||
if new_offset + relative_offset > actual_expansion.text_range().end() {
|
let actual_range = actual_expansion.text_range().end();
|
||||||
// offset outside of bounds from the original expansion,
|
let result = fake_mapped_tokens
|
||||||
// stop here to prevent problems from happening
|
.into_iter()
|
||||||
break 'expansion;
|
.filter_map(|(fake_mapped_token, rank)| {
|
||||||
}
|
let accumulated_offset = accumulated_offset_from_fake_tokens;
|
||||||
original_file = actual_expansion;
|
if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
|
||||||
speculative_file = fake_expansion;
|
// Proc macros can make the same span with different text, we don't
|
||||||
fake_ident_token = fake_mapped_token;
|
// want them to participate in completion because the macro author probably
|
||||||
offset = new_offset;
|
// didn't intend them to.
|
||||||
continue 'expansion;
|
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
|
if let Some(spec_adt) =
|
||||||
let orig_tt = match ancestors_at_offset(&original_file, offset)
|
spec_attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
|
||||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
|
||||||
.last()
|
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
|
||||||
|
ast::Item::Union(it) => Some(ast::Adt::Union(it)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
{
|
{
|
||||||
Some(it) => it,
|
// might be the path of derive helper or a token tree inside of one
|
||||||
None => break 'expansion,
|
if let Some(helpers) = sema.derive_helper(&orig_attr) {
|
||||||
};
|
for (_mac, file) in helpers {
|
||||||
let spec_tt = match ancestors_at_offset(&speculative_file, offset)
|
if let Some((fake_expansion, fake_mapped_tokens)) = sema.speculative_expand_raw(
|
||||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
file,
|
||||||
.last()
|
spec_adt.syntax(),
|
||||||
{
|
fake_ident_token.clone(),
|
||||||
Some(it) => it,
|
) {
|
||||||
None => break 'expansion,
|
// 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) {
|
let new_offset = fake_mapped_token.text_range().start()
|
||||||
(Either::Left(orig_tt), Either::Left(spec_tt)) => {
|
- TextSize::new(accumulated_offset as u32);
|
||||||
let attrs = orig_tt
|
if new_offset + relative_offset > actual_range {
|
||||||
.syntax()
|
// offset outside of bounds from the original expansion,
|
||||||
.parent()
|
// stop here to prevent problems from happening
|
||||||
.and_then(ast::Meta::cast)
|
return None;
|
||||||
.and_then(|it| it.parent_attr())
|
}
|
||||||
.zip(
|
let result = expand(
|
||||||
spec_tt
|
sema,
|
||||||
.syntax()
|
actual_expansion.clone(),
|
||||||
.parent()
|
fake_expansion.clone(),
|
||||||
.and_then(ast::Meta::cast)
|
new_offset,
|
||||||
.and_then(|it| it.parent_attr()),
|
fake_mapped_token,
|
||||||
);
|
relative_offset,
|
||||||
(Some((orig_tt, spec_tt)), attrs)
|
)?;
|
||||||
}
|
Some((result, rank))
|
||||||
(Either::Right(orig_path), Either::Right(spec_path)) => {
|
})
|
||||||
(None, orig_path.parent_attr().zip(spec_path.parent_attr()))
|
.min_by_key(|(_, rank)| *rank)
|
||||||
}
|
.map(|(result, _)| result);
|
||||||
_ => break 'expansion,
|
if result.is_some() {
|
||||||
};
|
return result;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// at this point we won't have any more successful expansions, so stop
|
|
||||||
break 'expansion;
|
|
||||||
}
|
}
|
||||||
|
// at this point we won't have any more successful expansions, so stop
|
||||||
// Expand fn-like macro calls
|
return None;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// Fill the completion context, this is what does semantic reasoning about the surrounding context
|
||||||
|
@ -285,8 +408,14 @@ fn analyze(
|
||||||
self_token: &SyntaxToken,
|
self_token: &SyntaxToken,
|
||||||
) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
|
) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
|
||||||
let _p = tracing::info_span!("CompletionContext::analyze").entered();
|
let _p = tracing::info_span!("CompletionContext::analyze").entered();
|
||||||
let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } =
|
let ExpansionResult {
|
||||||
expansion_result;
|
original_file,
|
||||||
|
speculative_file,
|
||||||
|
original_offset: _,
|
||||||
|
speculative_offset,
|
||||||
|
fake_ident_token,
|
||||||
|
derive_ctx,
|
||||||
|
} = expansion_result;
|
||||||
|
|
||||||
// Overwrite the path kind for derives
|
// Overwrite the path kind for derives
|
||||||
if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
|
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)
|
find_node_at_offset(&file_with_fake_ident, offset)
|
||||||
{
|
{
|
||||||
let parent = name_ref.syntax().parent()?;
|
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 {
|
if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
|
||||||
path_ctx.kind = PathKind::Derive {
|
path_ctx.kind = PathKind::Derive {
|
||||||
existing_derives: sema
|
existing_derives: sema
|
||||||
|
@ -314,7 +444,7 @@ fn analyze(
|
||||||
return None;
|
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()) {
|
let analysis = if let Some(original) = ast::String::cast(original_token.clone()) {
|
||||||
CompletionAnalysis::String { original, expanded: ast::String::cast(self_token.clone()) }
|
CompletionAnalysis::String { original, expanded: ast::String::cast(self_token.clone()) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -350,8 +480,13 @@ fn analyze(
|
||||||
}
|
}
|
||||||
ast::NameLike::NameRef(name_ref) => {
|
ast::NameLike::NameRef(name_ref) => {
|
||||||
let parent = name_ref.syntax().parent()?;
|
let parent = name_ref.syntax().parent()?;
|
||||||
let (nameref_ctx, qualifier_ctx) =
|
let (nameref_ctx, qualifier_ctx) = classify_name_ref(
|
||||||
classify_name_ref(sema, &original_file, name_ref, parent)?;
|
sema,
|
||||||
|
&original_file,
|
||||||
|
name_ref,
|
||||||
|
expansion_result.original_offset,
|
||||||
|
parent,
|
||||||
|
)?;
|
||||||
|
|
||||||
if let NameRefContext {
|
if let NameRefContext {
|
||||||
kind:
|
kind:
|
||||||
|
@ -636,9 +771,10 @@ fn classify_name_ref(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
original_file: &SyntaxNode,
|
original_file: &SyntaxNode,
|
||||||
name_ref: ast::NameRef,
|
name_ref: ast::NameRef,
|
||||||
|
original_offset: TextSize,
|
||||||
parent: SyntaxNode,
|
parent: SyntaxNode,
|
||||||
) -> Option<(NameRefContext, QualifierCtx)> {
|
) -> 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());
|
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.
|
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
|
||||||
// ex. trait Foo $0 {}
|
// ex. trait Foo $0 {}
|
||||||
// in these cases parser recovery usually kicks in for our inserted identifier, causing it
|
// 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.
|
// expression or an item list.
|
||||||
// The following code checks if the body is missing, if it is we either cut off the body
|
// 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
|
// 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) }
|
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut kind_macro_call = |it: ast::MacroCall| {
|
let kind_item = |it: &SyntaxNode| {
|
||||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
let parent = it.parent()?;
|
||||||
let parent = it.syntax().parent()?;
|
|
||||||
// Any path in an item list will be treated as a macro call by the parser
|
|
||||||
let kind = match_ast! {
|
let kind = match_ast! {
|
||||||
match parent {
|
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::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
|
||||||
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
||||||
Some(it) => match_ast! {
|
Some(it) => match_ast! {
|
||||||
|
@ -1126,6 +1257,23 @@ fn classify_name_ref(
|
||||||
};
|
};
|
||||||
Some(kind)
|
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 make_path_kind_attr = |meta: ast::Meta| {
|
||||||
let attr = meta.parent_attr()?;
|
let attr = meta.parent_attr()?;
|
||||||
let kind = attr.kind();
|
let kind = attr.kind();
|
||||||
|
@ -1153,94 +1301,98 @@ fn classify_name_ref(
|
||||||
|
|
||||||
// Infer the path kind
|
// Infer the path kind
|
||||||
let parent = path.syntax().parent()?;
|
let parent = path.syntax().parent()?;
|
||||||
let kind = match_ast! {
|
let kind = 'find_kind: {
|
||||||
match parent {
|
if parent.kind() == SyntaxKind::ERROR {
|
||||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
if let Some(kind) = inbetween_body_and_decl_check(parent.clone()) {
|
||||||
ast::PathExpr(it) => {
|
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||||
if let Some(p) = it.syntax().parent() {
|
}
|
||||||
let p_kind = p.kind();
|
|
||||||
// The syntax node of interest, for which we want to check whether
|
break 'find_kind kind_item(&parent)?;
|
||||||
// it is sandwiched between an item decl signature and its body.
|
}
|
||||||
let probe = if ast::ExprStmt::can_cast(p_kind) {
|
match_ast! {
|
||||||
Some(p)
|
match parent {
|
||||||
} else if ast::StmtList::can_cast(p_kind) {
|
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||||
Some(it.syntax().clone())
|
ast::PathExpr(it) => {
|
||||||
} else {
|
if let Some(p) = it.syntax().parent() {
|
||||||
None
|
let p_kind = p.kind();
|
||||||
};
|
// The syntax node of interest, for which we want to check whether
|
||||||
if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
|
// 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)));
|
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||||
}
|
}
|
||||||
}
|
make_path_kind_expr(it.into())
|
||||||
|
},
|
||||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
_ => return None,
|
||||||
|
}
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1320,9 +1472,7 @@ fn classify_name_ref(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
PathKind::Item { .. } => {
|
PathKind::Item { .. } => parent.ancestors().find(|it| it.kind() == SyntaxKind::ERROR),
|
||||||
parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(top) = top_node {
|
if let Some(top) = top_node {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use ide_db::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use stdx::{impl_from, never};
|
use stdx::{format_to, impl_from, never};
|
||||||
use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
|
use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -27,10 +27,7 @@ use crate::{
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CompletionItem {
|
pub struct CompletionItem {
|
||||||
/// Label in the completion pop up which identifies completion.
|
/// Label in the completion pop up which identifies completion.
|
||||||
pub label: SmolStr,
|
pub label: CompletionItemLabel,
|
||||||
/// 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>,
|
|
||||||
|
|
||||||
/// Range of identifier that is being completed.
|
/// Range of identifier that is being completed.
|
||||||
///
|
///
|
||||||
|
@ -89,11 +86,23 @@ pub struct CompletionItem {
|
||||||
pub import_to_add: SmallVec<[(String, String); 1]>,
|
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.
|
// We use custom debug for CompletionItem to make snapshot tests more readable.
|
||||||
impl fmt::Debug for CompletionItem {
|
impl fmt::Debug for CompletionItem {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut s = f.debug_struct("CompletionItem");
|
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 {
|
if self.text_edit.len() == 1 {
|
||||||
let atom = self.text_edit.iter().next().unwrap();
|
let atom = self.text_edit.iter().next().unwrap();
|
||||||
s.field("delete", &atom.delete);
|
s.field("delete", &atom.delete);
|
||||||
|
@ -102,7 +111,7 @@ impl fmt::Debug for CompletionItem {
|
||||||
s.field("text_edit", &self.text_edit);
|
s.field("text_edit", &self.text_edit);
|
||||||
}
|
}
|
||||||
s.field("kind", &self.kind);
|
s.field("kind", &self.kind);
|
||||||
if self.lookup() != self.label {
|
if self.lookup() != self.label.primary {
|
||||||
s.field("lookup", &self.lookup());
|
s.field("lookup", &self.lookup());
|
||||||
}
|
}
|
||||||
if let Some(detail) = &self.detail {
|
if let Some(detail) = &self.detail {
|
||||||
|
@ -434,7 +443,7 @@ impl CompletionItem {
|
||||||
|
|
||||||
self.ref_match.map(|(mutability, offset)| {
|
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(
|
ide_db::text_edit::Indel::insert(
|
||||||
offset,
|
offset,
|
||||||
format!("&{}", mutability.as_keyword_for_ref()),
|
format!("&{}", mutability.as_keyword_for_ref()),
|
||||||
|
@ -488,13 +497,13 @@ impl Builder {
|
||||||
let _p = tracing::info_span!("item::Builder::build").entered();
|
let _p = tracing::info_span!("item::Builder::build").entered();
|
||||||
|
|
||||||
let label = self.label;
|
let label = self.label;
|
||||||
let mut label_detail = None;
|
|
||||||
let mut lookup = self.lookup.unwrap_or_else(|| label.clone());
|
let mut lookup = self.lookup.unwrap_or_else(|| label.clone());
|
||||||
let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
|
let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
|
||||||
|
|
||||||
|
let mut detail_left = None;
|
||||||
if !self.doc_aliases.is_empty() {
|
if !self.doc_aliases.is_empty() {
|
||||||
let doc_aliases = self.doc_aliases.iter().join(", ");
|
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
|
let lookup_doc_aliases = self
|
||||||
.doc_aliases
|
.doc_aliases
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -516,16 +525,20 @@ impl Builder {
|
||||||
}
|
}
|
||||||
if let [import_edit] = &*self.imports_to_add {
|
if let [import_edit] = &*self.imports_to_add {
|
||||||
// snippets can have multiple imports, but normal completions only have up to one
|
// snippets can have multiple imports, but normal completions only have up to one
|
||||||
label_detail.replace(format_smolstr!(
|
let detail_left = detail_left.get_or_insert_with(String::new);
|
||||||
"{} (use {})",
|
format_to!(
|
||||||
label_detail.as_deref().unwrap_or_default(),
|
detail_left,
|
||||||
|
"{}(use {})",
|
||||||
|
if detail_left.is_empty() { "" } else { " " },
|
||||||
import_edit.import_path.display(db, self.edition)
|
import_edit.import_path.display(db, self.edition)
|
||||||
));
|
);
|
||||||
} else if let Some(trait_name) = self.trait_name {
|
} else if let Some(trait_name) = self.trait_name {
|
||||||
label_detail.replace(format_smolstr!(
|
let detail_left = detail_left.get_or_insert_with(String::new);
|
||||||
"{} (as {trait_name})",
|
format_to!(
|
||||||
label_detail.as_deref().unwrap_or_default(),
|
detail_left,
|
||||||
));
|
"{}(as {trait_name})",
|
||||||
|
if detail_left.is_empty() { "" } else { " " },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_edit = match self.text_edit {
|
let text_edit = match self.text_edit {
|
||||||
|
@ -546,8 +559,11 @@ impl Builder {
|
||||||
|
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
source_range: self.source_range,
|
source_range: self.source_range,
|
||||||
label,
|
label: CompletionItemLabel {
|
||||||
label_detail,
|
primary: label,
|
||||||
|
detail_left,
|
||||||
|
detail_right: self.detail.clone(),
|
||||||
|
},
|
||||||
text_edit,
|
text_edit,
|
||||||
is_snippet: self.is_snippet,
|
is_snippet: self.is_snippet,
|
||||||
detail: self.detail,
|
detail: self.detail,
|
||||||
|
|
|
@ -748,9 +748,9 @@ mod tests {
|
||||||
let tag = it.kind.tag();
|
let tag = it.kind.tag();
|
||||||
let relevance = display_relevance(it.relevance);
|
let relevance = display_relevance(it.relevance);
|
||||||
items.push(format!(
|
items.push(format!(
|
||||||
"{tag} {}{} {relevance}\n",
|
"{tag} {} {} {relevance}\n",
|
||||||
it.label,
|
it.label.primary,
|
||||||
it.label_detail.clone().unwrap_or_default(),
|
it.label.detail_right.clone().unwrap_or_default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
if let Some((label, _indel, relevance)) = it.ref_match() {
|
if let Some((label, _indel, relevance)) = it.ref_match() {
|
||||||
|
@ -812,13 +812,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st dep::test_mod_b::Struct {…} [type_could_unify]
|
st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type_could_unify]
|
||||||
ex 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]
|
st Struct Struct [type_could_unify+requires_import]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(Struct) []
|
||||||
md dep []
|
md dep []
|
||||||
st Struct (use dep::test_mod_a::Struct) [requires_import]
|
st Struct Struct [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -852,11 +852,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
un Union (use dep::test_mod_b::Union) [type_could_unify+requires_import]
|
un Union Union [type_could_unify+requires_import]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(Union) []
|
||||||
md dep []
|
md dep []
|
||||||
en Union (use dep::test_mod_a::Union) [requires_import]
|
en Union Union [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -888,13 +888,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev dep::test_mod_b::Enum::variant [type_could_unify]
|
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]
|
ex dep::test_mod_b::Enum::variant [type_could_unify]
|
||||||
en Enum (use dep::test_mod_b::Enum) [type_could_unify+requires_import]
|
en Enum Enum [type_could_unify+requires_import]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(Enum) []
|
||||||
md dep []
|
md dep []
|
||||||
en Enum (use dep::test_mod_a::Enum) [requires_import]
|
en Enum Enum [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -926,11 +926,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev dep::test_mod_b::Enum::Variant [type_could_unify]
|
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]
|
ex dep::test_mod_b::Enum::Variant [type_could_unify]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(Enum) []
|
||||||
md dep []
|
md dep []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -958,11 +958,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(fn(usize) -> i32) []
|
||||||
md dep []
|
md dep []
|
||||||
fn function (use dep::test_mod_a::function) [requires_import]
|
fn function fn(usize) -> i32 [requires_import]
|
||||||
fn function(…) (use dep::test_mod_b::function) [requires_import]
|
fn function(…) fn(isize) -> i32 [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -990,11 +990,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST (use dep::test_mod_b::CONST) [type_could_unify+requires_import]
|
ct CONST i32 [type_could_unify+requires_import]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(i32) []
|
||||||
md dep []
|
md dep []
|
||||||
ct CONST (use dep::test_mod_a::CONST) [requires_import]
|
ct CONST i64 [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1022,11 +1022,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sc STATIC (use dep::test_mod_b::STATIC) [type_could_unify+requires_import]
|
sc STATIC i32 [type_could_unify+requires_import]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(i32) []
|
||||||
md dep []
|
md dep []
|
||||||
sc STATIC (use dep::test_mod_a::STATIC) [requires_import]
|
sc STATIC i64 [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1058,7 +1058,7 @@ fn main() {
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me Function []
|
me Function fn(&self, i32) -> bool []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1081,14 +1081,14 @@ fn func(input: Struct) { }
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Struct [type]
|
st Struct Struct [type]
|
||||||
st Self [type]
|
st Self Self [type]
|
||||||
sp Self [type]
|
sp Self Struct [type]
|
||||||
st Struct [type]
|
st Struct Struct [type]
|
||||||
ex Struct [type]
|
ex Struct [type]
|
||||||
lc self [local]
|
lc self &Struct [local]
|
||||||
fn func(…) []
|
fn func(…) fn(Struct) []
|
||||||
me self.test() []
|
me self.test() fn(&self) []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1109,13 +1109,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc input [type+name+local]
|
lc input bool [type+name+local]
|
||||||
ex input [type]
|
ex input [type]
|
||||||
ex true [type]
|
ex true [type]
|
||||||
ex false [type]
|
ex false [type]
|
||||||
lc inputbad [local]
|
lc inputbad i32 [local]
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
fn test(…) []
|
fn test(…) fn(bool) []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1133,10 @@ fn main() { Foo::Fo$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "Foo {…}",
|
label: "Foo {…}",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"Foo { x: i32, y: i32 }",
|
||||||
|
),
|
||||||
source_range: 54..56,
|
source_range: 54..56,
|
||||||
delete: 54..56,
|
delete: 54..56,
|
||||||
insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
|
insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
|
||||||
|
@ -1161,6 +1165,10 @@ fn main() { Foo::Fo$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "Foo(…)",
|
label: "Foo(…)",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"Foo(i32, i32)",
|
||||||
|
),
|
||||||
source_range: 46..48,
|
source_range: 46..48,
|
||||||
delete: 46..48,
|
delete: 46..48,
|
||||||
insert: "Foo(${1:()}, ${2:()})$0",
|
insert: "Foo(${1:()}, ${2:()})$0",
|
||||||
|
@ -1189,6 +1197,10 @@ fn main() { fo$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "foo(…)",
|
label: "foo(…)",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(u32, u32, T) -> (u32, T)",
|
||||||
|
),
|
||||||
source_range: 68..70,
|
source_range: 68..70,
|
||||||
delete: 68..70,
|
delete: 68..70,
|
||||||
insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
|
insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
|
||||||
|
@ -1201,6 +1213,10 @@ fn main() { fo$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "main()",
|
label: "main()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 68..70,
|
source_range: 68..70,
|
||||||
delete: 68..70,
|
delete: 68..70,
|
||||||
insert: "main();$0",
|
insert: "main();$0",
|
||||||
|
@ -1228,6 +1244,10 @@ fn main() { Foo::Fo$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "Foo",
|
label: "Foo",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"Foo",
|
||||||
|
),
|
||||||
source_range: 35..37,
|
source_range: 35..37,
|
||||||
delete: 35..37,
|
delete: 35..37,
|
||||||
insert: "Foo$0",
|
insert: "Foo$0",
|
||||||
|
@ -1260,6 +1280,10 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "main()",
|
label: "main()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "main();$0",
|
insert: "main();$0",
|
||||||
|
@ -1271,6 +1295,8 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "m",
|
label: "m",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: None,
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "m",
|
insert: "m",
|
||||||
|
@ -1280,6 +1306,10 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "m::Spam::Bar(…)",
|
label: "m::Spam::Bar(…)",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"m::Spam::Bar(i32)",
|
||||||
|
),
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "m::Spam::Bar(${1:()})$0",
|
insert: "m::Spam::Bar(${1:()})$0",
|
||||||
|
@ -1305,6 +1335,10 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "m::Spam::Foo",
|
label: "m::Spam::Foo",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"m::Spam::Foo",
|
||||||
|
),
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "m::Spam::Foo$0",
|
insert: "m::Spam::Foo$0",
|
||||||
|
@ -1347,6 +1381,10 @@ fn main() { som$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "main()",
|
label: "main()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 56..59,
|
source_range: 56..59,
|
||||||
delete: 56..59,
|
delete: 56..59,
|
||||||
insert: "main();$0",
|
insert: "main();$0",
|
||||||
|
@ -1358,6 +1396,10 @@ fn main() { som$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "something_deprecated()",
|
label: "something_deprecated()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 56..59,
|
source_range: 56..59,
|
||||||
delete: 56..59,
|
delete: 56..59,
|
||||||
insert: "something_deprecated();$0",
|
insert: "something_deprecated();$0",
|
||||||
|
@ -1382,6 +1424,10 @@ fn foo() { A { the$0 } }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "the_field",
|
label: "the_field",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"u32",
|
||||||
|
),
|
||||||
source_range: 57..60,
|
source_range: 57..60,
|
||||||
delete: 57..60,
|
delete: 57..60,
|
||||||
insert: "the_field",
|
insert: "the_field",
|
||||||
|
@ -1429,6 +1475,10 @@ impl S {
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "bar()",
|
label: "bar()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(self)",
|
||||||
|
),
|
||||||
source_range: 94..94,
|
source_range: 94..94,
|
||||||
delete: 94..94,
|
delete: 94..94,
|
||||||
insert: "bar();$0",
|
insert: "bar();$0",
|
||||||
|
@ -1460,6 +1510,10 @@ impl S {
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "foo",
|
label: "foo",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"{unknown}",
|
||||||
|
),
|
||||||
source_range: 94..94,
|
source_range: 94..94,
|
||||||
delete: 94..94,
|
delete: 94..94,
|
||||||
insert: "foo",
|
insert: "foo",
|
||||||
|
@ -1498,6 +1552,8 @@ use self::E::*;
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "my",
|
label: "my",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: None,
|
||||||
source_range: 10..12,
|
source_range: 10..12,
|
||||||
delete: 10..12,
|
delete: 10..12,
|
||||||
insert: "my",
|
insert: "my",
|
||||||
|
@ -1510,6 +1566,10 @@ use self::E::*;
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "V",
|
label: "V",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"V",
|
||||||
|
),
|
||||||
source_range: 10..12,
|
source_range: 10..12,
|
||||||
delete: 10..12,
|
delete: 10..12,
|
||||||
insert: "V$0",
|
insert: "V$0",
|
||||||
|
@ -1524,6 +1584,10 @@ use self::E::*;
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "E",
|
label: "E",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"E",
|
||||||
|
),
|
||||||
source_range: 10..12,
|
source_range: 10..12,
|
||||||
delete: 10..12,
|
delete: 10..12,
|
||||||
insert: "E",
|
insert: "E",
|
||||||
|
@ -1556,6 +1620,10 @@ fn foo(s: S) { s.$0 }
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "the_method()",
|
label: "the_method()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(&self)",
|
||||||
|
),
|
||||||
source_range: 81..81,
|
source_range: 81..81,
|
||||||
delete: 81..81,
|
delete: 81..81,
|
||||||
insert: "the_method();$0",
|
insert: "the_method();$0",
|
||||||
|
@ -1729,9 +1797,9 @@ fn test(bar: u32) { }
|
||||||
fn foo(s: S) { test(s.$0) }
|
fn foo(s: S) { test(s.$0) }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd bar [type+name]
|
fd bar u32 [type+name]
|
||||||
fd baz [type]
|
fd baz u32 [type]
|
||||||
fd foo []
|
fd foo i64 []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1745,9 +1813,9 @@ struct B { x: (), y: f32, bar: u32 }
|
||||||
fn foo(a: A) { B { bar: a.$0 }; }
|
fn foo(a: A) { B { bar: a.$0 }; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd bar [type+name]
|
fd bar u32 [type+name]
|
||||||
fd baz [type]
|
fd baz u32 [type]
|
||||||
fd foo []
|
fd foo i64 []
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1768,6 +1836,10 @@ fn f() -> i32 {
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "0",
|
label: "0",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"i32",
|
||||||
|
),
|
||||||
source_range: 56..57,
|
source_range: 56..57,
|
||||||
delete: 56..57,
|
delete: 56..57,
|
||||||
insert: "0",
|
insert: "0",
|
||||||
|
@ -1804,9 +1876,9 @@ fn f(foo: i64) { }
|
||||||
fn foo(a: A) { B { bar: f(a.$0) }; }
|
fn foo(a: A) { B { bar: f(a.$0) }; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd foo [type+name]
|
fd foo i64 [type+name]
|
||||||
fd bar []
|
fd bar u32 []
|
||||||
fd baz []
|
fd baz u32 []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_relevance(
|
check_relevance(
|
||||||
|
@ -1817,9 +1889,9 @@ fn f(foo: i64) { }
|
||||||
fn foo(a: A) { f(B { bar: a.$0 }); }
|
fn foo(a: A) { f(B { bar: a.$0 }); }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd bar [type+name]
|
fd bar u32 [type+name]
|
||||||
fd baz [type]
|
fd baz u32 [type]
|
||||||
fd foo []
|
fd foo i64 []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1832,13 +1904,13 @@ struct WorldSnapshot { _f: () };
|
||||||
fn go(world: &WorldSnapshot) { go(w$0) }
|
fn go(world: &WorldSnapshot) { go(w$0) }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc world [type+name+local]
|
lc world &WorldSnapshot [type+name+local]
|
||||||
ex world [type]
|
ex world [type]
|
||||||
st WorldSnapshot {…} []
|
st WorldSnapshot {…} WorldSnapshot { _f: () } []
|
||||||
st &WorldSnapshot {…} [type]
|
st &WorldSnapshot {…} [type]
|
||||||
st WorldSnapshot []
|
st WorldSnapshot WorldSnapshot []
|
||||||
st &WorldSnapshot [type]
|
st &WorldSnapshot [type]
|
||||||
fn go(…) []
|
fn go(…) fn(&WorldSnapshot) []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1852,9 +1924,9 @@ struct Foo;
|
||||||
fn f(foo: &Foo) { f(foo, w$0) }
|
fn f(foo: &Foo) { f(foo, w$0) }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc foo [local]
|
lc foo &Foo [local]
|
||||||
st Foo []
|
st Foo Foo []
|
||||||
fn f(…) []
|
fn f(…) fn(&Foo) []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1869,12 +1941,12 @@ fn bar() -> u8 { 0 }
|
||||||
fn f() { A { bar: b$0 }; }
|
fn f() { A { bar: b$0 }; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn bar() [type+name]
|
fn bar() fn() -> u8 [type+name]
|
||||||
fn baz() [type]
|
fn baz() fn() -> u8 [type]
|
||||||
ex bar() [type]
|
ex bar() [type]
|
||||||
ex baz() [type]
|
ex baz() [type]
|
||||||
st A []
|
st A A []
|
||||||
fn f() []
|
fn f() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1895,9 +1967,9 @@ fn f() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me aaa() [type+name]
|
me aaa() fn(&self) -> u32 [type+name]
|
||||||
me bbb() [type]
|
me bbb() fn(&self) -> u32 [type]
|
||||||
me ccc() []
|
me ccc() fn(&self) -> u64 []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1916,7 +1988,7 @@ fn f() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me aaa() [name]
|
me aaa() fn(&self) -> u64 [name]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1934,14 +2006,14 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc s [name+local]
|
lc s S [name+local]
|
||||||
lc &mut s [type+name+local]
|
lc &mut s [type+name+local]
|
||||||
st S []
|
st S S []
|
||||||
st &mut S [type]
|
st &mut S [type]
|
||||||
st S []
|
st S S []
|
||||||
st &mut S [type]
|
st &mut S [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&mut S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_relevance(
|
check_relevance(
|
||||||
|
@ -1954,13 +2026,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc s [type+name+local]
|
lc s S [type+name+local]
|
||||||
st S [type]
|
st S S [type]
|
||||||
st S [type]
|
st S S [type]
|
||||||
ex s [type]
|
ex s [type]
|
||||||
ex S [type]
|
ex S [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&mut S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_relevance(
|
check_relevance(
|
||||||
|
@ -1973,13 +2045,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc ssss [type+local]
|
lc ssss S [type+local]
|
||||||
st S [type]
|
st S S [type]
|
||||||
st S [type]
|
st S S [type]
|
||||||
ex ssss [type]
|
ex ssss [type]
|
||||||
ex S [type]
|
ex S [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&mut S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2010,19 +2082,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
|
ex core::ops::Deref::deref(&t) [type_could_unify]
|
||||||
lc m [local]
|
lc m i32 [local]
|
||||||
lc t [local]
|
lc t T [local]
|
||||||
lc &t [type+local]
|
lc &t [type+local]
|
||||||
st S []
|
st S S []
|
||||||
st &S [type]
|
st &S [type]
|
||||||
st S []
|
st S S []
|
||||||
st &S [type]
|
st &S [type]
|
||||||
st T []
|
st T T []
|
||||||
st &T [type]
|
st &T [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
md core []
|
md core []
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2059,19 +2131,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
|
ex core::ops::DerefMut::deref_mut(&mut t) [type_could_unify]
|
||||||
lc m [local]
|
lc m i32 [local]
|
||||||
lc t [local]
|
lc t T [local]
|
||||||
lc &mut t [type+local]
|
lc &mut t [type+local]
|
||||||
st S []
|
st S S []
|
||||||
st &mut S [type]
|
st &mut S [type]
|
||||||
st S []
|
st S S []
|
||||||
st &mut S [type]
|
st &mut S [type]
|
||||||
st T []
|
st T T []
|
||||||
st &mut T [type]
|
st &mut T [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&mut S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
md core []
|
md core []
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2087,9 +2159,9 @@ fn foo(bar: u32) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc baz [local]
|
lc baz i32 [local]
|
||||||
lc bar [local]
|
lc bar u32 [local]
|
||||||
fn foo(…) []
|
fn foo(…) fn(u32) []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2105,13 +2177,13 @@ fn foo() {
|
||||||
fn bar(t: Foo) {}
|
fn bar(t: Foo) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Foo::A [type]
|
ev Foo::A Foo::A [type]
|
||||||
ev Foo::B [type]
|
ev Foo::B Foo::B [type]
|
||||||
en Foo [type]
|
en Foo Foo [type]
|
||||||
ex Foo::A [type]
|
ex Foo::A [type]
|
||||||
ex Foo::B [type]
|
ex Foo::B [type]
|
||||||
fn bar(…) []
|
fn bar(…) fn(Foo) []
|
||||||
fn foo() []
|
fn foo() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2127,14 +2199,14 @@ fn foo() {
|
||||||
fn bar(t: &Foo) {}
|
fn bar(t: &Foo) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Foo::A []
|
ev Foo::A Foo::A []
|
||||||
ev &Foo::A [type]
|
ev &Foo::A [type]
|
||||||
ev Foo::B []
|
ev Foo::B Foo::B []
|
||||||
ev &Foo::B [type]
|
ev &Foo::B [type]
|
||||||
en Foo []
|
en Foo Foo []
|
||||||
en &Foo [type]
|
en &Foo [type]
|
||||||
fn bar(…) []
|
fn bar(…) fn(&Foo) []
|
||||||
fn foo() []
|
fn foo() fn() []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2163,18 +2235,18 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify]
|
ex core::ops::Deref::deref(&bar()) [type_could_unify]
|
||||||
st S []
|
st S S []
|
||||||
st &S [type]
|
st &S [type]
|
||||||
st S []
|
st S S []
|
||||||
st &S [type]
|
st &S [type]
|
||||||
st T []
|
st T T []
|
||||||
st &T [type]
|
st &T [type]
|
||||||
fn bar() []
|
fn bar() fn() -> T []
|
||||||
fn &bar() [type]
|
fn &bar() [type]
|
||||||
fn foo(…) []
|
fn foo(…) fn(&S) []
|
||||||
fn main() []
|
fn main() fn() []
|
||||||
md core []
|
md core []
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2191,7 +2263,7 @@ impl Sub for u32 {}
|
||||||
fn foo(a: u32) { a.$0 }
|
fn foo(a: u32) { a.$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me sub(…) (as Sub) [op_method]
|
me sub(…) fn(self, Self) -> Self [op_method]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_relevance(
|
check_relevance(
|
||||||
|
@ -2212,9 +2284,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn new() []
|
fn new() fn() -> Foo []
|
||||||
me eq(…) (as PartialEq) [op_method]
|
me eq(…) fn(&self, &Rhs) -> bool [op_method]
|
||||||
me ne(…) (as PartialEq) [op_method]
|
me ne(…) fn(&self, &Rhs) -> bool [op_method]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2238,9 +2310,9 @@ fn test() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn fn_ctr() [type_could_unify]
|
fn fn_ctr() fn() -> Foo [type_could_unify]
|
||||||
fn fn_ctr_self() [type_could_unify]
|
fn fn_ctr_self() fn() -> Option<Foo> [type_could_unify]
|
||||||
fn fn_another(…) [type_could_unify]
|
fn fn_another(…) fn(u32) -> Other [type_could_unify]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2384,12 +2456,12 @@ fn test() {
|
||||||
// Constructor
|
// Constructor
|
||||||
// Others
|
// Others
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn fn_direct_ctr() [type_could_unify]
|
fn fn_direct_ctr() fn() -> Foo [type_could_unify]
|
||||||
fn fn_ctr_with_args(…) [type_could_unify]
|
fn fn_ctr_with_args(…) fn(u32) -> Foo [type_could_unify]
|
||||||
fn fn_builder() [type_could_unify]
|
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||||
fn fn_ctr() [type_could_unify]
|
fn fn_ctr() fn() -> Result<Foo> [type_could_unify]
|
||||||
me fn_no_ret(…) [type_could_unify]
|
me fn_no_ret(…) fn(&self) [type_could_unify]
|
||||||
fn fn_other() [type_could_unify]
|
fn fn_other() fn() -> Result<u32> [type_could_unify]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2420,14 +2492,14 @@ fn test() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn fn_direct_ctr() [type_could_unify]
|
fn fn_direct_ctr() fn() -> Foo<T> [type_could_unify]
|
||||||
fn fn_ctr_with_args(…) [type_could_unify]
|
fn fn_ctr_with_args(…) fn(T) -> Foo<T> [type_could_unify]
|
||||||
fn fn_builder() [type_could_unify]
|
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||||
fn fn_ctr_wrapped() [type_could_unify]
|
fn fn_ctr_wrapped() fn() -> Option<Foo<T>> [type_could_unify]
|
||||||
fn fn_ctr_wrapped_2() [type_could_unify]
|
fn fn_ctr_wrapped_2() fn() -> Result<Foo<T>, u32> [type_could_unify]
|
||||||
me fn_returns_unit(…) [type_could_unify]
|
me fn_returns_unit(…) fn(&self) [type_could_unify]
|
||||||
fn fn_other() [type_could_unify]
|
fn fn_other() fn() -> Option<u32> [type_could_unify]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2456,13 +2528,13 @@ fn test() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn fn_direct_ctr() [type_could_unify]
|
fn fn_direct_ctr() fn() -> Foo<T> [type_could_unify]
|
||||||
fn fn_ctr_with_args(…) [type_could_unify]
|
fn fn_ctr_with_args(…) fn(T) -> Foo<T> [type_could_unify]
|
||||||
fn fn_builder() [type_could_unify]
|
fn fn_builder() fn() -> FooBuilder [type_could_unify]
|
||||||
fn fn_ctr() [type_could_unify]
|
fn fn_ctr() fn() -> Option<Foo<T>> [type_could_unify]
|
||||||
fn fn_ctr2() [type_could_unify]
|
fn fn_ctr2() fn() -> Result<Foo<T>, u32> [type_could_unify]
|
||||||
me fn_no_ret(…) [type_could_unify]
|
me fn_no_ret(…) fn(&self) [type_could_unify]
|
||||||
fn fn_other() [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 {
|
CompletionItem {
|
||||||
label: "baz()",
|
label: "baz()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(&self) -> u32",
|
||||||
|
),
|
||||||
source_range: 109..110,
|
source_range: 109..110,
|
||||||
delete: 109..110,
|
delete: 109..110,
|
||||||
insert: "baz()$0",
|
insert: "baz()$0",
|
||||||
|
@ -2513,6 +2589,10 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "bar",
|
label: "bar",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"u32",
|
||||||
|
),
|
||||||
source_range: 109..110,
|
source_range: 109..110,
|
||||||
delete: 109..110,
|
delete: 109..110,
|
||||||
insert: "bar",
|
insert: "bar",
|
||||||
|
@ -2524,6 +2604,10 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "qux",
|
label: "qux",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 109..110,
|
source_range: 109..110,
|
||||||
text_edit: TextEdit {
|
text_edit: TextEdit {
|
||||||
indels: [
|
indels: [
|
||||||
|
@ -2562,6 +2646,10 @@ fn foo() {
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "field",
|
label: "field",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn()",
|
||||||
|
),
|
||||||
source_range: 76..78,
|
source_range: 76..78,
|
||||||
delete: 76..78,
|
delete: 76..78,
|
||||||
insert: "field",
|
insert: "field",
|
||||||
|
@ -2610,6 +2698,10 @@ fn main() {
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "foo()",
|
label: "foo()",
|
||||||
|
detail_left: None,
|
||||||
|
detail_right: Some(
|
||||||
|
"fn() -> S",
|
||||||
|
),
|
||||||
source_range: 95..95,
|
source_range: 95..95,
|
||||||
delete: 95..95,
|
delete: 95..95,
|
||||||
insert: "foo()$0",
|
insert: "foo()$0",
|
||||||
|
@ -2661,15 +2753,15 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
lc foo [type+local]
|
lc foo Foo<u32> [type+local]
|
||||||
ex foo [type]
|
ex foo [type]
|
||||||
ex Foo::B [type]
|
ex Foo::B [type]
|
||||||
ev Foo::A(…) [type_could_unify]
|
ev Foo::A(…) Foo::A(T) [type_could_unify]
|
||||||
ev Foo::B [type_could_unify]
|
ev Foo::B Foo::B [type_could_unify]
|
||||||
en Foo [type_could_unify]
|
en Foo Foo<{unknown}> [type_could_unify]
|
||||||
fn foo() []
|
fn foo() fn() []
|
||||||
fn bar() []
|
fn bar() fn() -> Foo<u8> []
|
||||||
fn baz() []
|
fn baz() fn() -> Foo<T> []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2697,20 +2789,20 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn not [snippet]
|
sn not !expr [snippet]
|
||||||
me not() (use ops::Not) [type_could_unify+requires_import]
|
me not() fn(self) -> <Self as Not>::Output [type_could_unify+requires_import]
|
||||||
sn if []
|
sn if if expr {} []
|
||||||
sn while []
|
sn while while expr {} []
|
||||||
sn ref []
|
sn ref &expr []
|
||||||
sn refm []
|
sn refm &mut expr []
|
||||||
sn deref []
|
sn deref *expr []
|
||||||
sn unsafe []
|
sn unsafe unsafe {} []
|
||||||
sn match []
|
sn match match expr {} []
|
||||||
sn box []
|
sn box Box::new(expr) []
|
||||||
sn dbg []
|
sn dbg dbg!(expr) []
|
||||||
sn dbgr []
|
sn dbgr dbg!(&expr) []
|
||||||
sn call []
|
sn call function(expr) []
|
||||||
sn return []
|
sn return return expr []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2730,19 +2822,19 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
&[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me f() []
|
me f() fn(&self) []
|
||||||
sn ref []
|
sn ref &expr []
|
||||||
sn refm []
|
sn refm &mut expr []
|
||||||
sn deref []
|
sn deref *expr []
|
||||||
sn unsafe []
|
sn unsafe unsafe {} []
|
||||||
sn match []
|
sn match match expr {} []
|
||||||
sn box []
|
sn box Box::new(expr) []
|
||||||
sn dbg []
|
sn dbg dbg!(expr) []
|
||||||
sn dbgr []
|
sn dbgr dbg!(&expr) []
|
||||||
sn call []
|
sn call function(expr) []
|
||||||
sn let []
|
sn let let []
|
||||||
sn letm []
|
sn letm let mut []
|
||||||
sn return []
|
sn return return expr []
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2765,12 +2857,12 @@ fn f() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Buffer []
|
st Buffer Buffer []
|
||||||
fn f() []
|
fn f() fn() []
|
||||||
md std []
|
md std []
|
||||||
tt BufRead (use std::io::BufRead) [requires_import]
|
tt BufRead [requires_import]
|
||||||
st BufReader (use std::io::BufReader) [requires_import]
|
st BufReader BufReader [requires_import]
|
||||||
st BufWriter (use std::io::BufWriter) [requires_import]
|
st BufWriter BufWriter [requires_import]
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2979,6 +3071,12 @@ fn main() {
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "flush()",
|
label: "flush()",
|
||||||
|
detail_left: Some(
|
||||||
|
"(as Write)",
|
||||||
|
),
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(&self)",
|
||||||
|
),
|
||||||
source_range: 193..193,
|
source_range: 193..193,
|
||||||
delete: 193..193,
|
delete: 193..193,
|
||||||
insert: "flush();$0",
|
insert: "flush();$0",
|
||||||
|
@ -3006,6 +3104,12 @@ fn main() {
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "write()",
|
label: "write()",
|
||||||
|
detail_left: Some(
|
||||||
|
"(as Write)",
|
||||||
|
),
|
||||||
|
detail_right: Some(
|
||||||
|
"fn(&self)",
|
||||||
|
),
|
||||||
source_range: 193..193,
|
source_range: 193..193,
|
||||||
delete: 193..193,
|
delete: 193..193,
|
||||||
insert: "write();$0",
|
insert: "write();$0",
|
||||||
|
|
|
@ -118,10 +118,16 @@ fn completion_list_with_config_raw(
|
||||||
let items = get_all_items(config, ra_fixture, trigger_character);
|
let items = get_all_items(config, ra_fixture, trigger_character);
|
||||||
items
|
items
|
||||||
.into_iter()
|
.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::Keyword)
|
||||||
.filter(|it| include_keywords || it.kind != CompletionItemKind::Snippet)
|
.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()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,27 +179,30 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
|
||||||
let label_width = completions
|
let label_width = completions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|it| {
|
.map(|it| {
|
||||||
monospace_width(&it.label)
|
monospace_width(&it.label.primary)
|
||||||
+ monospace_width(it.label_detail.as_deref().unwrap_or_default())
|
+ 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()
|
.max()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default();
|
||||||
.min(22);
|
|
||||||
completions
|
completions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|it| {
|
.map(|it| {
|
||||||
let tag = it.kind.tag();
|
let tag = it.kind.tag();
|
||||||
let var_name = format!("{tag} {}", it.label);
|
let mut buf = format!("{tag} {}", it.label.primary);
|
||||||
let mut buf = var_name;
|
if let Some(label_detail) = &it.label.detail_left {
|
||||||
if let Some(ref label_detail) = it.label_detail {
|
format_to!(buf, " {label_detail}");
|
||||||
format_to!(buf, "{label_detail}");
|
|
||||||
}
|
}
|
||||||
if let Some(detail) = it.detail {
|
if let Some(detail_right) = it.label.detail_right {
|
||||||
let width = label_width.saturating_sub(
|
let pad_with = label_width.saturating_sub(
|
||||||
monospace_width(&it.label)
|
monospace_width(&it.label.primary)
|
||||||
+ monospace_width(&it.label_detail.unwrap_or_default()),
|
+ 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 {
|
if it.deprecated {
|
||||||
format_to!(buf, " DEPRECATED");
|
format_to!(buf, " DEPRECATED");
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub struct Foo(#[m$0] i32);
|
||||||
at cold
|
at cold
|
||||||
at deny(…)
|
at deny(…)
|
||||||
at deprecated
|
at deprecated
|
||||||
at derive macro derive
|
at derive macro derive
|
||||||
at derive(…)
|
at derive(…)
|
||||||
at doc = "…"
|
at doc = "…"
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
|
@ -367,9 +367,9 @@ struct Foo;
|
||||||
at cfg_attr(…)
|
at cfg_attr(…)
|
||||||
at deny(…)
|
at deny(…)
|
||||||
at deprecated
|
at deprecated
|
||||||
at derive macro derive
|
at derive macro derive
|
||||||
at derive(…)
|
at derive(…)
|
||||||
at derive_const macro derive_const
|
at derive_const macro derive_const
|
||||||
at doc = "…"
|
at doc = "…"
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at doc(hidden)
|
at doc(hidden)
|
||||||
|
@ -790,10 +790,10 @@ mod derive {
|
||||||
#[derive($0)] struct Test;
|
#[derive($0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
de Clone macro Clone
|
de Clone macro Clone
|
||||||
de Clone, Copy
|
de Clone, Copy
|
||||||
de Default macro Default
|
de Default macro Default
|
||||||
de PartialEq macro PartialEq
|
de PartialEq macro PartialEq
|
||||||
de PartialEq, Eq
|
de PartialEq, Eq
|
||||||
de PartialEq, Eq, PartialOrd, Ord
|
de PartialEq, Eq, PartialOrd, Ord
|
||||||
de PartialEq, PartialOrd
|
de PartialEq, PartialOrd
|
||||||
|
@ -812,9 +812,9 @@ mod derive {
|
||||||
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
|
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
de Clone macro Clone
|
de Clone macro Clone
|
||||||
de Clone, Copy
|
de Clone, Copy
|
||||||
de Default macro Default
|
de Default macro Default
|
||||||
de Eq
|
de Eq
|
||||||
de Eq, PartialOrd, Ord
|
de Eq, PartialOrd, Ord
|
||||||
de PartialOrd
|
de PartialOrd
|
||||||
|
@ -833,9 +833,9 @@ mod derive {
|
||||||
#[derive($0 serde::Serialize, PartialEq)] struct Test;
|
#[derive($0 serde::Serialize, PartialEq)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
de Clone macro Clone
|
de Clone macro Clone
|
||||||
de Clone, Copy
|
de Clone, Copy
|
||||||
de Default macro Default
|
de Default macro Default
|
||||||
de Eq
|
de Eq
|
||||||
de Eq, PartialOrd, Ord
|
de Eq, PartialOrd, Ord
|
||||||
de PartialOrd
|
de PartialOrd
|
||||||
|
@ -854,9 +854,9 @@ mod derive {
|
||||||
#[derive(PartialEq, Eq, Or$0)] struct Test;
|
#[derive(PartialEq, Eq, Or$0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
de Clone macro Clone
|
de Clone macro Clone
|
||||||
de Clone, Copy
|
de Clone, Copy
|
||||||
de Default macro Default
|
de Default macro Default
|
||||||
de PartialOrd
|
de PartialOrd
|
||||||
de PartialOrd, Ord
|
de PartialOrd, Ord
|
||||||
md core
|
md core
|
||||||
|
|
|
@ -26,22 +26,22 @@ fn baz() {
|
||||||
"#,
|
"#,
|
||||||
// This should not contain `FooDesc {…}`.
|
// This should not contain `FooDesc {…}`.
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
fn baz() fn()
|
fn baz() fn()
|
||||||
fn create_foo(…) fn(&FooDesc)
|
fn create_foo(…) fn(&FooDesc)
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md _69latrick
|
md _69latrick
|
||||||
md module
|
md module
|
||||||
sc STATIC Unit
|
sc STATIC Unit
|
||||||
st FooDesc FooDesc
|
st FooDesc FooDesc
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
un Union Union
|
un Union Union
|
||||||
ev TupleV(…) TupleV(u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -76,14 +76,14 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn func(…) fn((i32, i32))
|
fn func(…) fn((i32, i32))
|
||||||
lc ifletlocal i32
|
lc ifletlocal i32
|
||||||
lc letlocal i32
|
lc letlocal i32
|
||||||
lc matcharm i32
|
lc matcharm i32
|
||||||
lc param0 (i32, i32)
|
lc param0 (i32, i32)
|
||||||
lc param1 i32
|
lc param1 i32
|
||||||
lc param2 i32
|
lc param2 i32
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -122,25 +122,25 @@ impl Unit {
|
||||||
"#,
|
"#,
|
||||||
// `self` is in here twice, once as the module, once as the local
|
// `self` is in here twice, once as the module, once as the local
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
cp CONST_PARAM
|
cp CONST_PARAM
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
fn local_func() fn()
|
fn local_func() fn()
|
||||||
me self.foo() fn(self)
|
me self.foo() fn(self)
|
||||||
lc self Unit
|
lc self Unit
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
md qualified
|
md qualified
|
||||||
sp Self Unit
|
sp Self Unit
|
||||||
sc STATIC Unit
|
sc STATIC Unit
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tp TypeParam
|
tp TypeParam
|
||||||
un Union Union
|
un Union Union
|
||||||
ev TupleV(…) TupleV(u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -187,19 +187,19 @@ impl Unit {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
md qualified
|
md qualified
|
||||||
sc STATIC Unit
|
sc STATIC Unit
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
ev TupleV(…) TupleV(u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
?? Unresolved
|
?? Unresolved
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -216,8 +216,8 @@ fn complete_in_block() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -264,8 +264,8 @@ fn complete_after_if_expr() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -313,8 +313,8 @@ fn complete_in_match_arm() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -337,8 +337,8 @@ fn completes_in_loop_ctx() {
|
||||||
check_empty(
|
check_empty(
|
||||||
r"fn my() { loop { $0 } }",
|
r"fn my() { loop { $0 } }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn my() fn()
|
fn my() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw break
|
kw break
|
||||||
kw const
|
kw const
|
||||||
|
@ -376,22 +376,22 @@ fn completes_in_loop_ctx() {
|
||||||
check_empty(
|
check_empty(
|
||||||
r"fn my() { loop { foo.$0 } }",
|
r"fn my() { loop { foo.$0 } }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn break break expr
|
sn break break expr
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
sn if if expr {}
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
sn not !expr
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
sn while while expr {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -401,8 +401,8 @@ fn completes_in_let_initializer() {
|
||||||
check_empty(
|
check_empty(
|
||||||
r#"fn main() { let _ = $0 }"#,
|
r#"fn main() { let _ = $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -434,9 +434,9 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -469,9 +469,9 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
lc bar i32
|
lc bar i32
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -499,10 +499,10 @@ fn quux(x: i32) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn quux(…) fn(i32)
|
fn quux(…) fn(i32)
|
||||||
lc x i32
|
lc x i32
|
||||||
ma m!(…) macro_rules! m
|
ma m!(…) macro_rules! m
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -526,10 +526,10 @@ fn quux(x: i32) {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn quux(…) fn(i32)
|
fn quux(…) fn(i32)
|
||||||
lc x i32
|
lc x i32
|
||||||
ma m!(…) macro_rules! m
|
ma m!(…) macro_rules! m
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -554,11 +554,11 @@ fn quux(x: i32) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn quux(…) fn(i32)
|
fn quux(…) fn(i32)
|
||||||
lc x i32
|
lc x i32
|
||||||
lc y i32
|
lc y i32
|
||||||
ma m!(…) macro_rules! m
|
ma m!(…) macro_rules! m
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -590,12 +590,12 @@ fn func() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||||
fn assoc_fn() fn()
|
fn assoc_fn() fn()
|
||||||
ta AssocType type AssocType = ()
|
ta AssocType type AssocType = ()
|
||||||
ev RecordV {…} RecordV { field: u32 }
|
ev RecordV {…} RecordV { field: u32 }
|
||||||
ev TupleV(…) TupleV(u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ev UnitV UnitV
|
ev UnitV UnitV
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -633,7 +633,7 @@ fn func() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn variant fn() -> Enum
|
fn variant fn() -> Enum
|
||||||
ev Variant Variant
|
ev Variant Variant
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -650,8 +650,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn() -> impl Trait<U>
|
fn foo() fn() -> impl Trait<U>
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
tt Trait
|
tt Trait
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -670,9 +670,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn bar() async fn() -> impl Trait<U>
|
fn bar() async fn() -> impl Trait<U>
|
||||||
fn foo() async fn() -> u8
|
fn foo() async fn() -> u8
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
tt Trait
|
tt Trait
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -692,9 +692,9 @@ fn main() {
|
||||||
Foo::$0
|
Foo::$0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
expect![[r"
|
expect![[r#"
|
||||||
fn bar(…) fn(impl Trait<U>)
|
fn bar(…) fn(impl Trait<U>)
|
||||||
"]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,7 +712,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn test() fn() -> Zulu
|
fn test() fn() -> Zulu
|
||||||
ex Zulu
|
ex Zulu
|
||||||
ex Zulu::test()
|
ex Zulu::test()
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -736,11 +736,11 @@ fn brr() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en HH HH
|
en HH HH
|
||||||
fn brr() fn()
|
fn brr() fn()
|
||||||
st YoloVariant YoloVariant
|
st YoloVariant YoloVariant
|
||||||
st YoloVariant {…} YoloVariant { f: usize }
|
st YoloVariant {…} YoloVariant { f: usize }
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -801,8 +801,8 @@ fn else_completion_after_if() {
|
||||||
fn foo() { if foo {} $0 }
|
fn foo() { if foo {} $0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -842,8 +842,8 @@ fn foo() { if foo {} $0 }
|
||||||
fn foo() { if foo {} el$0 }
|
fn foo() { if foo {} el$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -883,8 +883,8 @@ fn foo() { if foo {} el$0 }
|
||||||
fn foo() { bar(if foo {} $0) }
|
fn foo() { bar(if foo {} $0) }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw else
|
kw else
|
||||||
kw else if
|
kw else if
|
||||||
|
@ -907,8 +907,8 @@ fn foo() { bar(if foo {} $0) }
|
||||||
fn foo() { bar(if foo {} el$0) }
|
fn foo() { bar(if foo {} el$0) }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw else
|
kw else
|
||||||
kw else if
|
kw else if
|
||||||
|
@ -931,8 +931,8 @@ fn foo() { bar(if foo {} el$0) }
|
||||||
fn foo() { if foo {} $0 let x = 92; }
|
fn foo() { if foo {} $0 let x = 92; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -972,8 +972,8 @@ fn foo() { if foo {} $0 let x = 92; }
|
||||||
fn foo() { if foo {} el$0 let x = 92; }
|
fn foo() { if foo {} el$0 let x = 92; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1013,8 +1013,8 @@ fn foo() { if foo {} el$0 let x = 92; }
|
||||||
fn foo() { if foo {} el$0 { let x = 92; } }
|
fn foo() { if foo {} el$0 { let x = 92; } }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1065,9 +1065,9 @@ fn main() {
|
||||||
pub struct UnstableThisShouldNotBeListed;
|
pub struct UnstableThisShouldNotBeListed;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
md std
|
md std
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1117,10 +1117,10 @@ fn main() {
|
||||||
pub struct UnstableButWeAreOnNightlyAnyway;
|
pub struct UnstableButWeAreOnNightlyAnyway;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
md std
|
md std
|
||||||
st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
|
st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1170,17 +1170,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_empty(
|
check_empty(
|
||||||
|
@ -1196,17 +1196,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1226,17 +1226,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_empty(
|
check_empty(
|
||||||
|
@ -1252,17 +1252,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_empty(
|
check_empty(
|
||||||
|
@ -1278,17 +1278,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_empty(
|
check_empty(
|
||||||
|
@ -1304,19 +1304,89 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
sn if if expr {}
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
sn not !expr
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
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#"
|
expect![[r#"
|
||||||
st Rc (use dep::Rc) Rc
|
st Rc (use dep::Rc) Rc
|
||||||
st Rcar (use dep::Rcar) Rcar
|
st Rcar (use dep::Rcar) Rcar
|
||||||
st Rc (use dep::some_module::Rc) Rc
|
st Rc (use dep::some_module::Rc) Rc
|
||||||
st Rcar (use dep::some_module::Rcar) Rcar
|
st Rcar (use dep::some_module::Rcar) Rcar
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -165,11 +165,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct RC (use dep::RC) ()
|
ct RC (use dep::RC) ()
|
||||||
st Rc (use dep::Rc) Rc
|
st Rc (use dep::Rc) Rc
|
||||||
st Rcar (use dep::Rcar) Rcar
|
st Rcar (use dep::Rcar) Rcar
|
||||||
ct RC (use dep::some_module::RC) ()
|
ct RC (use dep::some_module::RC) ()
|
||||||
st Rc (use dep::some_module::Rc) Rc
|
st Rc (use dep::some_module::Rc) Rc
|
||||||
st Rcar (use dep::some_module::Rcar) Rcar
|
st Rcar (use dep::some_module::Rcar) Rcar
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -193,7 +193,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct RC (use dep::RC) ()
|
ct RC (use dep::RC) ()
|
||||||
ct RC (use dep::some_module::RC) ()
|
ct RC (use dep::some_module::RC) ()
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -227,7 +227,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
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 AfterThirdStruct (use dep::some_module::AfterThirdStruct) AfterThirdStruct
|
||||||
st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) ThiiiiiirdStruct
|
st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) ThiiiiiirdStruct
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -263,8 +263,8 @@ fn trait_function_fuzzy_completion() {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn weird_function() (use dep::test_mod::TestTrait) fn()
|
fn weird_function() (use dep::test_mod::TestTrait) fn()
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -356,8 +356,8 @@ fn trait_method_fuzzy_completion() {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me random_method() (use dep::test_mod::TestTrait) fn(&self)
|
me random_method() (use dep::test_mod::TestTrait) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -401,8 +401,8 @@ fn main() {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me some_method() (use foo::TestTrait) fn(&self)
|
me some_method() (use foo::TestTrait) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -448,8 +448,8 @@ fn main() {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me some_method() (use foo::TestTrait) fn(&self)
|
me some_method() (use foo::TestTrait) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -496,8 +496,8 @@ fn completion<T: Wrapper>(whatever: T) {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me not_in_scope() (use foo::NotInScope) fn(&self)
|
me not_in_scope() (use foo::NotInScope) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -539,8 +539,8 @@ fn main() {
|
||||||
check(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
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(
|
check(
|
||||||
fixture,
|
fixture,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn random_method() (use dep::test_mod::TestTrait) fn()
|
fn random_method() (use dep::test_mod::TestTrait) fn()
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
|
@ -737,8 +737,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
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(
|
check(
|
||||||
|
@ -767,8 +767,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||||
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1117,7 +1117,7 @@ fn main() {
|
||||||
tes$0
|
tes$0
|
||||||
}"#,
|
}"#,
|
||||||
expect![[r#"
|
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
|
fn test_function() (use foo::test_function) fn() -> i32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1175,8 +1175,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
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#"
|
expect![[r#"
|
||||||
st FooStruct (use outer::FooStruct) BarStruct
|
st FooStruct (use outer::FooStruct) BarStruct
|
||||||
md foo (use outer::foo)
|
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#"
|
expect![[r#"
|
||||||
st Bar
|
st Bar
|
||||||
bn Bar { bar }: Bar
|
bn Bar { bar }: Bar
|
||||||
bn Bar {…} Bar { bar$1 }: Bar$0
|
bn Bar {…} Bar { bar$1 }: Bar$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
|
|
@ -20,15 +20,15 @@ fn target_type_or_trait_in_impl_block() {
|
||||||
impl Tra$0
|
impl Tra$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -42,15 +42,15 @@ fn target_type_in_trait_impl_block() {
|
||||||
impl Trait for Str$0
|
impl Trait for Str$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn in_mod_item_list() {
|
||||||
check(
|
check(
|
||||||
r#"mod tests { $0 }"#,
|
r#"mod tests { $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -46,7 +46,7 @@ fn in_source_file_item_list() {
|
||||||
check(
|
check(
|
||||||
r#"$0"#,
|
r#"$0"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
|
@ -79,7 +79,7 @@ fn in_item_list_after_attr() {
|
||||||
check(
|
check(
|
||||||
r#"#[attr] $0"#,
|
r#"#[attr] $0"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
|
@ -182,7 +182,7 @@ fn in_impl_assoc_item_list() {
|
||||||
check(
|
check(
|
||||||
r#"impl Struct { $0 }"#,
|
r#"impl Struct { $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
|
@ -202,7 +202,7 @@ fn in_impl_assoc_item_list_after_attr() {
|
||||||
check(
|
check(
|
||||||
r#"impl Struct { #[attr] $0 }"#,
|
r#"impl Struct { #[attr] $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
|
@ -315,7 +315,7 @@ impl Test for () {
|
||||||
fn async fn function2()
|
fn async fn function2()
|
||||||
fn fn function1()
|
fn fn function1()
|
||||||
fn fn function2()
|
fn fn function2()
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
ta type Type1 =
|
ta type Type1 =
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -381,7 +381,7 @@ fn after_unit_struct() {
|
||||||
check(
|
check(
|
||||||
r#"struct S; f$0"#,
|
r#"struct S; f$0"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
|
@ -503,7 +503,7 @@ fn inside_extern_blocks() {
|
||||||
check(
|
check(
|
||||||
r#"extern { $0 }"#,
|
r#"extern { $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw crate::
|
kw crate::
|
||||||
kw fn
|
kw fn
|
||||||
|
@ -520,7 +520,7 @@ fn inside_extern_blocks() {
|
||||||
check(
|
check(
|
||||||
r#"unsafe extern { $0 }"#,
|
r#"unsafe extern { $0 }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
kw crate::
|
kw crate::
|
||||||
kw fn
|
kw fn
|
||||||
|
|
|
@ -122,15 +122,15 @@ fn foo() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST
|
ct CONST
|
||||||
en Enum
|
en Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record
|
st Record
|
||||||
st Tuple
|
st Tuple
|
||||||
st Unit
|
st Unit
|
||||||
ev TupleV
|
ev TupleV
|
||||||
bn Record {…} Record { field$1 }$0
|
bn Record {…} Record { field$1 }$0
|
||||||
bn Tuple(…) Tuple($1)$0
|
bn Tuple(…) Tuple($1)$0
|
||||||
bn TupleV(…) TupleV($1)$0
|
bn TupleV(…) TupleV($1)$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -151,15 +151,15 @@ fn foo() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en SingleVariantEnum
|
en SingleVariantEnum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record
|
st Record
|
||||||
st Tuple
|
st Tuple
|
||||||
st Unit
|
st Unit
|
||||||
ev Variant
|
ev Variant
|
||||||
bn Record {…} Record { field$1 }$0
|
bn Record {…} Record { field$1 }$0
|
||||||
bn Tuple(…) Tuple($1)$0
|
bn Tuple(…) Tuple($1)$0
|
||||||
bn Variant Variant$0
|
bn Variant Variant$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -174,13 +174,13 @@ fn foo(a$0) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record
|
st Record
|
||||||
st Tuple
|
st Tuple
|
||||||
st Unit
|
st Unit
|
||||||
bn Record {…} Record { field$1 }: Record$0
|
bn Record {…} Record { field$1 }: Record$0
|
||||||
bn Tuple(…) Tuple($1): Tuple$0
|
bn Tuple(…) Tuple($1): Tuple$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -191,13 +191,13 @@ fn foo(a$0: Tuple) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record
|
st Record
|
||||||
st Tuple
|
st Tuple
|
||||||
st Unit
|
st Unit
|
||||||
bn Record {…} Record { field$1 }$0
|
bn Record {…} Record { field$1 }$0
|
||||||
bn Tuple(…) Tuple($1)$0
|
bn Tuple(…) Tuple($1)$0
|
||||||
bn tuple
|
bn tuple
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
|
@ -240,7 +240,7 @@ fn foo() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en E
|
en E
|
||||||
ma m!(…) macro_rules! m
|
ma m!(…) macro_rules! m
|
||||||
bn E::X E::X$0
|
bn E::X E::X$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -268,7 +268,7 @@ fn outer() {
|
||||||
st Record
|
st Record
|
||||||
st Tuple
|
st Tuple
|
||||||
bn Record {…} Record { field$1, .. }$0
|
bn Record {…} Record { field$1, .. }$0
|
||||||
bn Tuple(…) Tuple($1, ..)$0
|
bn Tuple(…) Tuple($1, ..)$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -291,7 +291,7 @@ impl Foo {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
sp Self
|
sp Self
|
||||||
st Foo
|
st Foo
|
||||||
bn Foo(…) Foo($1)$0
|
bn Foo(…) Foo($1)$0
|
||||||
bn Self(…) Self($1)$0
|
bn Self(…) Self($1)$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
|
@ -315,8 +315,8 @@ fn func() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||||
bn RecordV {…} RecordV { field$1 }$0
|
bn RecordV {…} RecordV { field$1 }$0
|
||||||
bn TupleV(…) TupleV($1)$0
|
bn TupleV(…) TupleV($1)$0
|
||||||
bn UnitV UnitV$0
|
bn UnitV UnitV$0
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ fn outer(Foo { bar: $0 }: Foo) {}
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Bar
|
st Bar
|
||||||
st Foo
|
st Foo
|
||||||
bn Bar(…) Bar($1)$0
|
bn Bar(…) Bar($1)$0
|
||||||
bn Foo {…} Foo { bar$1 }$0
|
bn Foo {…} Foo { bar$1 }$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
|
@ -395,7 +395,7 @@ fn foo($0) {}
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Bar
|
st Bar
|
||||||
st Foo
|
st Foo
|
||||||
bn Bar(…) Bar($1): Bar$0
|
bn Bar(…) Bar($1): Bar$0
|
||||||
bn Foo {…} Foo { bar$1 }: Foo$0
|
bn Foo {…} Foo { bar$1 }: Foo$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
|
@ -416,7 +416,7 @@ fn foo() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Bar
|
st Bar
|
||||||
st Foo
|
st Foo
|
||||||
bn Bar(…) Bar($1)$0
|
bn Bar(…) Bar($1)$0
|
||||||
bn Foo {…} Foo { bar$1 }$0
|
bn Foo {…} Foo { bar$1 }$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
|
@ -436,7 +436,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Bar Bar
|
st Bar Bar
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -451,7 +451,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -535,10 +535,10 @@ fn foo() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum
|
en Enum
|
||||||
bn Enum::A Enum::A$0
|
bn Enum::A Enum::A$0
|
||||||
bn Enum::B {…} Enum::B { r#type$1 }$0
|
bn Enum::B {…} Enum::B { r#type$1 }$0
|
||||||
bn Enum::struct {…} Enum::r#struct { 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 mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -559,10 +559,10 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
bn A A$0
|
bn A A$0
|
||||||
bn B {…} B { r#type$1 }$0
|
bn B {…} B { r#type$1 }$0
|
||||||
bn struct {…} r#struct { 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
|
st Ty
|
||||||
bn &mut self
|
bn &mut self
|
||||||
bn &self
|
bn &self
|
||||||
bn Self(…) Self($1): Self$0
|
bn Self(…) Self($1): Self$0
|
||||||
bn Ty(…) Ty($1): Ty$0
|
bn Ty(…) Ty($1): Ty$0
|
||||||
bn mut self
|
bn mut self
|
||||||
bn self
|
bn self
|
||||||
kw mut
|
kw mut
|
||||||
|
@ -693,8 +693,8 @@ impl Ty {
|
||||||
st Ty
|
st Ty
|
||||||
bn &mut self
|
bn &mut self
|
||||||
bn &self
|
bn &self
|
||||||
bn Self(…) Self($1): Self$0
|
bn Self(…) Self($1): Self$0
|
||||||
bn Ty(…) Ty($1): Ty$0
|
bn Ty(…) Ty($1): Ty$0
|
||||||
bn mut self
|
bn mut self
|
||||||
bn self
|
bn self
|
||||||
kw mut
|
kw mut
|
||||||
|
@ -714,8 +714,8 @@ impl Ty {
|
||||||
st Ty
|
st Ty
|
||||||
bn &mut self
|
bn &mut self
|
||||||
bn &self
|
bn &self
|
||||||
bn Self(…) Self($1): Self$0
|
bn Self(…) Self($1): Self$0
|
||||||
bn Ty(…) Ty($1): Ty$0
|
bn Ty(…) Ty($1): Ty$0
|
||||||
bn mut self
|
bn mut self
|
||||||
bn self
|
bn self
|
||||||
kw mut
|
kw mut
|
||||||
|
@ -734,7 +734,7 @@ impl Ty {
|
||||||
sp Self
|
sp Self
|
||||||
st Ty
|
st Ty
|
||||||
bn Self(…) Self($1): Self$0
|
bn Self(…) Self($1): Self$0
|
||||||
bn Ty(…) Ty($1): Ty$0
|
bn Ty(…) Ty($1): Ty$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -763,7 +763,7 @@ fn f(x: EnumAlias<u8>) {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
bn Tuple(…) Tuple($1)$0
|
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 {}
|
struct Foo<'lt, T, const C: usize> where $0 {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo<…> Foo<'_, {unknown}, _>
|
st Foo<…> Foo<'_, {unknown}, _>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -89,16 +89,16 @@ fn param_list_for_for_pred() {
|
||||||
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
|
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo<…> Foo<'_, {unknown}, _>
|
st Foo<…> Foo<'_, {unknown}, _>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -114,16 +114,16 @@ impl Record {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
sp Self Record
|
sp Self Record
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
|
|
@ -24,19 +24,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -57,19 +57,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -92,19 +92,19 @@ impl Foo {
|
||||||
fn main() {}
|
fn main() {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -127,19 +127,19 @@ impl Foo {
|
||||||
fn main() {}
|
fn main() {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo() fn(&self)
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,8 @@ fn foo(baz: Baz) {
|
||||||
ev Ok
|
ev Ok
|
||||||
bn Baz::Bar Baz::Bar$0
|
bn Baz::Bar Baz::Bar$0
|
||||||
bn Baz::Foo Baz::Foo$0
|
bn Baz::Foo Baz::Foo$0
|
||||||
bn Err(…) Err($1)$0
|
bn Err(…) Err($1)$0
|
||||||
bn Ok(…) Ok($1)$0
|
bn Ok(…) Ok($1)$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -91,20 +91,20 @@ fn foo(baz: Baz) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Baz
|
en Baz
|
||||||
en Result
|
en Result
|
||||||
md core
|
md core
|
||||||
ev Bar
|
ev Bar
|
||||||
ev Err
|
ev Err
|
||||||
ev Foo
|
ev Foo
|
||||||
ev Ok
|
ev Ok
|
||||||
bn Bar Bar$0
|
bn Bar Bar$0
|
||||||
bn Err(…) Err($1)$0
|
bn Err(…) Err($1)$0
|
||||||
bn Foo Foo$0
|
bn Foo Foo$0
|
||||||
bn Ok(…) Ok($1)$0
|
bn Ok(…) Ok($1)$0
|
||||||
kw mut
|
kw mut
|
||||||
kw ref
|
kw ref
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,14 +184,14 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd ..Default::default()
|
fd ..Default::default()
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
lc foo Foo
|
lc foo Foo
|
||||||
lc thing i32
|
lc thing i32
|
||||||
md core
|
md core
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
st Foo {…} Foo { foo1: u32, foo2: u32 }
|
st Foo {…} Foo { foo1: u32, foo2: u32 }
|
||||||
tt Default
|
tt Default
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
ex Foo::default()
|
ex Foo::default()
|
||||||
|
@ -238,8 +238,8 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd ..Default::default()
|
fd ..Default::default()
|
||||||
fd foo1 u32
|
fd foo1 u32
|
||||||
fd foo2 u32
|
fd foo2 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ pub mod prelude {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
md std
|
md std
|
||||||
st Option Option
|
st Option Option
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ mod macros {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn f() fn()
|
fn f() fn()
|
||||||
ma concat!(…) macro_rules! concat
|
ma concat!(…) macro_rules! concat
|
||||||
md std
|
md std
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ pub mod prelude {
|
||||||
md core
|
md core
|
||||||
md std
|
md std
|
||||||
st String String
|
st String String
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ pub mod prelude {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn f() fn()
|
fn f() fn()
|
||||||
md std
|
md std
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -226,9 +226,9 @@ impl S {
|
||||||
fn foo() { let _ = lib::S::$0 }
|
fn foo() { let _ = lib::S::$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct PUBLIC_CONST pub const PUBLIC_CONST: u32
|
ct PUBLIC_CONST pub const PUBLIC_CONST: u32
|
||||||
fn public_method() fn()
|
fn public_method() fn()
|
||||||
ta PublicType pub type PublicType = u32
|
ta PublicType pub type PublicType = u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -317,14 +317,14 @@ trait Sub: Super {
|
||||||
fn foo<T: Sub>() { T::$0 }
|
fn foo<T: Sub>() { T::$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct C2 (as Sub) const C2: ()
|
ct C2 (as Sub) const C2: ()
|
||||||
ct CONST (as Super) const CONST: u8
|
ct CONST (as Super) const CONST: u8
|
||||||
fn func() (as Super) fn()
|
fn func() (as Super) fn()
|
||||||
fn subfunc() (as Sub) fn()
|
fn subfunc() (as Sub) fn()
|
||||||
me method(…) (as Super) fn(&self)
|
me method(…) (as Super) fn(&self)
|
||||||
me submethod(…) (as Sub) fn(&self)
|
me submethod(…) (as Sub) fn(&self)
|
||||||
ta SubTy (as Sub) type SubTy
|
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#"
|
expect![[r#"
|
||||||
ct C2 (as Sub) const C2: ()
|
ct C2 (as Sub) const C2: ()
|
||||||
ct CONST (as Super) const CONST: u8
|
ct CONST (as Super) const CONST: u8
|
||||||
fn func() (as Super) fn()
|
fn func() (as Super) fn()
|
||||||
fn subfunc() (as Sub) fn()
|
fn subfunc() (as Sub) fn()
|
||||||
me method(…) (as Super) fn(&self)
|
me method(…) (as Super) fn(&self)
|
||||||
me submethod(…) (as Sub) fn(&self)
|
me submethod(…) (as Sub) fn(&self)
|
||||||
ta SubTy (as Sub) type SubTy
|
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; }
|
fn main() { T::$0; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn bar() fn()
|
fn bar() fn()
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ macro_rules! foo { () => {} }
|
||||||
fn main() { let _ = crate::$0 }
|
fn main() { let _ = crate::$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
ma foo!(…) macro_rules! foo
|
ma foo!(…) macro_rules! foo
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -447,9 +447,9 @@ mod p {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct RIGHT_CONST u32
|
ct RIGHT_CONST u32
|
||||||
fn right_fn() fn()
|
fn right_fn() fn()
|
||||||
st RightType WrongType
|
st RightType WrongType
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -495,9 +495,9 @@ fn main() { m!(self::f$0); }
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,9 +513,9 @@ mod m {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn z() fn()
|
fn z() fn()
|
||||||
md z
|
md z
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,8 +534,8 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn new() fn() -> HashMap<K, V, RandomState>
|
fn new() fn() -> HashMap<K, V, RandomState>
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,8 +557,8 @@ impl Foo {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me foo(…) fn(self)
|
me foo(…) fn(self)
|
||||||
ev Bar Bar
|
ev Bar Bar
|
||||||
ev Baz Baz
|
ev Baz Baz
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -578,9 +578,9 @@ fn foo(self) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Bar Bar
|
ev Bar Bar
|
||||||
ev Baz Baz
|
ev Baz Baz
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_no_kw(
|
check_no_kw(
|
||||||
|
@ -598,8 +598,8 @@ enum Foo {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Baz Baz
|
ev Baz Baz
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,9 +623,9 @@ impl u8 {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct MAX pub const MAX: Self
|
ct MAX pub const MAX: Self
|
||||||
me func(…) fn(self)
|
me func(…) fn(self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,8 +643,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Bar Bar
|
ev Bar Bar
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,7 +723,7 @@ fn bar() -> Bar {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn bar() fn()
|
fn bar() fn()
|
||||||
fn foo() (as Foo) fn() -> Self
|
fn foo() (as Foo) fn() -> Self
|
||||||
ex Bar
|
ex Bar
|
||||||
ex bar()
|
ex bar()
|
||||||
|
@ -787,7 +787,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me by_macro() (as MyTrait) fn(&self)
|
me by_macro() (as MyTrait) fn(&self)
|
||||||
me not_by_macro() (as MyTrait) fn(&self)
|
me not_by_macro() (as MyTrait) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
|
@ -827,7 +827,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
me by_macro() (as MyTrait) fn(&self)
|
me by_macro() (as MyTrait) fn(&self)
|
||||||
me not_by_macro() (as MyTrait) fn(&self)
|
me not_by_macro() (as MyTrait) fn(&self)
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
|
@ -885,10 +885,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() fn()
|
fn main() fn()
|
||||||
lc foobar i32
|
lc foobar i32
|
||||||
ma x!(…) macro_rules! x
|
ma x!(…) macro_rules! x
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1014,7 +1014,7 @@ fn here_we_go() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn here_we_go() fn()
|
fn here_we_go() fn()
|
||||||
st Foo (alias Bar) Foo
|
st Foo (alias Bar) Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
|
@ -1064,9 +1064,9 @@ fn here_we_go() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn here_we_go() fn()
|
fn here_we_go() fn()
|
||||||
st Foo (alias Bar, Qux, Baz) Foo
|
st Foo (alias Bar, Qux, Baz) Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1160,20 +1160,20 @@ fn here_we_go() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fd bar u8
|
fd bar u8
|
||||||
me baz() (alias qux) fn(&self) -> u8
|
me baz() (alias qux) fn(&self) -> u8
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn let let
|
sn let let
|
||||||
sn letm let mut
|
sn letm let mut
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1189,7 +1189,7 @@ fn bar() { qu$0 }
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn bar() fn()
|
fn bar() fn()
|
||||||
fn foo() (alias qux) fn()
|
fn foo() (alias qux) fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1277,10 +1277,10 @@ fn here_we_go() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn here_we_go() fn()
|
fn here_we_go() fn()
|
||||||
md foo
|
md foo
|
||||||
st Bar (alias Qux) (use foo::Bar) Bar
|
st Bar (alias Qux) (use foo::Bar) Bar
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw false
|
kw false
|
||||||
kw for
|
kw for
|
||||||
|
@ -1315,10 +1315,9 @@ use krate::e;
|
||||||
fn main() {
|
fn main() {
|
||||||
e::$0
|
e::$0
|
||||||
}"#,
|
}"#,
|
||||||
expect![
|
expect![[r#"
|
||||||
"fn i_am_public() fn()
|
fn i_am_public() fn()
|
||||||
"
|
"#]],
|
||||||
],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1444,8 +1443,8 @@ fn foo() {
|
||||||
"#,
|
"#,
|
||||||
Some('_'),
|
Some('_'),
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo() fn()
|
fn foo() fn()
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw async
|
kw async
|
||||||
kw const
|
kw const
|
||||||
kw crate::
|
kw crate::
|
||||||
|
@ -1498,7 +1497,7 @@ fn foo(_: a_$0) { }
|
||||||
"#,
|
"#,
|
||||||
Some('_'),
|
Some('_'),
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -1512,7 +1511,7 @@ fn foo<T>() {
|
||||||
Some('_'),
|
Some('_'),
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
tp T
|
tp T
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
|
|
@ -17,18 +17,18 @@ struct Foo<'lt, T, const C: usize> {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
sp Self Foo<'_, {unknown}, _>
|
sp Self Foo<'_, {unknown}, _>
|
||||||
st Foo<…> Foo<'_, {unknown}, _>
|
st Foo<…> Foo<'_, {unknown}, _>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -42,18 +42,18 @@ fn tuple_struct_field() {
|
||||||
struct Foo<'lt, T, const C: usize>(f$0);
|
struct Foo<'lt, T, const C: usize>(f$0);
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
sp Self Foo<'_, {unknown}, _>
|
sp Self Foo<'_, {unknown}, _>
|
||||||
st Foo<…> Foo<'_, {unknown}, _>
|
st Foo<…> Foo<'_, {unknown}, _>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw pub
|
kw pub
|
||||||
kw pub(crate)
|
kw pub(crate)
|
||||||
|
@ -70,16 +70,16 @@ fn fn_return_type() {
|
||||||
fn x<'lt, T, const C: usize>() -> $0
|
fn x<'lt, T, const C: usize>() -> $0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -100,15 +100,15 @@ fn foo() -> B$0 {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it ()
|
it ()
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -124,16 +124,16 @@ struct Foo<T>(T);
|
||||||
const FOO: $0 = Foo(2);
|
const FOO: $0 = Foo(2);
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo<…> Foo<{unknown}>
|
st Foo<…> Foo<{unknown}>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it Foo<i32>
|
it Foo<i32>
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -151,15 +151,15 @@ fn f2() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it i32
|
it i32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -179,15 +179,15 @@ fn f2() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it u64
|
it u64
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -204,15 +204,15 @@ fn f2(x: u64) -> $0 {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it u64
|
it u64
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -230,15 +230,15 @@ fn f2(x: $0) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it i32
|
it i32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -262,17 +262,17 @@ fn foo<'lt, T, const C: usize>() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md a
|
md a
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it a::Foo<a::Foo<i32>>
|
it a::Foo<a::Foo<i32>>
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -291,17 +291,17 @@ fn foo<'lt, T, const C: usize>() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo<…> Foo<{unknown}>
|
st Foo<…> Foo<{unknown}>
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
it Foo<i32>
|
it Foo<i32>
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -319,16 +319,16 @@ fn foo<'lt, T, const C: usize>() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -341,14 +341,14 @@ fn foo<'lt, T, const C: usize>() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
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) {}
|
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ta Foo = (as Trait2) type Foo
|
ta Foo = (as Trait2) type Foo
|
||||||
ta Super = (as Trait1) type Super
|
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) {}
|
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tt Trait1
|
tt Trait1
|
||||||
tt Trait2
|
tt Trait2
|
||||||
tp T
|
tp T
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -409,15 +409,15 @@ trait Trait2<T> {
|
||||||
fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
|
fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
tt Trait2
|
tt Trait2
|
||||||
un Union Union
|
un Union Union
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -434,18 +434,18 @@ trait Tr<T> {
|
||||||
impl Tr<$0
|
impl Tr<$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
sp Self dyn Tr<{unknown}>
|
sp Self dyn Tr<{unknown}>
|
||||||
st Record Record
|
st Record Record
|
||||||
st S S
|
st S S
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Tr
|
tt Tr
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -481,16 +481,16 @@ trait MyTrait<T, U> {
|
||||||
fn f(t: impl MyTrait<u$0
|
fn f(t: impl MyTrait<u$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -506,16 +506,16 @@ trait MyTrait<T, U> {
|
||||||
fn f(t: impl MyTrait<u8, u$0
|
fn f(t: impl MyTrait<u8, u$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -549,16 +549,16 @@ trait MyTrait<T, U = u8> {
|
||||||
fn f(t: impl MyTrait<u$0
|
fn f(t: impl MyTrait<u$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -574,18 +574,18 @@ trait MyTrait<T, U = u8> {
|
||||||
fn f(t: impl MyTrait<u8, u$0
|
fn f(t: impl MyTrait<u8, u$0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
ta Item1 = (as MyTrait) type Item1
|
ta Item1 = (as MyTrait) type Item1
|
||||||
ta Item2 = (as MyTrait) type Item2
|
ta Item2 = (as MyTrait) type Item2
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -619,16 +619,16 @@ trait MyTrait {
|
||||||
fn f(t: impl MyTrait<Item1 = $0
|
fn f(t: impl MyTrait<Item1 = $0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -644,16 +644,16 @@ trait MyTrait {
|
||||||
fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
|
fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt MyTrait
|
tt MyTrait
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -668,7 +668,7 @@ trait MyTrait {
|
||||||
fn f(t: impl MyTrait<C = $0
|
fn f(t: impl MyTrait<C = $0
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -691,9 +691,9 @@ pub struct S;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
md std
|
md std
|
||||||
sp Self Foo
|
sp Self Foo
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -716,10 +716,10 @@ pub struct S;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
md std
|
md std
|
||||||
sp Self Foo
|
sp Self Foo
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
st S S
|
st S S
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -739,16 +739,16 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -766,8 +766,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -785,16 +785,16 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -809,8 +809,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -828,17 +828,17 @@ fn completes_const_and_type_generics_separately() {
|
||||||
fn foo(_: impl Bar<Baz<F$0, 0> = ()>) {}
|
fn foo(_: impl Bar<Baz<F$0, 0> = ()>) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum Enum
|
en Enum Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
st Record Record
|
st Record Record
|
||||||
st Tuple Tuple
|
st Tuple Tuple
|
||||||
st Unit Unit
|
st Unit Unit
|
||||||
tt Bar
|
tt Bar
|
||||||
tt Trait
|
tt Trait
|
||||||
un Union Union
|
un Union Union
|
||||||
bt u32 u32
|
bt u32 u32
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -853,8 +853,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
fn foo<T: Bar<Baz<(), $0> = ()>>() {}
|
fn foo<T: Bar<Baz<(), $0> = ()>>() {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -871,8 +871,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -890,8 +890,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -908,8 +908,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -924,8 +924,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
impl Foo<(), $0> for () {}
|
impl Foo<(), $0> for () {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
@ -942,8 +942,8 @@ fn completes_const_and_type_generics_separately() {
|
||||||
fn foo<T: Bar<X$0, ()>>() {}
|
fn foo<T: Bar<X$0, ()>>() {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ct X usize
|
ct X usize
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
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, _>; }
|
fn foo<'a>() { S::<F$0, _>; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
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, _>; }
|
fn foo<'a>() { S::<'static, 'static, F$0, _>; }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct CONST Unit
|
ct CONST Unit
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
|
|
|
@ -92,7 +92,7 @@ use self::{foo::*, bar$0};
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
md foo
|
md foo
|
||||||
st S S
|
st S S
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ struct Bar;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ma foo macro_rules! foo_
|
ma foo macro_rules! foo_
|
||||||
st Foo Foo
|
st Foo Foo
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -203,8 +203,8 @@ impl Foo {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev RecordVariant RecordVariant
|
ev RecordVariant RecordVariant
|
||||||
ev TupleVariant TupleVariant
|
ev TupleVariant TupleVariant
|
||||||
ev UnitVariant UnitVariant
|
ev UnitVariant UnitVariant
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ mod a {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ct A usize
|
ct A usize
|
||||||
md b
|
md b
|
||||||
kw super::
|
kw super::
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -450,9 +450,9 @@ pub fn foo() {}
|
||||||
marco_rules! m { () => {} }
|
marco_rules! m { () => {} }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo fn()
|
fn foo fn()
|
||||||
md simd
|
md simd
|
||||||
st S S
|
st S S
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
|
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,
|
SemanticsScope, Trait, TyFingerprint, Type,
|
||||||
};
|
};
|
||||||
use itertools::{EitherOrBoth, Itertools};
|
use itertools::Itertools;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, HasName},
|
ast::{self, make, HasName},
|
||||||
|
@ -13,7 +13,6 @@ use syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helpers::item_name,
|
|
||||||
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||||
FxIndexSet, RootDatabase,
|
FxIndexSet, RootDatabase,
|
||||||
};
|
};
|
||||||
|
@ -52,7 +51,7 @@ pub struct TraitImportCandidate {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PathImportCandidate {
|
pub struct PathImportCandidate {
|
||||||
/// Optional qualifier before name.
|
/// Optional qualifier before name.
|
||||||
pub qualifier: Option<Vec<SmolStr>>,
|
pub qualifier: Vec<SmolStr>,
|
||||||
/// The name the item (struct, trait, enum, etc.) should have.
|
/// The name the item (struct, trait, enum, etc.) should have.
|
||||||
pub name: NameToImport,
|
pub name: NameToImport,
|
||||||
}
|
}
|
||||||
|
@ -264,7 +263,6 @@ impl ImportAssets {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => return <FxIndexSet<_>>::default().into_iter(),
|
None => return <FxIndexSet<_>>::default().into_iter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let krate = self.module_with_candidate.krate();
|
let krate = self.module_with_candidate.krate();
|
||||||
let scope_definitions = self.scope_definitions(sema);
|
let scope_definitions = self.scope_definitions(sema);
|
||||||
let mod_path = |item| {
|
let mod_path = |item| {
|
||||||
|
@ -279,11 +277,14 @@ impl ImportAssets {
|
||||||
};
|
};
|
||||||
|
|
||||||
match &self.import_candidate {
|
match &self.import_candidate {
|
||||||
ImportCandidate::Path(path_candidate) => {
|
ImportCandidate::Path(path_candidate) => path_applicable_imports(
|
||||||
path_applicable_imports(sema, krate, path_candidate, mod_path, |item_to_import| {
|
sema,
|
||||||
!scope_definitions.contains(&ScopeDef::from(item_to_import))
|
&scope,
|
||||||
})
|
krate,
|
||||||
}
|
path_candidate,
|
||||||
|
mod_path,
|
||||||
|
|item_to_import| !scope_definitions.contains(&ScopeDef::from(item_to_import)),
|
||||||
|
),
|
||||||
ImportCandidate::TraitAssocItem(trait_candidate)
|
ImportCandidate::TraitAssocItem(trait_candidate)
|
||||||
| ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
|
| ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
|
||||||
sema,
|
sema,
|
||||||
|
@ -315,6 +316,7 @@ impl ImportAssets {
|
||||||
|
|
||||||
fn path_applicable_imports(
|
fn path_applicable_imports(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
scope: &SemanticsScope<'_>,
|
||||||
current_crate: Crate,
|
current_crate: Crate,
|
||||||
path_candidate: &PathImportCandidate,
|
path_candidate: &PathImportCandidate,
|
||||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
|
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
|
||||||
|
@ -322,8 +324,8 @@ fn path_applicable_imports(
|
||||||
) -> FxIndexSet<LocatedImport> {
|
) -> FxIndexSet<LocatedImport> {
|
||||||
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
|
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
|
||||||
|
|
||||||
match &path_candidate.qualifier {
|
match &*path_candidate.qualifier {
|
||||||
None => {
|
[] => {
|
||||||
items_locator::items_with_name(
|
items_locator::items_with_name(
|
||||||
sema,
|
sema,
|
||||||
current_crate,
|
current_crate,
|
||||||
|
@ -348,89 +350,107 @@ fn path_applicable_imports(
|
||||||
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
|
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
Some(qualifier) => items_locator::items_with_name(
|
[first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name(
|
||||||
sema,
|
sema,
|
||||||
current_crate,
|
current_crate,
|
||||||
path_candidate.name.clone(),
|
NameToImport::Exact(first_qsegment.to_string(), true),
|
||||||
AssocSearchMode::Include,
|
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())
|
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_for_item(
|
fn import_for_item(
|
||||||
db: &RootDatabase,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
scope: &SemanticsScope<'_>,
|
||||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
||||||
|
candidate: &NameToImport,
|
||||||
|
resolved_qualifier: ItemInNs,
|
||||||
unresolved_qualifier: &[SmolStr],
|
unresolved_qualifier: &[SmolStr],
|
||||||
original_item: ItemInNs,
|
|
||||||
scope_filter: impl Fn(ItemInNs) -> bool,
|
scope_filter: impl Fn(ItemInNs) -> bool,
|
||||||
) -> Option<LocatedImport> {
|
) -> Option<LocatedImport> {
|
||||||
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
|
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 qualifier = {
|
||||||
|
let mut adjusted_resolved_qualifier = resolved_qualifier;
|
||||||
let (original_item_candidate, trait_item_to_import) = match item_as_assoc {
|
if !unresolved_qualifier.is_empty() {
|
||||||
Some(assoc_item) => match assoc_item.container(db) {
|
match resolved_qualifier {
|
||||||
AssocItemContainer::Trait(trait_) => {
|
ItemInNs::Types(ModuleDef::Module(module)) => {
|
||||||
let trait_ = ItemInNs::from(ModuleDef::from(trait_));
|
adjusted_resolved_qualifier = sema
|
||||||
(trait_, Some(trait_))
|
.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)
|
|
||||||
}
|
match adjusted_resolved_qualifier {
|
||||||
},
|
ItemInNs::Types(def) => def,
|
||||||
None => (original_item, None),
|
_ => return None,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let import_path_candidate = mod_path(original_item_candidate)?;
|
let import_path_candidate = mod_path(resolved_qualifier)?;
|
||||||
|
let ty = match qualifier {
|
||||||
let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev();
|
ModuleDef::Module(module) => {
|
||||||
let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it {
|
return items_locator::items_with_name_in_module(
|
||||||
// segments match, check next one
|
sema,
|
||||||
EitherOrBoth::Both(a, b) if b.as_str() == &**a => None,
|
module,
|
||||||
// segments mismatch / qualifier is longer than the path, bail out
|
candidate.clone(),
|
||||||
EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false),
|
AssocSearchMode::Exclude,
|
||||||
// all segments match and we have exhausted the qualifier, proceed
|
)
|
||||||
EitherOrBoth::Right(_) => Some(true),
|
.find(|&it| scope_filter(it))
|
||||||
};
|
.map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
// 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,
|
_ => 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(
|
fn trait_applicable_items(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
current_crate: Crate,
|
current_crate: Crate,
|
||||||
|
@ -703,7 +684,7 @@ impl ImportCandidate {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(ImportCandidate::Path(PathImportCandidate {
|
Some(ImportCandidate::Path(PathImportCandidate {
|
||||||
qualifier: None,
|
qualifier: vec![],
|
||||||
name: NameToImport::exact_case_sensitive(name.to_string()),
|
name: NameToImport::exact_case_sensitive(name.to_string()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -730,7 +711,7 @@ fn path_import_candidate(
|
||||||
.segments()
|
.segments()
|
||||||
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
ImportCandidate::Path(PathImportCandidate { qualifier, name })
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -754,10 +735,10 @@ fn path_import_candidate(
|
||||||
}
|
}
|
||||||
Some(_) => return None,
|
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> {
|
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
|
//! 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.
|
//! are located in different caches, with different APIs.
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{import_map, Crate, ItemInNs, Semantics};
|
use hir::{import_map, Crate, ItemInNs, Module, Semantics};
|
||||||
use limit::Limit;
|
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.
|
/// A value to use, when uncertain which limit to pick.
|
||||||
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
|
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
|
||||||
|
@ -20,8 +24,7 @@ pub fn items_with_name<'a>(
|
||||||
name: NameToImport,
|
name: NameToImport,
|
||||||
assoc_item_search: AssocSearchMode,
|
assoc_item_search: AssocSearchMode,
|
||||||
) -> impl Iterator<Item = ItemInNs> + 'a {
|
) -> 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.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)
|
|
||||||
.entered();
|
.entered();
|
||||||
|
|
||||||
let prefix = matches!(name, NameToImport::Prefix(..));
|
let prefix = matches!(name, NameToImport::Prefix(..));
|
||||||
|
@ -66,6 +69,54 @@ pub fn items_with_name<'a>(
|
||||||
find_items(sema, krate, local_query, external_query)
|
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>(
|
fn find_items<'a>(
|
||||||
sema: &'a Semantics<'_, RootDatabase>,
|
sema: &'a Semantics<'_, RootDatabase>,
|
||||||
krate: Crate,
|
krate: Crate,
|
||||||
|
|
|
@ -377,6 +377,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
name
|
name
|
||||||
|
} else if let Some(inner_ty) = ty.remove_ref() {
|
||||||
|
return name_of_type(&inner_ty, db, edition);
|
||||||
} else {
|
} else {
|
||||||
return None;
|
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("()")
|
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;
|
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<'_>,
|
ctx: &DiagnosticsContext<'_>,
|
||||||
d: &hir::UnresolvedIdent,
|
d: &hir::UnresolvedIdent,
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
Diagnostic::new_with_syntax_node_ptr(
|
let mut range =
|
||||||
ctx,
|
ctx.sema.diagnostics_display_range(d.node.map(|(node, _)| node.syntax_node_ptr()));
|
||||||
DiagnosticCode::RustcHardError("E0425"),
|
if let Some(in_node_range) = d.node.value.1 {
|
||||||
"no such value in this scope",
|
range.range = in_node_range + range.range.start();
|
||||||
d.expr_or_pat.map(Into::into),
|
}
|
||||||
)
|
Diagnostic::new(DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", range)
|
||||||
.experimental()
|
.experimental()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::tests::check_diagnostics;
|
use crate::tests::check_diagnostics;
|
||||||
|
|
||||||
// FIXME: This should show a diagnostic
|
|
||||||
#[test]
|
#[test]
|
||||||
fn feature() {
|
fn feature() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
|
@ -28,6 +27,7 @@ mod tests {
|
||||||
//- minicore: fmt
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
format_args!("{unresolved}");
|
format_args!("{unresolved}");
|
||||||
|
// ^^^^^^^^^^ error: no such value in this scope
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ use ide_db::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use span::{Edition, TextSize};
|
use span::{Edition, TextSize};
|
||||||
use stdx::{always, format_to};
|
use stdx::format_to;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SmolStr, SyntaxNode, ToSmolStr,
|
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.
|
// 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 in_macro_expansion = FxHashMap::<hir::HirFileId, Vec<Runnable>>::default();
|
||||||
let mut add_opt = |runnable: Option<Runnable>, def| {
|
let mut add_opt = |runnable: Option<Runnable>, def| {
|
||||||
if let Some(runnable) = runnable.filter(|runnable| {
|
if let Some(runnable) = runnable.filter(|runnable| runnable.nav.file_id == file_id) {
|
||||||
always!(
|
|
||||||
runnable.nav.file_id == file_id,
|
|
||||||
"tried adding a runnable pointing to a different file: {:?} for {:?}",
|
|
||||||
runnable.kind,
|
|
||||||
file_id
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
if let Some(def) = def {
|
if let Some(def) = def {
|
||||||
let file_id = match def {
|
let file_id = match def {
|
||||||
Definition::Module(it) => {
|
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_),
|
Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
add_opt(
|
add_opt(runnable.or_else(|| module_def_doctest(sema.db, def)), Some(def));
|
||||||
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),
|
|
||||||
);
|
|
||||||
if let Definition::SelfType(impl_) = def {
|
if let Definition::SelfType(impl_) = def {
|
||||||
impl_.items(db).into_iter().for_each(|assoc| {
|
impl_.items(db).into_iter().for_each(|assoc| {
|
||||||
let runnable = match assoc {
|
let runnable = match assoc {
|
||||||
|
|
|
@ -174,6 +174,9 @@ fn on_delimited_node_typed(
|
||||||
kinds: &[fn(SyntaxKind) -> bool],
|
kinds: &[fn(SyntaxKind) -> bool],
|
||||||
) -> Option<TextEdit> {
|
) -> Option<TextEdit> {
|
||||||
let t = reparsed.syntax().token_at_offset(offset).right_biased()?;
|
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
|
let (filter, node) = t
|
||||||
.parent_ancestors()
|
.parent_ancestors()
|
||||||
.take_while(|n| n.text_range().start() == offset)
|
.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]
|
#[test]
|
||||||
fn adds_closing_parenthesis_for_pat() {
|
fn adds_closing_parenthesis_for_pat() {
|
||||||
type_char(
|
type_char(
|
||||||
|
|
|
@ -487,7 +487,7 @@ impl ProcMacroExpander for Expander {
|
||||||
match self.0.expand(
|
match self.0.expand(
|
||||||
subtree,
|
subtree,
|
||||||
attrs,
|
attrs,
|
||||||
env.clone(),
|
env.clone().into(),
|
||||||
def_site,
|
def_site,
|
||||||
call_site,
|
call_site,
|
||||||
mixed_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! ()
|
||||||
// macro_rules! []
|
// macro_rules! []
|
||||||
if paths::is_use_path_start(p) {
|
if paths::is_use_path_start(p) {
|
||||||
macro_call(p, m);
|
paths::use_path(p);
|
||||||
return;
|
// 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);
|
m.abandon(p);
|
||||||
|
@ -410,8 +421,7 @@ fn fn_(p: &mut Parser<'_>, m: Marker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macro_call(p: &mut Parser<'_>, m: Marker) {
|
fn macro_call(p: &mut Parser<'_>, m: Marker) {
|
||||||
assert!(paths::is_use_path_start(p));
|
assert!(p.at(T![!]));
|
||||||
paths::use_path(p);
|
|
||||||
match macro_call_after_excl(p) {
|
match macro_call_after_excl(p) {
|
||||||
BlockLike::Block => (),
|
BlockLike::Block => (),
|
||||||
BlockLike::NotBlock => {
|
BlockLike::NotBlock => {
|
||||||
|
|
|
@ -30,22 +30,20 @@ fn source_file() {
|
||||||
TopEntryPoint::SourceFile,
|
TopEntryPoint::SourceFile,
|
||||||
"@error@",
|
"@error@",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SOURCE_FILE
|
SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
AT "@"
|
AT "@"
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "error"
|
IDENT "error"
|
||||||
ERROR
|
ERROR
|
||||||
AT "@"
|
AT "@"
|
||||||
error 0: expected an item
|
error 0: expected an item
|
||||||
error 6: expected BANG
|
error 6: expected an item
|
||||||
error 6: expected `{`, `[`, `(`
|
error 6: expected an item
|
||||||
error 6: expected SEMICOLON
|
"#]],
|
||||||
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");
|
run_and_expect_errors("test_data/parser/inline/err/missing_fn_param_type.rs");
|
||||||
}
|
}
|
||||||
#[test]
|
#[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() {
|
fn pointer_type_no_mutability() {
|
||||||
run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
|
run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,20 @@ SOURCE_FILE
|
||||||
USE_KW "use"
|
USE_KW "use"
|
||||||
ERROR
|
ERROR
|
||||||
SLASH "/"
|
SLASH "/"
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "bin"
|
IDENT "bin"
|
||||||
ERROR
|
ERROR
|
||||||
SLASH "/"
|
SLASH "/"
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "env"
|
IDENT "env"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -33,13 +33,7 @@ error 23: expected `[`
|
||||||
error 23: expected an item
|
error 23: expected an item
|
||||||
error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
|
error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
|
||||||
error 28: expected SEMICOLON
|
error 28: expected SEMICOLON
|
||||||
error 31: expected BANG
|
|
||||||
error 31: expected `{`, `[`, `(`
|
|
||||||
error 31: expected SEMICOLON
|
|
||||||
error 31: expected an item
|
error 31: expected an item
|
||||||
error 35: expected BANG
|
error 31: expected an item
|
||||||
error 35: expected `{`, `[`, `(`
|
error 35: expected an item
|
||||||
error 35: expected SEMICOLON
|
error 41: expected an item
|
||||||
error 41: expected BANG
|
|
||||||
error 41: expected `{`, `[`, `(`
|
|
||||||
error 41: expected SEMICOLON
|
|
||||||
|
|
|
@ -14,14 +14,15 @@ SOURCE_FILE
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
R_CURLY "}"
|
R_CURLY "}"
|
||||||
WHITESPACE "\n\n"
|
WHITESPACE "\n\n"
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "bar"
|
IDENT "bar"
|
||||||
TOKEN_TREE
|
ERROR
|
||||||
L_PAREN "("
|
L_PAREN "("
|
||||||
R_PAREN ")"
|
ERROR
|
||||||
|
R_PAREN ")"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
ERROR
|
ERROR
|
||||||
L_CURLY "{"
|
L_CURLY "{"
|
||||||
|
@ -75,6 +76,7 @@ SOURCE_FILE
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
R_CURLY "}"
|
R_CURLY "}"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
error 17: expected BANG
|
error 17: expected an item
|
||||||
error 19: expected SEMICOLON
|
error 17: expected an item
|
||||||
|
error 18: expected an item
|
||||||
error 20: expected an item
|
error 20: expected an item
|
||||||
|
|
|
@ -46,7 +46,7 @@ SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
AT "@"
|
AT "@"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -72,9 +72,7 @@ error 67: expected R_ANGLE
|
||||||
error 67: expected R_PAREN
|
error 67: expected R_PAREN
|
||||||
error 67: expected SEMICOLON
|
error 67: expected SEMICOLON
|
||||||
error 67: expected an item
|
error 67: expected an item
|
||||||
error 72: expected BANG
|
error 72: expected an item
|
||||||
error 72: expected `{`, `[`, `(`
|
|
||||||
error 72: expected SEMICOLON
|
|
||||||
error 72: expected an item
|
error 72: expected an item
|
||||||
error 73: expected an item
|
error 73: expected an item
|
||||||
error 79: expected an item
|
error 79: expected an item
|
||||||
|
|
|
@ -26,14 +26,15 @@ SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
FN_KW "fn"
|
FN_KW "fn"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "bar"
|
IDENT "bar"
|
||||||
TOKEN_TREE
|
ERROR
|
||||||
L_PAREN "("
|
L_PAREN "("
|
||||||
R_PAREN ")"
|
ERROR
|
||||||
|
R_PAREN ")"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
ERROR
|
ERROR
|
||||||
L_CURLY "{"
|
L_CURLY "{"
|
||||||
|
@ -43,6 +44,7 @@ error 6: expected fn, trait or impl
|
||||||
error 38: expected a name
|
error 38: expected a name
|
||||||
error 40: missing type for `const` or `static`
|
error 40: missing type for `const` or `static`
|
||||||
error 40: expected SEMICOLON
|
error 40: expected SEMICOLON
|
||||||
error 44: expected BANG
|
error 44: expected an item
|
||||||
error 46: expected SEMICOLON
|
error 44: expected an item
|
||||||
|
error 45: expected an item
|
||||||
error 47: expected an item
|
error 47: expected an item
|
||||||
|
|
|
@ -12,15 +12,16 @@ SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
USE_KW "use"
|
USE_KW "use"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "std"
|
IDENT "std"
|
||||||
|
ERROR
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
error 8: expected R_ANGLE
|
error 8: expected R_ANGLE
|
||||||
error 8: expected type
|
error 8: expected type
|
||||||
error 11: expected `{`
|
error 11: expected `{`
|
||||||
error 15: expected BANG
|
error 15: expected an item
|
||||||
error 15: expected `{`, `[`, `(`
|
error 15: expected an item
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
SOURCE_FILE
|
SOURCE_FILE
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -22,7 +22,7 @@ SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
ASYNC_KW "async"
|
ASYNC_KW "async"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
MACRO_CALL
|
ERROR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -42,10 +42,6 @@ SOURCE_FILE
|
||||||
L_CURLY "{"
|
L_CURLY "{"
|
||||||
R_CURLY "}"
|
R_CURLY "}"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
error 3: expected BANG
|
error 3: expected an item
|
||||||
error 3: expected `{`, `[`, `(`
|
|
||||||
error 3: expected SEMICOLON
|
|
||||||
error 24: expected fn, trait or impl
|
error 24: expected fn, trait or impl
|
||||||
error 28: expected BANG
|
error 28: expected an item
|
||||||
error 28: expected `{`, `[`, `(`
|
|
||||||
error 28: expected SEMICOLON
|
|
||||||
|
|
|
@ -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]
|
[dependencies]
|
||||||
camino.workspace = true
|
camino.workspace = true
|
||||||
serde = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
serde1 = ["camino/serde1", "dep:serde"]
|
serde1 = ["camino/serde1"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -14,6 +14,7 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
serde_json = { workspace = true, features = ["unbounded_depth"] }
|
serde_json = { workspace = true, features = ["unbounded_depth"] }
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
rustc-hash.workspace = true
|
rustc-hash.workspace = true
|
||||||
|
@ -23,11 +24,9 @@ indexmap.workspace = true
|
||||||
paths = { workspace = true, features = ["serde1"] }
|
paths = { workspace = true, features = ["serde1"] }
|
||||||
tt.workspace = true
|
tt.workspace = true
|
||||||
stdx.workspace = true
|
stdx.workspace = true
|
||||||
# Ideally this crate would not depend on salsa things, but we need span information here which wraps
|
# span = {workspace = true, default-features = false} does not work
|
||||||
# InternIds for the syntax context
|
span = { path = "../span", version = "0.0.0", default-features = false}
|
||||||
span.workspace = true
|
|
||||||
# only here due to the `Env` newtype :/
|
|
||||||
base-db.workspace = true
|
|
||||||
intern.workspace = true
|
intern.workspace = true
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|
|
@ -9,7 +9,6 @@ pub mod json;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
mod process;
|
mod process;
|
||||||
|
|
||||||
use base_db::Env;
|
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
use span::Span;
|
use span::Span;
|
||||||
use std::{fmt, io, sync::Arc};
|
use std::{fmt, io, sync::Arc};
|
||||||
|
@ -148,7 +147,7 @@ impl ProcMacro {
|
||||||
&self,
|
&self,
|
||||||
subtree: &tt::Subtree<Span>,
|
subtree: &tt::Subtree<Span>,
|
||||||
attr: Option<&tt::Subtree<Span>>,
|
attr: Option<&tt::Subtree<Span>>,
|
||||||
env: Env,
|
env: Vec<(String, String)>,
|
||||||
def_site: Span,
|
def_site: Span,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
mixed_site: Span,
|
mixed_site: Span,
|
||||||
|
@ -179,7 +178,7 @@ impl ProcMacro {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lib: self.dylib_path.to_path_buf().into(),
|
lib: self.dylib_path.to_path_buf().into(),
|
||||||
env: env.into(),
|
env,
|
||||||
current_dir,
|
current_dir,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ pub(crate) mod flat;
|
||||||
use std::io::{self, BufRead, Write};
|
use std::io::{self, BufRead, Write};
|
||||||
|
|
||||||
use paths::Utf8PathBuf;
|
use paths::Utf8PathBuf;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ProcMacroKind;
|
use crate::ProcMacroKind;
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ impl ExpnGlobals {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Message: Serialize + DeserializeOwned {
|
pub trait Message: serde::Serialize + DeserializeOwned {
|
||||||
fn read<R: BufRead>(
|
fn read<R: BufRead>(
|
||||||
from_proto: ProtocolRead<R>,
|
from_proto: ProtocolRead<R>,
|
||||||
inp: &mut R,
|
inp: &mut R,
|
||||||
|
|
|
@ -39,10 +39,10 @@ use std::collections::VecDeque;
|
||||||
|
|
||||||
use intern::Symbol;
|
use intern::Symbol;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use span::{EditionedFileId, ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange};
|
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 =
|
pub type SpanDataIndexMap =
|
||||||
indexmap::IndexSet<Span, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
indexmap::IndexSet<Span, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||||
|
@ -145,7 +145,11 @@ impl FlatTree {
|
||||||
w.write(subtree);
|
w.write(subtree);
|
||||||
|
|
||||||
FlatTree {
|
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 {
|
literal: if version >= EXTENDED_LEAF_DATA {
|
||||||
write_vec(w.literal, LiteralRepr::write_with_kind)
|
write_vec(w.literal, LiteralRepr::write_with_kind)
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,7 +183,11 @@ impl FlatTree {
|
||||||
w.write(subtree);
|
w.write(subtree);
|
||||||
|
|
||||||
FlatTree {
|
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 {
|
literal: if version >= EXTENDED_LEAF_DATA {
|
||||||
write_vec(w.literal, LiteralRepr::write_with_kind)
|
write_vec(w.literal, LiteralRepr::write_with_kind)
|
||||||
} else {
|
} else {
|
||||||
|
@ -202,7 +210,11 @@ impl FlatTree {
|
||||||
span_data_table: &SpanDataIndexMap,
|
span_data_table: &SpanDataIndexMap,
|
||||||
) -> tt::Subtree<Span> {
|
) -> tt::Subtree<Span> {
|
||||||
Reader {
|
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 {
|
literal: if version >= EXTENDED_LEAF_DATA {
|
||||||
read_vec(self.literal, LiteralRepr::read_with_kind)
|
read_vec(self.literal, LiteralRepr::read_with_kind)
|
||||||
} else {
|
} else {
|
||||||
|
@ -224,7 +236,11 @@ impl FlatTree {
|
||||||
|
|
||||||
pub fn to_subtree_unresolved(self, version: u32) -> tt::Subtree<TokenId> {
|
pub fn to_subtree_unresolved(self, version: u32) -> tt::Subtree<TokenId> {
|
||||||
Reader {
|
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 {
|
literal: if version >= EXTENDED_LEAF_DATA {
|
||||||
read_vec(self.literal, LiteralRepr::read_with_kind)
|
read_vec(self.literal, LiteralRepr::read_with_kind)
|
||||||
} else {
|
} 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 {
|
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 {
|
let kind = match self.kind {
|
||||||
tt::DelimiterKind::Invisible => 0,
|
tt::DelimiterKind::Invisible => 0,
|
||||||
tt::DelimiterKind::Parenthesis => 1,
|
tt::DelimiterKind::Parenthesis => 1,
|
||||||
|
@ -266,7 +301,7 @@ impl SubtreeRepr {
|
||||||
};
|
};
|
||||||
[self.open.0, self.close.0, kind, self.tt[0], self.tt[1]]
|
[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 {
|
let kind = match kind {
|
||||||
0 => tt::DelimiterKind::Invisible,
|
0 => tt::DelimiterKind::Invisible,
|
||||||
1 => tt::DelimiterKind::Parenthesis,
|
1 => tt::DelimiterKind::Parenthesis,
|
||||||
|
|
|
@ -56,25 +56,8 @@ impl ProcMacroProcessSrv {
|
||||||
match srv.version_check() {
|
match srv.version_check() {
|
||||||
Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
|
Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!(
|
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}).
|
||||||
"The version of the proc-macro server ({v}) in your Rust toolchain \
|
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current 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."
|
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
|
@ -89,10 +72,10 @@ impl ProcMacroProcessSrv {
|
||||||
tracing::info!("Proc-macro server span mode: {:?}", srv.mode);
|
tracing::info!("Proc-macro server span mode: {:?}", srv.mode);
|
||||||
Ok(srv)
|
Ok(srv)
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => {
|
||||||
io::ErrorKind::Other,
|
tracing::info!(%e, "proc-macro version check failed, restarting and assuming version 0");
|
||||||
format!("Failed to fetch proc-macro server version: {e}"),
|
create_srv(false)
|
||||||
)),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ stdx.workspace = true
|
||||||
tt.workspace = true
|
tt.workspace = true
|
||||||
syntax-bridge.workspace = true
|
syntax-bridge.workspace = true
|
||||||
paths.workspace = true
|
paths.workspace = true
|
||||||
base-db.workspace = true
|
# span = {workspace = true, default-features = false} does not work
|
||||||
span.workspace = true
|
span = { path = "../span", version = "0.0.0", default-features = false}
|
||||||
proc-macro-api.workspace = true
|
proc-macro-api.workspace = true
|
||||||
intern.workspace = true
|
intern.workspace = true
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ rustc-hash.workspace = true
|
||||||
semver.workspace = true
|
semver.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
triomphe.workspace = true
|
triomphe.workspace = true
|
||||||
la-arena.workspace = true
|
la-arena.workspace = true
|
||||||
|
|
|
@ -15,7 +15,7 @@ use itertools::Itertools;
|
||||||
use la_arena::ArenaMap;
|
use la_arena::ArenaMap;
|
||||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize as _;
|
||||||
use toolchain::Tool;
|
use toolchain::Tool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -8,7 +8,7 @@ use cargo_metadata::{CargoOpt, MetadataCommand};
|
||||||
use la_arena::{Arena, Idx};
|
use la_arena::{Arena, Idx};
|
||||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use serde::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
use serde_json::from_value;
|
use serde_json::from_value;
|
||||||
use span::Edition;
|
use span::Edition;
|
||||||
use toolchain::Tool;
|
use toolchain::Tool;
|
||||||
|
|
|
@ -20,7 +20,7 @@ parking_lot = "0.12.1"
|
||||||
rustc-hash = "2.0.0"
|
rustc-hash = "2.0.0"
|
||||||
smallvec = "1.0.0"
|
smallvec = "1.0.0"
|
||||||
oorandom = "11"
|
oorandom = "11"
|
||||||
triomphe = "0.1.11"
|
triomphe.workspace = true
|
||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
|
|
||||||
ra-salsa-macros = { version = "0.0.0", path = "ra-salsa-macros", package = "salsa-macros" }
|
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
|
rustc-hash.workspace = true
|
||||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
tenthash = "0.4.0"
|
tenthash = "0.4.0"
|
||||||
num_cpus = "1.15.0"
|
num_cpus = "1.15.0"
|
||||||
mimalloc = { version = "0.1.30", default-features = false, optional = true }
|
mimalloc = { version = "0.1.30", default-features = false, optional = true }
|
||||||
|
|
|
@ -644,7 +644,8 @@ config_data! {
|
||||||
/// Aliased as `"checkOnSave.targets"`.
|
/// Aliased as `"checkOnSave.targets"`.
|
||||||
check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = None,
|
check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = None,
|
||||||
/// Whether `--workspace` should be passed to `cargo check`.
|
/// 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,
|
check_workspace: bool = true,
|
||||||
|
|
||||||
/// These proc-macros will be ignored when trying to expand them.
|
/// These proc-macros will be ignored when trying to expand them.
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub(crate) mod to_proto;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use cargo_metadata::PackageId;
|
||||||
use ide::FileId;
|
use ide::FileId;
|
||||||
use ide_db::FxHashMap;
|
use ide_db::FxHashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -13,7 +14,8 @@ use triomphe::Arc;
|
||||||
|
|
||||||
use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext, main_loop::DiagnosticsTaskKind};
|
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)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct DiagnosticsMapConfig {
|
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_syntax: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
|
||||||
pub(crate) native_semantic: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
|
pub(crate) native_semantic: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
|
||||||
// FIXME: should be Vec<flycheck::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,
|
pub(crate) check_fixes: CheckFixes,
|
||||||
changes: IntSet<FileId>,
|
changes: IntSet<FileId>,
|
||||||
/// Counter for supplying a new generation number for diagnostics.
|
/// Counter for supplying a new generation number for diagnostics.
|
||||||
|
@ -50,18 +55,37 @@ pub(crate) struct Fix {
|
||||||
|
|
||||||
impl DiagnosticCollection {
|
impl DiagnosticCollection {
|
||||||
pub(crate) fn clear_check(&mut self, flycheck_id: usize) {
|
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) {
|
let Some(check) = self.check.get_mut(&flycheck_id) else {
|
||||||
it.clear();
|
return;
|
||||||
}
|
};
|
||||||
if let Some(it) = self.check.get_mut(&flycheck_id) {
|
self.changes.extend(check.drain().flat_map(|(_, v)| v.into_keys()));
|
||||||
self.changes.extend(it.drain().map(|(key, _value)| key));
|
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) {
|
pub(crate) fn clear_check_all(&mut self) {
|
||||||
Arc::make_mut(&mut self.check_fixes).clear();
|
Arc::make_mut(&mut self.check_fixes).clear();
|
||||||
self.changes
|
self.changes.extend(
|
||||||
.extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key)))
|
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) {
|
pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
|
||||||
|
@ -73,11 +97,19 @@ impl DiagnosticCollection {
|
||||||
pub(crate) fn add_check_diagnostic(
|
pub(crate) fn add_check_diagnostic(
|
||||||
&mut self,
|
&mut self,
|
||||||
flycheck_id: usize,
|
flycheck_id: usize,
|
||||||
|
package_id: &Option<Arc<PackageId>>,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
diagnostic: lsp_types::Diagnostic,
|
diagnostic: lsp_types::Diagnostic,
|
||||||
fix: Option<Box<Fix>>,
|
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() {
|
for existing_diagnostic in diagnostics.iter() {
|
||||||
if are_diagnostics_equal(existing_diagnostic, &diagnostic) {
|
if are_diagnostics_equal(existing_diagnostic, &diagnostic) {
|
||||||
return;
|
return;
|
||||||
|
@ -86,7 +118,14 @@ impl DiagnosticCollection {
|
||||||
|
|
||||||
if let Some(fix) = fix {
|
if let Some(fix) = fix {
|
||||||
let check_fixes = Arc::make_mut(&mut self.check_fixes);
|
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);
|
diagnostics.push(diagnostic);
|
||||||
self.changes.insert(file_id);
|
self.changes.insert(file_id);
|
||||||
|
@ -135,7 +174,12 @@ impl DiagnosticCollection {
|
||||||
) -> impl Iterator<Item = &lsp_types::Diagnostic> {
|
) -> impl Iterator<Item = &lsp_types::Diagnostic> {
|
||||||
let native_syntax = self.native_syntax.get(&file_id).into_iter().flat_map(|(_, d)| d);
|
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 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)
|
native_syntax.chain(native_semantic).chain(check)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
//! Flycheck provides the functionality needed to run `cargo check` to provide
|
//! Flycheck provides the functionality needed to run `cargo check` to provide
|
||||||
//! LSP diagnostics based on the output of the command.
|
//! 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 crossbeam_channel::{select_biased, unbounded, Receiver, Sender};
|
||||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize as _;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
pub(crate) use cargo_metadata::diagnostic::{
|
pub(crate) use cargo_metadata::diagnostic::{
|
||||||
Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
|
Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
|
||||||
};
|
};
|
||||||
use toolchain::Tool;
|
use toolchain::Tool;
|
||||||
|
use triomphe::Arc;
|
||||||
|
|
||||||
use crate::command::{CommandHandle, ParseFromLine};
|
use crate::command::{CommandHandle, ParseFromLine};
|
||||||
|
|
||||||
|
@ -150,10 +153,19 @@ impl FlycheckHandle {
|
||||||
|
|
||||||
pub(crate) enum FlycheckMessage {
|
pub(crate) enum FlycheckMessage {
|
||||||
/// Request adding a diagnostic with fixes included to a file
|
/// 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
|
/// Request clearing all outdated diagnostics.
|
||||||
ClearDiagnostics { id: usize },
|
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
|
/// Request check progress notification to client
|
||||||
Progress {
|
Progress {
|
||||||
|
@ -166,15 +178,18 @@ pub(crate) enum FlycheckMessage {
|
||||||
impl fmt::Debug for FlycheckMessage {
|
impl fmt::Debug for FlycheckMessage {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => f
|
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => f
|
||||||
.debug_struct("AddDiagnostic")
|
.debug_struct("AddDiagnostic")
|
||||||
.field("id", id)
|
.field("id", id)
|
||||||
.field("workspace_root", workspace_root)
|
.field("workspace_root", workspace_root)
|
||||||
|
.field("package_id", package_id)
|
||||||
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
|
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
|
||||||
.finish(),
|
.finish(),
|
||||||
FlycheckMessage::ClearDiagnostics { id } => {
|
FlycheckMessage::ClearDiagnostics { id, package_id } => f
|
||||||
f.debug_struct("ClearDiagnostics").field("id", id).finish()
|
.debug_struct("ClearDiagnostics")
|
||||||
}
|
.field("id", id)
|
||||||
|
.field("package_id", package_id)
|
||||||
|
.finish(),
|
||||||
FlycheckMessage::Progress { id, progress } => {
|
FlycheckMessage::Progress { id, progress } => {
|
||||||
f.debug_struct("Progress").field("id", id).field("progress", progress).finish()
|
f.debug_struct("Progress").field("id", id).field("progress", progress).finish()
|
||||||
}
|
}
|
||||||
|
@ -200,12 +215,13 @@ enum StateChange {
|
||||||
struct FlycheckActor {
|
struct FlycheckActor {
|
||||||
/// The workspace id of this flycheck instance.
|
/// The workspace id of this flycheck instance.
|
||||||
id: usize,
|
id: usize,
|
||||||
|
|
||||||
sender: Sender<FlycheckMessage>,
|
sender: Sender<FlycheckMessage>,
|
||||||
config: FlycheckConfig,
|
config: FlycheckConfig,
|
||||||
manifest_path: Option<AbsPathBuf>,
|
manifest_path: Option<AbsPathBuf>,
|
||||||
/// Either the workspace root of the workspace we are flychecking,
|
/// Either the workspace root of the workspace we are flychecking,
|
||||||
/// or the project root of the project.
|
/// or the project root of the project.
|
||||||
root: AbsPathBuf,
|
root: Arc<AbsPathBuf>,
|
||||||
sysroot_root: Option<AbsPathBuf>,
|
sysroot_root: Option<AbsPathBuf>,
|
||||||
/// CargoHandle exists to wrap around the communication needed to be able to
|
/// CargoHandle exists to wrap around the communication needed to be able to
|
||||||
/// run `cargo check` without blocking. Currently the Rust standard library
|
/// run `cargo check` without blocking. Currently the Rust standard library
|
||||||
|
@ -215,8 +231,13 @@ struct FlycheckActor {
|
||||||
command_handle: Option<CommandHandle<CargoCheckMessage>>,
|
command_handle: Option<CommandHandle<CargoCheckMessage>>,
|
||||||
/// The receiver side of the channel mentioned above.
|
/// The receiver side of the channel mentioned above.
|
||||||
command_receiver: Option<Receiver<CargoCheckMessage>>,
|
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)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
@ -225,13 +246,6 @@ enum Event {
|
||||||
CheckEvent(Option<CargoCheckMessage>),
|
CheckEvent(Option<CargoCheckMessage>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
enum FlycheckStatus {
|
|
||||||
Started,
|
|
||||||
DiagnosticSent,
|
|
||||||
Finished,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
|
pub(crate) const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
|
||||||
|
|
||||||
impl FlycheckActor {
|
impl FlycheckActor {
|
||||||
|
@ -249,11 +263,11 @@ impl FlycheckActor {
|
||||||
sender,
|
sender,
|
||||||
config,
|
config,
|
||||||
sysroot_root,
|
sysroot_root,
|
||||||
root: workspace_root,
|
root: Arc::new(workspace_root),
|
||||||
manifest_path,
|
manifest_path,
|
||||||
command_handle: None,
|
command_handle: None,
|
||||||
command_receiver: 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_handle = Some(command_handle);
|
||||||
self.command_receiver = Some(receiver);
|
self.command_receiver = Some(receiver);
|
||||||
self.report_progress(Progress::DidStart);
|
self.report_progress(Progress::DidStart);
|
||||||
self.status = FlycheckStatus::Started;
|
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
self.report_progress(Progress::DidFailToRestart(format!(
|
self.report_progress(Progress::DidFailToRestart(format!(
|
||||||
"Failed to run the following command: {formatted_command} error={error}"
|
"Failed to run the following command: {formatted_command} error={error}"
|
||||||
)));
|
)));
|
||||||
self.status = FlycheckStatus::Finished;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,37 +344,62 @@ impl FlycheckActor {
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if self.status == FlycheckStatus::Started {
|
if self.package_status.is_empty() {
|
||||||
self.send(FlycheckMessage::ClearDiagnostics { id: self.id });
|
// 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.report_progress(Progress::DidFinish(res));
|
||||||
self.status = FlycheckStatus::Finished;
|
|
||||||
}
|
}
|
||||||
Event::CheckEvent(Some(message)) => match message {
|
Event::CheckEvent(Some(message)) => match message {
|
||||||
CargoCheckMessage::CompilerArtifact(msg) => {
|
CargoCheckMessage::CompilerArtifact(msg) => {
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
flycheck_id = self.id,
|
flycheck_id = self.id,
|
||||||
artifact = msg.target.name,
|
artifact = msg.target.name,
|
||||||
|
package_id = msg.package_id.repr,
|
||||||
"artifact received"
|
"artifact received"
|
||||||
);
|
);
|
||||||
self.report_progress(Progress::DidCheckCrate(msg.target.name));
|
self.report_progress(Progress::DidCheckCrate(msg.target.name));
|
||||||
|
self.package_status
|
||||||
|
.entry(Arc::new(msg.package_id))
|
||||||
|
.or_insert(DiagnosticReceived::No);
|
||||||
}
|
}
|
||||||
|
CargoCheckMessage::Diagnostic { diagnostic, package_id } => {
|
||||||
CargoCheckMessage::Diagnostic(msg) => {
|
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
flycheck_id = self.id,
|
flycheck_id = self.id,
|
||||||
message = msg.message,
|
message = diagnostic.message,
|
||||||
|
package_id = package_id.as_ref().map(|it| &it.repr),
|
||||||
"diagnostic received"
|
"diagnostic received"
|
||||||
);
|
);
|
||||||
if self.status == FlycheckStatus::Started {
|
if let Some(package_id) = &package_id {
|
||||||
self.send(FlycheckMessage::ClearDiagnostics { id: self.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 {
|
self.send(FlycheckMessage::AddDiagnostic {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
|
package_id,
|
||||||
workspace_root: self.root.clone(),
|
workspace_root: self.root.clone(),
|
||||||
diagnostic: msg,
|
diagnostic,
|
||||||
});
|
});
|
||||||
self.status = FlycheckStatus::DiagnosticSent;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -380,7 +417,7 @@ impl FlycheckActor {
|
||||||
command_handle.cancel();
|
command_handle.cancel();
|
||||||
self.command_receiver.take();
|
self.command_receiver.take();
|
||||||
self.report_progress(Progress::DidCancel);
|
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.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
|
||||||
}
|
}
|
||||||
cmd.arg(command);
|
cmd.arg(command);
|
||||||
cmd.current_dir(&self.root);
|
cmd.current_dir(&*self.root);
|
||||||
|
|
||||||
match package {
|
match package {
|
||||||
Some(pkg) => cmd.arg("-p").arg(pkg),
|
Some(pkg) => cmd.arg("-p").arg(pkg),
|
||||||
|
@ -442,11 +479,11 @@ impl FlycheckActor {
|
||||||
|
|
||||||
match invocation_strategy {
|
match invocation_strategy {
|
||||||
InvocationStrategy::Once => {
|
InvocationStrategy::Once => {
|
||||||
cmd.current_dir(&self.root);
|
cmd.current_dir(&*self.root);
|
||||||
}
|
}
|
||||||
InvocationStrategy::PerWorkspace => {
|
InvocationStrategy::PerWorkspace => {
|
||||||
// FIXME: cmd.current_dir(&affected_workspace);
|
// 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)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum CargoCheckMessage {
|
enum CargoCheckMessage {
|
||||||
CompilerArtifact(cargo_metadata::Artifact),
|
CompilerArtifact(cargo_metadata::Artifact),
|
||||||
Diagnostic(Diagnostic),
|
Diagnostic { diagnostic: Diagnostic, package_id: Option<Arc<PackageId>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseFromLine for CargoCheckMessage {
|
impl ParseFromLine for CargoCheckMessage {
|
||||||
|
@ -501,11 +538,16 @@ impl ParseFromLine for CargoCheckMessage {
|
||||||
Some(CargoCheckMessage::CompilerArtifact(artifact))
|
Some(CargoCheckMessage::CompilerArtifact(artifact))
|
||||||
}
|
}
|
||||||
cargo_metadata::Message::CompilerMessage(msg) => {
|
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,
|
_ => 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
|
// status
|
||||||
pub(crate) shutdown_requested: bool,
|
pub(crate) shutdown_requested: bool,
|
||||||
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
|
pub(crate) last_reported_status: lsp_ext::ServerStatusParams,
|
||||||
|
|
||||||
// proc macros
|
// proc macros
|
||||||
pub(crate) proc_macro_clients: Arc<[anyhow::Result<ProcMacroServer>]>,
|
pub(crate) proc_macro_clients: Arc<[anyhow::Result<ProcMacroServer>]>,
|
||||||
|
@ -238,7 +238,11 @@ impl GlobalState {
|
||||||
mem_docs: MemDocs::default(),
|
mem_docs: MemDocs::default(),
|
||||||
semantic_tokens_cache: Arc::new(Default::default()),
|
semantic_tokens_cache: Arc::new(Default::default()),
|
||||||
shutdown_requested: false,
|
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(),
|
source_root_config: SourceRootConfig::default(),
|
||||||
local_roots_parent_map: Arc::new(FxHashMap::default()),
|
local_roots_parent_map: Arc::new(FxHashMap::default()),
|
||||||
config_errors: Default::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
|
/// 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`].
|
/// 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,
|
&mut self,
|
||||||
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
|
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
|
||||||
default: impl FnOnce() -> 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) {
|
if !state.config.check_on_save(Some(sr)) || run_flycheck(state, vfs_path) {
|
||||||
return Ok(());
|
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.
|
// No specific flycheck was triggered, so let's trigger all of them.
|
||||||
for flycheck in state.flycheck.iter() {
|
for flycheck in state.flycheck.iter() {
|
||||||
flycheck.restart_workspace(None);
|
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);
|
let file_id = state.vfs.read().0.file_id(&vfs_path);
|
||||||
if let Some(file_id) = file_id {
|
if let Some(file_id) = file_id {
|
||||||
let world = state.snapshot();
|
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 mut updated = false;
|
||||||
let task = move || -> std::result::Result<(), ide::Cancelled> {
|
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.
|
// 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());
|
let saved_file = vfs_path.as_path().map(|p| p.to_owned());
|
||||||
|
|
||||||
// Find and trigger corresponding flychecks
|
// 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() {
|
for (id, package) in workspace_ids.clone() {
|
||||||
if id == flycheck.id() {
|
if id == flycheck.id() {
|
||||||
updated = true;
|
updated = true;
|
||||||
match package.filter(|_| !world.config.flycheck_workspace(source_root_id)) {
|
if may_flycheck_workspace {
|
||||||
Some(package) => flycheck
|
flycheck.restart_workspace(saved_file.clone())
|
||||||
.restart_for_package(package, target.clone().map(TupleExt::head)),
|
} else if let Some(package) = package {
|
||||||
None => flycheck.restart_workspace(saved_file.clone()),
|
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.
|
// 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() {
|
for flycheck in world.flycheck.iter() {
|
||||||
flycheck.restart_workspace(saved_file.clone());
|
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.
|
// No specific flycheck was triggered, so let's trigger all of them.
|
||||||
for flycheck in state.flycheck.iter() {
|
if state.config.flycheck_workspace(None) {
|
||||||
flycheck.restart_workspace(None);
|
for flycheck in state.flycheck.iter() {
|
||||||
|
flycheck.restart_workspace(None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,27 +481,28 @@ pub(crate) fn handle_document_diagnostics(
|
||||||
snap: GlobalStateSnapshot,
|
snap: GlobalStateSnapshot,
|
||||||
params: lsp_types::DocumentDiagnosticParams,
|
params: lsp_types::DocumentDiagnosticParams,
|
||||||
) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
|
) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
|
||||||
const EMPTY: lsp_types::DocumentDiagnosticReportResult =
|
let empty = || {
|
||||||
lsp_types::DocumentDiagnosticReportResult::Report(
|
lsp_types::DocumentDiagnosticReportResult::Report(
|
||||||
lsp_types::DocumentDiagnosticReport::Full(
|
lsp_types::DocumentDiagnosticReport::Full(
|
||||||
lsp_types::RelatedFullDocumentDiagnosticReport {
|
lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||||
related_documents: None,
|
related_documents: None,
|
||||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||||
result_id: None,
|
result_id: Some("rust-analyzer".to_owned()),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?;
|
let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?;
|
||||||
let source_root = snap.analysis.source_root_id(file_id)?;
|
let source_root = snap.analysis.source_root_id(file_id)?;
|
||||||
if !snap.analysis.is_local_source_root(source_root)? {
|
if !snap.analysis.is_local_source_root(source_root)? {
|
||||||
return Ok(EMPTY);
|
return Ok(empty());
|
||||||
}
|
}
|
||||||
let config = snap.config.diagnostics(Some(source_root));
|
let config = snap.config.diagnostics(Some(source_root));
|
||||||
if !config.enabled {
|
if !config.enabled {
|
||||||
return Ok(EMPTY);
|
return Ok(empty());
|
||||||
}
|
}
|
||||||
let line_index = snap.file_line_index(file_id)?;
|
let line_index = snap.file_line_index(file_id)?;
|
||||||
let supports_related = snap.config.text_document_diagnostic_related_document_support();
|
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(
|
Ok(lsp_types::DocumentDiagnosticReportResult::Report(
|
||||||
lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
|
lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||||
result_id: None,
|
result_id: Some("rust-analyzer".to_owned()),
|
||||||
items: diagnostics.collect(),
|
items: diagnostics.collect(),
|
||||||
},
|
},
|
||||||
related_documents: related_documents.is_empty().not().then(|| {
|
related_documents: related_documents.is_empty().not().then(|| {
|
||||||
|
@ -539,7 +540,10 @@ pub(crate) fn handle_document_diagnostics(
|
||||||
(
|
(
|
||||||
to_proto::url(&snap, id),
|
to_proto::url(&snap, id),
|
||||||
lsp_types::DocumentDiagnosticReportKind::Full(
|
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| {
|
let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
|
||||||
// Avoid computing hashes for items that obviously do not match
|
// 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
|
// 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)
|
&& resolve_data_hash == completion_item_hash(completion_item, resolve_data.for_ref)
|
||||||
}) else {
|
}) else {
|
||||||
return Ok(original_completion);
|
return Ok(original_completion);
|
||||||
|
@ -1441,7 +1445,13 @@ pub(crate) fn handle_code_action(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixes from `cargo check`.
|
// 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
|
// FIXME: this mapping is awkward and shouldn't exist. Refactor
|
||||||
// `snap.check_fixes` to not convert to LSP prematurely.
|
// `snap.check_fixes` to not convert to LSP prematurely.
|
||||||
let intersect_fix_range = fix
|
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.deprecated),
|
||||||
u8::from(item.trigger_call_info),
|
u8::from(item.trigger_call_info),
|
||||||
]);
|
]);
|
||||||
hasher.update(&item.label);
|
hasher.update(&item.label.primary);
|
||||||
if let Some(label_detail) = &item.label_detail {
|
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);
|
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
|
// 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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct CompletionResolveData {
|
pub struct CompletionResolveData {
|
||||||
pub position: lsp_types::TextDocumentPositionParams,
|
pub position: lsp_types::TextDocumentPositionParams,
|
||||||
|
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||||
pub imports: Vec<CompletionImport>,
|
pub imports: Vec<CompletionImport>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
pub version: Option<i32>,
|
pub version: Option<i32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
pub trigger_character: Option<char>,
|
pub trigger_character: Option<char>,
|
||||||
pub for_ref: bool,
|
pub for_ref: bool,
|
||||||
pub hash: String,
|
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
|
// This is a string instead of a u64 as javascript can't represent u64 fully
|
||||||
pub hash: String,
|
pub hash: String,
|
||||||
pub resolve_range: lsp_types::Range,
|
pub resolve_range: lsp_types::Range,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
pub version: Option<i32>,
|
pub version: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
iter::once,
|
iter::once,
|
||||||
mem,
|
mem,
|
||||||
|
ops::Not as _,
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -353,14 +354,17 @@ fn completion_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut lsp_item = lsp_types::CompletionItem {
|
let mut lsp_item = lsp_types::CompletionItem {
|
||||||
label: item.label.to_string(),
|
label: item.label.primary.to_string(),
|
||||||
detail,
|
detail,
|
||||||
filter_text,
|
filter_text,
|
||||||
kind: Some(completion_item_kind(item.kind)),
|
kind: Some(completion_item_kind(item.kind)),
|
||||||
text_edit,
|
text_edit,
|
||||||
additional_text_edits: Some(additional_text_edits),
|
additional_text_edits: additional_text_edits
|
||||||
|
.is_empty()
|
||||||
|
.not()
|
||||||
|
.then_some(additional_text_edits),
|
||||||
documentation,
|
documentation,
|
||||||
deprecated: Some(item.deprecated),
|
deprecated: item.deprecated.then_some(item.deprecated),
|
||||||
tags,
|
tags,
|
||||||
command,
|
command,
|
||||||
insert_text_format,
|
insert_text_format,
|
||||||
|
@ -368,15 +372,17 @@ fn completion_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.completion_label_details_support() {
|
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 {
|
if fields_to_resolve.resolve_label_details {
|
||||||
something_to_resolve |= true;
|
something_to_resolve |= has_label_details;
|
||||||
} else {
|
} else if has_label_details {
|
||||||
lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
|
lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
|
||||||
detail: item.label_detail.as_ref().map(ToString::to_string),
|
detail: item.label.detail_left.clone(),
|
||||||
description: item.detail.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());
|
lsp_item.label.push_str(label_detail.as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1578,22 +1584,26 @@ pub(crate) fn code_lens(
|
||||||
};
|
};
|
||||||
|
|
||||||
let lens_config = snap.config.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);
|
if has_root {
|
||||||
acc.push(lsp_types::CodeLens {
|
if lens_config.run && client_commands_config.run_single {
|
||||||
range: annotation_range,
|
let command = command::run_single(&r, &title);
|
||||||
command: Some(command),
|
acc.push(lsp_types::CodeLens {
|
||||||
data: None,
|
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 {
|
if lens_config.debug && can_debug && client_commands_config.debug_single {
|
||||||
range: annotation_range,
|
let command = command::debug_single(&r);
|
||||||
command: Some(command),
|
acc.push(lsp_types::CodeLens {
|
||||||
data: None,
|
range: annotation_range,
|
||||||
})
|
command: Some(command),
|
||||||
|
data: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if lens_config.interpret {
|
if lens_config.interpret {
|
||||||
let command = command::interpret_single(&r);
|
let command = command::interpret_single(&r);
|
||||||
acc.push(lsp_types::CodeLens {
|
acc.push(lsp_types::CodeLens {
|
||||||
|
|
|
@ -408,7 +408,10 @@ impl GlobalState {
|
||||||
if self.is_quiescent() {
|
if self.is_quiescent() {
|
||||||
let became_quiescent = !was_quiescent;
|
let became_quiescent = !was_quiescent;
|
||||||
if became_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
|
// Project has loaded properly, kick off initial flycheck
|
||||||
self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
|
self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
|
||||||
}
|
}
|
||||||
|
@ -656,8 +659,8 @@ impl GlobalState {
|
||||||
|
|
||||||
fn update_status_or_notify(&mut self) {
|
fn update_status_or_notify(&mut self) {
|
||||||
let status = self.current_status();
|
let status = self.current_status();
|
||||||
if self.last_reported_status.as_ref() != Some(&status) {
|
if self.last_reported_status != status {
|
||||||
self.last_reported_status = Some(status.clone());
|
self.last_reported_status = status.clone();
|
||||||
|
|
||||||
if self.config.server_status_notification() {
|
if self.config.server_status_notification() {
|
||||||
self.send_notification::<lsp_ext::ServerStatusNotification>(status);
|
self.send_notification::<lsp_ext::ServerStatusNotification>(status);
|
||||||
|
@ -715,6 +718,7 @@ impl GlobalState {
|
||||||
error!("FetchWorkspaceError: {e}");
|
error!("FetchWorkspaceError: {e}");
|
||||||
}
|
}
|
||||||
self.wants_to_switch = Some("fetched workspace".to_owned());
|
self.wants_to_switch = Some("fetched workspace".to_owned());
|
||||||
|
self.diagnostics.clear_check_all();
|
||||||
(Progress::End, None)
|
(Progress::End, None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -956,7 +960,7 @@ impl GlobalState {
|
||||||
|
|
||||||
fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
|
fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
|
||||||
match message {
|
match message {
|
||||||
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => {
|
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => {
|
||||||
let snap = self.snapshot();
|
let snap = self.snapshot();
|
||||||
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
|
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
|
||||||
&self.config.diagnostics_map(None),
|
&self.config.diagnostics_map(None),
|
||||||
|
@ -968,6 +972,7 @@ impl GlobalState {
|
||||||
match url_to_file_id(&self.vfs.read().0, &diag.url) {
|
match url_to_file_id(&self.vfs.read().0, &diag.url) {
|
||||||
Ok(file_id) => self.diagnostics.add_check_diagnostic(
|
Ok(file_id) => self.diagnostics.add_check_diagnostic(
|
||||||
id,
|
id,
|
||||||
|
&package_id,
|
||||||
file_id,
|
file_id,
|
||||||
diag.diagnostic,
|
diag.diagnostic,
|
||||||
diag.fix,
|
diag.fix,
|
||||||
|
@ -981,9 +986,12 @@ impl GlobalState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FlycheckMessage::ClearDiagnostics { id, package_id: None } => {
|
||||||
FlycheckMessage::ClearDiagnostics { id } => self.diagnostics.clear_check(id),
|
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 } => {
|
FlycheckMessage::Progress { id, progress } => {
|
||||||
let (state, message) = match progress {
|
let (state, message) = match progress {
|
||||||
flycheck::Progress::DidStart => (Progress::Begin, None),
|
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)
|
.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.
|
// FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
|
||||||
// All other request handlers
|
// 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::DocumentDiagnosticReport::Full(
|
||||||
lsp_types::RelatedFullDocumentDiagnosticReport {
|
lsp_types::RelatedFullDocumentDiagnosticReport {
|
||||||
related_documents: None,
|
related_documents: None,
|
||||||
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
|
||||||
result_id: None,
|
result_id: Some("rust-analyzer".to_owned()),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,7 +70,6 @@ impl GlobalState {
|
||||||
/// are ready to do semantic work.
|
/// are ready to do semantic work.
|
||||||
pub(crate) fn is_quiescent(&self) -> bool {
|
pub(crate) fn is_quiescent(&self) -> bool {
|
||||||
self.vfs_done
|
self.vfs_done
|
||||||
&& self.last_reported_status.is_some()
|
|
||||||
&& !self.fetch_workspaces_queue.op_in_progress()
|
&& !self.fetch_workspaces_queue.op_in_progress()
|
||||||
&& !self.fetch_build_data_queue.op_in_progress()
|
&& !self.fetch_build_data_queue.op_in_progress()
|
||||||
&& !self.fetch_proc_macros_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 crossbeam_channel::Sender;
|
||||||
use paths::AbsPath;
|
use paths::AbsPath;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize as _;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
use toolchain::Tool;
|
use toolchain::Tool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -54,7 +54,7 @@ where
|
||||||
fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {}
|
fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {}
|
||||||
|
|
||||||
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
|
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde_derive::Serialize)]
|
||||||
struct JsonDataInner {
|
struct JsonDataInner {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
elapsed_ms: u128,
|
elapsed_ms: u128,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
env, fs,
|
env, fs,
|
||||||
sync::{Once, OnceLock},
|
sync::Once,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,34 +141,15 @@ impl Project<'_> {
|
||||||
/// file in the config dir after server is run, something where our naive approach comes short.
|
/// 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.
|
/// 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 {
|
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 {
|
let config_dir_guard = if config_lock {
|
||||||
Some({
|
Some({
|
||||||
let (path, mutex) = CONFIG_DIR_LOCK.get_or_init(|| {
|
let guard = CONFIG_DIR_LOCK.lock();
|
||||||
let value = TestDir::new().keep().path().to_owned();
|
let test_dir = TestDir::new();
|
||||||
env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
|
let value = test_dir.path().to_owned();
|
||||||
(value, Mutex::new(()))
|
env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
|
||||||
});
|
(guard, test_dir)
|
||||||
#[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>
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -311,14 +292,12 @@ pub(crate) struct Server {
|
||||||
client: Connection,
|
client: Connection,
|
||||||
/// XXX: remove the tempdir last
|
/// XXX: remove the tempdir last
|
||||||
dir: TestDir,
|
dir: TestDir,
|
||||||
#[allow(dyn_drop)]
|
_config_dir_guard: Option<(MutexGuard<'static, ()>, TestDir)>,
|
||||||
_config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
#[allow(dyn_drop)]
|
|
||||||
fn new(
|
fn new(
|
||||||
config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>,
|
config_dir_guard: Option<(MutexGuard<'static, ()>, TestDir)>,
|
||||||
dir: TestDir,
|
dir: TestDir,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Server {
|
) -> Server {
|
||||||
|
|
|
@ -12,7 +12,7 @@ authors.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
la-arena.workspace = true
|
la-arena.workspace = true
|
||||||
ra-salsa.workspace = true
|
ra-salsa = { workspace = true, optional = true }
|
||||||
rustc-hash.workspace = true
|
rustc-hash.workspace = true
|
||||||
hashbrown.workspace = true
|
hashbrown.workspace = true
|
||||||
text-size.workspace = true
|
text-size.workspace = true
|
||||||
|
@ -22,5 +22,8 @@ vfs.workspace = true
|
||||||
syntax.workspace = true
|
syntax.workspace = true
|
||||||
stdx.workspace = true
|
stdx.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["ra-salsa"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ra-salsa"))]
|
||||||
|
use crate::InternId;
|
||||||
|
#[cfg(feature = "ra-salsa")]
|
||||||
use ra_salsa::{InternId, InternValue};
|
use ra_salsa::{InternId, InternValue};
|
||||||
|
|
||||||
use crate::MacroCallId;
|
use crate::MacroCallId;
|
||||||
|
@ -39,6 +42,7 @@ impl fmt::Debug for SyntaxContextId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ra-salsa")]
|
||||||
impl ra_salsa::InternKey for SyntaxContextId {
|
impl ra_salsa::InternKey for SyntaxContextId {
|
||||||
fn from_intern_id(v: ra_salsa::InternId) -> Self {
|
fn from_intern_id(v: ra_salsa::InternId) -> Self {
|
||||||
SyntaxContextId(v)
|
SyntaxContextId(v)
|
||||||
|
@ -92,6 +96,7 @@ pub struct SyntaxContextData {
|
||||||
pub opaque_and_semitransparent: SyntaxContextId,
|
pub opaque_and_semitransparent: SyntaxContextId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ra-salsa")]
|
||||||
impl InternValue for SyntaxContextData {
|
impl InternValue for SyntaxContextData {
|
||||||
type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
|
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