aboutsummaryrefslogtreecommitdiff
path: root/docs/dev/README.md
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-02-02 18:59:27 +0000
committerAleksey Kladov <[email protected]>2021-02-03 11:26:23 +0000
commit1008aaae5821ce38975495c76d93b004888f2ed5 (patch)
treeee7f8e67bf73bc5acac04d775c16db9d57a4d0d8 /docs/dev/README.md
parent7e66cde76460d61cb19a19e4bb7bc1f6642e993d (diff)
Make architecture more informative
Call out boundaries and invariants
Diffstat (limited to 'docs/dev/README.md')
-rw-r--r--docs/dev/README.md91
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
10should be enough to get you started! 10should be enough to get you started!
11 11
12To learn more about how rust-analyzer works, see 12To learn more about how rust-analyzer works, see [./architecture.md](./architecture.md) document.
13[./architecture.md](./architecture.md) document. 13It also explains the high-level layout of the source code.
14Do skim through that document.
14 15
15We also publish rustdoc docs to pages: 16We also publish rustdoc docs to pages:
16 17
@@ -99,25 +100,6 @@ I don't have a specific workflow for this case.
99Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. 100Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis.
100This is primarily useful for performance optimizations, or for bug minimization. 101This is primarily useful for performance optimizations, or for bug minimization.
101 102
102## Parser Tests
103
104Tests for the parser (`parser`) live in the `syntax` crate (see `test_data` directory).
105There 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
110The 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.
111If 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
113To update test data, run with `UPDATE_EXPECT` variable:
114
115```bash
116env UPDATE_EXPECT=1 cargo qt
117```
118
119After 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
123If you change files under `editors/code` and would like to run the tests and linter, install npm and run: 105If 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
128npm run lint 110npm run lint
129``` 111```
130 112
131# Code organization
132
133All Rust code lives in the `crates` top-level directory, and is organized as a single Cargo workspace.
134The `editors` top-level directory contains code for integrating with editors.
135Currently, it contains the plugin for VS Code (in TypeScript).
136The `docs` top-level directory contains both developer and user documentation.
137
138We have some automation infra in Rust in the `xtask` package.
139It contains stuff like formatting checking, code generation and powers `cargo xtask install`.
140The latter syntax is achieved with the help of cargo aliases (see `.cargo` directory).
141
142# Architecture Invariants
143
144This section tries to document high-level design constraints, which are not
145always obvious from the low-level code.
146
147## Incomplete syntax trees
148
149Syntax trees are by design incomplete and do not enforce well-formedness.
150If 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
154rust-analyzer is independent from LSP.
155It provides features for a hypothetical perfect Rust-specific IDE client.
156Internal 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
160There's a semi-hard split between "compiler" and "IDE", at the `hir` crate.
161Compiler derives new facts about source code.
162It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution).
163
164IDE assumes that all information is available at all times.
165
166IDE 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
171The main IDE crate (`ide`) uses "Plain Old Data" for the API.
172Rather than talking in definitions and references, it talks in Strings and textual offsets.
173In 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.
174The results are 100% Rust specific though.
175Shout 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
179The protocol is implemented in the mostly stateless way.
180A 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.
181If some action requires multi-step protocol, each step should be self-contained.
182
183A good example here is code action resolving process.
184TO display the lightbulb, we compute the list of code actions without computing edits.
185Figuring out the edit is done in a separate `codeAction/resolve` call.
186Rather 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.)
188The 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
190While we don't currently implement any complicated refactors with complex GUI, I imagine we'd use the same techniques for refactors.
191After 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
195CI does not test rust-analyzer, CI is a core part of rust-analyzer, and is maintained with above average standard of quality.
196CI 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
200Do see [./style.md](./style.md). 115Do see [./style.md](./style.md).