diff options
Diffstat (limited to 'docs/dev/README.md')
-rw-r--r-- | docs/dev/README.md | 117 |
1 files changed, 24 insertions, 93 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index dd2bfc493..b91013f13 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 | ||
@@ -43,6 +44,10 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | |||
43 | while unactionable ones are effectively wont-fix. Each triaged issue should have one of these labels. | 44 | while unactionable ones are effectively wont-fix. Each triaged issue should have one of these labels. |
44 | * [fun](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) | 45 | * [fun](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) |
45 | is for cool, but probably hard stuff. | 46 | is for cool, but probably hard stuff. |
47 | * [Design](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design) | ||
48 | is for moderate/large scale architecture discussion. | ||
49 | Also a kind of fun. | ||
50 | These issues should generally include a link to a Zulip discussion thread. | ||
46 | 51 | ||
47 | # CI | 52 | # CI |
48 | 53 | ||
@@ -53,8 +58,6 @@ Use `env RUN_SLOW_TESTS=1 cargo test` to run the full suite. | |||
53 | 58 | ||
54 | We use bors-ng to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule. | 59 | We use bors-ng to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule. |
55 | 60 | ||
56 | You can run `cargo xtask install-pre-commit-hook` to install git-hook to run rustfmt on commit. | ||
57 | |||
58 | # Launching rust-analyzer | 61 | # Launching rust-analyzer |
59 | 62 | ||
60 | Debugging the language server can be tricky. | 63 | Debugging the language server can be tricky. |
@@ -95,25 +98,6 @@ I don't have a specific workflow for this case. | |||
95 | Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. | 98 | Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. |
96 | This is primarily useful for performance optimizations, or for bug minimization. | 99 | This is primarily useful for performance optimizations, or for bug minimization. |
97 | 100 | ||
98 | ## Parser Tests | ||
99 | |||
100 | Tests for the parser (`parser`) live in the `syntax` crate (see `test_data` directory). | ||
101 | There are two kinds of tests: | ||
102 | |||
103 | * Manually written test cases in `parser/ok` and `parser/err` | ||
104 | * "Inline" tests in `parser/inline` (these are generated) from comments in `parser` crate. | ||
105 | |||
106 | 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. | ||
107 | 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. | ||
108 | |||
109 | To update test data, run with `UPDATE_EXPECT` variable: | ||
110 | |||
111 | ```bash | ||
112 | env UPDATE_EXPECT=1 cargo qt | ||
113 | ``` | ||
114 | |||
115 | After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above. | ||
116 | |||
117 | ## TypeScript Tests | 101 | ## TypeScript Tests |
118 | 102 | ||
119 | If you change files under `editors/code` and would like to run the tests and linter, install npm and run: | 103 | If you change files under `editors/code` and would like to run the tests and linter, install npm and run: |
@@ -124,77 +108,18 @@ npm ci | |||
124 | npm run lint | 108 | npm run lint |
125 | ``` | 109 | ``` |
126 | 110 | ||
127 | # Code organization | ||
128 | |||
129 | All Rust code lives in the `crates` top-level directory, and is organized as a single Cargo workspace. | ||
130 | The `editors` top-level directory contains code for integrating with editors. | ||
131 | Currently, it contains the plugin for VS Code (in TypeScript). | ||
132 | The `docs` top-level directory contains both developer and user documentation. | ||
133 | |||
134 | We have some automation infra in Rust in the `xtask` package. | ||
135 | It contains stuff like formatting checking, code generation and powers `cargo xtask install`. | ||
136 | The latter syntax is achieved with the help of cargo aliases (see `.cargo` directory). | ||
137 | |||
138 | # Architecture Invariants | ||
139 | |||
140 | This section tries to document high-level design constraints, which are not | ||
141 | always obvious from the low-level code. | ||
142 | |||
143 | ## Incomplete syntax trees | ||
144 | |||
145 | Syntax trees are by design incomplete and do not enforce well-formedness. | ||
146 | If an AST method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar. | ||
147 | |||
148 | ## LSP independence | ||
149 | |||
150 | rust-analyzer is independent from LSP. | ||
151 | It provides features for a hypothetical perfect Rust-specific IDE client. | ||
152 | Internal representations are lowered to LSP in the `rust-analyzer` crate (the only crate which is allowed to use LSP types). | ||
153 | |||
154 | ## IDE/Compiler split | ||
155 | |||
156 | There's a semi-hard split between "compiler" and "IDE", at the `hir` crate. | ||
157 | Compiler derives new facts about source code. | ||
158 | It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution). | ||
159 | |||
160 | IDE assumes that all information is available at all times. | ||
161 | |||
162 | IDE should use only types from `hir`, and should not depend on the underling compiler types. | ||
163 | `hir` is a facade. | ||
164 | |||
165 | ## IDE API | ||
166 | |||
167 | The main IDE crate (`ide`) uses "Plain Old Data" for the API. | ||
168 | Rather than talking in definitions and references, it talks in Strings and textual offsets. | ||
169 | 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. | ||
170 | The results are 100% Rust specific though. | ||
171 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. | ||
172 | |||
173 | ## LSP is stateless | ||
174 | |||
175 | The protocol is implemented in the mostly stateless way. | ||
176 | 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. | ||
177 | If some action requires multi-step protocol, each step should be self-contained. | ||
178 | |||
179 | A good example here is code action resolving process. | ||
180 | TO display the lightbulb, we compute the list of code actions without computing edits. | ||
181 | Figuring out the edit is done in a separate `codeAction/resolve` call. | ||
182 | 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. | ||
183 | (See [this post](https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html) for more details.) | ||
184 | 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. | ||
185 | |||
186 | While we don't currently implement any complicated refactors with complex GUI, I imagine we'd use the same techniques for refactors. | ||
187 | After clicking each "Next" button during refactor, the client would send all the info which server needs to re-recreate the context from scratch. | ||
188 | |||
189 | ## CI | ||
190 | |||
191 | CI does not test rust-analyzer, CI is a core part of rust-analyzer, and is maintained with above average standard of quality. | ||
192 | CI is reproducible -- it can only be broken by changes to files in this repository, any dependence on externalities is a bug. | ||
193 | |||
194 | # Code Style & Review Process | 111 | # Code Style & Review Process |
195 | 112 | ||
196 | Do see [./style.md](./style.md). | 113 | Do see [./style.md](./style.md). |
197 | 114 | ||
115 | # How to ... | ||
116 | |||
117 | * ... add an assist? [#7535](https://github.com/rust-analyzer/rust-analyzer/pull/7535) | ||
118 | * ... add a new protocol extension? [#4569](https://github.com/rust-analyzer/rust-analyzer/pull/4569) | ||
119 | * ... add a new configuration option? [#7451](https://github.com/rust-analyzer/rust-analyzer/pull/7451) | ||
120 | * ... add a new completion? [#6964](https://github.com/rust-analyzer/rust-analyzer/pull/6964) | ||
121 | * ... allow new syntax in the parser? [#7338](https://github.com/rust-analyzer/rust-analyzer/pull/7338) | ||
122 | |||
198 | # Logging | 123 | # Logging |
199 | 124 | ||
200 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 125 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to |
@@ -212,7 +137,7 @@ To log all communication between the server and the client, there are two choice | |||
212 | 137 | ||
213 | * you can log on the server side, by running something like | 138 | * you can log on the server side, by running something like |
214 | ``` | 139 | ``` |
215 | env RA_LOG=gen_lsp_server=trace code . | 140 | env RA_LOG=lsp_server=debug code . |
216 | ``` | 141 | ``` |
217 | 142 | ||
218 | * you can log on the client side, by enabling `"rust-analyzer.trace.server": | 143 | * you can log on the client side, by enabling `"rust-analyzer.trace.server": |
@@ -251,6 +176,9 @@ RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more tha | |||
251 | 176 | ||
252 | In particular, I have `export RA_PROFILE='*>10'` in my shell profile. | 177 | In particular, I have `export RA_PROFILE='*>10'` in my shell profile. |
253 | 178 | ||
179 | We also have a "counting" profiler which counts number of instances of popular structs. | ||
180 | It is enabled by `RA_COUNT=1`. | ||
181 | |||
254 | To measure time for from-scratch analysis, use something like this: | 182 | To measure time for from-scratch analysis, use something like this: |
255 | 183 | ||
256 | ``` | 184 | ``` |
@@ -288,13 +216,16 @@ Release steps: | |||
288 | * makes a GitHub release | 216 | * makes a GitHub release |
289 | * pushes VS Code extension to the marketplace | 217 | * pushes VS Code extension to the marketplace |
290 | * create new changelog in `rust-analyzer.github.io` | 218 | * create new changelog in `rust-analyzer.github.io` |
291 | * create `rust-analyzer.github.io/git.log` file with the log of merge commits since last release | 219 | 2. While the release is in progress, fill in the changelog |
292 | 2. While the release is in progress, fill-in the changelog using `git.log` | ||
293 | 3. Commit & push the changelog | 220 | 3. Commit & push the changelog |
294 | 4. Tweet | 221 | 4. Tweet |
295 | 5. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. | 222 | 5. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. |
296 | Self-approve the PR. | 223 | Self-approve the PR. |
297 | 224 | ||
225 | If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console. | ||
226 | If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over. | ||
227 | Make sure to remove the new changelog post created when running `cargo xtask release` a second time. | ||
228 | |||
298 | # Permissions | 229 | # Permissions |
299 | 230 | ||
300 | There are three sets of people with extra permissions: | 231 | There are three sets of people with extra permissions: |