Skip to content

Compile-Error Coverage — Roadmap & Live-Status

Begleitdokument zu compile-error-analysis.md. Hier wird der aktuelle Umsetzungsstand der dort beschriebenen Wellen gepflegt. Quelle der Lücken: autoritativer Microsoft-Katalog (MicrosoftDocs/VBA-Docs, Language/Reference/error-messages, ~400 Meldungen), gefiltert auf statisch aus dem Quelltext erkennbare Compile-Fehler.

Statuslegende: ✅ fertig · 🟡 in Arbeit · ⬜ geplant

Gesamtfortschritt

Welle Thema Regel-IDs Status
1 Block-Terminator-Paarung VBA110–VBA119 ✅ fertig
2 Deklarations-Typauflösung VBA120,122,123 (VBA121 zurückgestellt) ✅ fertig
3 Argumentlisten-Wohlgeformtheit VBA130–VBA136 ✅ fertig
4 Benannte Argumente an Aufrufstellen VBA140–VBA142 ✅ fertig
5 Prozedur-/Property-Konsistenz VBA150,152,153 (151/154 zurückgestellt) ✅ fertig
6 Zuweisungs-/Ausdrucks-Semantik VBA160,164,165 (161/162/163/166 zurückgestellt) ✅ fertig
7 Schleifen-/Label-Kontext VBA170–VBA175 ✅ fertig
8 Statement-Platzierung / Def / Option VBA180–VBA184 (VBA185 zurückgestellt) ✅ fertig
9 Bedingte Kompilierung (#If) VBA190–VBA192 ✅ fertig
10 Lexer-Ergänzungen VBA_LEX004–006 (VBA_LEX003 zurückgestellt) ✅ fertig

Regeln gesamt: 41 → 90 (10 Wellen + Maximum-Coverage-Nachschub).


Welle 1 — Block-Terminator-Paarung ✅

Abgeschlossen. Jeder Block-Opener wird jetzt auf seinen passenden Terminator geprüft; ein verwaister Terminator ohne Opener wird ebenfalls gemeldet.

Neue Regeln (Phase 1.5):

ID Meldung Auslöser
VBA110 For without Next For/For Each ohne Next
VBA111 Do without Loop Do ohne Loop
VBA112 While without Wend While ohne Wend
VBA113 Expected End With With ohne End With
VBA114 Select Case without End Select Select Case ohne End Select
VBA115 Block If without End If mehrzeiliges If … Then ohne End If
VBA116 Next without For verwaistes Next
VBA117 Loop without Do verwaistes Loop
VBA118 Wend without While verwaistes Wend
VBA119 Block terminator without matching opener Else/ElseIf/End If/End Select/End With ohne Opener

Umsetzung: - src/parser.py: parse_for/parse_do/parse_while/parse_with/ parse_select/parse_if_stmt prüfen jetzt den Rückgabewert von consume(...); bei fehlendem Terminator → _record_syntax_error(..., rule_id=…). Block-If verfolgt end_if_seen. parse_block mappt die inversen Terminatoren auf VBA116–VBA119. - src/rules.py: Registry-Einträge VBA110–VBA119 (Abschnitt „Phase 1.5"). - docs/rules/VBA11x.md: via tools/generate_rule_docs.py generiert.

Tests (alle grün): - tests/test_phase15_block_terminators.py: je Regel ein Direkttest + „balanced blocks bleiben sauber". - tests/samples/compile_errors/block_terminator/: 7 Fixtures, Kategorie-Keywords in tests/test_compile_error_samples.py. - Falsch-Positiv-Wächter tests/test_awesome_vba_regression.py: unverändert grün (Terminator-Checks feuern nur bei echtem Fehlen).

Bekannte Einschränkung (Refinement für später): Bei einem fehlenden Terminator wird zusätzlich zur primären Meldung (z. B. VBA110) gelegentlich ein sekundäres VBA119 für das verschluckte End Sub erzeugt. Beide zeigen auf dieselbe Fehlerregion; die primäre Meldung ist korrekt. Eine Entkopplung (Proc-Terminatoren nicht in parse_block konsumieren) ist als spätere Verfeinerung notiert.


Welle 3 — Argumentlisten-Wohlgeformtheit ✅

Abgeschlossen. Neuer Validator _validate_param_lists(mod) (analyzer.py), rein syntaktisch über proc.args, aufgerufen in pass2_resolution.

ID Meldung Auslöser
VBA130 Required parameter after Optional Pflichtparameter nach Optional
VBA131 ParamArray is not the last parameter ParamArray nicht als letzter
VBA132 More than one ParamArray mehr als ein ParamArray
VBA133 ParamArray combined with Optional Optional + ParamArray gemischt
VBA134 ParamArray element type is not Variant ParamArray x() As <≠Variant>
VBA136 Array parameter passed ByVal ByVal arr() As …

Wichtige FP-Korrektur: Der Wert-Parameter (RHS) eines Property Let/Set ist implizit Pflicht und darf nach Optional-Index-Parametern stehen — der letzte Parameter von Let/Set ist daher von VBA130 ausgenommen (sonst Falsch-Positive in realen Bibliotheken wie JSONBag/stdVBA).

VBA135 (Invalid optional parameter type) zurückgestellt: kontextabhängig, kein eindeutiger Compile-Fehler → hohes FP-Risiko, bewusst nicht implementiert.

Tests: tests/test_phase210_param_lists.py (je Regel + „well-formed bleibt sauber"), Fixtures in tests/samples/compile_errors/param_list/. FP-Wächter grün.


Welle 7 — Schleifen-/Label-Kontext ✅

Abgeschlossen. Loop-Kontext-Stacks (self._loop_stack, self._for_var_stack) werden pro Prozedur in analyze_procedure zurückgesetzt und in analyze_block beim Betreten von ForNode/DoNode gepusht/gepoppt. parse_for erfasst jetzt die Variable des schließenden Next (inkl. Next j, i-Mehrfachschließung).

ID Meldung Auslöser
VBA170 Exit For not within For...Next Exit For außerhalb einer For-Schleife
VBA171 Exit Do not within Do...Loop Exit Do außerhalb Do (auch in While...Wend)
VBA172 Next control variable mismatch Next j ≠ For-Zähler (außer Next j, i)
VBA173 For control variable already in use verschachtelte For mit gleichem Zähler
VBA174 For Each control variable must be Variant/object For Each i mit i As Long o. ä.
VBA175 Duplicate label Label zweimal in derselben Prozedur

Next j, i-Mehrfachschließung: im Review behoben. Der innerste parse_for konsumiert die komplette Variablenliste und merkt sich über self._pending_next_closes, wie viele umschließende Schleifen mitgeschlossen wurden; parse_block beendet die betroffenen Frames sauber, sodass kein fälschliches VBA110/VBA119 entsteht (Tests in test_phase15_block_terminators.py). VBA172 bleibt bewusst auf die Einzel- Next-Form beschränkt (Mehrfachform hat keinen eindeutigen Einzelbezug).

Tests: tests/test_phase211_loop_label.py (12 Fälle inkl. Gegenbeispiele), Fixtures in tests/samples/compile_errors/loop_label/. FP-Wächter grün.


Welle 8 — Statement-Platzierung / Def / Option ✅

Abgeschlossen (parser-seitig).

ID Meldung Auslöser
VBA180 Statement invalid inside Enum block fehlplatziertes Statement in Enum
VBA181 Statement invalid inside Type block fehlplatziertes Statement in Type
VBA182 Deftype must precede declarations DefXxx nach erster Deklaration
VBA183 Duplicate Deftype letter range überlappende DefXxx-Buchstabenbereiche
VBA184 Duplicate Option statement dieselbe Option-Anweisung doppelt

Wichtige FP-Korrektur (VBA180/181): VBA erlaubt viele Keywords als Feldnamen (Type As Long, Name As String, …). Die ursprüngliche Keyword-Blacklist erzeugte 38 Falsch-Positive in stdVBA. Ersetzt durch einen Shape-Test: eine Zeile, die mit zwei aufeinanderfolgenden Identifiern beginnt und deren zweiter nicht As ist (z. B. Dim x …, Sub Foo), kann keine Member-Deklaration sein → fehlplatziertes Statement. FP-Wächter grün.

VBA185 (Must be first statement on the line) zurückgestellt: kontext- und formatabhängig, hohes FP-Risiko.

Tests: tests/test_phase37_placement_def_option.py (je Regel + Gegenbeispiele), Fixtures in tests/samples/compile_errors/placement_def_option/.


Welle 9 — Bedingte Kompilierung ✅

Abgeschlossen (preprocessor-seitig). Preprocessor sammelt jetzt Fehler (self.errors) und bekommt einen filename; alle vier Aufrufstellen (api.py ×2, conftest.py ×2) hängen pp.errors an analyzer.errors.

ID Meldung Auslöser
VBA190 Conditional directive without matching #If #Else/#ElseIf/#End If ohne offenes #If (Stack-Unterlauf)
VBA191 Missing #End If Stack am Ende > Root → unterminiertes #If
VBA192 Invalid #Const declaration #Const ohne Name oder = expression

Tests: tests/test_phase38_conditional_compilation.py (6 Fälle inkl. Gegenbeispiele), Fixtures in tests/samples/compile_errors/conditional_compilation/.


Welle 10 — Lexer-Ergänzungen ✅

Abgeschlossen (lexer-seitig).

ID Meldung Auslöser
VBA_LEX004 Unterminated string / missing end bracket "… ohne ", [… ohne ]
VBA_LEX005 Identifier too long Bezeichner > 255 Zeichen
VBA_LEX006 Line too long physische Zeile > 1023 Zeichen

VBA_LEX003 (Type-declaration character mismatch) zurückgestellt: braucht Parser-/Deklarationskontext (Dim x% As String), gehört nicht auf Lexer-Ebene — bewusst nicht implementiert (FP-Risiko, falsche Schicht).

Tests: tests/test_phase39_lexer_limits.py (7 Fälle inkl. Gegenbeispiele), Fixtures in tests/samples/compile_errors/lexer_limits/.


Welle 5 — Prozedur-/Property-Konsistenz ✅

Abgeschlossen.

ID Meldung Auslöser
VBA150 Ambiguous name detected (duplicate procedure) zwei Prozeduren gleichen Namens (Property Get/Let/Set ausgenommen)
VBA152 Property Get/Let type inconsistent Get-Rückgabetyp ≠ Let-Wertparametertyp (nur klar-skalare Typen)
VBA153 Implements method signature mismatch Implementierungsmethode mit falscher Parameteranzahl

Umsetzung: neuer Validator _validate_duplicate_procedures (VBA150); VBA152 in _validate_property_arity ergänzt (auf klar-skalare Typen beschränkt → FP-sicher); VBA153 erweitert den bestehenden _validate_implements um einen Parameteranzahl-Abgleich.

VBA151 (Only comments after End Sub/Function/Property) zurückgestellt: überlappt mit VBA361 (executable at module level). VBA154 (Procedure type mismatch / AddressOf) zurückgestellt: erfordert Signatur-Typsystem, hohe Komplexität/FP.

Tests: tests/test_phase212_proc_consistency.py (7 Fälle inkl. Mehrmodul-Implements), Fixtures in tests/samples/compile_errors/proc_consistency/.


Welle 2 — Deklarations-Typauflösung ✅

Abgeschlossen. Neuer Validator _validate_declared_types(mod) + Resolver _is_known_type / _check_type_known; lokale Dim-Typen zusätzlich in process_dim geprüft.

ID Meldung Severity Auslöser
VBA120 User-defined type not defined warning unauflösbarer Typname
VBA122 User-defined type without members error leeres Type … End Type
VBA123 Empty Enum not allowed error leeres Enum … End Enum

Severity-Entscheidung (wichtig): VBA120 ist warning, nicht error. Mit einem prinzipiell unvollständigen Host-Modell lässt sich ein Tippfehler nicht sicher von einem nicht-modellierten Host-Typ unterscheiden. VBA120 macht das Risiko sichtbar, ohne die Compile-Safety zu blockieren — und der FP-Wächter (zählt nur error) bleibt grün. VBA122/123 sind modellunabhängig und bleiben harte Fehler.

FP-Reduktion: kuratierte Allowlist universeller VBA/stdole/MSForms- Intrinsics (OLE_COLOR, vbTriState, Form, Font, Picture, …) + großzügige Behandlung bibliotheksqualifizierter Namen (Scripting.Dictionary).

VBA121 (Forward reference to UDT) zurückgestellt: subtile Sonderfall- Semantik, geringer Nutzen, FP-Risiko.

Tests: tests/test_phase16_declared_types.py (9 Fälle), Fixtures in tests/samples/compile_errors/declared_type/. FP-Wächter grün.


Welle 6 — Zuweisungs-/Ausdrucks-Semantik ✅

Abgeschlossen.

ID Meldung Auslöser
VBA160 Assignment to constant not permitted Zuweisung an Const/Enum-Member
VBA164 Invalid use of Me keyword Zuweisung an Me
VBA165 Invalid use of New keyword As New <primitive/Object/Variant>

Umsetzung: VBA160/164 in _validate_set_vs_let integriert; VBA165 in process_dim (Flag saw_new). Nebenbei einen Parser-Quirk behoben: ein modulweites bloßes Const X = … (ohne Public/Private) wurde mit is_const=False registriert — jetzt korrekt als Const (Default-Scope Private), wodurch auch VBA231/VBA160 dafür greifen.

Zurückgestellt: VBA161 (Can't assign to an array), VBA162 (Function call on LHS), VBA163 (Wrong/Too many dimensions), VBA166 (Invalid use of AddressOf) — erfordern ein Ausdruck-Typsystem, das der Analyzer nicht vollständig besitzt; hohes FP-Risiko.

Tests: tests/test_phase213_assignment_semantics.py (6 Fälle), Fixtures in tests/samples/compile_errors/assignment_semantics/. FP-Wächter grün.


Welle 4 — Benannte Argumente an Aufrufstellen ✅

Abgeschlossen. Neuer Helfer _validate_named_args, aufgerufen aus validate_signature (greift für geklammerte Aufrufe auflösbarer Prozeduren).

ID Meldung Auslöser
VBA140 Named argument not found name:= ohne passenden Parameter (nur bei zuverlässig bekannten Quell-Signaturen)
VBA141 Named argument specified more than once doppeltes name:= im selben Aufruf (rein syntaktisch)
VBA142 Named arguments with ParamArray benannte Argumente bei ParamArray-Prozedur

FP-Schutz (im Review verschärft): VBA140 feuert ausschließlich für gescannte Quell-Prozeduren (isinstance(extra, ProcedureNode)). Host-Modell- Parameternamen sind nur beratend (sie können den echten API-Namen abkürzen/ umbenennen, z. B. Range.Find(What:=…)) und lösen daher kein VBA140 aus. VBA141 ist rein syntaktisch.

Bekannte Einschränkung: validiert wird nur die geklammerte Aufrufform (Foo(a:=1)); die klammerlose Statement-Form (Foo a:=1) erreicht validate_signature nicht und bleibt ungeprüft.


Maximum-Coverage-Nachschub (nach dem Review)

Erneute kritische Durchsicht der zurückgestellten Regeln und des Microsoft-Katalogs: alles, was sich FP-arm umsetzen lässt, wurde nachgezogen (jeweils vorab gegen den realen awesome_vba-Korpus auf 0 Treffer geprüft):

ID Meldung Schicht
VBA137 User-defined type passed ByVal (ByVal p As <UDT>; Enums ausgenommen) Analyzer
VBA151 Code/Statement nach End Sub/Function/Property (nur Kommentare erlaubt) Parser
VBA270 Typkennzeichen ≠ As-Typ (Dim x% As Long; ersetzt das geplante VBA_LEX003) Analyzer
VBA370 Public Const/Array/Declare als Member eines Objektmoduls (Class/Form) Analyzer

Status: abgeschlossen 🎉

Alle 10 Wellen + Maximum-Coverage-Nachschub. 41 → 90 Regeln.

Verbleibende, bewusst nicht umgesetzte Regeln — jede würde ein vollständiges Ausdruck-/Array-Typsystem erfordern oder ist nicht eindeutig statisch entscheidbar (Umsetzung würde Falsch-Positive riskieren, was dem Zweck eines Compile-Safety-Tools widerspricht):

Regel Thema Grund der Nichtumsetzung
VBA121 Forward reference to UDT Sonderfall-Semantik, in der Praxis selten relevant
VBA135 Invalid optional parameter type kein eindeutiger Compile-Fehler
VBA154 Procedure type mismatch (AddressOf) Signatur-Typsystem für AddressOf-Ziele nötig
VBA161 Can't assign to an array Array-Kopie (a = b) ist gültiges VBA → FP-Risiko
VBA162 Function call on LHS must return … Rückgabetyp-Inferenz auf der linken Seite nötig
VBA163 Too many / wrong number of dimensions Array-Shape-Tracking nötig; >60 Dims praktisch irrelevant
VBA166 Invalid use of AddressOf Ziel kann in anderem Modul liegen → FP-Risiko
VBA185 Must be first statement on the line format-/kontextabhängig

Der awesome_vba-Falsch-Positiv-Wächter ist über alle Wellen und den Nachschub grün geblieben (395 Tests).