diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/dev/README.md | 3 | ||||
-rw-r--r-- | docs/dev/style.md | 59 |
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 | ||
252 | In particular, I have `export RA_PROFILE='*>10'` in my shell profile. | 252 | In particular, I have `export RA_PROFILE='*>10'` in my shell profile. |
253 | 253 | ||
254 | We also have a "counting" profiler which counts number of instances of popular structs. | ||
255 | It is enabled by `RA_COUNT=1`. | ||
256 | |||
254 | To measure time for from-scratch analysis, use something like this: | 257 | To 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: | |||
6 | It 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. | 6 | It 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. |
7 | Sending small cleanup PRs (like renaming a single local variable) is encouraged. | 7 | Sending small cleanup PRs (like renaming a single local variable) is encouraged. |
8 | 8 | ||
9 | When reviewing pull requests prefer extending this document to leaving | ||
10 | non-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 | ||
140 | Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code. | 143 | Formatting 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 | |||
147 | Use | ||
148 | [`mark::hit! / mark::check!`](https://github.com/rust-analyzer/rust-analyzer/blob/71fe719dd5247ed8615641d9303d7ca1aa201c2f/crates/test_utils/src/mark.rs) | ||
149 | when testing specific conditions. | ||
150 | Do not place several marks into a single test or condition. | ||
151 | Do not reuse marks between several tests. | ||
152 | |||
153 | **Rationale:** marks provide an easy way to find the canonical test for each bit of code. | ||
154 | This makes it much easier to understand. | ||
155 | |||
142 | ## Function Preconditions | 156 | ## Function Preconditions |
143 | 157 | ||
144 | Express function preconditions in types and force the caller to provide them (rather than checking in callee): | 158 | Express 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 | ||
297 | Use `Vec::new` rather than `vec![]`. **Rationale:** uniformity, strength | ||
298 | reduction. | ||
299 | |||
283 | ## Functions Over Objects | 300 | ## Functions Over Objects |
284 | 301 | ||
285 | Avoid creating "doer" objects. | 302 | Avoid creating "doer" objects. |
@@ -372,6 +389,14 @@ This allows for exceptionally good performance, but leads to increased compile t | |||
372 | Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot. | 389 | Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot. |
373 | Compile time **does not** obey this rule -- all code has to be compiled. | 390 | Compile time **does not** obey this rule -- all code has to be compiled. |
374 | 391 | ||
392 | ## Appropriate String Types | ||
393 | |||
394 | When 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 | |||
397 | Use `AbsPathBuf` and `AbsPath` over `std::Path`. | ||
398 | **Rationale:** rust-analyzer is a long-lived process which handles several projects at the same time. | ||
399 | It 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. |
419 | It is also more efficient when the caller already owns the allocation. | 444 | It is also more efficient when the caller already owns the allocation. |
420 | 445 | ||
421 | ## Collection types | 446 | ## Collection Types |
422 | 447 | ||
423 | Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. | 448 | Prefer `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 | |||
454 | When writing a recursive function to compute a sets of things, use an accumulator parameter instead of returning a fresh collection. | ||
455 | Accumulator goes first in the list of arguments. | ||
456 | |||
457 | ```rust | ||
458 | // GOOD | ||
459 | pub fn reachable_nodes(node: Node) -> FxHashSet<Node> { | ||
460 | let mut res = FxHashSet::default(); | ||
461 | go(&mut res, node); | ||
462 | res | ||
463 | } | ||
464 | fn 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 | ||
472 | pub 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 |