aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/runnables.rs46
-rw-r--r--docs/dev/style.md34
2 files changed, 53 insertions, 27 deletions
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 13582e61f..47a85dc45 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -101,24 +101,22 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
101 Some(it) => it, 101 Some(it) => it,
102 }; 102 };
103 103
104 runnables_mod(&sema, module) 104 let mut res = Vec::new();
105 runnables_mod(&sema, &mut res, module);
106 res
105} 107}
106 108
107fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Runnable> { 109fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module: hir::Module) {
108 let mut res: Vec<Runnable> = module 110 acc.extend(module.declarations(sema.db).into_iter().filter_map(|def| {
109 .declarations(sema.db) 111 let runnable = match def {
110 .into_iter() 112 hir::ModuleDef::Module(it) => runnable_mod(&sema, it),
111 .filter_map(|def| { 113 hir::ModuleDef::Function(it) => runnable_fn(&sema, it),
112 let runnable = match def { 114 _ => None,
113 hir::ModuleDef::Module(it) => runnable_mod(&sema, it), 115 };
114 hir::ModuleDef::Function(it) => runnable_fn(&sema, it), 116 runnable.or_else(|| module_def_doctest(&sema, def))
115 _ => None, 117 }));
116 };
117 runnable.or_else(|| module_def_doctest(&sema, def))
118 })
119 .collect();
120 118
121 res.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( 119 acc.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map(
122 |def| match def { 120 |def| match def {
123 hir::AssocItem::Function(it) => { 121 hir::AssocItem::Function(it) => {
124 runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) 122 runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into()))
@@ -128,18 +126,14 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Run
128 }, 126 },
129 )); 127 ));
130 128
131 res.extend(module.declarations(sema.db).into_iter().flat_map(|def| match def { 129 for def in module.declarations(sema.db) {
132 hir::ModuleDef::Module(submodule) => match submodule.definition_source(sema.db).value { 130 if let hir::ModuleDef::Module(submodule) = def {
133 hir::ModuleSource::SourceFile(_) => { 131 match submodule.definition_source(sema.db).value {
134 mark::hit!(dont_recurse_in_outline_submodules); 132 hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule),
135 Vec::new() 133 hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules),
136 } 134 }
137 hir::ModuleSource::Module(_) => runnables_mod(sema, submodule), 135 }
138 }, 136 }
139 _ => Vec::new(),
140 }));
141
142 res
143} 137}
144 138
145pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { 139pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
diff --git a/docs/dev/style.md b/docs/dev/style.md
index aed15cee9..389649398 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -421,12 +421,44 @@ fn frobnicate(s: &str) {
421**Rationale:** reveals the costs. 421**Rationale:** reveals the costs.
422It is also more efficient when the caller already owns the allocation. 422It is also more efficient when the caller already owns the allocation.
423 423
424## Collection types 424## Collection Types
425 425
426Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. 426Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`.
427 427
428**Rationale:** they use a hasher that's significantly faster and using them consistently will reduce code size by some small amount. 428**Rationale:** they use a hasher that's significantly faster and using them consistently will reduce code size by some small amount.
429 429
430## Avoid Intermediate Collections
431
432When writing a recursive function to compute a sets of things, use an accumulator parameter instead of returning a fresh collection.
433Accumulator goes first in the list of arguments.
434
435```rust
436// GOOD
437pub fn reachable_nodes(node: Node) -> FxHashSet<Node> {
438 let mut res = FxHashSet::default();
439 go(&mut res, node);
440 res
441}
442fn go(acc: &mut FxHashSet<Node>, node: Node) {
443 acc.insert(node);
444 for n in node.neighbors() {
445 go(acc, n);
446 }
447}
448
449// BAD
450pub fn reachable_nodes(node: Node) -> FxHashSet<Node> {
451 let mut res = FxHashSet::default();
452 res.insert(node);
453 for n in node.neighbors() {
454 res.extend(reachable_nodes(n));
455 }
456 res
457}
458```
459
460**Rational:** re-use allocations, accumulator style is more concise for complex cases.
461
430# Style 462# Style
431 463
432## Order of Imports 464## Order of Imports