diff options
Diffstat (limited to 'docs/dev')
-rw-r--r-- | docs/dev/README.md | 25 | ||||
-rw-r--r-- | docs/dev/architecture.md | 24 | ||||
-rw-r--r-- | docs/dev/guide.md | 66 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 8 | ||||
-rw-r--r-- | docs/dev/style.md | 51 | ||||
-rw-r--r-- | docs/dev/syntax.md | 4 |
6 files changed, 109 insertions, 69 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index 67813a9c0..36edddc70 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -14,7 +14,7 @@ To learn more about how rust-analyzer works, see | |||
14 | 14 | ||
15 | We also publish rustdoc docs to pages: | 15 | We also publish rustdoc docs to pages: |
16 | 16 | ||
17 | https://rust-analyzer.github.io/rust-analyzer/ra_ide/ | 17 | https://rust-analyzer.github.io/rust-analyzer/ide/ |
18 | 18 | ||
19 | Various organizational and process issues are discussed in this document. | 19 | Various organizational and process issues are discussed in this document. |
20 | 20 | ||
@@ -92,11 +92,11 @@ This is primarily useful for performance optimizations, or for bug minimization. | |||
92 | 92 | ||
93 | ## Parser Tests | 93 | ## Parser Tests |
94 | 94 | ||
95 | Tests for the parser (`ra_parser`) live in the `ra_syntax` crate (see `test_data` directory). | 95 | Tests for the parser (`parser`) live in the `syntax` crate (see `test_data` directory). |
96 | There are two kinds of tests: | 96 | There are two kinds of tests: |
97 | 97 | ||
98 | * Manually written test cases in `parser/ok` and `parser/err` | 98 | * Manually written test cases in `parser/ok` and `parser/err` |
99 | * "Inline" tests in `parser/inline` (these are generated) from comments in `ra_parser` crate. | 99 | * "Inline" tests in `parser/inline` (these are generated) from comments in `parser` crate. |
100 | 100 | ||
101 | The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. | 101 | The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. |
102 | If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. | 102 | If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. |
@@ -148,23 +148,28 @@ Internal representations are lowered to LSP in the `rust-analyzer` crate (the on | |||
148 | 148 | ||
149 | ## IDE/Compiler split | 149 | ## IDE/Compiler split |
150 | 150 | ||
151 | There's a semi-hard split between "compiler" and "IDE", at the `ra_hir` crate. | 151 | There's a semi-hard split between "compiler" and "IDE", at the `hir` crate. |
152 | Compiler derives new facts about source code. | 152 | Compiler derives new facts about source code. |
153 | It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution). | 153 | It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution). |
154 | 154 | ||
155 | IDE assumes that all information is available at all times. | 155 | IDE assumes that all information is available at all times. |
156 | 156 | ||
157 | IDE should use only types from `ra_hir`, and should not depend on the underling compiler types. | 157 | IDE should use only types from `hir`, and should not depend on the underling compiler types. |
158 | `ra_hir` is a facade. | 158 | `hir` is a facade. |
159 | 159 | ||
160 | ## IDE API | 160 | ## IDE API |
161 | 161 | ||
162 | The main IDE crate (`ra_ide`) uses "Plain Old Data" for the API. | 162 | The main IDE crate (`ide`) uses "Plain Old Data" for the API. |
163 | Rather than talking in definitions and references, it talks in Strings and textual offsets. | 163 | Rather than talking in definitions and references, it talks in Strings and textual offsets. |
164 | In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath. | 164 | In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath. |
165 | The results are 100% Rust specific though. | 165 | The results are 100% Rust specific though. |
166 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. | 166 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. |
167 | 167 | ||
168 | ## CI | ||
169 | |||
170 | CI does not test rust-analyzer, CI is a core part of rust-analyzer, and is maintained with above average standard of quality. | ||
171 | CI is reproducible -- it can only be broken by changes to files in this repository, any dependence on externalities is a bug. | ||
172 | |||
168 | # Code Style & Review Process | 173 | # Code Style & Review Process |
169 | 174 | ||
170 | Do see [./style.md](./style.md). | 175 | Do see [./style.md](./style.md). |
@@ -256,9 +261,9 @@ Release steps: | |||
256 | * checkout the `release` branch | 261 | * checkout the `release` branch |
257 | * reset it to `upstream/nightly` | 262 | * reset it to `upstream/nightly` |
258 | * push it to `upstream`. This triggers GitHub Actions which: | 263 | * push it to `upstream`. This triggers GitHub Actions which: |
259 | ** runs `cargo xtask dist` to package binaries and VS Code extension | 264 | * runs `cargo xtask dist` to package binaries and VS Code extension |
260 | ** makes a GitHub release | 265 | * makes a GitHub release |
261 | ** pushes VS Code extension to the marketplace | 266 | * pushes VS Code extension to the marketplace |
262 | * create new changelog in `rust-analyzer.github.io` | 267 | * create new changelog in `rust-analyzer.github.io` |
263 | * create `rust-analyzer.github.io/git.log` file with the log of merge commits since last release | 268 | * create `rust-analyzer.github.io/git.log` file with the log of merge commits since last release |
264 | 2. While the release is in progress, fill-in the changelog using `git.log` | 269 | 2. While the release is in progress, fill-in the changelog using `git.log` |
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index d0c6eea61..6f1377f2f 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -56,7 +56,7 @@ In particular, `cargo xtask codegen` generates: | |||
56 | 2. [`ast/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/src/ast/generated.rs) | 56 | 2. [`ast/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/src/ast/generated.rs) |
57 | -- AST data structure. | 57 | -- AST data structure. |
58 | 58 | ||
59 | 3. [`doc_tests/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_assists/src/doc_tests/generated.rs), | 59 | 3. [`doc_tests/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/assists/src/doc_tests/generated.rs), |
60 | [`test_data/parser/inline`](https://github.com/rust-analyzer/rust-analyzer/tree/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/test_data/parser/inline) | 60 | [`test_data/parser/inline`](https://github.com/rust-analyzer/rust-analyzer/tree/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/test_data/parser/inline) |
61 | -- tests for assists and the parser. | 61 | -- tests for assists and the parser. |
62 | 62 | ||
@@ -64,7 +64,7 @@ The source for 1 and 2 is in [`ast_src.rs`](https://github.com/rust-analyzer/rus | |||
64 | 64 | ||
65 | ## Code Walk-Through | 65 | ## Code Walk-Through |
66 | 66 | ||
67 | ### `crates/ra_syntax`, `crates/ra_parser` | 67 | ### `crates/ra_syntax`, `crates/parser` |
68 | 68 | ||
69 | Rust syntax tree structure and parser. See | 69 | Rust syntax tree structure and parser. See |
70 | [RFC](https://github.com/rust-lang/rfcs/pull/2256) and [./syntax.md](./syntax.md) for some design notes. | 70 | [RFC](https://github.com/rust-lang/rfcs/pull/2256) and [./syntax.md](./syntax.md) for some design notes. |
@@ -92,17 +92,17 @@ in particular: it shows off various methods of working with syntax tree. | |||
92 | See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which | 92 | See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which |
93 | fixes a bug in the grammar. | 93 | fixes a bug in the grammar. |
94 | 94 | ||
95 | ### `crates/ra_db` | 95 | ### `crates/base_db` |
96 | 96 | ||
97 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and | 97 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and |
98 | on-demand computation. Roughly, you can think of salsa as a key-value store, but | 98 | on-demand computation. Roughly, you can think of salsa as a key-value store, but |
99 | it also can compute derived values using specified functions. The `ra_db` crate | 99 | it also can compute derived values using specified functions. The `base_db` crate |
100 | provides basic infrastructure for interacting with salsa. Crucially, it | 100 | provides basic infrastructure for interacting with salsa. Crucially, it |
101 | defines most of the "input" queries: facts supplied by the client of the | 101 | defines most of the "input" queries: facts supplied by the client of the |
102 | analyzer. Reading the docs of the `ra_db::input` module should be useful: | 102 | analyzer. Reading the docs of the `base_db::input` module should be useful: |
103 | everything else is strictly derived from those inputs. | 103 | everything else is strictly derived from those inputs. |
104 | 104 | ||
105 | ### `crates/ra_hir*` crates | 105 | ### `crates/hir*` crates |
106 | 106 | ||
107 | HIR provides high-level "object oriented" access to Rust code. | 107 | HIR provides high-level "object oriented" access to Rust code. |
108 | 108 | ||
@@ -113,12 +113,12 @@ is responsible for guessing a HIR for a particular source position. | |||
113 | 113 | ||
114 | Underneath, HIR works on top of salsa, using a `HirDatabase` trait. | 114 | Underneath, HIR works on top of salsa, using a `HirDatabase` trait. |
115 | 115 | ||
116 | `ra_hir_xxx` crates have a strong ECS flavor, in that they work with raw ids and | 116 | `hir_xxx` crates have a strong ECS flavor, in that they work with raw ids and |
117 | directly query the database. | 117 | directly query the database. |
118 | 118 | ||
119 | The top-level `ra_hir` façade crate wraps ids into a more OO-flavored API. | 119 | The top-level `hir` façade crate wraps ids into a more OO-flavored API. |
120 | 120 | ||
121 | ### `crates/ra_ide` | 121 | ### `crates/ide` |
122 | 122 | ||
123 | A stateful library for analyzing many Rust files as they change. `AnalysisHost` | 123 | A stateful library for analyzing many Rust files as they change. `AnalysisHost` |
124 | is a mutable entity (clojure's atom) which holds the current state, incorporates | 124 | is a mutable entity (clojure's atom) which holds the current state, incorporates |
@@ -136,11 +136,11 @@ offsets and strings as output. This works on top of rich code model powered by | |||
136 | 136 | ||
137 | ### `crates/rust-analyzer` | 137 | ### `crates/rust-analyzer` |
138 | 138 | ||
139 | An LSP implementation which wraps `ra_ide` into a language server protocol. | 139 | An LSP implementation which wraps `ide` into a language server protocol. |
140 | 140 | ||
141 | ### `ra_vfs` | 141 | ### `ra_vfs` |
142 | 142 | ||
143 | Although `hir` and `ra_ide` don't do any IO, we need to be able to read | 143 | Although `hir` and `ide` don't do any IO, we need to be able to read |
144 | files from disk at the end of the day. This is what `ra_vfs` does. It also | 144 | files from disk at the end of the day. This is what `ra_vfs` does. It also |
145 | manages overlays: "dirty" files in the editor, whose "true" contents is | 145 | manages overlays: "dirty" files in the editor, whose "true" contents is |
146 | different from data on disk. This is more or less the single really | 146 | different from data on disk. This is more or less the single really |
@@ -161,7 +161,7 @@ disk. For this reason, we try to avoid writing too many tests on this boundary: | |||
161 | in a statically typed language, it's hard to make an error in the protocol | 161 | in a statically typed language, it's hard to make an error in the protocol |
162 | itself if messages are themselves typed. | 162 | itself if messages are themselves typed. |
163 | 163 | ||
164 | The middle, and most important, boundary is `ra_ide`. Unlike | 164 | The middle, and most important, boundary is `ide`. Unlike |
165 | `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended to | 165 | `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended to |
166 | use by various tools. Typical test creates an `AnalysisHost`, calls some | 166 | use by various tools. Typical test creates an `AnalysisHost`, calls some |
167 | `Analysis` functions and compares the results against expectation. | 167 | `Analysis` functions and compares the results against expectation. |
diff --git a/docs/dev/guide.md b/docs/dev/guide.md index c3252f1f6..b5a5d7c93 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md | |||
@@ -40,8 +40,8 @@ terms of files and offsets, and **not** in terms of Rust concepts like structs, | |||
40 | traits, etc. The "typed" API with Rust specific types is slightly lower in the | 40 | traits, etc. The "typed" API with Rust specific types is slightly lower in the |
41 | stack, we'll talk about it later. | 41 | stack, we'll talk about it later. |
42 | 42 | ||
43 | [`AnalysisHost`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284 | 43 | [`AnalysisHost`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L265-L284 |
44 | [`Analysis`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478 | 44 | [`Analysis`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L291-L478 |
45 | 45 | ||
46 | The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply | 46 | The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply |
47 | changes "uniquely", but we might also want to fork an `Analysis` and send it to | 47 | changes "uniquely", but we might also want to fork an `Analysis` and send it to |
@@ -69,7 +69,7 @@ the `AnalysisHost::apply_change` method, which accepts a single argument, a | |||
69 | "transaction", so it suffices to study its methods to understand all of the | 69 | "transaction", so it suffices to study its methods to understand all of the |
70 | input data. | 70 | input data. |
71 | 71 | ||
72 | [`AnalysisChange`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L119-L167 | 72 | [`AnalysisChange`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L119-L167 |
73 | 73 | ||
74 | The `(add|change|remove)_file` methods control the set of the input files, where | 74 | The `(add|change|remove)_file` methods control the set of the input files, where |
75 | each file has an integer id (`FileId`, picked by the client), text (`String`) | 75 | each file has an integer id (`FileId`, picked by the client), text (`String`) |
@@ -253,13 +253,13 @@ All analyzer information is stored in a salsa database. `Analysis` and | |||
253 | `AnalysisHost` types are newtype wrappers for [`RootDatabase`] -- a salsa | 253 | `AnalysisHost` types are newtype wrappers for [`RootDatabase`] -- a salsa |
254 | database. | 254 | database. |
255 | 255 | ||
256 | [`RootDatabase`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/db.rs#L88-L134 | 256 | [`RootDatabase`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/db.rs#L88-L134 |
257 | 257 | ||
258 | Salsa input queries are defined in [`FilesDatabase`] (which is a part of | 258 | Salsa input queries are defined in [`FilesDatabase`] (which is a part of |
259 | `RootDatabase`). They closely mirror the familiar `AnalysisChange` structure: | 259 | `RootDatabase`). They closely mirror the familiar `AnalysisChange` structure: |
260 | indeed, what `apply_change` does is it sets the values of input queries. | 260 | indeed, what `apply_change` does is it sets the values of input queries. |
261 | 261 | ||
262 | [`FilesDatabase`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_db/src/input.rs#L150-L174 | 262 | [`FilesDatabase`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/base_db/src/input.rs#L150-L174 |
263 | 263 | ||
264 | ## From text to semantic model | 264 | ## From text to semantic model |
265 | 265 | ||
@@ -275,7 +275,7 @@ several times, with different sets of `cfg`s enabled. The IDE-specific task of | |||
275 | mapping source code position into a semantic model is inherently imprecise for | 275 | mapping source code position into a semantic model is inherently imprecise for |
276 | this reason, and is handled by the [`source_binder`]. | 276 | this reason, and is handled by the [`source_binder`]. |
277 | 277 | ||
278 | [`source_binder`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/source_binder.rs | 278 | [`source_binder`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/source_binder.rs |
279 | 279 | ||
280 | The semantic interface is declared in the [`code_model_api`] module. Each entity is | 280 | The semantic interface is declared in the [`code_model_api`] module. Each entity is |
281 | identified by an integer ID and has a bunch of methods which take a salsa database | 281 | identified by an integer ID and has a bunch of methods which take a salsa database |
@@ -283,8 +283,8 @@ as an argument and returns other entities (which are also IDs). Internally, thes | |||
283 | methods invoke various queries on the database to build the model on demand. | 283 | methods invoke various queries on the database to build the model on demand. |
284 | Here's [the list of queries]. | 284 | Here's [the list of queries]. |
285 | 285 | ||
286 | [`code_model_api`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/code_model_api.rs | 286 | [`code_model_api`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/code_model_api.rs |
287 | [the list of queries]: https://github.com/rust-analyzer/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/ra_hir/src/db.rs#L20-L106 | 287 | [the list of queries]: https://github.com/rust-analyzer/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/hir/src/db.rs#L20-L106 |
288 | 288 | ||
289 | The first step of building the model is parsing the source code. | 289 | The first step of building the model is parsing the source code. |
290 | 290 | ||
@@ -341,7 +341,7 @@ The algorithm for building a tree of modules is to start with a crate root | |||
341 | declarations and recursively process child modules. This is handled by the | 341 | declarations and recursively process child modules. This is handled by the |
342 | [`module_tree_query`], with two slight variations. | 342 | [`module_tree_query`], with two slight variations. |
343 | 343 | ||
344 | [`module_tree_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L116-L123 | 344 | [`module_tree_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L116-L123 |
345 | 345 | ||
346 | First, rust-analyzer builds a module tree for all crates in a source root | 346 | First, rust-analyzer builds a module tree for all crates in a source root |
347 | simultaneously. The main reason for this is historical (`module_tree` predates | 347 | simultaneously. The main reason for this is historical (`module_tree` predates |
@@ -364,7 +364,7 @@ the same, we don't have to re-execute [`module_tree_query`]. In fact, we only | |||
364 | need to re-execute it when we add/remove new files or when we change mod | 364 | need to re-execute it when we add/remove new files or when we change mod |
365 | declarations. | 365 | declarations. |
366 | 366 | ||
367 | [`submodules_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L41 | 367 | [`submodules_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L41 |
368 | 368 | ||
369 | We store the resulting modules in a `Vec`-based indexed arena. The indices in | 369 | We store the resulting modules in a `Vec`-based indexed arena. The indices in |
370 | the arena becomes module IDs. And this brings us to the next topic: | 370 | the arena becomes module IDs. And this brings us to the next topic: |
@@ -392,8 +392,8 @@ integers which can "intern" a location and return an integer ID back. The salsa | |||
392 | database we use includes a couple of [interners]. How to "garbage collect" | 392 | database we use includes a couple of [interners]. How to "garbage collect" |
393 | unused locations is an open question. | 393 | unused locations is an open question. |
394 | 394 | ||
395 | [`LocationInterner`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_db/src/loc2id.rs#L65-L71 | 395 | [`LocationInterner`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/base_db/src/loc2id.rs#L65-L71 |
396 | [interners]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23 | 396 | [interners]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/db.rs#L22-L23 |
397 | 397 | ||
398 | For example, we use `LocationInterner` to assign IDs to definitions of functions, | 398 | For example, we use `LocationInterner` to assign IDs to definitions of functions, |
399 | structs, enums, etc. The location, [`DefLoc`] contains two bits of information: | 399 | structs, enums, etc. The location, [`DefLoc`] contains two bits of information: |
@@ -407,7 +407,7 @@ using offsets, text ranges or syntax trees as keys and values for queries. What | |||
407 | we do instead is we store "index" of the item among all of the items of a file | 407 | we do instead is we store "index" of the item among all of the items of a file |
408 | (so, a positional based ID, but localized to a single file). | 408 | (so, a positional based ID, but localized to a single file). |
409 | 409 | ||
410 | [`DefLoc`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L127-L139 | 410 | [`DefLoc`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L127-L139 |
411 | 411 | ||
412 | One thing we've glossed over for the time being is support for macros. We have | 412 | One thing we've glossed over for the time being is support for macros. We have |
413 | only proof of concept handling of macros at the moment, but they are extremely | 413 | only proof of concept handling of macros at the moment, but they are extremely |
@@ -440,7 +440,7 @@ terms of `HirFileId`! This does not recur infinitely though: any chain of | |||
440 | `HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file | 440 | `HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file |
441 | actually written by the user. | 441 | actually written by the user. |
442 | 442 | ||
443 | [`HirFileId`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L18-L125 | 443 | [`HirFileId`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L18-L125 |
444 | 444 | ||
445 | Now that we understand how to identify a definition, in a source or in a | 445 | Now that we understand how to identify a definition, in a source or in a |
446 | macro-generated file, we can discuss name resolution a bit. | 446 | macro-generated file, we can discuss name resolution a bit. |
@@ -454,14 +454,14 @@ each module into a position-independent representation which does not change if | |||
454 | we modify bodies of the items. After that we [loop] resolving all imports until | 454 | we modify bodies of the items. After that we [loop] resolving all imports until |
455 | we've reached a fixed point. | 455 | we've reached a fixed point. |
456 | 456 | ||
457 | [lower]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L117 | 457 | [lower]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L113-L117 |
458 | [loop]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres.rs#L186-L196 | 458 | [loop]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres.rs#L186-L196 |
459 | 459 | ||
460 | And, given all our preparation with IDs and a position-independent representation, | 460 | And, given all our preparation with IDs and a position-independent representation, |
461 | it is satisfying to [test] that typing inside function body does not invalidate | 461 | it is satisfying to [test] that typing inside function body does not invalidate |
462 | name resolution results. | 462 | name resolution results. |
463 | 463 | ||
464 | [test]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/tests.rs#L376 | 464 | [test]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/tests.rs#L376 |
465 | 465 | ||
466 | An interesting fact about name resolution is that it "erases" all of the | 466 | An interesting fact about name resolution is that it "erases" all of the |
467 | intermediate paths from the imports: in the end, we know which items are defined | 467 | intermediate paths from the imports: in the end, we know which items are defined |
@@ -496,10 +496,10 @@ there's an intermediate [projection query] which returns only the first | |||
496 | position-independent part of the lowering. The result of this query is stable. | 496 | position-independent part of the lowering. The result of this query is stable. |
497 | Naturally, name resolution [uses] this stable projection query. | 497 | Naturally, name resolution [uses] this stable projection query. |
498 | 498 | ||
499 | [imports]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59 | 499 | [imports]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59 |
500 | [`SourceMap`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59 | 500 | [`SourceMap`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59 |
501 | [projection query]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L97-L103 | 501 | [projection query]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L97-L103 |
502 | [uses]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/query_definitions.rs#L49 | 502 | [uses]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/query_definitions.rs#L49 |
503 | 503 | ||
504 | ## Type inference | 504 | ## Type inference |
505 | 505 | ||
@@ -521,10 +521,10 @@ construct a mapping from `ExprId`s to types. | |||
521 | 521 | ||
522 | [@flodiebold]: https://github.com/flodiebold | 522 | [@flodiebold]: https://github.com/flodiebold |
523 | [#327]: https://github.com/rust-analyzer/rust-analyzer/pull/327 | 523 | [#327]: https://github.com/rust-analyzer/rust-analyzer/pull/327 |
524 | [lower the AST]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs | 524 | [lower the AST]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs |
525 | [positional ID]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L13-L15 | 525 | [positional ID]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L13-L15 |
526 | [a source map]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L41-L44 | 526 | [a source map]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L41-L44 |
527 | [type inference]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ty.rs#L1208-L1223 | 527 | [type inference]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/ty.rs#L1208-L1223 |
528 | 528 | ||
529 | ## Tying it all together: completion | 529 | ## Tying it all together: completion |
530 | 530 | ||
@@ -565,11 +565,11 @@ the type to completion. | |||
565 | [schedule it on the threadpool]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L428 | 565 | [schedule it on the threadpool]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L428 |
566 | [catch]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442 | 566 | [catch]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442 |
567 | [the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps | 567 | [the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps |
568 | [ask analysis for completion]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L439-L444 | 568 | [ask analysis for completion]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L439-L444 |
569 | [completion implementation]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L46-L62 | 569 | [completion implementation]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L46-L62 |
570 | [`CompletionContext`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L14-L37 | 570 | [`CompletionContext`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L14-L37 |
571 | ["IntelliJ Trick"]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L72-L75 | 571 | ["IntelliJ Trick"]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L72-L75 |
572 | [find an ancestor `fn` node]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L116-L120 | 572 | [find an ancestor `fn` node]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L116-L120 |
573 | [semantic model]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L123 | 573 | [semantic model]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L123 |
574 | [series of independent completion routines]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L52-L59 | 574 | [series of independent completion routines]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L52-L59 |
575 | [`complete_dot`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/complete_dot.rs#L6-L22 | 575 | [`complete_dot`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/complete_dot.rs#L6-L22 |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 1be01fd88..2e3133449 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -412,7 +412,13 @@ Reloads project information (that is, re-executes `cargo metadata`). | |||
412 | 412 | ||
413 | **Method:** `rust-analyzer/status` | 413 | **Method:** `rust-analyzer/status` |
414 | 414 | ||
415 | **Notification:** `"loading" | "ready" | "invalid" | "needsReload"` | 415 | **Notification:** |
416 | |||
417 | ```typescript | ||
418 | interface StatusParams { | ||
419 | status: "loading" | "ready" | "invalid" | "needsReload", | ||
420 | } | ||
421 | ``` | ||
416 | 422 | ||
417 | This notification is sent from server to client. | 423 | This notification is sent from server to client. |
418 | The client can use it to display persistent status to the user (in modline). | 424 | The client can use it to display persistent status to the user (in modline). |
diff --git a/docs/dev/style.md b/docs/dev/style.md index 1c68f5702..8effddcda 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -65,7 +65,7 @@ There are many benefits to this: | |||
65 | It also makes sense to format snippets more compactly (for example, by placing enum definitions like `enum E { Foo, Bar }` on a single line), | 65 | It also makes sense to format snippets more compactly (for example, by placing enum definitions like `enum E { Foo, Bar }` on a single line), |
66 | as long as they are still readable. | 66 | as long as they are still readable. |
67 | 67 | ||
68 | ## Order of Imports | 68 | # Order of Imports |
69 | 69 | ||
70 | Separate import groups with blank lines. | 70 | Separate import groups with blank lines. |
71 | Use one `use` per crate. | 71 | Use one `use` per crate. |
@@ -91,19 +91,19 @@ use super::{} | |||
91 | Module declarations come before the imports. | 91 | Module declarations come before the imports. |
92 | Order them in "suggested reading order" for a person new to the code base. | 92 | Order them in "suggested reading order" for a person new to the code base. |
93 | 93 | ||
94 | ## Import Style | 94 | # Import Style |
95 | 95 | ||
96 | Qualify items from `hir` and `ast`. | 96 | Qualify items from `hir` and `ast`. |
97 | 97 | ||
98 | ```rust | 98 | ```rust |
99 | // Good | 99 | // Good |
100 | use ra_syntax::ast; | 100 | use syntax::ast; |
101 | 101 | ||
102 | fn frobnicate(func: hir::Function, strukt: ast::StructDef) {} | 102 | fn frobnicate(func: hir::Function, strukt: ast::StructDef) {} |
103 | 103 | ||
104 | // Not as good | 104 | // Not as good |
105 | use hir::Function; | 105 | use hir::Function; |
106 | use ra_syntax::ast::StructDef; | 106 | use syntax::ast::StructDef; |
107 | 107 | ||
108 | fn frobnicate(func: Function, strukt: StructDef) {} | 108 | fn frobnicate(func: Function, strukt: StructDef) {} |
109 | ``` | 109 | ``` |
@@ -112,7 +112,7 @@ Avoid local `use MyEnum::*` imports. | |||
112 | 112 | ||
113 | Prefer `use crate::foo::bar` to `use super::bar`. | 113 | Prefer `use crate::foo::bar` to `use super::bar`. |
114 | 114 | ||
115 | ## Order of Items | 115 | # Order of Items |
116 | 116 | ||
117 | Optimize for the reader who sees the file for the first time, and wants to get a general idea about what's going on. | 117 | Optimize for the reader who sees the file for the first time, and wants to get a general idea about what's going on. |
118 | People read things from top to bottom, so place most important things first. | 118 | People read things from top to bottom, so place most important things first. |
@@ -143,7 +143,7 @@ struct Foo { | |||
143 | } | 143 | } |
144 | ``` | 144 | ``` |
145 | 145 | ||
146 | ## Variable Naming | 146 | # Variable Naming |
147 | 147 | ||
148 | Use boring and long names for local variables ([yay code completion](https://github.com/rust-analyzer/rust-analyzer/pull/4162#discussion_r417130973)). | 148 | Use boring and long names for local variables ([yay code completion](https://github.com/rust-analyzer/rust-analyzer/pull/4162#discussion_r417130973)). |
149 | The default name is a lowercased name of the type: `global_state: GlobalState`. | 149 | The default name is a lowercased name of the type: `global_state: GlobalState`. |
@@ -151,12 +151,12 @@ Avoid ad-hoc acronyms and contractions, but use the ones that exist consistently | |||
151 | The default name for "result of the function" local variable is `res`. | 151 | The default name for "result of the function" local variable is `res`. |
152 | The default name for "I don't really care about the name" variable is `it`. | 152 | The default name for "I don't really care about the name" variable is `it`. |
153 | 153 | ||
154 | ## Collection types | 154 | # Collection types |
155 | 155 | ||
156 | Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. | 156 | Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. |
157 | They use a hasher that's slightly faster and using them consistently will reduce code size by some small amount. | 157 | They use a hasher that's slightly faster and using them consistently will reduce code size by some small amount. |
158 | 158 | ||
159 | ## Preconditions | 159 | # Preconditions |
160 | 160 | ||
161 | Express function preconditions in types and force the caller to provide them (rather than checking in callee): | 161 | Express function preconditions in types and force the caller to provide them (rather than checking in callee): |
162 | 162 | ||
@@ -176,7 +176,36 @@ fn frobnicate(walrus: Option<Walrus>) { | |||
176 | } | 176 | } |
177 | ``` | 177 | ``` |
178 | 178 | ||
179 | ## Premature Pessimization | 179 | # Getters & Setters |
180 | |||
181 | If a field can have any value without breaking invariants, make the field public. | ||
182 | Conversely, if there is an invariant, document it, enforce it in the "constructor" function, make the field private, and provide a getter. | ||
183 | Never provide setters. | ||
184 | |||
185 | Getters should return borrowed data: | ||
186 | |||
187 | ``` | ||
188 | struct Person { | ||
189 | // Invariant: never empty | ||
190 | first_name: String, | ||
191 | middle_name: Option<String> | ||
192 | } | ||
193 | |||
194 | // Good | ||
195 | impl Person { | ||
196 | fn first_name(&self) -> &str { self.first_name.as_str() } | ||
197 | fn middle_name(&self) -> Option<&str> { self.middle_name.as_ref() } | ||
198 | } | ||
199 | |||
200 | // Not as good | ||
201 | impl Person { | ||
202 | fn first_name(&self) -> String { self.first_name.clone() } | ||
203 | fn middle_name(&self) -> &Option<String> { &self.middle_name } | ||
204 | } | ||
205 | ``` | ||
206 | |||
207 | |||
208 | # Premature Pessimization | ||
180 | 209 | ||
181 | Avoid writing code which is slower than it needs to be. | 210 | Avoid writing code which is slower than it needs to be. |
182 | Don't allocate a `Vec` where an iterator would do, don't allocate strings needlessly. | 211 | Don't allocate a `Vec` where an iterator would do, don't allocate strings needlessly. |
@@ -197,12 +226,12 @@ if words.len() != 2 { | |||
197 | } | 226 | } |
198 | ``` | 227 | ``` |
199 | 228 | ||
200 | ## Documentation | 229 | # Documentation |
201 | 230 | ||
202 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. | 231 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. |
203 | If the line is too long, you want to split the sentence in two :-) | 232 | If the line is too long, you want to split the sentence in two :-) |
204 | 233 | ||
205 | ## Commit Style | 234 | # Commit Style |
206 | 235 | ||
207 | We don't have specific rules around git history hygiene. | 236 | We don't have specific rules around git history hygiene. |
208 | Maintaining clean git history is encouraged, but not enforced. | 237 | Maintaining clean git history is encouraged, but not enforced. |
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index d4bc4b07c..c08062ef4 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md | |||
@@ -11,7 +11,7 @@ The things described are implemented in two places | |||
11 | * [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees. | 11 | * [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees. |
12 | * [ra_syntax](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API. | 12 | * [ra_syntax](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API. |
13 | Nothing in rust-analyzer except this crate knows about `rowan`. | 13 | Nothing in rust-analyzer except this crate knows about `rowan`. |
14 | * [ra_parser](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_parser) crate parses input tokens into an `ra_syntax` tree | 14 | * [parser](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/parser) crate parses input tokens into an `ra_syntax` tree |
15 | 15 | ||
16 | ## Design Goals | 16 | ## Design Goals |
17 | 17 | ||
@@ -74,7 +74,7 @@ Points of note: | |||
74 | * The original text can be recovered by concatenating the texts of all tokens in order. | 74 | * The original text can be recovered by concatenating the texts of all tokens in order. |
75 | * Accessing a child of particular type (for example, parameter list of a function) generally involves linerary traversing the children, looking for a specific `kind`. | 75 | * Accessing a child of particular type (for example, parameter list of a function) generally involves linerary traversing the children, looking for a specific `kind`. |
76 | * Modifying the tree is roughly `O(depth)`. | 76 | * Modifying the tree is roughly `O(depth)`. |
77 | We don't make special efforts to guarantree that the depth is not liner, but, in practice, syntax trees are branchy and shallow. | 77 | We don't make special efforts to guarantee that the depth is not linear, but, in practice, syntax trees are branchy and shallow. |
78 | * If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. | 78 | * If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. |
79 | * If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. | 79 | * If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. |
80 | * Parser errors are not a part of syntax tree. | 80 | * Parser errors are not a part of syntax tree. |