aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/dev/README.md3
-rw-r--r--docs/dev/style.md59
2 files changed, 61 insertions, 1 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md
index dd2bfc493..24197b332 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -251,6 +251,9 @@ RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more tha
251 251
252In particular, I have `export RA_PROFILE='*>10'` in my shell profile. 252In particular, I have `export RA_PROFILE='*>10'` in my shell profile.
253 253
254We also have a "counting" profiler which counts number of instances of popular structs.
255It is enabled by `RA_COUNT=1`.
256
254To measure time for from-scratch analysis, use something like this: 257To measure time for from-scratch analysis, use something like this:
255 258
256``` 259```
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 21330948b..428cee3ad 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -6,6 +6,9 @@ Our approach to "clean code" is two-fold:
6It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author. 6It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author.
7Sending small cleanup PRs (like renaming a single local variable) is encouraged. 7Sending small cleanup PRs (like renaming a single local variable) is encouraged.
8 8
9When reviewing pull requests prefer extending this document to leaving
10non-reusable comments on the pull request itself.
11
9# General 12# General
10 13
11## Scale of Changes 14## Scale of Changes
@@ -139,6 +142,17 @@ There are many benefits to this:
139 142
140Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code. 143Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code.
141 144
145## Marked Tests
146
147Use
148[`mark::hit! / mark::check!`](https://github.com/rust-analyzer/rust-analyzer/blob/71fe719dd5247ed8615641d9303d7ca1aa201c2f/crates/test_utils/src/mark.rs)
149when testing specific conditions.
150Do not place several marks into a single test or condition.
151Do not reuse marks between several tests.
152
153**Rationale:** marks provide an easy way to find the canonical test for each bit of code.
154This makes it much easier to understand.
155
142## Function Preconditions 156## Function Preconditions
143 157
144Express function preconditions in types and force the caller to provide them (rather than checking in callee): 158Express function preconditions in types and force the caller to provide them (rather than checking in callee):
@@ -280,6 +294,9 @@ Prefer `Default` even it has to be implemented manually.
280 294
281**Rationale:** less typing in the common case, uniformity. 295**Rationale:** less typing in the common case, uniformity.
282 296
297Use `Vec::new` rather than `vec![]`. **Rationale:** uniformity, strength
298reduction.
299
283## Functions Over Objects 300## Functions Over Objects
284 301
285Avoid creating "doer" objects. 302Avoid creating "doer" objects.
@@ -372,6 +389,14 @@ This allows for exceptionally good performance, but leads to increased compile t
372Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot. 389Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot.
373Compile time **does not** obey this rule -- all code has to be compiled. 390Compile time **does not** obey this rule -- all code has to be compiled.
374 391
392## Appropriate String Types
393
394When interfacing with OS APIs, use `OsString`, even if the original source of data is utf-8 encoded.
395**Rationale:** cleanly delineates the boundary when the data goes into the OS-land.
396
397Use `AbsPathBuf` and `AbsPath` over `std::Path`.
398**Rationale:** rust-analyzer is a long-lived process which handles several projects at the same time.
399It is important not to leak cwd by accident.
375 400
376# Premature Pessimization 401# Premature Pessimization
377 402
@@ -418,12 +443,44 @@ fn frobnicate(s: &str) {
418**Rationale:** reveals the costs. 443**Rationale:** reveals the costs.
419It is also more efficient when the caller already owns the allocation. 444It is also more efficient when the caller already owns the allocation.
420 445
421## Collection types 446## Collection Types
422 447
423Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. 448Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`.
424 449
425**Rationale:** they use a hasher that's significantly faster and using them consistently will reduce code size by some small amount. 450**Rationale:** they use a hasher that's significantly faster and using them consistently will reduce code size by some small amount.
426 451
452## Avoid Intermediate Collections
453
454When writing a recursive function to compute a sets of things, use an accumulator parameter instead of returning a fresh collection.
455Accumulator goes first in the list of arguments.
456
457```rust
458// GOOD
459pub fn reachable_nodes(node: Node) -> FxHashSet<Node> {
460 let mut res = FxHashSet::default();
461 go(&mut res, node);
462 res
463}
464fn go(acc: &mut FxHashSet<Node>, node: Node) {
465 acc.insert(node);
466 for n in node.neighbors() {
467 go(acc, n);
468 }
469}
470
471// BAD
472pub fn reachable_nodes(node: Node) -> FxHashSet<Node> {
473 let mut res = FxHashSet::default();
474 res.insert(node);
475 for n in node.neighbors() {
476 res.extend(reachable_nodes(n));
477 }
478 res
479}
480```
481
482**Rational:** re-use allocations, accumulator style is more concise for complex cases.
483
427# Style 484# Style
428 485
429## Order of Imports 486## Order of Imports