diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..b5de25a0 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,50 @@ +--- +Checks: > + -*, + bugprone-*, + modernize-*, + performance-*, + readability-*, + -modernize-use-trailing-return-type, + -readability-magic-numbers, + -readability-else-after-return, + -readability-braces-around-statements, + -readability-avoid-const-params-in-decls, + -readability-named-parameter, + -readability-implicit-bool-conversion, + -readability-use-anyofallof, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -bugprone-narrowing-conversions, + -modernize-use-nodiscard, + +WarningsAsErrors: "" + +HeaderFilterRegex: "(src|tests)/.*" + +CheckOptions: + # Naming conventions matching project style + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.StructCase + value: CamelCase + - key: readability-identifier-naming.EnumCase + value: CamelCase + - key: readability-identifier-naming.EnumConstantCase + value: CamelCase + - key: readability-identifier-naming.TemplateParameterCase + value: CamelCase + - key: readability-identifier-naming.TypeAliasCase + value: CamelCase + - key: readability-identifier-naming.FunctionCase + value: lower_case + - key: readability-identifier-naming.MethodCase + value: lower_case + - key: readability-identifier-naming.VariableCase + value: lower_case + - key: readability-identifier-naming.ParameterCase + value: lower_case + - key: readability-identifier-naming.MemberCase + value: lower_case + - key: readability-identifier-naming.NamespaceCase + value: lower_case diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 00000000..6f2efe64 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,268 @@ +# clice — Project Guide + +## Project Overview + +clice is a next-generation C++ language server (LSP) built on LLVM/Clang, targeting modern C++ (C++20/23). It uses a multi-process architecture with a master server coordinating stateless and stateful workers. + +## Core Correction Patterns — Lessons from Past Interactions + +The following patterns were extracted from extensive real-world collaboration. These are recurring mistakes that MUST be avoided. Read them carefully — they represent hard-won lessons, not hypothetical concerns. + +### Pattern 1: Misjudging Real-World Priorities + +AI tends to optimize whatever metric looks most impressive, rather than what actually matters in the user's real scenario. + +**Example**: During performance optimization, the AI proudly reported "hot cache is 4-7x faster!" — but the function in question runs at LSP server startup, which is ALWAYS a cold start. Optimizing hot cache was completely meaningless. + +**Rule**: Before optimizing or analyzing anything, first understand the REAL usage scenario. Ask yourself: "When does this code actually run? What does the user actually experience?" Do not chase metrics that look good on paper but are irrelevant in practice. + +### Pattern 2: Pushing Without Local Verification + +The most common and most damaging pattern. AI proposes a fix, pushes it immediately, CI fails, then another fix, push, fail again — wasting CI cycles and the user's time. + +**Rule**: NEVER push code that you haven't verified locally. Before every push: + +- Build locally with the same configuration CI uses. +- Run the relevant tests locally and confirm they pass. +- If you cannot reproduce the CI environment locally, say so — do not just "try and see." +- "It compiles" is NOT sufficient. Tests must pass. + +### Pattern 3: Superficial Refactoring + +When asked to refactor, AI tends to do mechanical code movement (copy functions from A to B) without understanding the deeper design intent (ownership, responsibility boundaries, API cleanliness). + +**Example**: When splitting `MasterServer` into `Workspace` and `Session`, the AI moved functions but kept ugly APIs like `f(path_id, sessions_map)` instead of the clean `f(Session&)` that the refactoring was meant to achieve. + +**Rule**: When refactoring, understand the WHY. Ask: "What design problem is this refactoring solving?" If you're just moving code around without improving the abstractions, you're not refactoring — you're rearranging deck chairs. + +### Pattern 4: Fixing Only the Immediate Instance, Not the Pattern + +When given a cleanup instruction, AI applies it to the single file or function currently being discussed, ignoring all other occurrences in the project. + +**Example**: User says "remove decorative `===` comment separators." AI removes them from `workspace.cpp` only. User has to say: "The other files too!" + +**Rule**: When given a cleanup or style instruction, apply it project-wide. Use `Grep` to find ALL occurrences and fix them all in one pass. Think: "Where else does this pattern appear?" + +### Pattern 5: Never Skip, Disable, or Work Around Failing Tests + +When stuck on a difficult bug (especially flaky CI, race conditions, platform-specific issues), AI may propose marking tests as `continue-on-error`, skipping them, or adding `expected-failure` annotations to make CI green. + +**Rule**: This is ABSOLUTELY FORBIDDEN. If a test fails, fix the root cause. There are ZERO exceptions. Skipping a test to make CI green is not "fixing" — it is hiding a bug. If you ever find yourself thinking "maybe we should just skip this test," stop and reconsider your approach entirely. + +### Pattern 6: Excessive Confirmation Seeking vs. Premature Execution + +AI oscillates between two extremes: asking "should I do X?" for every trivial decision, or silently executing major changes without confirmation. + +**Rule**: Calibrate based on reversibility and impact: + +- **Small, reversible changes** (formatting, renaming a local variable, adding a test): just do it. +- **Architecture decisions, API changes, large refactors**: propose the plan first, wait for confirmation. +- **Pushing to remote, creating PRs, modifying CI**: always confirm. +- When the user says "go ahead" or "do it," execute fully without asking again mid-way. + +## Code Reuse & Understanding Before Implementation + +**This is the single most important rule in this project.** Before writing ANY new code, you MUST thoroughly read and understand the existing codebase first. This project has a rich set of utilities, abstractions, and patterns already in place — duplicating them wastes effort and creates maintenance burden. + +Concrete requirements: + +1. **Read before you write.** Before implementing a feature or fix, explore the relevant modules in `src/`. Search for existing helpers, utilities, and patterns that solve the same or similar problems. Use `Grep`, `Glob`, and `Agent` tools to investigate thoroughly — do not assume something doesn't exist just because you haven't seen it yet. + +2. **Reuse existing infrastructure.** This project already has: + - A `Lexer` class (`src/syntax/lexer.h`) — do not hand-write token scanning logic. + - A `PositionMapper` for source location conversion — do not reimplement offset-to-line/column math. + - `CompilationUnitRef` methods (`decompose_location`, `decompose_range`, `file_path`, `directives`, etc.) — use them instead of raw Clang APIs. + - `SemanticVisitor` for AST traversal — extend it, do not write custom recursive AST walkers. + - `Tester` framework for unit tests with VFS, annotation support, and multi-phase compilation — use it, do not create ad-hoc test setups. + - Utility functions in `src/support/` — check there before writing new helpers. + +3. **Follow established patterns.** When adding a new feature (e.g., a new LSP request handler), look at how 2-3 existing features of the same kind are implemented. Match their structure: same file organization, same function signatures, same error handling patterns. If every other feature in `src/feature/` follows a certain pattern, yours should too. + +4. **Do not reinvent what the project already has.** If you find yourself writing a helper function that feels generic (string manipulation, path handling, JSON serialization, source range conversion), STOP and search the codebase first. There is a high probability it already exists. Creating duplicates leads to inconsistencies and bugs when one copy gets updated but the other doesn't. + +5. **When in doubt, ask.** If you're unsure whether an existing utility covers your use case or whether to extend an existing abstraction vs. create a new one, ask the user rather than guessing. + +## Source Layout + +- `src/server/` — LSP server core: master server, compiler, indexer, stateful/stateless workers +- `src/feature/` — LSP feature implementations: hover, completion, document links, semantic tokens, etc. +- `src/compile/` — Compilation orchestration: compilation unit, directives, diagnostics +- `src/index/` — Symbol indexing: TUIndex, ProjectIndex, MergedIndex, include graph +- `src/semantic/` — Semantic analysis: symbol kinds, relations, AST visitor, template resolver +- `src/syntax/` — Lexer, scanner, token types, dependency graph +- `src/command/` — CLI parsing, compilation database, toolchain detection +- `src/support/` — Utilities: logging, filesystem, JSON, string helpers + +## Build System + +- Uses **pixi** for environment management and **CMake + Ninja** for building. +- Two build types: `Debug` and `RelWithDebInfo` (default). +- Build output goes to `build/[type]/`. +- See `/build`, `/test`, `/format` commands for common operations. + +## Commit Message Format + +Use **conventional commits** — enforced by CI: + +``` +(): +``` + +- **Types**: `feat`, `fix`, `refactor`, `chore`, `docs`, `ci`, `test` +- **Scopes**: match `src/` subdirectories or feature names, e.g. `completion`, `server`, `index`, `tests`, `document links` +- Keep the subject line under 70 characters. + +## Tests + +Three types of tests, all must pass before committing: + +- **Unit tests** (`tests/unit/`): C++ tests using the project's own test framework. Test names should be at most 4 words. +- **Integration tests** (`tests/integration/`): Python pytest tests that start a real clice server and communicate via LSP. +- **Smoke tests** (`tests/smoke/`): Replay recorded LSP sessions via `tests/replay.py`. + +### Integration Test Style + +- Keep tests concise. Do NOT write large comment blocks explaining the test layout or expected behavior. +- Use descriptive test function names and short inline comments only where logic is non-obvious. + +## Pre-PR Review + +Before opening a PR, launch **3 parallel subagents** to review the diff independently: + +1. **Correctness reviewer**: Check for logic errors, edge cases, undefined behavior, and off-by-one mistakes. +2. **Style reviewer**: Verify the code follows this project's naming conventions, coding style, and CLAUDE.md rules. +3. **Test reviewer**: Confirm test coverage is adequate — new functionality has tests, edge cases are covered, and no existing tests were broken or weakened. + +Each agent should read the full diff (`git diff main...HEAD`) and report issues. Fix all reported issues before opening the PR. + +## Pre-commit Checklist + +Before committing code, you MUST: + +1. **Run `pixi run format`** to format all source files. +2. **Pass all three types of tests:** + - Unit tests: `pixi run unit-test [type]` + - Integration tests: `pixi run integration-test [type]` + - Smoke tests: `pixi run smoke-test [type]` +3. **All test failures must be fixed before committing.** This is a HARD REQUIREMENT with NO exceptions: + - If a test fails, it MUST be fixed before you commit. Do NOT commit with known failures. + - Do NOT skip, disable, or mark tests as expected-failure to work around breakage. + - Do NOT argue "this test was already broken before my changes" — if it fails on your branch, it is YOUR responsibility to fix it before committing. The main branch CI is green; any failure on your branch is caused by your changes, period. + - Do NOT defer fixing to a follow-up PR. Fix it NOW, in this branch, before committing. + +--- + +## C++ Coding Style + +### Template & Type Traits + +- Do NOT blindly add `std::remove_cvref_t` on every template parameter. Understand C++ template argument deduction rules: + - `template void f(T x)` — `T` is always deduced as a non-reference, non-cv-qualified type. No need for `remove_cvref_t`. + - `template void f(T& x)` — `T` is deduced as the referred-to type (possibly cv-qualified, but never a reference). No need for `remove_cvref_t` to strip references. + - `template void f(const T& x)` — `T` is deduced as a non-const, non-reference type. No need for `remove_cvref_t`. + - `template void f(T&& x)` — **forwarding reference**: `T` CAN be deduced as an lvalue reference (e.g., `int&`). This is the ONLY case where `std::remove_cvref_t` is needed to get the bare type. + - Class template parameters and return types are also never deduced as references; don't add `remove_cvref_t` on them either. + +### Type Traits & Concepts (C++20/23) + +- This project targets C++20/23. Use variable templates directly for type traits — do NOT use the old pattern of wrapping a class template static member in a variable template. Prefer: + + ```cpp + // Good: directly specialize a variable template + template + inline constexpr bool is_my_type_v = false; + + template<> + inline constexpr bool is_my_type_v = true; + ``` + + ```cpp + // Bad: unnecessary class template wrapper + template + struct is_my_type : std::false_type {}; + + template<> + struct is_my_type : std::true_type {}; + + template + inline constexpr bool is_my_type_v = is_my_type::value; + ``` + +- When defining a concept that checks a type trait, do NOT add `std::remove_cvref_t` unless you specifically intend the concept to see through references/cv-qualifiers. If the concept is meant for a bare type, just use `T` directly — the caller is responsible for passing the right type. + + ```cpp + // Good + template + concept MyTrait = is_my_type_v; + + // Bad: unnecessary remove_cvref_t + template + concept MyTrait = is_my_type_v>; + ``` + +### Naming Conventions + +- **Variables, member fields, function names**: `snake_case`. Class member fields do NOT use any special suffix/prefix (no trailing `_`, no `m_` prefix). +- **Class names, template parameter names, enum names**: `PascalCase`. Exception: some class names also use `snake_case` — follow the existing style in the project. +- **Enum values**: `PascalCase`. + +### String Literals + +- Prefer C++11 raw string literals `R"(...)"` over escaped strings. Avoid `\"`, `\\`, `\n` in string literals when a raw literal is cleaner. + +### Error Handling + +- **Prefer `if` with init-statements to tightly scope error variables**, but avoid them when they compromise code readability or flatten control flow. +- **Omit redundant conditions:** If the error type provides an `operator bool` or evaluates implicitly (e.g., standard error codes, custom error wrappers), omit the redundant condition check. +- **Avoid forced `else` branches:** If scoping the variable inside the `if` requires you to introduce an `else` block for the success path (especially when returning early on error), declare the variable in the local scope instead to keep the control flow flat. + +```cpp +// Good: Omit redundant condition when the type has operator bool +if (auto err = foo()) { + /* handle error */ +} + +// Bad: Redundant condition check +if (auto err = foo(); err) { + /* handle error */ +} + +// Good: Use init-statement when a custom condition is required, +// AND the variable isn't needed outside the if-statement +if (auto result = foo(); !result.has_value()) { + /* handle error */ +} + +// --- Scope and Control Flow Considerations --- + +// Bad: Using init-statement forces an 'else' block because 'result' +// goes out of scope, leading to nested/redundant code. +if (auto result = get_data(); !result.has_value()) { + return result.error(); +} else { + process(result.value()); // Success path is forced into a nested block +} + +// Good: Declare as a regular local variable to allow early exit +// and keep the success path un-nested (flat control flow). +auto result = get_data(); +if (!result.has_value()) { + return result.error(); +} +process(result.value()); +``` + +### Style + +- Prefer `[[maybe_unused]]` over `(void)` for intentionally unused variables or parameters. + +### Modern C++ Usage + +- Use C++20/23 APIs whenever possible. Do NOT use `` facilities (`std::cout`, `std::cin`, `std::cerr`, etc.). Also do NOT use C-style I/O (`printf`, `fprintf`, etc.). +- Prefer `std::ranges` / `std::views` APIs over raw loops and traditional `` calls. +- If the project depends on LLVM, prefer LLVM's efficient data structures (e.g., `llvm::SmallVector`, `llvm::DenseMap`, `llvm::StringMap`, `llvm::StringRef`) over their `std` counterparts when appropriate. + +### Parameter Passing Preferences + +- For string parameters, prefer `llvm::StringRef` > `std::string_view` > `const std::string&`. +- For array/span parameters, prefer `llvm::ArrayRef` > `std::span` > `const std::vector&`. diff --git a/.claude/commands/build.md b/.claude/commands/build.md new file mode 100644 index 00000000..f440703e --- /dev/null +++ b/.claude/commands/build.md @@ -0,0 +1,15 @@ +Build the project. Accepts an optional argument for build type: `Debug` or `RelWithDebInfo` (default). + +Available build commands: + +- CMake configure only: `pixi run cmake-config [type]` +- CMake build only (skip configure): `pixi run cmake-build [type]` +- Full build (configure + build): `pixi run build [type]` +- Build a specific target: `pixi run cmake-build [type]` then `cmake --build build/[type] --target [target]` + +Common targets: `clice`, `unit_tests` + +Example usage: + +- `/build` — full build RelWithDebInfo +- `/build Debug` — full build Debug diff --git a/.claude/commands/format.md b/.claude/commands/format.md new file mode 100644 index 00000000..44be875e --- /dev/null +++ b/.claude/commands/format.md @@ -0,0 +1,5 @@ +Format all project source files. + +Run: `pixi run format` + +Formats C++, Python, Lua, JS/TS, Markdown, JSON, TOML, and YAML files. diff --git a/.claude/commands/test.md b/.claude/commands/test.md new file mode 100644 index 00000000..161ff272 --- /dev/null +++ b/.claude/commands/test.md @@ -0,0 +1,19 @@ +Run tests. Accepts an optional argument for build type: `Debug` or `RelWithDebInfo` (default). + +Available test commands: + +- Unit tests: `pixi run unit-test [type]` +- Integration tests: `pixi run integration-test [type]` +- Smoke tests: `pixi run smoke-test [type]` +- All tests (unit + integration): `pixi run test [type]` + +Filtering specific tests: + +- Unit tests: `pixi run unit-test [type] --test-filter=SuiteName.CaseName` +- Integration tests: `pixi run pytest tests/integration -k "test_name" --executable=./build/[type]/bin/clice` +- Smoke tests: `pixi run python tests/replay.py tests/smoke/specific.jsonl --clice=./build/[type]/bin/clice` + +Example usage: + +- `/test` — run all tests (RelWithDebInfo) +- `/test Debug` — run all tests (Debug) diff --git a/.gitignore b/.gitignore index 8fe8decc..abd5c2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,6 @@ tests/unit/Local/ !/.vscode/tasks.json .vs/ .idea/ -.claude .clangd # pixi environments @@ -70,5 +69,7 @@ tests/unit/Local/ !.pixi/config.toml .codex/ -.claude/ +.claude/* +!.claude/CLAUDE.md +!.claude/commands/ openspec/ diff --git a/pixi.lock b/pixi.lock index 11aa887f..3c9e4fa0 100644 --- a/pixi.lock +++ b/pixi.lock @@ -18,6 +18,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ccache-4.13.2-hedf47ba_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-20-20.1.8-default_h99862b1_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-20.1.8-default_h36abe19_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20-20.1.8-default_h99862b1_14.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20.1.8-default_h99862b1_14.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-tools-20.1.8-default_h57a47db_14.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clangxx-20.1.8-default_h363a0c9_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.2.1-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/compiler-rt-20.1.8-hb700be7_1.conda @@ -32,6 +35,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45-default_hbd61a6d_105.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.8-default_h99862b1_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.17.0-h4e3cde8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -44,6 +48,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.3.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.1-hf7376ad_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda @@ -81,7 +86,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl osx-arm64: @@ -91,6 +96,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ccache-4.13.2-h414bf82_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-20-20.1.8-default_h73dfc95_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-20.1.8-default_hf9bcbb7_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20-20.1.8-default_hf3020a7_14.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20.1.8-default_hf3020a7_14.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-tools-20.1.8-default_h1589341_14.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-20.1.8-default_h36137df_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.2.1-h54ad630_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-20.1.8-h855ad52_1.conda @@ -98,6 +106,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.1-h38cb7af_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp20.1-20.1.8-default_h73dfc95_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang13-21.1.8-default_h13b06bd_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.17.0-hdece5d2_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.8-hf598326_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-20.1.8-h6dc3340_3.conda @@ -109,6 +118,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.3.0-h286801f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm20-20.1.8-h8e0c9ce_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm21-21.1.8-h8e0c9ce_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h5505292_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.67.0-hc438710_0.conda @@ -140,7 +150,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl win-64: @@ -148,12 +158,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.11.12-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clang-20-20.1.8-default_hac490eb_5.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clang-20.1.8-default_hac490eb_5.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/clang-format-20.1.8-default_hac490eb_14.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/clang-tools-20.1.8-default_hac490eb_14.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clangxx-20.1.8-default_hac490eb_5.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cmake-4.2.1-hdcbee5b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/compiler-rt-20.1.8-h49e36cd_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_win-64-20.1.8-h49e36cd_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/icu-78.1-h637d24d_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libclang13-22.1.0-default_ha2db4b5_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.17.0-h43ecb02_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.3-hac47afa_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h52bdfb6_0.conda @@ -190,7 +203,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl format: @@ -370,6 +383,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ccache-4.13.2-hedf47ba_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-20-20.1.8-default_h99862b1_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-20.1.8-default_h36abe19_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20-20.1.8-default_h99862b1_14.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20.1.8-default_h99862b1_14.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-tools-20.1.8-default_h57a47db_14.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/clangxx-20.1.8-default_h363a0c9_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.2.1-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/compiler-rt-20.1.8-hb700be7_1.conda @@ -383,6 +399,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45-default_hbd61a6d_104.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.8-default_h99862b1_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.17.0-h4e3cde8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -395,6 +412,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.3.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.1-hf7376ad_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-devel-5.8.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda @@ -436,7 +454,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl osx-arm64: @@ -446,12 +464,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ccache-4.13.2-h414bf82_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-20-20.1.8-default_h73dfc95_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-20.1.8-default_hf9bcbb7_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20-20.1.8-default_hf3020a7_14.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20.1.8-default_hf3020a7_14.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-tools-20.1.8-default_h1589341_14.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-20.1.8-default_h36137df_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.2.1-h54ad630_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-20.1.8-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-20.1.8-he32a8d3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp20.1-20.1.8-default_h73dfc95_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang13-21.1.7-default_h13b06bd_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.17.0-hdece5d2_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.7-hf598326_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-20.1.8-h6dc3340_3.conda @@ -463,6 +485,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.3.0-h286801f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm20-20.1.8-h8e0c9ce_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm21-21.1.8-h8e0c9ce_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-devel-5.8.1-h39f12f2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h5505292_0.conda @@ -498,7 +521,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl win-64: @@ -506,11 +529,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.11.12-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clang-20-20.1.8-default_hac490eb_5.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clang-20.1.8-default_hac490eb_5.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/clang-format-20.1.8-default_hac490eb_14.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/clang-tools-20.1.8-default_hac490eb_14.conda - conda: https://conda.anaconda.org/conda-forge/win-64/clangxx-20.1.8-default_hac490eb_5.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cmake-4.2.1-hdcbee5b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/compiler-rt-20.1.8-h49e36cd_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_win-64-20.1.8-h49e36cd_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libclang13-22.1.0-default_ha2db4b5_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.17.0-h43ecb02_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.3-hac47afa_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h52bdfb6_0.conda @@ -550,7 +576,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/1a/208293b6c350f5abea6941d5606080d4a492644052504f5312e5de30a902/pygls-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl packages: @@ -803,6 +829,21 @@ packages: purls: [] size: 73427981 timestamp: 1764398987103 +- conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20.1.8-default_h99862b1_14.conda + sha256: b58148bb200231f21a0a78e90456414be7de8dd4fc115ebdf6e9d808d151e9e6 + md5: de9baf19d75c9ca7b4e88f5609db0347 + depends: + - __glibc >=2.17,<3.0.a0 + - clang-format-20 20.1.8 default_h99862b1_14 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libgcc >=14 + - libllvm20 >=20.1.8,<20.2.0a0 + - libstdcxx >=14 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 71009 + timestamp: 1773111214926 - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-21.1.7-default_h99862b1_2.conda sha256: 8a9c2e0df0fd55da3ea9352fc356d1ca9d9312bbf275e1a5e22552bfb63affb9 md5: 8e0b6ced8948217e4748ad0c26f8df4d @@ -817,6 +858,20 @@ packages: license_family: Apache size: 27733 timestamp: 1766016586518 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20.1.8-default_hf3020a7_14.conda + sha256: 0967d59e8a89c5f9c1cfa3579403ee3295f5770c01b308c9abb434df47acc5db + md5: 86639340249e4d8fa1b37ab92e581d26 + depends: + - __osx >=11.0 + - clang-format-20 20.1.8 default_hf3020a7_14 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libcxx >=20.1.8 + - libllvm20 >=20.1.8,<20.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 71355 + timestamp: 1773110589745 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-21.1.7-default_hf3020a7_2.conda sha256: 2b91ed7e567a1618fd342100ba43bcd670bff8a1183a5c65032cefc0a436d3d6 md5: 37585890edaa4842a62037a7fa6e1e64 @@ -830,6 +885,18 @@ packages: license_family: Apache size: 28328 timestamp: 1766167306042 +- conda: https://conda.anaconda.org/conda-forge/win-64/clang-format-20.1.8-default_hac490eb_14.conda + sha256: 7c657222c2b310387e11a316bf835910181c04ed54f2e35e28885cc5423c8496 + md5: 188355e2c07643a0232b9b817c230a36 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 1265666 + timestamp: 1773142030144 - conda: https://conda.anaconda.org/conda-forge/win-64/clang-format-21.1.7-default_hac490eb_2.conda sha256: afa22671525e890a98445d1c2abc35e8b87c4c208d053e6527c5d2cbf6f7c938 md5: 8afc1288250ef6c77e8f7aa0df683a65 @@ -841,6 +908,33 @@ packages: license_family: Apache size: 1233929 timestamp: 1766022144370 +- conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-20-20.1.8-default_h99862b1_14.conda + sha256: 17b84830ca43b9db271b50d8474a4231204321016f9ff5c2c690dddeb0d66f28 + md5: 55910d2902458004d9c4e443648c5841 + depends: + - __glibc >=2.17,<3.0.a0 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libgcc >=14 + - libllvm20 >=20.1.8,<20.2.0a0 + - libstdcxx >=14 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 114295 + timestamp: 1773111143555 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-format-20-20.1.8-default_hf3020a7_14.conda + sha256: 52f77009e2f69db348c10cb20371e0b1bf6f49e2e91e026d5fb93addc6526ef6 + md5: 2250c216f6da8f1f875f2b6a794d5e67 + depends: + - __osx >=11.0 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libcxx >=20.1.8 + - libllvm20 >=20.1.8,<20.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 108365 + timestamp: 1773110420001 - conda: https://conda.anaconda.org/conda-forge/linux-64/clang-format-21-21.1.7-default_h99862b1_2.conda sha256: 4d360c464ddab6c47c8fceca87b625b58d6a3b3cd523958a314e8db7d5f4eb94 md5: 5589c06b39ae5be8aca4d16e28a43518 @@ -866,6 +960,65 @@ packages: license_family: Apache size: 65217 timestamp: 1766167190049 +- conda: https://conda.anaconda.org/conda-forge/linux-64/clang-tools-20.1.8-default_h57a47db_14.conda + sha256: 565bbd489160501c5374fe346dca83a6ec4dac23aecc5bc48c276fe47ca2c263 + md5: 897e3de8e6310eb23d01004907520513 + depends: + - __glibc >=2.17,<3.0.a0 + - clang-format 20.1.8 default_h99862b1_14 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libclang13 >=20.1.8 + - libgcc >=14 + - libllvm20 >=20.1.8,<20.2.0a0 + - libstdcxx >=14 + - libxml2 + - libxml2-16 >=2.14.6 + constrains: + - clangdev 20.1.8 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 21897132 + timestamp: 1773111341498 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-tools-20.1.8-default_h1589341_14.conda + sha256: 372c9e722fd99e42838528d33148ca1fa7dd84a02cf06ac7d291657f657e7026 + md5: 8a25b0558245abf052a89a38eb8dbb58 + depends: + - __osx >=11.0 + - clang-format 20.1.8 default_hf3020a7_14 + - libclang-cpp20.1 >=20.1.8,<20.2.0a0 + - libclang13 >=20.1.8 + - libcxx >=20.1.8 + - libllvm20 >=20.1.8,<20.2.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + constrains: + - clangdev 20.1.8 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 14941399 + timestamp: 1773110809290 +- conda: https://conda.anaconda.org/conda-forge/win-64/clang-tools-20.1.8-default_hac490eb_14.conda + sha256: 25b5962d5e46c01edd9e91b0092a1cbe840276cfce6e0ccd8752ff9d21deb0fb + md5: 7f081578424e00ff4724ded6228f1be8 + depends: + - clang-format 20.1.8 default_hac490eb_14 + - libclang13 >=20.1.8 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - clangdev 20.1.8 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 319341053 + timestamp: 1773142869937 - conda: https://conda.anaconda.org/conda-forge/linux-64/clangxx-20.1.8-default_h363a0c9_5.conda sha256: d30843fc1012ff5fb6c95e07c15182d22f03a37c380ae350ba069adf75092828 md5: 692c84fedd1a3302ff26dbc9a211f626 @@ -1386,6 +1539,57 @@ packages: license_family: Apache size: 13672685 timestamp: 1766166376555 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda + sha256: 4a9dd814492a129f2ff40cd4ab0b942232c9e3c6dbc0d0aaf861f1f65e99cc7d + md5: 140459a7413d8f6884eb68205ce39a0d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libllvm22 >=22.1.0,<22.2.0a0 + - libstdcxx >=14 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 12817500 + timestamp: 1772101411287 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang13-21.1.7-default_h13b06bd_4.conda + sha256: ed55559f8af599838de775c099fbf644c19d1720b9f57064a2abb0ab2ff99765 + md5: e886d09eb4ae02f446edd4c32c351ca6 + depends: + - __osx >=11.0 + - libcxx >=21.1.7 + - libllvm21 >=21.1.7,<21.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 8517139 + timestamp: 1767751023683 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang13-21.1.8-default_h13b06bd_3.conda + sha256: dc803069f4001aae4bdd6069af20140785a9c1a0c9abe6a3704e0ef87ad0f4c2 + md5: d111e982033ec02a55845e994a6db09a + depends: + - __osx >=11.0 + - libcxx >=21.1.8 + - libllvm21 >=21.1.8,<21.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 8516482 + timestamp: 1771032974531 +- conda: https://conda.anaconda.org/conda-forge/win-64/libclang13-22.1.0-default_ha2db4b5_0.conda + sha256: c8e34362c6bf7305ef50f0de4e16292cd97e31650ab6465282eeeac62f0a05c4 + md5: 7ad437870ea7d487e1b0e663503b6b1d + depends: + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 30584641 + timestamp: 1772353741135 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.17.0-h4e3cde8_1.conda sha256: 2d7be2fe0f58a0945692abee7bb909f8b19284b518d958747e5ff51d0655c303 md5: 117499f93e892ea1e57fdca16c2e8351 @@ -1761,8 +1965,25 @@ packages: - zstd >=1.5.7,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] size: 29398498 timestamp: 1765924904821 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.1-hf7376ad_0.conda + sha256: 1145f9e85f0fbbdba88f1da5c8c48672bee7702e2f40c563b2dd48350ab4d413 + md5: 97cc6dad22677304846a798c8a65064d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 44256563 + timestamp: 1773371774629 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 md5: 1a580f7796c7bf6393fddb8bbbde58dc @@ -2837,10 +3058,10 @@ packages: requires_dist: - colorama>=0.4.6 ; extra == 'windows-terminal' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl +- pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl name: pytest - version: 9.0.2 - sha256: 711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b + version: 9.0.3 + sha256: 2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9 requires_dist: - colorama>=0.4 ; sys_platform == 'win32' - exceptiongroup>=1 ; python_full_version < '3.11' diff --git a/pixi.toml b/pixi.toml index f60975cc..9fd9556b 100644 --- a/pixi.toml +++ b/pixi.toml @@ -33,6 +33,7 @@ clang = "==20.1.8" clangxx = "==20.1.8" lld = "==20.1.8" llvm-tools = "==20.1.8" +clang-tools = "==20.1.8" compiler-rt = "==20.1.8" [feature.build.target.win-64.dependencies] @@ -103,6 +104,10 @@ depends-on = [ { task = "cmake-build", args = ["{{ type }}"] }, ] +[feature.build.tasks.clang-tidy] +args = [{ arg = "type", default = "RelWithDebInfo" }] +depends-on = [{ task = "lint-cpp", args = ["{{ type }}"] }] + [feature.build.tasks.unit-test] args = [{ arg = "type", default = "RelWithDebInfo" }] cmd = './build/{{ type }}/bin/unit_tests --test-dir="./tests/data"' @@ -205,3 +210,20 @@ format = { depends-on = [ "format-toml", "format-yaml" ] } + +# ============================================================================== # +# LINT # +# ============================================================================== # +[feature.format.tasks.lint-python] +cmd = "ruff check ." + +[feature.build.tasks.lint-cpp] +args = [{ arg = "type", default = "RelWithDebInfo" }] +cmd = "python scripts/run_clang_tidy.py build/{{ type }}" + +[feature.build.tasks.lint] +args = [{ arg = "type", default = "RelWithDebInfo" }] +depends-on = [ + "lint-python", + { task = "lint-cpp", args = ["{{ type }}"] }, +] diff --git a/scripts/run_clang_tidy.py b/scripts/run_clang_tidy.py new file mode 100644 index 00000000..429ac426 --- /dev/null +++ b/scripts/run_clang_tidy.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Run clang-tidy in parallel on all files in compile_commands.json.""" + +import json +import subprocess +import sys +import threading +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path + + +def main(): + build_dir = sys.argv[1] if len(sys.argv) > 1 else "build/RelWithDebInfo" + cdb_path = Path(build_dir) / "compile_commands.json" + + if not cdb_path.exists(): + print(f"Error: {cdb_path} not found. Run cmake-config first.", file=sys.stderr) + sys.exit(1) + + project_root = Path(__file__).resolve().parent.parent + src_dirs = (project_root / "src", project_root / "tests") + + cdb = json.loads(cdb_path.read_text()) + files = [ + entry["file"] + for entry in cdb + if any(Path(entry["file"]).resolve().is_relative_to(d) for d in src_dirs) + ] + total = len(files) + + lock = threading.Lock() + done = 0 + failed = [] + + def run(file: str) -> tuple[str, int, str]: + result = subprocess.run( + ["clang-tidy", "-p", build_dir, "--quiet", file], + capture_output=True, + text=True, + ) + return file, result.returncode, result.stdout + result.stderr + + with ThreadPoolExecutor() as pool: + futures = {pool.submit(run, f): f for f in files} + for future in as_completed(futures): + file, code, output = future.result() + with lock: + done += 1 + name = Path(file).name + if code != 0: + failed.append(file) + print(f"[{done}/{total}] FAIL {name}") + if output.strip(): + print(output, end="") + else: + print(f"[{done}/{total}] OK {name}") + + if failed: + print(f"\nclang-tidy failed on {len(failed)}/{total} files.", file=sys.stderr) + sys.exit(1) + + print(f"\nclang-tidy passed on {total} files.") + + +if __name__ == "__main__": + main()