aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs40
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs73
-rw-r--r--crates/ide_completion/src/completions/postfix.rs14
-rw-r--r--crates/rust-analyzer/src/config.rs48
-rw-r--r--crates/syntax/Cargo.toml2
5 files changed, 124 insertions, 53 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c4691d34c..d5a3d9034 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -812,13 +812,11 @@ impl Function {
812 /// Get this function's return type 812 /// Get this function's return type
813 pub fn ret_type(self, db: &dyn HirDatabase) -> Type { 813 pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
814 let resolver = self.id.resolver(db.upcast()); 814 let resolver = self.id.resolver(db.upcast());
815 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
815 let ret_type = &db.function_data(self.id).ret_type; 816 let ret_type = &db.function_data(self.id).ret_type;
816 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 817 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
817 let environment = TraitEnvironment::lower(db, &resolver); 818 let ty = Ty::from_hir_ext(&ctx, ret_type).0;
818 Type { 819 Type::new_with_resolver_inner(db, krate, &resolver, ty)
819 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
820 ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment },
821 }
822 } 820 }
823 821
824 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { 822 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
@@ -830,6 +828,7 @@ impl Function {
830 828
831 pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { 829 pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
832 let resolver = self.id.resolver(db.upcast()); 830 let resolver = self.id.resolver(db.upcast());
831 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
833 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 832 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
834 let environment = TraitEnvironment::lower(db, &resolver); 833 let environment = TraitEnvironment::lower(db, &resolver);
835 db.function_data(self.id) 834 db.function_data(self.id)
@@ -837,7 +836,7 @@ impl Function {
837 .iter() 836 .iter()
838 .map(|type_ref| { 837 .map(|type_ref| {
839 let ty = Type { 838 let ty = Type {
840 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), 839 krate,
841 ty: InEnvironment { 840 ty: InEnvironment {
842 value: Ty::from_hir_ext(&ctx, type_ref).0, 841 value: Ty::from_hir_ext(&ctx, type_ref).0,
843 environment: environment.clone(), 842 environment: environment.clone(),
@@ -1403,12 +1402,9 @@ impl TypeParam {
1403 1402
1404 pub fn ty(self, db: &dyn HirDatabase) -> Type { 1403 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1405 let resolver = self.id.parent.resolver(db.upcast()); 1404 let resolver = self.id.parent.resolver(db.upcast());
1406 let environment = TraitEnvironment::lower(db, &resolver); 1405 let krate = self.id.parent.module(db.upcast()).krate();
1407 let ty = Ty::Placeholder(self.id); 1406 let ty = Ty::Placeholder(self.id);
1408 Type { 1407 Type::new_with_resolver_inner(db, krate, &resolver, ty)
1409 krate: self.id.parent.module(db.upcast()).krate(),
1410 ty: InEnvironment { value: ty, environment },
1411 }
1412 } 1408 }
1413 1409
1414 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { 1410 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
@@ -1427,14 +1423,11 @@ impl TypeParam {
1427 let params = db.generic_defaults(self.id.parent); 1423 let params = db.generic_defaults(self.id.parent);
1428 let local_idx = hir_ty::param_idx(db, self.id)?; 1424 let local_idx = hir_ty::param_idx(db, self.id)?;
1429 let resolver = self.id.parent.resolver(db.upcast()); 1425 let resolver = self.id.parent.resolver(db.upcast());
1430 let environment = TraitEnvironment::lower(db, &resolver); 1426 let krate = self.id.parent.module(db.upcast()).krate();
1431 let ty = params.get(local_idx)?.clone(); 1427 let ty = params.get(local_idx)?.clone();
1432 let subst = Substs::type_params(db, self.id.parent); 1428 let subst = Substs::type_params(db, self.id.parent);
1433 let ty = ty.subst(&subst.prefix(local_idx)); 1429 let ty = ty.subst(&subst.prefix(local_idx));
1434 Some(Type { 1430 Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
1435 krate: self.id.parent.module(db.upcast()).krate(),
1436 ty: InEnvironment { value: ty, environment },
1437 })
1438 } 1431 }
1439} 1432}
1440 1433
@@ -1523,13 +1516,10 @@ impl Impl {
1523 pub fn target_ty(self, db: &dyn HirDatabase) -> Type { 1516 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1524 let impl_data = db.impl_data(self.id); 1517 let impl_data = db.impl_data(self.id);
1525 let resolver = self.id.resolver(db.upcast()); 1518 let resolver = self.id.resolver(db.upcast());
1519 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
1526 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 1520 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1527 let environment = TraitEnvironment::lower(db, &resolver);
1528 let ty = Ty::from_hir(&ctx, &impl_data.target_type); 1521 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1529 Type { 1522 Type::new_with_resolver_inner(db, krate, &resolver, ty)
1530 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
1531 ty: InEnvironment { value: ty, environment },
1532 }
1533 } 1523 }
1534 1524
1535 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { 1525 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
@@ -1725,13 +1715,11 @@ impl Type {
1725 }; 1715 };
1726 1716
1727 match db.trait_solve(self.krate, goal)? { 1717 match db.trait_solve(self.krate, goal)? {
1728 Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), 1718 Solution::Unique(SolutionVariables(subst)) => {
1719 subst.value.first().map(|ty| self.derived(ty.clone()))
1720 }
1729 Solution::Ambig(_) => None, 1721 Solution::Ambig(_) => None,
1730 } 1722 }
1731 .map(|ty| Type {
1732 krate: self.krate,
1733 ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) },
1734 })
1735 } 1723 }
1736 1724
1737 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { 1725 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 3870b7e75..6f95b1a07 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -83,17 +83,18 @@ struct FunctionTemplate {
83 leading_ws: String, 83 leading_ws: String,
84 fn_def: ast::Fn, 84 fn_def: ast::Fn,
85 ret_type: ast::RetType, 85 ret_type: ast::RetType,
86 should_render_snippet: bool,
86 trailing_ws: String, 87 trailing_ws: String,
87 file: FileId, 88 file: FileId,
88} 89}
89 90
90impl FunctionTemplate { 91impl FunctionTemplate {
91 fn to_string(&self, cap: Option<SnippetCap>) -> String { 92 fn to_string(&self, cap: Option<SnippetCap>) -> String {
92 let f = match cap { 93 let f = match (cap, self.should_render_snippet) {
93 Some(cap) => { 94 (Some(cap), true) => {
94 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) 95 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax()))
95 } 96 }
96 None => self.fn_def.to_string(), 97 _ => self.fn_def.to_string(),
97 }; 98 };
98 format!("{}{}{}", self.leading_ws, f, self.trailing_ws) 99 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
99 } 100 }
@@ -104,6 +105,8 @@ struct FunctionBuilder {
104 fn_name: ast::Name, 105 fn_name: ast::Name,
105 type_params: Option<ast::GenericParamList>, 106 type_params: Option<ast::GenericParamList>,
106 params: ast::ParamList, 107 params: ast::ParamList,
108 ret_type: ast::RetType,
109 should_render_snippet: bool,
107 file: FileId, 110 file: FileId,
108 needs_pub: bool, 111 needs_pub: bool,
109} 112}
@@ -132,7 +135,43 @@ impl FunctionBuilder {
132 let fn_name = fn_name(&path)?; 135 let fn_name = fn_name(&path)?;
133 let (type_params, params) = fn_args(ctx, target_module, &call)?; 136 let (type_params, params) = fn_args(ctx, target_module, &call)?;
134 137
135 Some(Self { target, fn_name, type_params, params, file, needs_pub }) 138 // should_render_snippet intends to express a rough level of confidence about
139 // the correctness of the return type.
140 //
141 // If we are able to infer some return type, and that return type is not unit, we
142 // don't want to render the snippet. The assumption here is in this situation the
143 // return type is just as likely to be correct as any other part of the generated
144 // function.
145 //
146 // In the case where the return type is inferred as unit it is likely that the
147 // user does in fact intend for this generated function to return some non unit
148 // type, but that the current state of their code doesn't allow that return type
149 // to be accurately inferred.
150 let (ret_ty, should_render_snippet) = {
151 match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) {
152 Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true),
153 Some(ty) => {
154 let rendered = ty.display_source_code(ctx.db(), target_module.into());
155 match rendered {
156 Ok(rendered) => (make::ty(&rendered), false),
157 Err(_) => (make::ty_unit(), true),
158 }
159 }
160 None => (make::ty_unit(), true),
161 }
162 };
163 let ret_type = make::ret_type(ret_ty);
164
165 Some(Self {
166 target,
167 fn_name,
168 type_params,
169 params,
170 ret_type,
171 should_render_snippet,
172 file,
173 needs_pub,
174 })
136 } 175 }
137 176
138 fn render(self) -> FunctionTemplate { 177 fn render(self) -> FunctionTemplate {
@@ -145,7 +184,7 @@ impl FunctionBuilder {
145 self.type_params, 184 self.type_params,
146 self.params, 185 self.params,
147 fn_body, 186 fn_body,
148 Some(make::ret_type(make::ty_unit())), 187 Some(self.ret_type),
149 ); 188 );
150 let leading_ws; 189 let leading_ws;
151 let trailing_ws; 190 let trailing_ws;
@@ -171,6 +210,7 @@ impl FunctionBuilder {
171 insert_offset, 210 insert_offset,
172 leading_ws, 211 leading_ws,
173 ret_type: fn_def.ret_type().unwrap(), 212 ret_type: fn_def.ret_type().unwrap(),
213 should_render_snippet: self.should_render_snippet,
174 fn_def, 214 fn_def,
175 trailing_ws, 215 trailing_ws,
176 file: self.file, 216 file: self.file,
@@ -546,7 +586,7 @@ impl Baz {
546 } 586 }
547} 587}
548 588
549fn bar(baz: Baz) ${0:-> ()} { 589fn bar(baz: Baz) -> Baz {
550 todo!() 590 todo!()
551} 591}
552", 592",
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} {
1060 } 1100 }
1061 1101
1062 #[test] 1102 #[test]
1103 fn add_function_with_return_type() {
1104 check_assist(
1105 generate_function,
1106 r"
1107fn main() {
1108 let x: u32 = foo$0();
1109}
1110",
1111 r"
1112fn main() {
1113 let x: u32 = foo();
1114}
1115
1116fn foo() -> u32 {
1117 todo!()
1118}
1119",
1120 )
1121 }
1122
1123 #[test]
1063 fn add_function_not_applicable_if_function_already_exists() { 1124 fn add_function_not_applicable_if_function_already_exists() {
1064 check_assist_not_applicable( 1125 check_assist_not_applicable(
1065 generate_function, 1126 generate_function,
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 9c34ed0b6..d45ad7944 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -187,6 +187,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
187 ctx, 187 ctx,
188 cap, 188 cap,
189 &dot_receiver, 189 &dot_receiver,
190 "err",
191 "Err(expr)",
192 &format!("Err({})", receiver_text),
193 )
194 .add_to(acc);
195
196 postfix_snippet(
197 ctx,
198 cap,
199 &dot_receiver,
190 "some", 200 "some",
191 "Some(expr)", 201 "Some(expr)",
192 &format!("Some({})", receiver_text), 202 &format!("Some({})", receiver_text),
@@ -325,6 +335,7 @@ fn main() {
325 sn match match expr {} 335 sn match match expr {}
326 sn box Box::new(expr) 336 sn box Box::new(expr)
327 sn ok Ok(expr) 337 sn ok Ok(expr)
338 sn err Err(expr)
328 sn some Some(expr) 339 sn some Some(expr)
329 sn dbg dbg!(expr) 340 sn dbg dbg!(expr)
330 sn dbgr dbg!(&expr) 341 sn dbgr dbg!(&expr)
@@ -357,6 +368,7 @@ fn main() {
357 sn match match expr {} 368 sn match match expr {}
358 sn box Box::new(expr) 369 sn box Box::new(expr)
359 sn ok Ok(expr) 370 sn ok Ok(expr)
371 sn err Err(expr)
360 sn some Some(expr) 372 sn some Some(expr)
361 sn dbg dbg!(expr) 373 sn dbg dbg!(expr)
362 sn dbgr dbg!(&expr) 374 sn dbgr dbg!(&expr)
@@ -380,6 +392,7 @@ fn main() {
380 sn match match expr {} 392 sn match match expr {}
381 sn box Box::new(expr) 393 sn box Box::new(expr)
382 sn ok Ok(expr) 394 sn ok Ok(expr)
395 sn err Err(expr)
383 sn some Some(expr) 396 sn some Some(expr)
384 sn dbg dbg!(expr) 397 sn dbg dbg!(expr)
385 sn dbgr dbg!(&expr) 398 sn dbgr dbg!(&expr)
@@ -408,6 +421,7 @@ fn main() {
408 sn match match expr {} 421 sn match match expr {}
409 sn box Box::new(expr) 422 sn box Box::new(expr)
410 sn ok Ok(expr) 423 sn ok Ok(expr)
424 sn err Err(expr)
411 sn some Some(expr) 425 sn some Some(expr)
412 sn dbg dbg!(expr) 426 sn dbg dbg!(expr)
413 sn dbgr dbg!(&expr) 427 sn dbgr dbg!(&expr)
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 078c83f75..25df13554 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -16,7 +16,6 @@ use ide_db::helpers::{
16 insert_use::{InsertUseConfig, MergeBehavior}, 16 insert_use::{InsertUseConfig, MergeBehavior},
17 SnippetCap, 17 SnippetCap,
18}; 18};
19use itertools::Itertools;
20use lsp_types::{ClientCapabilities, MarkupKind}; 19use lsp_types::{ClientCapabilities, MarkupKind};
21use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource}; 20use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource};
22use rustc_hash::FxHashSet; 21use rustc_hash::FxHashSet;
@@ -98,13 +97,15 @@ config_data! {
98 diagnostics_enableExperimental: bool = "true", 97 diagnostics_enableExperimental: bool = "true",
99 /// List of rust-analyzer diagnostics to disable. 98 /// List of rust-analyzer diagnostics to disable.
100 diagnostics_disabled: FxHashSet<String> = "[]", 99 diagnostics_disabled: FxHashSet<String> = "[]",
101 /// List of warnings that should be displayed with info severity.\n\nThe 100 /// List of warnings that should be displayed with info severity.
102 /// warnings will be indicated by a blue squiggly underline in code and 101 ///
103 /// a blue icon in the `Problems Panel`. 102 /// The warnings will be indicated by a blue squiggly underline in code
103 /// and a blue icon in the `Problems Panel`.
104 diagnostics_warningsAsHint: Vec<String> = "[]", 104 diagnostics_warningsAsHint: Vec<String> = "[]",
105 /// List of warnings that should be displayed with hint severity.\n\nThe 105 /// List of warnings that should be displayed with hint severity.
106 /// warnings will be indicated by faded text or three dots in code and 106 ///
107 /// will not show up in the `Problems Panel`. 107 /// The warnings will be indicated by faded text or three dots in code
108 /// and will not show up in the `Problems Panel`.
108 diagnostics_warningsAsInfo: Vec<String> = "[]", 109 diagnostics_warningsAsInfo: Vec<String> = "[]",
109 110
110 /// Controls file watching implementation. 111 /// Controls file watching implementation.
@@ -158,7 +159,9 @@ config_data! {
158 lens_references: bool = "false", 159 lens_references: bool = "false",
159 160
160 /// Disable project auto-discovery in favor of explicitly specified set 161 /// Disable project auto-discovery in favor of explicitly specified set
161 /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, 162 /// of projects.
163 ///
164 /// Elements must be paths pointing to `Cargo.toml`,
162 /// `rust-project.json`, or JSON objects in `rust-project.json` format. 165 /// `rust-project.json`, or JSON objects in `rust-project.json` format.
163 linkedProjects: Vec<ManifestOrProjectJson> = "[]", 166 linkedProjects: Vec<ManifestOrProjectJson> = "[]",
164 167
@@ -177,13 +180,17 @@ config_data! {
177 /// Command to be executed instead of 'cargo' for runnables. 180 /// Command to be executed instead of 'cargo' for runnables.
178 runnables_overrideCargo: Option<String> = "null", 181 runnables_overrideCargo: Option<String> = "null",
179 /// Additional arguments to be passed to cargo for runnables such as 182 /// Additional arguments to be passed to cargo for runnables such as
180 /// tests or binaries.\nFor example, it may be `--release`. 183 /// tests or binaries. For example, it may be `--release`.
181 runnables_cargoExtraArgs: Vec<String> = "[]", 184 runnables_cargoExtraArgs: Vec<String> = "[]",
182 185
183 /// Path to the rust compiler sources, for usage in rustc_private projects, or "discover" 186 /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
184 /// to try to automatically find it. Any project which uses rust-analyzer with the rustcPrivate 187 /// projects, or "discover" to try to automatically find it.
188 ///
189 /// Any project which uses rust-analyzer with the rustcPrivate
185 /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. 190 /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
186 rustcSource : Option<String> = "null", 191 ///
192 /// This option is not reloaded automatically; you must restart rust-analyzer for it to take effect.
193 rustcSource: Option<String> = "null",
187 194
188 /// Additional arguments to `rustfmt`. 195 /// Additional arguments to `rustfmt`.
189 rustfmt_extraArgs: Vec<String> = "[]", 196 rustfmt_extraArgs: Vec<String> = "[]",
@@ -761,7 +768,8 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json:
761} 768}
762 769
763fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { 770fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value {
764 let doc = doc.iter().map(|it| it.trim()).join(" "); 771 let doc = doc_comment_to_string(doc);
772 let doc = doc.trim_end_matches('\n');
765 assert!( 773 assert!(
766 doc.ends_with('.') && doc.starts_with(char::is_uppercase), 774 doc.ends_with('.') && doc.starts_with(char::is_uppercase),
767 "bad docs for {}: {:?}", 775 "bad docs for {}: {:?}",
@@ -850,11 +858,16 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
850 .iter() 858 .iter()
851 .map(|(field, _ty, doc, default)| { 859 .map(|(field, _ty, doc, default)| {
852 let name = format!("rust-analyzer.{}", field.replace("_", ".")); 860 let name = format!("rust-analyzer.{}", field.replace("_", "."));
853 format!("[[{}]]{} (default: `{}`)::\n{}\n", name, name, default, doc.join(" ")) 861 let doc = doc_comment_to_string(*doc);
862 format!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name, name, default, doc)
854 }) 863 })
855 .collect::<String>() 864 .collect::<String>()
856} 865}
857 866
867fn doc_comment_to_string(doc: &[&str]) -> String {
868 doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{}\n", it)).collect()
869}
870
858#[cfg(test)] 871#[cfg(test)]
859mod tests { 872mod tests {
860 use std::fs; 873 use std::fs;
@@ -897,13 +910,8 @@ mod tests {
897 #[test] 910 #[test]
898 fn generate_config_documentation() { 911 fn generate_config_documentation() {
899 let docs_path = project_root().join("docs/user/generated_config.adoc"); 912 let docs_path = project_root().join("docs/user/generated_config.adoc");
900 let current = fs::read_to_string(&docs_path).unwrap();
901 let expected = ConfigData::manual(); 913 let expected = ConfigData::manual();
902 914 ensure_file_contents(&docs_path, &expected);
903 if remove_ws(&current) != remove_ws(&expected) {
904 fs::write(&docs_path, expected).unwrap();
905 panic!("updated config manual");
906 }
907 } 915 }
908 916
909 fn remove_ws(text: &str) -> String { 917 fn remove_ws(text: &str) -> String {
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index c39095def..33bde099b 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -25,10 +25,10 @@ serde = { version = "1.0.106", features = ["derive"] }
25stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { path = "../stdx", version = "0.0.0" }
26text_edit = { path = "../text_edit", version = "0.0.0" } 26text_edit = { path = "../text_edit", version = "0.0.0" }
27parser = { path = "../parser", version = "0.0.0" } 27parser = { path = "../parser", version = "0.0.0" }
28test_utils = { path = "../test_utils", version = "0.0.0" }
29profile = { path = "../profile", version = "0.0.0" } 28profile = { path = "../profile", version = "0.0.0" }
30 29
31[dev-dependencies] 30[dev-dependencies]
31test_utils = { path = "../test_utils" }
32walkdir = "2.3.1" 32walkdir = "2.3.1"
33rayon = "1" 33rayon = "1"
34expect-test = "1.1" 34expect-test = "1.1"