aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock24
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir_def/src/attr.rs2
-rw-r--r--crates/hir_def/src/db.rs2
-rw-r--r--crates/hir_ty/src/db.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs14
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs6
-rw-r--r--crates/hir_ty/src/display.rs21
-rw-r--r--crates/hir_ty/src/infer/expr.rs24
-rw-r--r--crates/hir_ty/src/infer/pat.rs2
-rw-r--r--crates/hir_ty/src/lib.rs22
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/method_resolution.rs14
-rw-r--r--crates/hir_ty/src/traits/chalk.rs14
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs16
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs10
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs56
-rw-r--r--crates/ide_assists/src/handlers/pull_assignment_up.rs43
-rw-r--r--crates/ide_completion/src/completions/attribute.rs3
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs27
-rw-r--r--crates/ide_completion/src/completions/keyword.rs35
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs12
-rw-r--r--crates/mbe/src/tests.rs3
-rw-r--r--crates/parser/src/grammar.rs3
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs80
-rw-r--r--crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt2
-rw-r--r--crates/rust-analyzer/src/config.rs11
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--crates/rust-analyzer/src/reload.rs2
-rw-r--r--docs/user/generated_config.adoc6
-rw-r--r--docs/user/manual.adoc2
-rw-r--r--editors/code/package.json6
-rw-r--r--xtask/src/flags.rs24
-rw-r--r--xtask/src/install.rs120
-rw-r--r--xtask/src/main.rs32
36 files changed, 368 insertions, 284 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 799127891..39f27098a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -113,9 +113,9 @@ checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
113 113
114[[package]] 114[[package]]
115name = "camino" 115name = "camino"
116version = "1.0.1" 116version = "1.0.2"
117source = "registry+https://github.com/rust-lang/crates.io-index" 117source = "registry+https://github.com/rust-lang/crates.io-index"
118checksum = "9bb47ab72bdba43021afa16dc1ef4d80c980d366b17ed37ea8d2ebe2087075b9" 118checksum = "cd065703998b183ed0b348a22555691373a9345a1431141e5778b48bb17e4703"
119dependencies = [ 119dependencies = [
120 "serde", 120 "serde",
121] 121]
@@ -789,9 +789,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
789 789
790[[package]] 790[[package]]
791name = "libc" 791name = "libc"
792version = "0.2.87" 792version = "0.2.88"
793source = "registry+https://github.com/rust-lang/crates.io-index" 793source = "registry+https://github.com/rust-lang/crates.io-index"
794checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" 794checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
795 795
796[[package]] 796[[package]]
797name = "libloading" 797name = "libloading"
@@ -1127,9 +1127,9 @@ dependencies = [
1127 1127
1128[[package]] 1128[[package]]
1129name = "pin-project-lite" 1129name = "pin-project-lite"
1130version = "0.2.5" 1130version = "0.2.6"
1131source = "registry+https://github.com/rust-lang/crates.io-index" 1131source = "registry+https://github.com/rust-lang/crates.io-index"
1132checksum = "0cf491442e4b033ed1c722cb9f0df5fcfcf4de682466c46469c36bc47dc5548a" 1132checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
1133 1133
1134[[package]] 1134[[package]]
1135name = "proc-macro-hack" 1135name = "proc-macro-hack"
@@ -1561,9 +1561,9 @@ dependencies = [
1561 1561
1562[[package]] 1562[[package]]
1563name = "syn" 1563name = "syn"
1564version = "1.0.60" 1564version = "1.0.61"
1565source = "registry+https://github.com/rust-lang/crates.io-index" 1565source = "registry+https://github.com/rust-lang/crates.io-index"
1566checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" 1566checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5"
1567dependencies = [ 1567dependencies = [
1568 "proc-macro2", 1568 "proc-macro2",
1569 "quote", 1569 "quote",
@@ -1919,18 +1919,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
1919 1919
1920[[package]] 1920[[package]]
1921name = "xflags" 1921name = "xflags"
1922version = "0.1.3" 1922version = "0.1.4"
1923source = "registry+https://github.com/rust-lang/crates.io-index" 1923source = "registry+https://github.com/rust-lang/crates.io-index"
1924checksum = "ddb4b07c0db813f8e2b5e1b2189ef56fcddb27a6f9ef71314dbf8cc50096a5db" 1924checksum = "222e914b43cec5d7305ac5116d10a14b3a52c50e9062d642c92631f3beabc729"
1925dependencies = [ 1925dependencies = [
1926 "xflags-macros", 1926 "xflags-macros",
1927] 1927]
1928 1928
1929[[package]] 1929[[package]]
1930name = "xflags-macros" 1930name = "xflags-macros"
1931version = "0.1.3" 1931version = "0.1.4"
1932source = "registry+https://github.com/rust-lang/crates.io-index" 1932source = "registry+https://github.com/rust-lang/crates.io-index"
1933checksum = "f8e168a99d6ce9d5dd0d0913f1bded279377843952dd8ff83f81b862a1dad0e1" 1933checksum = "52f18f5b4aa7f95e209d5b9274f6164c3938920b4d5c75f97f0dd16daee25ddd"
1934dependencies = [ 1934dependencies = [
1935 "proc-macro2", 1935 "proc-macro2",
1936] 1936]
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index fc1a74641..7656db974 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -1700,7 +1700,7 @@ impl Type {
1700 1700
1701 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { 1701 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1702 let adt_id = match self.ty.value { 1702 let adt_id = match self.ty.value {
1703 Ty::Adt(adt_id, ..) => adt_id, 1703 Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
1704 _ => return false, 1704 _ => return false,
1705 }; 1705 };
1706 1706
@@ -1728,8 +1728,8 @@ impl Type {
1728 1728
1729 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { 1729 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1730 let (variant_id, substs) = match self.ty.value { 1730 let (variant_id, substs) = match self.ty.value {
1731 Ty::Adt(AdtId::StructId(s), ref substs) => (s.into(), substs), 1731 Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
1732 Ty::Adt(AdtId::UnionId(u), ref substs) => (u.into(), substs), 1732 Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
1733 _ => return Vec::new(), 1733 _ => return Vec::new(),
1734 }; 1734 };
1735 1735
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index fe4c3fa28..24ffa6c3a 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -367,7 +367,7 @@ fn inner_attributes(
367 // Excerpt from the reference: 367 // Excerpt from the reference:
368 // Block expressions accept outer and inner attributes, but only when they are the outer 368 // Block expressions accept outer and inner attributes, but only when they are the outer
369 // expression of an expression statement or the final expression of another block expression. 369 // expression of an expression statement or the final expression of another block expression.
370 ast::BlockExpr(it) => return None, 370 ast::BlockExpr(_it) => return None,
371 _ => return None, 371 _ => return None,
372 } 372 }
373 }; 373 };
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 6c01f1ed0..cca5a086b 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -133,7 +133,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
133 fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; 133 fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
134} 134}
135 135
136fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<DefMap> { 136fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
137 let _p = profile::span("crate_def_map:wait"); 137 let _p = profile::span("crate_def_map:wait");
138 db.crate_def_map_query(krate) 138 db.crate_def_map_query(krate)
139} 139}
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index b3af82444..06714409f 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -130,7 +130,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
130 ) -> chalk_ir::ProgramClauses<chalk::Interner>; 130 ) -> chalk_ir::ProgramClauses<chalk::Interner>;
131} 131}
132 132
133fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 133fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
134 let _p = profile::span("infer:wait").detail(|| match def { 134 let _p = profile::span("infer:wait").detail(|| match def {
135 DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), 135 DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(),
136 DefWithBodyId::StaticId(it) => { 136 DefWithBodyId::StaticId(it) => {
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 66a88e2b6..2751cd304 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -2,9 +2,7 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId};
6 expr::Statement, path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId,
7};
8use hir_expand::{diagnostics::DiagnosticSink, name}; 6use hir_expand::{diagnostics::DiagnosticSink, name};
9use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
10use syntax::{ast, AstPtr}; 8use syntax::{ast, AstPtr};
@@ -17,7 +15,7 @@ use crate::{
17 MissingPatFields, RemoveThisSemicolon, 15 MissingPatFields, RemoveThisSemicolon,
18 }, 16 },
19 utils::variant_data, 17 utils::variant_data,
20 InferenceResult, Ty, 18 AdtId, InferenceResult, Ty,
21}; 19};
22 20
23pub(crate) use hir_def::{ 21pub(crate) use hir_def::{
@@ -382,10 +380,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
382 }; 380 };
383 381
384 let (params, required) = match mismatch.expected { 382 let (params, required) = match mismatch.expected {
385 Ty::Adt(AdtId::EnumId(enum_id), ref parameters) if enum_id == core_result_enum => { 383 Ty::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters)
384 if enum_id == core_result_enum =>
385 {
386 (parameters, "Ok".to_string()) 386 (parameters, "Ok".to_string())
387 } 387 }
388 Ty::Adt(AdtId::EnumId(enum_id), ref parameters) if enum_id == core_option_enum => { 388 Ty::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters)
389 if enum_id == core_option_enum =>
390 {
389 (parameters, "Some".to_string()) 391 (parameters, "Some".to_string())
390 } 392 }
391 _ => return, 393 _ => return,
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 86fee0050..04d39c571 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -222,12 +222,12 @@ use hir_def::{
222 adt::VariantData, 222 adt::VariantData,
223 body::Body, 223 body::Body,
224 expr::{Expr, Literal, Pat, PatId}, 224 expr::{Expr, Literal, Pat, PatId},
225 AdtId, EnumVariantId, StructId, VariantId, 225 EnumVariantId, StructId, VariantId,
226}; 226};
227use la_arena::Idx; 227use la_arena::Idx;
228use smallvec::{smallvec, SmallVec}; 228use smallvec::{smallvec, SmallVec};
229 229
230use crate::{db::HirDatabase, InferenceResult, Ty}; 230use crate::{db::HirDatabase, AdtId, InferenceResult, Ty};
231 231
232#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
233/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
@@ -627,7 +627,7 @@ pub(super) fn is_useful(
627 // - `!` type 627 // - `!` type
628 // In those cases, no match arm is useful. 628 // In those cases, no match arm is useful.
629 match cx.infer[cx.match_expr].strip_references() { 629 match cx.infer[cx.match_expr].strip_references() {
630 Ty::Adt(AdtId::EnumId(enum_id), ..) => { 630 Ty::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
631 if cx.db.enum_data(*enum_id).variants.is_empty() { 631 if cx.db.enum_data(*enum_id).variants.is_empty() {
632 return Ok(Usefulness::NotUseful); 632 return Ok(Usefulness::NotUseful);
633 } 633 }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index d4a8b48e6..a0882a2a1 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -2,19 +2,20 @@
2 2
3use std::{borrow::Cow, fmt}; 3use std::{borrow::Cow, fmt};
4 4
5use crate::{
6 db::HirDatabase, primitive, utils::generics, AliasTy, CallableDefId, CallableSig,
7 GenericPredicate, Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs,
8 TraitRef, Ty,
9};
10use arrayvec::ArrayVec; 5use arrayvec::ArrayVec;
11use chalk_ir::Mutability; 6use chalk_ir::Mutability;
12use hir_def::{ 7use hir_def::{
13 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, 8 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
14 AssocContainerId, HasModule, Lookup, ModuleId, TraitId, 9 AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
15}; 10};
16use hir_expand::name::Name; 11use hir_expand::name::Name;
17 12
13use crate::{
14 db::HirDatabase, primitive, utils::generics, AdtId, AliasTy, CallableDefId, CallableSig,
15 GenericPredicate, Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs,
16 TraitRef, Ty,
17};
18
18pub struct HirFormatter<'a> { 19pub struct HirFormatter<'a> {
19 pub db: &'a dyn HirDatabase, 20 pub db: &'a dyn HirDatabase,
20 fmt: &'a mut dyn fmt::Write, 21 fmt: &'a mut dyn fmt::Write,
@@ -400,13 +401,13 @@ impl HirDisplay for Ty {
400 write!(f, " -> {}", ret_display)?; 401 write!(f, " -> {}", ret_display)?;
401 } 402 }
402 } 403 }
403 Ty::Adt(def_id, parameters) => { 404 Ty::Adt(AdtId(def_id), parameters) => {
404 match f.display_target { 405 match f.display_target {
405 DisplayTarget::Diagnostics | DisplayTarget::Test => { 406 DisplayTarget::Diagnostics | DisplayTarget::Test => {
406 let name = match *def_id { 407 let name = match *def_id {
407 AdtId::StructId(it) => f.db.struct_data(it).name.clone(), 408 hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
408 AdtId::UnionId(it) => f.db.union_data(it).name.clone(), 409 hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
409 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), 410 hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
410 }; 411 };
411 write!(f, "{}", name)?; 412 write!(f, "{}", name)?;
412 } 413 }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index cf1f1038a..ec2c13154 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -8,7 +8,7 @@ use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
11 AdtId, AssocContainerId, FieldId, Lookup, 11 AssocContainerId, FieldId, Lookup,
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::{name, Name};
14use syntax::ast::RangeOp; 14use syntax::ast::RangeOp;
@@ -21,8 +21,8 @@ use crate::{
21 primitive::{self, UintTy}, 21 primitive::{self, UintTy},
22 traits::{FnTrait, InEnvironment}, 22 traits::{FnTrait, InEnvironment},
23 utils::{generics, variant_data, Generics}, 23 utils::{generics, variant_data, Generics},
24 Binders, CallableDefId, FnPointer, FnSig, Obligation, OpaqueTyId, Rawness, Scalar, Substs, 24 AdtId, Binders, CallableDefId, FnPointer, FnSig, Obligation, OpaqueTyId, Rawness, Scalar,
25 TraitRef, Ty, 25 Substs, TraitRef, Ty,
26}; 26};
27 27
28use super::{ 28use super::{
@@ -429,14 +429,14 @@ impl<'a> InferenceContext<'a> {
429 Ty::Tuple(_, substs) => { 429 Ty::Tuple(_, substs) => {
430 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned()) 430 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
431 } 431 }
432 Ty::Adt(AdtId::StructId(s), parameters) => { 432 Ty::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
433 self.db.struct_data(s).variant_data.field(name).map(|local_id| { 433 self.db.struct_data(s).variant_data.field(name).map(|local_id| {
434 let field = FieldId { parent: s.into(), local_id }; 434 let field = FieldId { parent: s.into(), local_id };
435 self.write_field_resolution(tgt_expr, field); 435 self.write_field_resolution(tgt_expr, field);
436 self.db.field_types(s.into())[field.local_id].clone().subst(&parameters) 436 self.db.field_types(s.into())[field.local_id].clone().subst(&parameters)
437 }) 437 })
438 } 438 }
439 Ty::Adt(AdtId::UnionId(u), parameters) => { 439 Ty::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
440 self.db.union_data(u).variant_data.field(name).map(|local_id| { 440 self.db.union_data(u).variant_data.field(name).map(|local_id| {
441 let field = FieldId { parent: u.into(), local_id }; 441 let field = FieldId { parent: u.into(), local_id };
442 self.write_field_resolution(tgt_expr, field); 442 self.write_field_resolution(tgt_expr, field);
@@ -498,7 +498,7 @@ impl<'a> InferenceContext<'a> {
498 _ => (), 498 _ => (),
499 } 499 }
500 sb = sb.fill(repeat_with(|| self.table.new_type_var())); 500 sb = sb.fill(repeat_with(|| self.table.new_type_var()));
501 Ty::Adt(box_, sb.build()) 501 Ty::adt_ty(box_, sb.build())
502 } else { 502 } else {
503 Ty::Unknown 503 Ty::Unknown
504 } 504 }
@@ -586,31 +586,31 @@ impl<'a> InferenceContext<'a> {
586 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); 586 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
587 match (range_type, lhs_ty, rhs_ty) { 587 match (range_type, lhs_ty, rhs_ty) {
588 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { 588 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
589 Some(adt) => Ty::Adt(adt, Substs::empty()), 589 Some(adt) => Ty::adt_ty(adt, Substs::empty()),
590 None => Ty::Unknown, 590 None => Ty::Unknown,
591 }, 591 },
592 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { 592 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
593 Some(adt) => Ty::Adt(adt, Substs::single(ty)), 593 Some(adt) => Ty::adt_ty(adt, Substs::single(ty)),
594 None => Ty::Unknown, 594 None => Ty::Unknown,
595 }, 595 },
596 (RangeOp::Inclusive, None, Some(ty)) => { 596 (RangeOp::Inclusive, None, Some(ty)) => {
597 match self.resolve_range_to_inclusive() { 597 match self.resolve_range_to_inclusive() {
598 Some(adt) => Ty::Adt(adt, Substs::single(ty)), 598 Some(adt) => Ty::adt_ty(adt, Substs::single(ty)),
599 None => Ty::Unknown, 599 None => Ty::Unknown,
600 } 600 }
601 } 601 }
602 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { 602 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
603 Some(adt) => Ty::Adt(adt, Substs::single(ty)), 603 Some(adt) => Ty::adt_ty(adt, Substs::single(ty)),
604 None => Ty::Unknown, 604 None => Ty::Unknown,
605 }, 605 },
606 (RangeOp::Inclusive, Some(_), Some(ty)) => { 606 (RangeOp::Inclusive, Some(_), Some(ty)) => {
607 match self.resolve_range_inclusive() { 607 match self.resolve_range_inclusive() {
608 Some(adt) => Ty::Adt(adt, Substs::single(ty)), 608 Some(adt) => Ty::adt_ty(adt, Substs::single(ty)),
609 None => Ty::Unknown, 609 None => Ty::Unknown,
610 } 610 }
611 } 611 }
612 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { 612 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
613 Some(adt) => Ty::Adt(adt, Substs::single(ty)), 613 Some(adt) => Ty::adt_ty(adt, Substs::single(ty)),
614 None => Ty::Unknown, 614 None => Ty::Unknown,
615 }, 615 },
616 (RangeOp::Inclusive, _, None) => Ty::Unknown, 616 (RangeOp::Inclusive, _, None) => Ty::Unknown,
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index eb099311c..987793e2e 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -237,7 +237,7 @@ impl<'a> InferenceContext<'a> {
237 }; 237 };
238 238
239 let inner_ty = self.infer_pat(*inner, inner_expected, default_bm); 239 let inner_ty = self.infer_pat(*inner, inner_expected, default_bm);
240 Ty::Adt(box_adt, Substs::single(inner_ty)) 240 Ty::adt_ty(box_adt, Substs::single(inner_ty))
241 } 241 }
242 None => Ty::Unknown, 242 None => Ty::Unknown,
243 }, 243 },
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index c2a20c480..e77f24e4e 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -27,9 +27,9 @@ use std::{iter, mem, ops::Deref, sync::Arc};
27 27
28use base_db::salsa; 28use base_db::salsa;
29use hir_def::{ 29use hir_def::{
30 builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AdtId, AssocContainerId, 30 builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, DefWithBodyId,
31 DefWithBodyId, FunctionId, GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, 31 FunctionId, GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId,
32 TypeAliasId, TypeParamId, 32 TypeParamId,
33}; 33};
34use itertools::Itertools; 34use itertools::Itertools;
35 35
@@ -47,7 +47,9 @@ pub use lower::{
47}; 47};
48pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 48pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
49 49
50pub use chalk_ir::{BoundVar, DebruijnIndex, Mutability, Scalar, TyVariableKind}; 50pub use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Mutability, Scalar, TyVariableKind};
51
52pub(crate) use crate::traits::chalk::Interner;
51 53
52#[derive(Clone, PartialEq, Eq, Debug, Hash)] 54#[derive(Clone, PartialEq, Eq, Debug, Hash)]
53pub enum Lifetime { 55pub enum Lifetime {
@@ -131,7 +133,7 @@ pub enum AliasTy {
131#[derive(Clone, PartialEq, Eq, Debug, Hash)] 133#[derive(Clone, PartialEq, Eq, Debug, Hash)]
132pub enum Ty { 134pub enum Ty {
133 /// Structures, enumerations and unions. 135 /// Structures, enumerations and unions.
134 Adt(AdtId, Substs), 136 Adt(AdtId<Interner>, Substs),
135 137
136 /// Represents an associated item like `Iterator::Item`. This is used 138 /// Represents an associated item like `Iterator::Item`. This is used
137 /// when we have tried to normalize a projection like `T::Item` but 139 /// when we have tried to normalize a projection like `T::Item` but
@@ -602,6 +604,10 @@ impl Ty {
602 Ty::Tuple(0, Substs::empty()) 604 Ty::Tuple(0, Substs::empty())
603 } 605 }
604 606
607 pub fn adt_ty(adt: hir_def::AdtId, substs: Substs) -> Ty {
608 Ty::Adt(AdtId(adt), substs)
609 }
610
605 pub fn fn_ptr(sig: CallableSig) -> Self { 611 pub fn fn_ptr(sig: CallableSig) -> Self {
606 Ty::Function(FnPointer { 612 Ty::Function(FnPointer {
607 num_args: sig.params().len(), 613 num_args: sig.params().len(),
@@ -650,9 +656,9 @@ impl Ty {
650 t 656 t
651 } 657 }
652 658
653 pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { 659 pub fn as_adt(&self) -> Option<(hir_def::AdtId, &Substs)> {
654 match self { 660 match self {
655 Ty::Adt(adt_def, parameters) => Some((*adt_def, parameters)), 661 Ty::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
656 _ => None, 662 _ => None,
657 } 663 }
658 } 664 }
@@ -666,7 +672,7 @@ impl Ty {
666 672
667 pub fn as_generic_def(&self) -> Option<GenericDefId> { 673 pub fn as_generic_def(&self) -> Option<GenericDefId> {
668 match *self { 674 match *self {
669 Ty::Adt(adt, ..) => Some(adt.into()), 675 Ty::Adt(AdtId(adt), ..) => Some(adt.into()),
670 Ty::FnDef(callable, ..) => Some(callable.into()), 676 Ty::FnDef(callable, ..) => Some(callable.into()),
671 Ty::AssociatedType(type_alias, ..) => Some(type_alias.into()), 677 Ty::AssociatedType(type_alias, ..) => Some(type_alias.into()),
672 Ty::ForeignType(type_alias, ..) => Some(type_alias.into()), 678 Ty::ForeignType(type_alias, ..) => Some(type_alias.into()),
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 1b5843d48..5fe5b8ad1 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -1100,7 +1100,7 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
1100fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { 1100fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
1101 let generics = generics(db.upcast(), adt.into()); 1101 let generics = generics(db.upcast(), adt.into());
1102 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); 1102 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
1103 Binders::new(substs.len(), Ty::Adt(adt, substs)) 1103 Binders::new(substs.len(), Ty::adt_ty(adt, substs))
1104} 1104}
1105 1105
1106fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { 1106fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index f301a8477..dfcf346fb 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,8 +8,8 @@ use arrayvec::ArrayVec;
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::Mutability; 9use chalk_ir::Mutability;
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, AdtId, AssocContainerId, AssocItemId, FunctionId, GenericDefId, 11 lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule,
12 HasModule, ImplId, Lookup, ModuleId, TraitId, TypeAliasId, 12 ImplId, Lookup, ModuleId, TraitId, TypeAliasId,
13}; 13};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::{FxHashMap, FxHashSet};
@@ -19,8 +19,8 @@ use crate::{
19 db::HirDatabase, 19 db::HirDatabase,
20 primitive::{self, FloatTy, IntTy, UintTy}, 20 primitive::{self, FloatTy, IntTy, UintTy},
21 utils::all_super_traits, 21 utils::all_super_traits,
22 Canonical, DebruijnIndex, FnPointer, FnSig, InEnvironment, Scalar, Substs, TraitEnvironment, 22 AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, InEnvironment, Scalar, Substs,
23 TraitRef, Ty, TypeWalk, 23 TraitEnvironment, TraitRef, Ty, TypeWalk,
24}; 24};
25 25
26/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -32,7 +32,7 @@ pub enum TyFingerprint {
32 Never, 32 Never,
33 RawPtr(Mutability), 33 RawPtr(Mutability),
34 Scalar(Scalar), 34 Scalar(Scalar),
35 Adt(AdtId), 35 Adt(hir_def::AdtId),
36 Dyn(TraitId), 36 Dyn(TraitId),
37 Tuple(usize), 37 Tuple(usize),
38 ForeignType(TypeAliasId), 38 ForeignType(TypeAliasId),
@@ -50,7 +50,7 @@ impl TyFingerprint {
50 &Ty::Slice(..) => TyFingerprint::Slice, 50 &Ty::Slice(..) => TyFingerprint::Slice,
51 &Ty::Array(..) => TyFingerprint::Array, 51 &Ty::Array(..) => TyFingerprint::Array,
52 &Ty::Scalar(scalar) => TyFingerprint::Scalar(scalar), 52 &Ty::Scalar(scalar) => TyFingerprint::Scalar(scalar),
53 &Ty::Adt(adt, _) => TyFingerprint::Adt(adt), 53 &Ty::Adt(AdtId(adt), _) => TyFingerprint::Adt(adt),
54 &Ty::Tuple(cardinality, _) => TyFingerprint::Tuple(cardinality), 54 &Ty::Tuple(cardinality, _) => TyFingerprint::Tuple(cardinality),
55 &Ty::Raw(mutability, ..) => TyFingerprint::RawPtr(mutability), 55 &Ty::Raw(mutability, ..) => TyFingerprint::RawPtr(mutability),
56 &Ty::ForeignType(alias_id, ..) => TyFingerprint::ForeignType(alias_id), 56 &Ty::ForeignType(alias_id, ..) => TyFingerprint::ForeignType(alias_id),
@@ -231,7 +231,7 @@ impl Ty {
231 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect()); 231 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect());
232 232
233 let lang_item_targets = match self { 233 let lang_item_targets = match self {
234 Ty::Adt(def_id, _) => { 234 Ty::Adt(AdtId(def_id), _) => {
235 return mod_to_crate_ids(def_id.module(db.upcast())); 235 return mod_to_crate_ids(def_id.module(db.upcast()));
236 } 236 }
237 Ty::ForeignType(type_alias_id) => { 237 Ty::ForeignType(type_alias_id) => {
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index e513fa8f4..4378a9723 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -315,9 +315,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
315 let id = from_chalk(self.db, trait_id); 315 let id = from_chalk(self.db, trait_id);
316 self.db.trait_data(id).name.to_string() 316 self.db.trait_data(id).name.to_string()
317 } 317 }
318 fn adt_name(&self, adt_id: chalk_ir::AdtId<Interner>) -> String { 318 fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
319 let id = from_chalk(self.db, adt_id); 319 match adt_id {
320 match id {
321 hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(), 320 hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(),
322 hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(), 321 hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(),
323 hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(), 322 hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(),
@@ -488,8 +487,8 @@ pub(crate) fn struct_datum_query(
488 struct_id: AdtId, 487 struct_id: AdtId,
489) -> Arc<StructDatum> { 488) -> Arc<StructDatum> {
490 debug!("struct_datum {:?}", struct_id); 489 debug!("struct_datum {:?}", struct_id);
491 let adt_id = from_chalk(db, struct_id); 490 let type_ctor = Ty::Adt(struct_id, Substs::empty());
492 let type_ctor = Ty::Adt(adt_id, Substs::empty()); 491 let chalk_ir::AdtId(adt_id) = struct_id;
493 debug!("struct {:?} = {:?}", struct_id, type_ctor); 492 debug!("struct {:?} = {:?}", struct_id, type_ctor);
494 let num_params = generics(db.upcast(), adt_id.into()).len(); 493 let num_params = generics(db.upcast(), adt_id.into()).len();
495 let upstream = adt_id.module(db.upcast()).krate() != krate; 494 let upstream = adt_id.module(db.upcast()).krate() != krate;
@@ -684,10 +683,9 @@ pub(crate) fn fn_def_variance_query(
684pub(crate) fn adt_variance_query( 683pub(crate) fn adt_variance_query(
685 db: &dyn HirDatabase, 684 db: &dyn HirDatabase,
686 _krate: CrateId, 685 _krate: CrateId,
687 adt_id: AdtId, 686 chalk_ir::AdtId(adt_id): AdtId,
688) -> Variances { 687) -> Variances {
689 let adt: crate::AdtId = from_chalk(db, adt_id); 688 let generic_params = generics(db.upcast(), adt_id.into());
690 let generic_params = generics(db.upcast(), adt.into());
691 Variances::from_iter( 689 Variances::from_iter(
692 &Interner, 690 &Interner,
693 std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()), 691 std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index db1760e6c..3a08b67e9 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -86,7 +86,7 @@ impl ToChalk for Ty {
86 86
87 Ty::Adt(adt_id, substs) => { 87 Ty::Adt(adt_id, substs) => {
88 let substitution = substs.to_chalk(db); 88 let substitution = substs.to_chalk(db);
89 chalk_ir::TyKind::Adt(chalk_ir::AdtId(adt_id), substitution).intern(&Interner) 89 chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
90 } 90 }
91 Ty::Alias(AliasTy::Projection(proj_ty)) => { 91 Ty::Alias(AliasTy::Projection(proj_ty)) => {
92 let associated_ty_id = TypeAliasAsAssocType(proj_ty.associated_ty).to_chalk(db); 92 let associated_ty_id = TypeAliasAsAssocType(proj_ty.associated_ty).to_chalk(db);
@@ -183,7 +183,7 @@ impl ToChalk for Ty {
183 Ty::Dyn(predicates) 183 Ty::Dyn(predicates)
184 } 184 }
185 185
186 chalk_ir::TyKind::Adt(struct_id, subst) => Ty::Adt(struct_id.0, from_chalk(db, subst)), 186 chalk_ir::TyKind::Adt(adt_id, subst) => Ty::Adt(adt_id, from_chalk(db, subst)),
187 chalk_ir::TyKind::AssociatedType(type_id, subst) => Ty::AssociatedType( 187 chalk_ir::TyKind::AssociatedType(type_id, subst) => Ty::AssociatedType(
188 from_chalk::<TypeAliasAsAssocType, _>(db, type_id).0, 188 from_chalk::<TypeAliasAsAssocType, _>(db, type_id).0,
189 from_chalk(db, subst), 189 from_chalk(db, subst),
@@ -325,18 +325,6 @@ impl ToChalk for hir_def::ImplId {
325 } 325 }
326} 326}
327 327
328impl ToChalk for hir_def::AdtId {
329 type Chalk = AdtId;
330
331 fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
332 chalk_ir::AdtId(self.into())
333 }
334
335 fn from_chalk(_db: &dyn HirDatabase, id: AdtId) -> Self {
336 id.0
337 }
338}
339
340impl ToChalk for CallableDefId { 328impl ToChalk for CallableDefId {
341 type Chalk = FnDefId; 329 type Chalk = FnDefId;
342 330
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 1e7baed20..65f60891e 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -189,7 +189,7 @@ pub(crate) fn doc_owner_to_def(
189) -> Option<Definition> { 189) -> Option<Definition> {
190 let res: hir::ModuleDef = match_ast! { 190 let res: hir::ModuleDef = match_ast! {
191 match item { 191 match item {
192 ast::SourceFile(it) => sema.scope(&item).module()?.into(), 192 ast::SourceFile(_it) => sema.scope(&item).module()?.into(),
193 ast::Fn(it) => sema.to_def(&it)?.into(), 193 ast::Fn(it) => sema.to_def(&it)?.into(),
194 ast::Struct(it) => sema.to_def(&it)?.into(), 194 ast::Struct(it) => sema.to_def(&it)?.into(),
195 ast::Enum(it) => sema.to_def(&it)?.into(), 195 ast::Enum(it) => sema.to_def(&it)?.into(),
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 9f34cc725..8779d8bd1 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -112,7 +112,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
112 112
113 let fn_def = format_function(ctx, module, &fun, old_indent, new_indent); 113 let fn_def = format_function(ctx, module, &fun, old_indent, new_indent);
114 let insert_offset = insert_after.text_range().end(); 114 let insert_offset = insert_after.text_range().end();
115 builder.insert(insert_offset, fn_def); 115 match ctx.config.snippet_cap {
116 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
117 None => builder.insert(insert_offset, fn_def),
118 }
116 }, 119 },
117 ) 120 )
118} 121}
@@ -1079,7 +1082,10 @@ fn format_function(
1079 let params = make_param_list(ctx, module, fun); 1082 let params = make_param_list(ctx, module, fun);
1080 let ret_ty = make_ret_ty(ctx, module, fun); 1083 let ret_ty = make_ret_ty(ctx, module, fun);
1081 let body = make_body(ctx, old_indent, new_indent, fun); 1084 let body = make_body(ctx, old_indent, new_indent, fun);
1082 format_to!(fn_def, "\n\n{}fn $0{}{}", new_indent, fun.name, params); 1085 match ctx.config.snippet_cap {
1086 Some(_) => format_to!(fn_def, "\n\n{}fn $0{}{}", new_indent, fun.name, params),
1087 None => format_to!(fn_def, "\n\n{}fn {}{}", new_indent, fun.name, params),
1088 }
1083 if let Some(ret_ty) = ret_ty { 1089 if let Some(ret_ty) = ret_ty {
1084 format_to!(fn_def, " {}", ret_ty); 1090 format_to!(fn_def, " {}", ret_ty);
1085 } 1091 }
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 959824981..3870b7e75 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -1,6 +1,7 @@
1use hir::HirDisplay; 1use hir::HirDisplay;
2use ide_db::{base_db::FileId, helpers::SnippetCap}; 2use ide_db::{base_db::FileId, helpers::SnippetCap};
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4use stdx::to_lower_snake_case;
4use syntax::{ 5use syntax::{
5 ast::{ 6 ast::{
6 self, 7 self,
@@ -257,14 +258,15 @@ fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
257fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> { 258fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
258 match fn_arg { 259 match fn_arg {
259 ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?), 260 ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
260 _ => Some( 261 _ => {
261 fn_arg 262 let s = fn_arg
262 .syntax() 263 .syntax()
263 .descendants() 264 .descendants()
264 .filter(|d| ast::NameRef::can_cast(d.kind())) 265 .filter(|d| ast::NameRef::can_cast(d.kind()))
265 .last()? 266 .last()?
266 .to_string(), 267 .to_string();
267 ), 268 Some(to_lower_snake_case(&s))
269 }
268 } 270 }
269} 271}
270 272
@@ -448,6 +450,52 @@ mod baz {
448 } 450 }
449 451
450 #[test] 452 #[test]
453 fn add_function_with_upper_camel_case_arg() {
454 check_assist(
455 generate_function,
456 r"
457struct BazBaz;
458fn foo() {
459 bar$0(BazBaz);
460}
461",
462 r"
463struct BazBaz;
464fn foo() {
465 bar(BazBaz);
466}
467
468fn bar(baz_baz: BazBaz) ${0:-> ()} {
469 todo!()
470}
471",
472 );
473 }
474
475 #[test]
476 fn add_function_with_upper_camel_case_arg_as_cast() {
477 check_assist(
478 generate_function,
479 r"
480struct BazBaz;
481fn foo() {
482 bar$0(&BazBaz as *const BazBaz);
483}
484",
485 r"
486struct BazBaz;
487fn foo() {
488 bar(&BazBaz as *const BazBaz);
489}
490
491fn bar(baz_baz: *const BazBaz) ${0:-> ()} {
492 todo!()
493}
494",
495 );
496 }
497
498 #[test]
451 fn add_function_with_function_call_arg() { 499 fn add_function_with_function_call_arg() {
452 check_assist( 500 check_assist(
453 generate_function, 501 generate_function,
diff --git a/crates/ide_assists/src/handlers/pull_assignment_up.rs b/crates/ide_assists/src/handlers/pull_assignment_up.rs
index 13e1cb754..377ed4f2f 100644
--- a/crates/ide_assists/src/handlers/pull_assignment_up.rs
+++ b/crates/ide_assists/src/handlers/pull_assignment_up.rs
@@ -156,6 +156,17 @@ fn is_equivalent(
156 false 156 false
157 } 157 }
158 } 158 }
159 (ast::Expr::PrefixExpr(prefix0), ast::Expr::PrefixExpr(prefix1))
160 if prefix0.op_kind() == Some(ast::PrefixOp::Deref)
161 && prefix1.op_kind() == Some(ast::PrefixOp::Deref) =>
162 {
163 mark::hit!(test_pull_assignment_up_deref);
164 if let (Some(prefix0), Some(prefix1)) = (prefix0.expr(), prefix1.expr()) {
165 is_equivalent(sema, &prefix0, &prefix1)
166 } else {
167 false
168 }
169 }
159 _ => false, 170 _ => false,
160 } 171 }
161} 172}
@@ -397,4 +408,36 @@ fn foo() {
397}"#, 408}"#,
398 ) 409 )
399 } 410 }
411
412 #[test]
413 fn test_pull_assignment_up_deref() {
414 mark::check!(test_pull_assignment_up_deref);
415 check_assist(
416 pull_assignment_up,
417 r#"
418fn foo() {
419 let mut a = 1;
420 let b = &mut a;
421
422 if true {
423 $0*b = 2;
424 } else {
425 *b = 3;
426 }
427}
428"#,
429 r#"
430fn foo() {
431 let mut a = 1;
432 let b = &mut a;
433
434 *b = if true {
435 2
436 } else {
437 3
438 };
439}
440"#,
441 )
442 }
400} 443}
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 3a5bc4381..cb05e85fc 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -39,7 +39,8 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
39} 39}
40 40
41fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) { 41fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
42 for attr_completion in ATTRIBUTES { 42 let is_inner = attribute.kind() == ast::AttrKind::Inner;
43 for attr_completion in ATTRIBUTES.iter().filter(|compl| is_inner || !compl.prefer_inner) {
43 let mut item = CompletionItem::new( 44 let mut item = CompletionItem::new(
44 CompletionKind::Attribute, 45 CompletionKind::Attribute,
45 ctx.source_range(), 46 ctx.source_range(),
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 38e33a93e..1bcc8727f 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -25,9 +25,12 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
25 return; 25 return;
26 } 26 }
27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { 27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
28 let text = param.syntax().text().to_string(); 28 if let Some(pat) = param.pat() {
29 params.entry(text).or_insert(param); 29 let text = param.syntax().text().to_string();
30 }) 30 let lookup = pat.syntax().text().to_string();
31 params.entry(text).or_insert(lookup);
32 }
33 });
31 }; 34 };
32 35
33 for node in ctx.token.parent().ancestors() { 36 for node in ctx.token.parent().ancestors() {
@@ -50,18 +53,12 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
50 }; 53 };
51 } 54 }
52 55
53 params 56 params.into_iter().for_each(|(label, lookup)| {
54 .into_iter() 57 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
55 .filter_map(|(label, param)| { 58 .kind(CompletionItemKind::Binding)
56 let lookup = param.pat()?.syntax().text().to_string(); 59 .lookup_by(lookup)
57 Some((label, lookup)) 60 .add_to(acc)
58 }) 61 });
59 .for_each(|(label, lookup)| {
60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(CompletionItemKind::Binding)
62 .lookup_by(lookup)
63 .add_to(acc)
64 });
65} 62}
66 63
67#[cfg(test)] 64#[cfg(test)]
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index eb81f9765..03c6dd454 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -1,5 +1,7 @@
1//! Completes keywords. 1//! Completes keywords.
2 2
3use std::iter;
4
3use syntax::SyntaxKind; 5use syntax::SyntaxKind;
4use test_utils::mark; 6use test_utils::mark;
5 7
@@ -19,10 +21,14 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
19 CompletionItem::new(CompletionKind::Keyword, source_range, "self") 21 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
20 .kind(CompletionItemKind::Keyword) 22 .kind(CompletionItemKind::Keyword)
21 .add_to(acc); 23 .add_to(acc);
22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::") 24 if iter::successors(ctx.path_qual.clone(), |p| p.qualifier())
23 .kind(CompletionItemKind::Keyword) 25 .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
24 .insert_text("super::") 26 {
25 .add_to(acc); 27 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
28 .kind(CompletionItemKind::Keyword)
29 .insert_text("super::")
30 .add_to(acc);
31 }
26 } 32 }
27 33
28 // Suggest .await syntax for types that implement Future trait 34 // Suggest .await syntax for types that implement Future trait
@@ -85,6 +91,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
85 if ctx.is_expr { 91 if ctx.is_expr {
86 add_keyword(ctx, acc, "match", "match $0 {}"); 92 add_keyword(ctx, acc, "match", "match $0 {}");
87 add_keyword(ctx, acc, "while", "while $0 {}"); 93 add_keyword(ctx, acc, "while", "while $0 {}");
94 add_keyword(ctx, acc, "while let", "while let $1 = $0 {}");
88 add_keyword(ctx, acc, "loop", "loop {$0}"); 95 add_keyword(ctx, acc, "loop", "loop {$0}");
89 add_keyword(ctx, acc, "if", "if $0 {}"); 96 add_keyword(ctx, acc, "if", "if $0 {}");
90 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}"); 97 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
@@ -204,9 +211,17 @@ mod tests {
204 "#]], 211 "#]],
205 ); 212 );
206 213
214 // FIXME: `self` shouldn't be shown here and the check below
207 check( 215 check(
208 r"use a::$0", 216 r"use a::$0",
209 expect![[r#" 217 expect![[r#"
218 kw self
219 "#]],
220 );
221
222 check(
223 r"use super::$0",
224 expect![[r#"
210 kw self 225 kw self
211 kw super:: 226 kw super::
212 "#]], 227 "#]],
@@ -215,9 +230,8 @@ mod tests {
215 check( 230 check(
216 r"use a::{b, $0}", 231 r"use a::{b, $0}",
217 expect![[r#" 232 expect![[r#"
218 kw self 233 kw self
219 kw super:: 234 "#]],
220 "#]],
221 ); 235 );
222 } 236 }
223 237
@@ -256,6 +270,7 @@ mod tests {
256 kw trait 270 kw trait
257 kw match 271 kw match
258 kw while 272 kw while
273 kw while let
259 kw loop 274 kw loop
260 kw if 275 kw if
261 kw if let 276 kw if let
@@ -283,6 +298,7 @@ mod tests {
283 kw trait 298 kw trait
284 kw match 299 kw match
285 kw while 300 kw while
301 kw while let
286 kw loop 302 kw loop
287 kw if 303 kw if
288 kw if let 304 kw if let
@@ -310,6 +326,7 @@ mod tests {
310 kw trait 326 kw trait
311 kw match 327 kw match
312 kw while 328 kw while
329 kw while let
313 kw loop 330 kw loop
314 kw if 331 kw if
315 kw if let 332 kw if let
@@ -344,6 +361,7 @@ fn quux() -> i32 {
344 expect![[r#" 361 expect![[r#"
345 kw match 362 kw match
346 kw while 363 kw while
364 kw while let
347 kw loop 365 kw loop
348 kw if 366 kw if
349 kw if let 367 kw if let
@@ -393,6 +411,7 @@ fn quux() -> i32 {
393 kw trait 411 kw trait
394 kw match 412 kw match
395 kw while 413 kw while
414 kw while let
396 kw loop 415 kw loop
397 kw if 416 kw if
398 kw if let 417 kw if let
@@ -552,6 +571,7 @@ pub mod future {
552 expect![[r#" 571 expect![[r#"
553 kw match 572 kw match
554 kw while 573 kw while
574 kw while let
555 kw loop 575 kw loop
556 kw if 576 kw if
557 kw if let 577 kw if let
@@ -611,6 +631,7 @@ fn foo() {
611 expect![[r#" 631 expect![[r#"
612 kw match 632 kw match
613 kw while 633 kw while
634 kw while let
614 kw loop 635 kw loop
615 kw if 636 kw if
616 kw if let 637 kw if let
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 2afa6979e..72fb757b1 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -81,9 +81,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
81 return None; 81 return None;
82 } 82 }
83 match item { 83 match item {
84 hir::AssocItem::Function(func) => { 84 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
85 acc.add_function(ctx, func, None);
86 }
87 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 85 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
88 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 86 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
89 } 87 }
@@ -110,9 +108,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
110 continue; 108 continue;
111 } 109 }
112 match item { 110 match item {
113 hir::AssocItem::Function(func) => { 111 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
114 acc.add_function(ctx, func, None);
115 }
116 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 112 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
117 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 113 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
118 } 114 }
@@ -143,9 +139,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
143 // them. 139 // them.
144 if seen.insert(item) { 140 if seen.insert(item) {
145 match item { 141 match item {
146 hir::AssocItem::Function(func) => { 142 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
147 acc.add_function(ctx, func, None);
148 }
149 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 143 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
150 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 144 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
151 } 145 }
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 5c641ebf2..08acd4ac2 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -954,7 +954,8 @@ fn test_meta() {
954 .assert_expand_items( 954 .assert_expand_items(
955 r#"foo! { cfg(target_os = "windows") }"#, 955 r#"foo! { cfg(target_os = "windows") }"#,
956 r#"# [cfg (target_os = "windows")] fn bar () {}"#, 956 r#"# [cfg (target_os = "windows")] fn bar () {}"#,
957 ); 957 )
958 .assert_expand_items(r#"foo! { hello::world }"#, r#"# [hello :: world] fn bar () {}"#);
958} 959}
959 960
960#[test] 961#[test]
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 6913e9ec2..6159d064c 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -95,7 +95,7 @@ pub(crate) mod fragments {
95 // https://doc.rust-lang.org/reference/paths.html#simple-paths 95 // https://doc.rust-lang.org/reference/paths.html#simple-paths
96 // The start of an meta must be a simple path 96 // The start of an meta must be a simple path
97 match p.current() { 97 match p.current() {
98 IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump_any(), 98 IDENT | T![super] | T![self] | T![crate] => p.bump_any(),
99 T![=] => { 99 T![=] => {
100 p.bump_any(); 100 p.bump_any();
101 match p.current() { 101 match p.current() {
@@ -105,6 +105,7 @@ pub(crate) mod fragments {
105 } 105 }
106 break; 106 break;
107 } 107 }
108 _ if p.at(T![::]) => p.bump(T![::]),
108 _ => break, 109 _ => break,
109 } 110 }
110 } 111 }
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index 952b4a97f..14c853c77 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -184,6 +184,7 @@ pub mod token_stream {
184 let (subtree, _token_map) = 184 let (subtree, _token_map) =
185 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; 185 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
186 186
187 let subtree = subtree_replace_token_ids_with_unspecified(subtree);
187 Ok(TokenStream { subtree }) 188 Ok(TokenStream { subtree })
188 } 189 }
189 } 190 }
@@ -226,6 +227,44 @@ pub mod token_stream {
226 } 227 }
227 } 228 }
228 } 229 }
230
231 fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
232 tt::Subtree {
233 delimiter: subtree
234 .delimiter
235 .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
236 token_trees: subtree
237 .token_trees
238 .into_iter()
239 .map(|t| token_tree_replace_token_ids_with_unspecified(t))
240 .collect(),
241 }
242 }
243
244 fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree {
245 match tt {
246 tt::TokenTree::Leaf(leaf) => {
247 tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf))
248 }
249 tt::TokenTree::Subtree(subtree) => {
250 tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree))
251 }
252 }
253 }
254
255 fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
256 match leaf {
257 tt::Leaf::Literal(lit) => {
258 tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
259 }
260 tt::Leaf::Punct(punct) => {
261 tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
262 }
263 tt::Leaf::Ident(ident) => {
264 tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
265 }
266 }
267 }
229} 268}
230 269
231impl TokenStreamBuilder { 270impl TokenStreamBuilder {
@@ -277,42 +316,6 @@ impl server::FreeFunctions for Rustc {
277 } 316 }
278} 317}
279 318
280fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
281 tt::Subtree {
282 delimiter: subtree.delimiter.map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
283 token_trees: subtree
284 .token_trees
285 .into_iter()
286 .map(|t| token_tree_replace_token_ids_with_unspecified(t))
287 .collect(),
288 }
289}
290
291fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree {
292 match tt {
293 tt::TokenTree::Leaf(leaf) => {
294 tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf))
295 }
296 tt::TokenTree::Subtree(subtree) => {
297 tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree))
298 }
299 }
300}
301
302fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
303 match leaf {
304 tt::Leaf::Literal(lit) => {
305 tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
306 }
307 tt::Leaf::Punct(punct) => {
308 tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
309 }
310 tt::Leaf::Ident(ident) => {
311 tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
312 }
313 }
314}
315
316impl server::TokenStream for Rustc { 319impl server::TokenStream for Rustc {
317 fn new(&mut self) -> Self::TokenStream { 320 fn new(&mut self) -> Self::TokenStream {
318 Self::TokenStream::new() 321 Self::TokenStream::new()
@@ -322,8 +325,9 @@ impl server::TokenStream for Rustc {
322 stream.is_empty() 325 stream.is_empty()
323 } 326 }
324 fn from_str(&mut self, src: &str) -> Self::TokenStream { 327 fn from_str(&mut self, src: &str) -> Self::TokenStream {
325 let (subtree, _) = mbe::parse_to_token_tree(src).expect("cannot parse string"); 328 use std::str::FromStr;
326 TokenStream::with_subtree(subtree_replace_token_ids_with_unspecified(subtree)) 329
330 Self::TokenStream::from_str(src).expect("cannot parse string")
327 } 331 }
328 fn to_string(&mut self, stream: &Self::TokenStream) -> String { 332 fn to_string(&mut self, stream: &Self::TokenStream) -> String {
329 stream.to_string() 333 stream.to_string()
diff --git a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
index ea34e688f..fa581f110 100644
--- a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
+++ b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
@@ -101,7 +101,7 @@ SUBTREE $
101 PUNCH : [alone] 4294967295 101 PUNCH : [alone] 4294967295
102 IDENT Serialize 4294967295 102 IDENT Serialize 4294967295
103 IDENT for 4294967295 103 IDENT for 4294967295
104 IDENT Foo 1 104 IDENT Foo 4294967295
105 SUBTREE {} 4294967295 105 SUBTREE {} 4294967295
106 IDENT fn 4294967295 106 IDENT fn 4294967295
107 IDENT serialize 4294967295 107 IDENT serialize 4294967295
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 556fc2eeb..367136702 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -46,8 +46,8 @@ config_data! {
46 cargo_allFeatures: bool = "false", 46 cargo_allFeatures: bool = "false",
47 /// List of features to activate. 47 /// List of features to activate.
48 cargo_features: Vec<String> = "[]", 48 cargo_features: Vec<String> = "[]",
49 /// Run `cargo check` on startup to get the correct value for package 49 /// Run build scripts (`build.rs`) for more precise code analysis.
50 /// OUT_DIRs. 50 cargo_runBuildScripts |
51 cargo_loadOutDirsFromCheck: bool = "false", 51 cargo_loadOutDirsFromCheck: bool = "false",
52 /// Do not activate the `default` feature. 52 /// Do not activate the `default` feature.
53 cargo_noDefaultFeatures: bool = "false", 53 cargo_noDefaultFeatures: bool = "false",
@@ -167,8 +167,7 @@ config_data! {
167 /// Whether to show `can't find Cargo.toml` error message. 167 /// Whether to show `can't find Cargo.toml` error message.
168 notifications_cargoTomlNotFound: bool = "true", 168 notifications_cargoTomlNotFound: bool = "true",
169 169
170 /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be 170 /// Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.
171 /// enabled.
172 procMacro_enable: bool = "false", 171 procMacro_enable: bool = "false",
173 /// Internal config, path to proc-macro server executable (typically, 172 /// Internal config, path to proc-macro server executable (typically,
174 /// this is rust-analyzer itself, but we override this in tests). 173 /// this is rust-analyzer itself, but we override this in tests).
@@ -480,8 +479,8 @@ impl Config {
480 pub fn cargo_autoreload(&self) -> bool { 479 pub fn cargo_autoreload(&self) -> bool {
481 self.data.cargo_autoreload 480 self.data.cargo_autoreload
482 } 481 }
483 pub fn load_out_dirs_from_check(&self) -> bool { 482 pub fn run_build_scripts(&self) -> bool {
484 self.data.cargo_loadOutDirsFromCheck 483 self.data.cargo_runBuildScripts || self.data.procMacro_enable
485 } 484 }
486 pub fn cargo(&self) -> CargoConfig { 485 pub fn cargo(&self) -> CargoConfig {
487 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { 486 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 2829d5970..f0cb309e4 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -312,7 +312,7 @@ impl GlobalState {
312 } else { 312 } else {
313 assert_eq!(n_done, n_total); 313 assert_eq!(n_done, n_total);
314 new_status = Status::Ready { 314 new_status = Status::Ready {
315 partial: self.config.load_out_dirs_from_check() 315 partial: self.config.run_build_scripts()
316 && self.workspace_build_data.is_none() 316 && self.workspace_build_data.is_none()
317 || config_version < self.vfs_config_version, 317 || config_version < self.vfs_config_version,
318 }; 318 };
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index c07efa330..aa8504c3d 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -337,7 +337,7 @@ impl GlobalState {
337 }; 337 };
338 change.set_crate_graph(crate_graph); 338 change.set_crate_graph(crate_graph);
339 339
340 if self.config.load_out_dirs_from_check() && workspace_build_data.is_none() { 340 if self.config.run_build_scripts() && workspace_build_data.is_none() {
341 let mut collector = BuildDataCollector::default(); 341 let mut collector = BuildDataCollector::default();
342 for ws in &workspaces { 342 for ws in &workspaces {
343 ws.collect_build_data_configs(&mut collector); 343 ws.collect_build_data_configs(&mut collector);
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index f91e04c31..1dbf2a611 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -10,8 +10,8 @@
10 Activate all available features (`--all-features`). 10 Activate all available features (`--all-features`).
11[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: 11[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
12 List of features to activate. 12 List of features to activate.
13[[rust-analyzer.cargo.loadOutDirsFromCheck]]rust-analyzer.cargo.loadOutDirsFromCheck (default: `false`):: 13[[rust-analyzer.cargo.runBuildScripts]]rust-analyzer.cargo.runBuildScripts (default: `false`)::
14 Run `cargo check` on startup to get the correct value for package OUT_DIRs. 14 Run build scripts (`build.rs`) for more precise code analysis.
15[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: 15[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`)::
16 Do not activate the `default` feature. 16 Do not activate the `default` feature.
17[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`):: 17[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
@@ -97,7 +97,7 @@
97[[rust-analyzer.notifications.cargoTomlNotFound]]rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: 97[[rust-analyzer.notifications.cargoTomlNotFound]]rust-analyzer.notifications.cargoTomlNotFound (default: `true`)::
98 Whether to show `can't find Cargo.toml` error message. 98 Whether to show `can't find Cargo.toml` error message.
99[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `false`):: 99[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `false`)::
100 Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled. 100 Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.
101[[rust-analyzer.procMacro.server]]rust-analyzer.procMacro.server (default: `null`):: 101[[rust-analyzer.procMacro.server]]rust-analyzer.procMacro.server (default: `null`)::
102 Internal config, path to proc-macro server executable (typically, this is rust-analyzer itself, but we override this in tests). 102 Internal config, path to proc-macro server executable (typically, this is rust-analyzer itself, but we override this in tests).
103[[rust-analyzer.runnables.overrideCargo]]rust-analyzer.runnables.overrideCargo (default: `null`):: 103[[rust-analyzer.runnables.overrideCargo]]rust-analyzer.runnables.overrideCargo (default: `null`)::
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 9f28237ff..4f2217546 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -226,6 +226,8 @@ The are several LSP client implementations for vim or neovim:
226 * inlay hints for variables and method chaining, _Neovim Only_ 226 * inlay hints for variables and method chaining, _Neovim Only_
227 * semantic highlighting is not implemented yet 227 * semantic highlighting is not implemented yet
228 228
229Note: for code actions, use `coc-codeaction-cursor` and `coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line` are unlikely to be useful.
230
229==== LanguageClient-neovim 231==== LanguageClient-neovim
230 232
2311. Install LanguageClient-neovim by following the instructions 2331. Install LanguageClient-neovim by following the instructions
diff --git a/editors/code/package.json b/editors/code/package.json
index e3e0ebff0..1987364bc 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -408,8 +408,8 @@
408 "type": "string" 408 "type": "string"
409 } 409 }
410 }, 410 },
411 "rust-analyzer.cargo.loadOutDirsFromCheck": { 411 "rust-analyzer.cargo.runBuildScripts": {
412 "markdownDescription": "Run `cargo check` on startup to get the correct value for package OUT_DIRs.", 412 "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
413 "default": false, 413 "default": false,
414 "type": "boolean" 414 "type": "boolean"
415 }, 415 },
@@ -678,7 +678,7 @@
678 "type": "boolean" 678 "type": "boolean"
679 }, 679 },
680 "rust-analyzer.procMacro.enable": { 680 "rust-analyzer.procMacro.enable": {
681 "markdownDescription": "Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled.", 681 "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.",
682 "default": false, 682 "default": false,
683 "type": "boolean" 683 "type": "boolean"
684 }, 684 },
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 5710fbdb5..56eda5b1e 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -1,5 +1,7 @@
1#![allow(unreachable_pub)] 1#![allow(unreachable_pub)]
2 2
3use crate::install::{ClientOpt, Malloc, ServerOpt};
4
3xflags::args_parser! { 5xflags::args_parser! {
4 /// Run custom build command. 6 /// Run custom build command.
5 cmd xtask { 7 cmd xtask {
@@ -137,3 +139,25 @@ impl Xtask {
137 } 139 }
138} 140}
139// generated end 141// generated end
142
143impl Install {
144 pub(crate) fn server(&self) -> Option<ServerOpt> {
145 if self.client && !self.server {
146 return None;
147 }
148 let malloc = if self.mimalloc {
149 Malloc::Mimalloc
150 } else if self.jemalloc {
151 Malloc::Jemalloc
152 } else {
153 Malloc::System
154 };
155 Some(ServerOpt { malloc })
156 }
157 pub(crate) fn client(&self) -> Option<ClientOpt> {
158 if !self.client && self.server {
159 return None;
160 }
161 Some(ClientOpt { code_bin: self.code_bin.clone() })
162 }
163}
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index ea2194248..177028b08 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -5,60 +5,32 @@ use std::{env, path::PathBuf, str};
5use anyhow::{bail, format_err, Context, Result}; 5use anyhow::{bail, format_err, Context, Result};
6use xshell::{cmd, pushd}; 6use xshell::{cmd, pushd};
7 7
8use crate::flags;
9
8// Latest stable, feel free to send a PR if this lags behind. 10// Latest stable, feel free to send a PR if this lags behind.
9const REQUIRED_RUST_VERSION: u32 = 50; 11const REQUIRED_RUST_VERSION: u32 = 50;
10 12
11pub(crate) struct InstallCmd { 13impl flags::Install {
12 pub(crate) client: Option<ClientOpt>, 14 pub(crate) fn run(self) -> Result<()> {
13 pub(crate) server: Option<ServerOpt>, 15 if cfg!(target_os = "macos") {
14} 16 fix_path_for_mac().context("Fix path for mac")?
15 17 }
16#[derive(Clone, Copy)] 18 if let Some(server) = self.server() {
17pub(crate) enum ClientOpt { 19 install_server(server).context("install server")?;
18 VsCode, 20 }
19 VsCodeExploration, 21 if let Some(client) = self.client() {
20 VsCodeInsiders, 22 install_client(client).context("install client")?;
21 VsCodium,
22 VsCodeOss,
23 Any,
24}
25
26impl ClientOpt {
27 pub(crate) const fn as_cmds(&self) -> &'static [&'static str] {
28 match self {
29 ClientOpt::VsCode => &["code"],
30 ClientOpt::VsCodeExploration => &["code-exploration"],
31 ClientOpt::VsCodeInsiders => &["code-insiders"],
32 ClientOpt::VsCodium => &["codium"],
33 ClientOpt::VsCodeOss => &["code-oss"],
34 ClientOpt::Any => &["code", "code-exploration", "code-insiders", "codium", "code-oss"],
35 } 23 }
24 Ok(())
36 } 25 }
37} 26}
38 27
39impl Default for ClientOpt { 28#[derive(Clone)]
40 fn default() -> Self { 29pub(crate) struct ClientOpt {
41 ClientOpt::Any 30 pub(crate) code_bin: Option<String>,
42 }
43} 31}
44 32
45impl std::str::FromStr for ClientOpt { 33const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium", "code-oss"];
46 type Err = anyhow::Error;
47
48 fn from_str(s: &str) -> Result<Self, Self::Err> {
49 [
50 ClientOpt::VsCode,
51 ClientOpt::VsCodeExploration,
52 ClientOpt::VsCodeInsiders,
53 ClientOpt::VsCodium,
54 ClientOpt::VsCodeOss,
55 ]
56 .iter()
57 .copied()
58 .find(|c| [s] == c.as_cmds())
59 .ok_or_else(|| anyhow::format_err!("no such client"))
60 }
61}
62 34
63pub(crate) struct ServerOpt { 35pub(crate) struct ServerOpt {
64 pub(crate) malloc: Malloc, 36 pub(crate) malloc: Malloc,
@@ -70,21 +42,6 @@ pub(crate) enum Malloc {
70 Jemalloc, 42 Jemalloc,
71} 43}
72 44
73impl InstallCmd {
74 pub(crate) fn run(self) -> Result<()> {
75 if cfg!(target_os = "macos") {
76 fix_path_for_mac().context("Fix path for mac")?
77 }
78 if let Some(server) = self.server {
79 install_server(server).context("install server")?;
80 }
81 if let Some(client) = self.client {
82 install_client(client).context("install client")?;
83 }
84 Ok(())
85 }
86}
87
88fn fix_path_for_mac() -> Result<()> { 45fn fix_path_for_mac() -> Result<()> {
89 let mut vscode_path: Vec<PathBuf> = { 46 let mut vscode_path: Vec<PathBuf> = {
90 const COMMON_APP_PATH: &str = 47 const COMMON_APP_PATH: &str =
@@ -121,21 +78,12 @@ fn fix_path_for_mac() -> Result<()> {
121fn install_client(client_opt: ClientOpt) -> Result<()> { 78fn install_client(client_opt: ClientOpt) -> Result<()> {
122 let _dir = pushd("./editors/code"); 79 let _dir = pushd("./editors/code");
123 80
124 let find_code = |f: fn(&str) -> bool| -> Result<&'static str> { 81 // Package extension.
125 client_opt.as_cmds().iter().copied().find(|bin| f(bin)).ok_or_else(|| { 82 if cfg!(unix) {
126 format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
127 })
128 };
129
130 let installed_extensions = if cfg!(unix) {
131 cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?; 83 cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
132 cmd!("npm ci").run()?; 84 cmd!("npm ci").run()?;
133 85
134 cmd!("npm run package --scripts-prepend-node-path").run()?; 86 cmd!("npm run package --scripts-prepend-node-path").run()?;
135
136 let code = find_code(|bin| cmd!("{bin} --version").read().is_ok())?;
137 cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
138 cmd!("{code} --list-extensions").read()?
139 } else { 87 } else {
140 cmd!("cmd.exe /c npm --version") 88 cmd!("cmd.exe /c npm --version")
141 .run() 89 .run()
@@ -143,8 +91,36 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
143 cmd!("cmd.exe /c npm ci").run()?; 91 cmd!("cmd.exe /c npm ci").run()?;
144 92
145 cmd!("cmd.exe /c npm run package").run()?; 93 cmd!("cmd.exe /c npm run package").run()?;
94 };
95
96 // Find the appropriate VS Code binary.
97 let lifetime_extender;
98 let candidates: &[&str] = match client_opt.code_bin.as_deref() {
99 Some(it) => {
100 lifetime_extender = [it];
101 &lifetime_extender[..]
102 }
103 None => VS_CODES,
104 };
105 let code = candidates
106 .iter()
107 .copied()
108 .find(|&bin| {
109 if cfg!(unix) {
110 cmd!("{bin} --version").read().is_ok()
111 } else {
112 cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
113 }
114 })
115 .ok_or_else(|| {
116 format_err!("Can't execute `{} --version`. Perhaps it is not in $PATH?", candidates[0])
117 })?;
146 118
147 let code = find_code(|bin| cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok())?; 119 // Install & verify.
120 let installed_extensions = if cfg!(unix) {
121 cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
122 cmd!("{code} --list-extensions").read()?
123 } else {
148 cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?; 124 cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
149 cmd!("cmd.exe /c {code}.cmd --list-extensions").read()? 125 cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
150 }; 126 };
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index e419db7a7..3c4332f75 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -28,11 +28,7 @@ use std::{
28use walkdir::{DirEntry, WalkDir}; 28use walkdir::{DirEntry, WalkDir};
29use xshell::{cmd, cp, pushd, pushenv}; 29use xshell::{cmd, cp, pushd, pushenv};
30 30
31use crate::{ 31use crate::{codegen::Mode, dist::DistCmd};
32 codegen::Mode,
33 dist::DistCmd,
34 install::{InstallCmd, Malloc, ServerOpt},
35};
36 32
37fn main() -> Result<()> { 33fn main() -> Result<()> {
38 let _d = pushd(project_root())?; 34 let _d = pushd(project_root())?;
@@ -43,31 +39,7 @@ fn main() -> Result<()> {
43 println!("{}", flags::Xtask::HELP); 39 println!("{}", flags::Xtask::HELP);
44 return Ok(()); 40 return Ok(());
45 } 41 }
46 flags::XtaskCmd::Install(flags) => { 42 flags::XtaskCmd::Install(cmd) => cmd.run(),
47 if flags.server && flags.client {
48 eprintln!(
49 "error: The argument `--server` cannot be used with `--client`\n\n\
50 For more information try --help"
51 );
52 return Ok(());
53 }
54
55 let malloc = if flags.mimalloc {
56 Malloc::Mimalloc
57 } else if flags.jemalloc {
58 Malloc::Jemalloc
59 } else {
60 Malloc::System
61 };
62
63 let client_bin = flags.code_bin.map(|it| it.parse()).transpose()?;
64
65 InstallCmd {
66 client: if flags.server { None } else { client_bin },
67 server: if flags.client { None } else { Some(ServerOpt { malloc }) },
68 }
69 .run()
70 }
71 flags::XtaskCmd::Codegen(cmd) => cmd.run(), 43 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
72 flags::XtaskCmd::Lint(_) => run_clippy(), 44 flags::XtaskCmd::Lint(_) => run_clippy(),
73 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), 45 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),