diff options
Diffstat (limited to 'docs/dev/README.md')
-rw-r--r-- | docs/dev/README.md | 91 |
1 files changed, 3 insertions, 88 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index 4cc608b07..9c0af68e3 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -9,8 +9,9 @@ $ cargo test | |||
9 | 9 | ||
10 | should be enough to get you started! | 10 | should be enough to get you started! |
11 | 11 | ||
12 | To learn more about how rust-analyzer works, see | 12 | To learn more about how rust-analyzer works, see [./architecture.md](./architecture.md) document. |
13 | [./architecture.md](./architecture.md) document. | 13 | It also explains the high-level layout of the source code. |
14 | Do skim through that document. | ||
14 | 15 | ||
15 | We also publish rustdoc docs to pages: | 16 | We also publish rustdoc docs to pages: |
16 | 17 | ||
@@ -99,25 +100,6 @@ I don't have a specific workflow for this case. | |||
99 | Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. | 100 | Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. |
100 | This is primarily useful for performance optimizations, or for bug minimization. | 101 | This is primarily useful for performance optimizations, or for bug minimization. |
101 | 102 | ||
102 | ## Parser Tests | ||
103 | |||
104 | Tests for the parser (`parser`) live in the `syntax` crate (see `test_data` directory). | ||
105 | There are two kinds of tests: | ||
106 | |||
107 | * Manually written test cases in `parser/ok` and `parser/err` | ||
108 | * "Inline" tests in `parser/inline` (these are generated) from comments in `parser` crate. | ||
109 | |||
110 | 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. | ||
111 | 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. | ||
112 | |||
113 | To update test data, run with `UPDATE_EXPECT` variable: | ||
114 | |||
115 | ```bash | ||
116 | env UPDATE_EXPECT=1 cargo qt | ||
117 | ``` | ||
118 | |||
119 | After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above. | ||
120 | |||
121 | ## TypeScript Tests | 103 | ## TypeScript Tests |
122 | 104 | ||
123 | If you change files under `editors/code` and would like to run the tests and linter, install npm and run: | 105 | If you change files under `editors/code` and would like to run the tests and linter, install npm and run: |
@@ -128,73 +110,6 @@ npm ci | |||
128 | npm run lint | 110 | npm run lint |
129 | ``` | 111 | ``` |
130 | 112 | ||
131 | # Code organization | ||
132 | |||
133 | All Rust code lives in the `crates` top-level directory, and is organized as a single Cargo workspace. | ||
134 | The `editors` top-level directory contains code for integrating with editors. | ||
135 | Currently, it contains the plugin for VS Code (in TypeScript). | ||
136 | The `docs` top-level directory contains both developer and user documentation. | ||
137 | |||
138 | We have some automation infra in Rust in the `xtask` package. | ||
139 | It contains stuff like formatting checking, code generation and powers `cargo xtask install`. | ||
140 | The latter syntax is achieved with the help of cargo aliases (see `.cargo` directory). | ||
141 | |||
142 | # Architecture Invariants | ||
143 | |||
144 | This section tries to document high-level design constraints, which are not | ||
145 | always obvious from the low-level code. | ||
146 | |||
147 | ## Incomplete syntax trees | ||
148 | |||
149 | Syntax trees are by design incomplete and do not enforce well-formedness. | ||
150 | If an AST method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar. | ||
151 | |||
152 | ## LSP independence | ||
153 | |||
154 | rust-analyzer is independent from LSP. | ||
155 | It provides features for a hypothetical perfect Rust-specific IDE client. | ||
156 | Internal representations are lowered to LSP in the `rust-analyzer` crate (the only crate which is allowed to use LSP types). | ||
157 | |||
158 | ## IDE/Compiler split | ||
159 | |||
160 | There's a semi-hard split between "compiler" and "IDE", at the `hir` crate. | ||
161 | Compiler derives new facts about source code. | ||
162 | It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution). | ||
163 | |||
164 | IDE assumes that all information is available at all times. | ||
165 | |||
166 | IDE should use only types from `hir`, and should not depend on the underling compiler types. | ||
167 | `hir` is a facade. | ||
168 | |||
169 | ## IDE API | ||
170 | |||
171 | The main IDE crate (`ide`) uses "Plain Old Data" for the API. | ||
172 | Rather than talking in definitions and references, it talks in Strings and textual offsets. | ||
173 | 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. | ||
174 | The results are 100% Rust specific though. | ||
175 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. | ||
176 | |||
177 | ## LSP is stateless | ||
178 | |||
179 | The protocol is implemented in the mostly stateless way. | ||
180 | A good mental model is HTTP, which doesn't store per-client state, and instead relies on devices like cookies to maintain an illusion of state. | ||
181 | If some action requires multi-step protocol, each step should be self-contained. | ||
182 | |||
183 | A good example here is code action resolving process. | ||
184 | TO display the lightbulb, we compute the list of code actions without computing edits. | ||
185 | Figuring out the edit is done in a separate `codeAction/resolve` call. | ||
186 | Rather than storing some `lazy_edit: Box<dyn FnOnce() -> Edit>` somewhere, we use a string ID of action to re-compute the list of actions during the resolve process. | ||
187 | (See [this post](https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html) for more details.) | ||
188 | The benefit here is that, generally speaking, the state of the world might change between `codeAction` and `codeAction` resolve requests, so any closure we store might become invalid. | ||
189 | |||
190 | While we don't currently implement any complicated refactors with complex GUI, I imagine we'd use the same techniques for refactors. | ||
191 | After clicking each "Next" button during refactor, the client would send all the info which server needs to re-recreate the context from scratch. | ||
192 | |||
193 | ## CI | ||
194 | |||
195 | CI does not test rust-analyzer, CI is a core part of rust-analyzer, and is maintained with above average standard of quality. | ||
196 | CI is reproducible -- it can only be broken by changes to files in this repository, any dependence on externalities is a bug. | ||
197 | |||
198 | # Code Style & Review Process | 113 | # Code Style & Review Process |
199 | 114 | ||
200 | Do see [./style.md](./style.md). | 115 | Do see [./style.md](./style.md). |