Skip to content

Commit 85c1586

Browse files
alanzmeta-codesync[bot]
authored andcommitted
Add initial CLAUDE.md
Summary: As title. Also tweak elp_development.md Reviewed By: TheGeorge Differential Revision: D86507504 fbshipit-source-id: 0c3d92728014914c2954e1201d9da8fca56c19c0
1 parent 6f2ee22 commit 85c1586

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

elp_development.md

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
---
2+
llms-gk: 'devmate_elp_development_md'
3+
apply_to_regex: '^(.*\.rs|.*\.md)$'
4+
oncalls: ['vscode_erlang']
5+
---
6+
# ELP Development Rules for LLMs (OSS)
7+
8+
## Project Overview
9+
10+
ELP (Erlang Language Platform) is a language server and development tools suite
11+
for Erlang, built in Rust. This project provides IDE features, diagnostics, and
12+
code analysis for Erlang codebases.
13+
14+
## Diagnostic Code Management
15+
16+
### Adding New Diagnostic Codes
17+
18+
When adding new diagnostic codes to `DiagnosticCode` enum:
19+
20+
1. **Naming Convention**: Use descriptive PascalCase names that clearly indicate
21+
the issue
22+
- Good: `UnusedFunctionArg`, `MissingCompileWarnMissingSpec`
23+
- Bad: `Error1`, `BadCode`
24+
25+
2. **Code Assignment**: Follow the established numbering scheme
26+
- `W0000-W9999`: Native ELP diagnostics, visible in the OSS version
27+
- Use the next available number in the appropriate range
28+
- Never change the number of an existing diagnostic code
29+
- Never change the label of an existing diagnostic code
30+
- Always add the new diagnostic constructor to the end of the list
31+
32+
3. **Required Methods**: When adding a new variant, update ALL match statements:
33+
- `as_code()`: Return the diagnostic code (e.g., "W0053")
34+
- `as_label()`: Return snake_case label (e.g., "unused_function_arg")
35+
- `allows_fixme_comment()`: Determine if FIXME comments are allowed
36+
- `is_syntax_error()`: Mark if this is a syntax error
37+
38+
4. **Documentation**: Add comments explaining complex diagnostic codes
39+
40+
5. **Documentation File**: Create a corresponding documentation file in the
41+
website
42+
- Location: `website/docs/erlang-error-index/{namespace}/{code}.md`
43+
- Example: `W0051``website/docs/erlang-error-index/w/W0051.md`
44+
- Include frontmatter with `sidebar_position` matching the code number
45+
- Structure should include:
46+
- Title with code and brief description
47+
- Severity level (Error, Warning, WeakWarning, Information)
48+
- Code example showing the diagnostic in action
49+
- Explanation section describing the issue and why it matters
50+
- Optional: Fix suggestions or alternatives
51+
- The `as_uri()` method automatically generates URLs pointing to these docs
52+
53+
### Creating DiagnosticDescriptor
54+
55+
Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines
56+
when and how the diagnostic runs:
57+
58+
1. **Static Descriptor Declaration**: Create a public static descriptor in your
59+
diagnostic module
60+
- Use `pub(crate) static DESCRIPTOR: DiagnosticDescriptor` pattern
61+
- Define `DiagnosticConditions` with appropriate flags
62+
- Provide a checker function that implements the diagnostic logic
63+
64+
2. **Diagnostic Conditions**: Configure when the diagnostic should run
65+
- `experimental`: Mark as true for experimental/unstable diagnostics
66+
- `include_generated`: Set to false if diagnostic shouldn't run on generated
67+
code
68+
- `include_tests`: Set to false if diagnostic shouldn't run on test files
69+
- `default_disabled`: Set to true if diagnostic requires explicit enabling
70+
71+
3. **Checker Function**: Implement the diagnostic logic
72+
- Must match signature: `&dyn AdhocSemanticDiagnostics`
73+
- Push diagnostics to the `diags` vector using `Diagnostic::new()`
74+
- Use helper functions to keep the checker clean and focused
75+
76+
4. **Registration**: Add the descriptor to `diagnostics_descriptors()` function
77+
in `diagnostics.rs`
78+
- Include your module's `DESCRIPTOR` in the returned vector
79+
80+
5. **Module Structure**: Follow the established pattern
81+
- Create separate module files for each diagnostic type
82+
- Export the `DESCRIPTOR` as `pub(crate) static`
83+
- Include comprehensive tests with `#[cfg(test)]`
84+
- Use SSR patterns when appropriate for complex matching
85+
86+
## Rust Code Style
87+
88+
### Error Handling
89+
90+
- Use `Result<T, E>` for fallible operations
91+
- Prefer `?` operator over explicit match for error propagation
92+
- Use descriptive error messages with context
93+
94+
### Pattern Matching
95+
96+
- Use exhaustive matches for enums to catch new variants at compile time
97+
- Add explicit comments when intentionally using catch-all patterns
98+
- Prefer early returns to reduce nesting
99+
100+
### String Handling
101+
102+
- Use `&str` for borrowed strings, `String` for owned
103+
- Use `format!()` for complex string formatting
104+
- Use `to_string()` for simple conversions
105+
106+
### Collections
107+
108+
- Use `FxHashMap` instead of `std::HashMap` for better performance
109+
- Use `lazy_static!` for expensive static computations
110+
- Prefer iterators over manual loops where possible
111+
112+
## Testing Guidelines
113+
114+
### Test Structure
115+
116+
- Use `expect_test` for snapshot testing of complex outputs
117+
- Group related tests in the same module
118+
- Use descriptive test names that explain the scenario
119+
120+
### Declarative Test Fixtures
121+
122+
ELP uses a declarative test fixture system that allows you to write tests with
123+
inline annotations and markers directly in test strings. This system is defined
124+
in `crates/project_model/src/test_fixture.rs`.
125+
126+
#### Key Features
127+
128+
1. **File Organization**: Use `//- /path/to/file.erl` to define multiple files
129+
in a single test
130+
2. **Metadata Markers**: Specify app names, include paths, OTP apps, etc. using
131+
metadata after the path
132+
3. **Annotations**: Mark expected diagnostics or ranges using `%% ^^^` syntax
133+
4. **Cursors and Ranges**: Use `~` markers to indicate positions or ranges in
134+
test code
135+
136+
#### Annotation Syntax
137+
138+
Annotations allow you to mark expected diagnostics, types, or other information
139+
directly in test code:
140+
141+
- **Basic annotation**: `%% ^^^ some text` - Points to the range above matching
142+
the caret length
143+
- **Top-of-file marker**: `%% <<< text` (at file start) - Creates annotation at
144+
position 0..0
145+
- **File-wide annotation**: `%% ^^^file text` - Annotation spans the entire file
146+
contents
147+
- **Left-margin annotation**: `%%<^^^ text` - Annotation starts at `%%` position
148+
instead of first `^`
149+
- **Multiline annotations**: Use continuation lines with `%% | next line`
150+
151+
#### Example Test Fixture
152+
153+
```rust
154+
let fixture = r#"
155+
//- /src/main.erl
156+
-module(main).
157+
158+
foo(X) ->
159+
X + undefined.
160+
%% ^^^^^^^^^ error: type mismatch
161+
"#;
162+
```
163+
164+
### Test Data
165+
166+
- Create minimal test cases that focus on specific functionality
167+
- Use realistic Erlang code examples in tests
168+
- Test both positive and negative cases
169+
170+
### Running Tests for Specific Crates
171+
172+
When running tests for a specific crate, you need to specify the crate name, not
173+
the directory name. The mapping is:
174+
175+
| Crate Name | Directory Name |
176+
| -------------------- | ----------------------- |
177+
| `elp` | `crates/elp` |
178+
| `elp_base_db` | `crates/base_db` |
179+
| `elp_eqwalizer` | `crates/eqwalizer` |
180+
| `elp_erlang_service` | `crates/erlang_service` |
181+
| `elp_ide` | `crates/ide` |
182+
| `elp_ide_assists` | `crates/ide_assists` |
183+
| `elp_ide_completion` | `crates/ide_completion` |
184+
| `elp_ide_db` | `crates/ide_db` |
185+
| `elp_ide_ssr` | `crates/ide_ssr` |
186+
| `elp_log` | `crates/elp_log` |
187+
| `elp_project_model` | `crates/project_model` |
188+
| `elp_syntax` | `crates/syntax` |
189+
| `elp_text_edit` | `crates/text_edit` |
190+
| `elp_types_db` | `crates/types_db` |
191+
| `hir` | `crates/hir` |
192+
193+
Example: To run tests for the `elp_ide` crate:
194+
195+
```bash
196+
cargo test -p elp_ide
197+
```
198+
199+
Or to run tests in a specific directory:
200+
201+
```bash
202+
cargo test --manifest-path crates/ide/Cargo.toml
203+
```
204+
205+
### Existing tests
206+
207+
- Do not change existing tests without asking
208+
209+
## Documentation
210+
211+
### Code Comments
212+
213+
- Document complex algorithms and business logic
214+
- Explain WHY, not just WHAT the code does
215+
- Use `///` for public API documentation
216+
- Use `//` for internal implementation notes
217+
218+
### Error Messages
219+
220+
- Make error messages actionable and user-friendly
221+
- Include context about what was expected vs. what was found
222+
- Provide suggestions for fixing the issue when possible
223+
224+
## Performance Considerations
225+
226+
### Memory Usage
227+
228+
- Use `Box<T>` for large enum variants to keep enum size small
229+
- Consider using `Cow<str>` for strings that might be borrowed or owned
230+
- Use `Arc<T>` for shared immutable data
231+
232+
### Computation
233+
234+
- Cache expensive computations using `lazy_static!` or `once_cell`
235+
- Use appropriate data structures (HashMap for lookups, Vec for sequences)
236+
- Profile code paths that handle large Erlang codebases
237+
238+
## Integration Guidelines
239+
240+
### Erlang Service Integration
241+
242+
- Handle Erlang service errors gracefully
243+
- Use appropriate namespaces for different error sources
244+
- Maintain backward compatibility with existing error codes
245+
246+
### IDE Integration
247+
248+
- Provide rich diagnostic information (ranges, severity, fixes)
249+
- Support quick fixes and code actions where appropriate
250+
- Ensure diagnostics are fast enough for real-time feedback
251+
252+
## Maintenance
253+
254+
### Backward Compatibility
255+
256+
- Don't change existing diagnostic codes or their meanings
257+
- Deprecate old codes before removing them
258+
- Maintain serialization compatibility for configuration files
259+
260+
### Code Organization
261+
262+
- Keep related functionality together in modules
263+
- Use clear module boundaries and public APIs
264+
- Minimize dependencies between modules
265+
266+
### Version Management
267+
268+
- Follow semantic versioning for public APIs
269+
- Document breaking changes in release notes
270+
- Provide migration guides for major changes
271+
272+
## Common Patterns
273+
274+
### Regex Usage
275+
276+
- Use `lazy_static!` for compiled regexes
277+
- Prefer specific patterns over overly broad ones
278+
- Test regex patterns thoroughly with edge cases
279+
280+
### Configuration
281+
282+
- Support both code-based and label-based diagnostic references
283+
- Use serde for serialization/deserialization
284+
- Provide sensible defaults for all configuration options
285+
286+
### Error Recovery
287+
288+
- Continue processing after encountering errors when possible
289+
- Collect multiple errors rather than failing on the first one
290+
- Provide partial results when full analysis isn't possible
291+
292+
### Process
293+
294+
- Always run tests before finishing
295+
- Always run `cargo clippy --tests` before submitting PRs
296+
- Use `cargo fmt` for code formatting

0 commit comments

Comments
 (0)