- Rust 100%
- 11 Regeln aus den echten Compiler-Meldungen, identische Meldungen und Exit-Codes - Paritätstest vergleicht stdout und Exit gegen das Python-Original auf demselben Fixture - Ausgabe auf den echten ipad-notizen-app-Quellen byte-identisch |
||
|---|---|---|
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
swift6-lint-rs
Rust-Port von native/lint-swift.py aus ipad-notizen-app: statische
Prüfung von Swift-Quellen auf Fehler, die Swift 6 ablehnt — für Rechner ohne Swift-Compiler.
Warum
Auf diesem Host gibt es kein Xcode, aber die Fehler tauchten in Swift Playgrounds auf. Das Python-Skript hat die Regeln aus echten Compiler-Meldungen zusammengestellt; hier laufen dieselben Regeln als Binary, damit sie in einem Gate ohne Interpreter starten.
Bauen und benutzen
cargo build --release # target/release/swift6-lint
cargo test # 4 Tests, inkl. Parität gegen das Original
./target/release/swift6-lint # prüft ./Sources neben dem Binary (wie das Original)
./target/release/swift6-lint path/Sources
Exit 0 = keine Fehler, Exit 1 = mindestens ein Fehler. Die Hinweise (Warnungen) ändern den Exit-Code nicht — genau wie im Original.
Regeln
| Regel | Warum |
|---|---|
@MainActor an perform/entities/suggestedEntities/resolve, wenn der Rumpf NoteStore.shared oder @MainActor anfasst |
AppIntent-Methoden laufen nicht auf dem Main Actor |
let-Bindungen, die in keiner Datei benutzt werden |
„was never used"-Warnung, dateiübergreifend gesucht |
AppShortcut ohne shortTitle / systemImageName |
bindet an die iOS-17-deprecatete Überladung |
Interpolation in AppShortcut-phrases |
Phrases müssen Compile-Time-Konstanten sein |
PKToolPicker.shared |
deprecated seit iOS 14 |
onChange(of:) mit parameterloser Closure |
veraltete Signatur, braucht { _, neu in } |
settings.<member> ohne Member in struct AppSettings |
genau der Fall, den die lokalen Gates übersahen |
Timer.scheduledTimer in einer @MainActor-Klasse (Hinweis) |
Closure erbt die Isolation nicht |
onChange() direkt in updateUIView ohne Task (Hinweis) |
kann State während des View-Updates ändern |
Closure-Feld (let cb: (…) -> Void) ohne @MainActor (Hinweis) |
Swift 6 verlangt die Annotation |
Parität
cargo test
output_is_byte_identical_to_the_python_original— kopiert das Fixture in einen Scratch-Baum, legtlint-swift.pydaneben (es suchtSources/neben sich) und vergleicht stdout und Exit-Code beider Implementierungen byteweise. Fehltpython3oder das Original, wird der Test übersprungen statt rot.the_fixture_still_trips_every_rule— das Fixture muss jede Regel auslösen, sonst prüft der Paritätstest zwei Implementierungen, die beide nichts finden.a_clean_tree_passes— sauberer Baum →Keine Swift-6-Fehler gefunden., Exit 0.
Zusätzlich manuell gegen die echten Quellen geprüft:
$ diff <(python3 lint-swift.py) <(swift6-lint Sources) → identisch
Abweichungen
Sources/-Auflösung: das Original nimmt immer<script_dir>/Sources. Hier ist das der Default, ein Pfad-Argument hat Vorrang — sonst müsste man das Binary ins Repo kopieren.- Regex-Bau einmal statt pro Zeile (
OnceLock): reine Laufzeitfrage, die Meldungen sind identisch, was der Paritätstest beweist. - Die Prüfung auf
phrases-Interpolation sieht — wie das Original — nur Folgezeilen einerphrases:-Zeile. Eine einzeiligephrases: [...]wird von beiden nicht geprüft; das Fixture nutzt deshalb die mehrzeilige Form.
Herkunft
Portiert am 2026-11-05 aus ipad-notizen-app/native/lint-swift.py (180 Zeilen Python).
Das Original bleibt liegen; der Aufruf im Repo kann auf das Binary umgestellt werden.