Background
The NAV SDK RegisterCodeBlockAction callback can be skipped during incremental compilation when the SDK determines a declaration has not changed (via AnalysisState.declarationAnalysisDataMap caching). This was the root cause of AC0032 false positives (fixed in #253).
While CodeBlockAction results are typically cached and replayed correctly for pure per-method analysis, analyzers that depend on external state (settings, compilation-wide indexes, other objects) risk producing stale diagnostics when that external state changes but the analyzed method does not.
Risky patterns
- RegisterCodeBlockAction — can be skipped entirely for unchanged declarations during incremental compilation in VS Code
- CompilationStart + accumulator + CompilationEnd — accumulator will be incomplete if inner callbacks are skipped (no instances found currently, but guard against future additions)
Safe patterns
RegisterSyntaxNodeAction — always fires, never skipped
RegisterOperationAction — always fires, never skipped
RegisterSymbolAction — fires per-symbol, safe for object-level analysis
CompilationStart → RegisterSymbolAction — safe (used for pre-building indexes)
Audit results
Analyzers using RegisterCodeBlockAction (5 total)
| Analyzer |
Cop |
Diagnostic IDs |
External state dependency |
Risk |
| CognitiveComplexity |
LinterCop |
LC0059 |
Settings threshold (loaded in CompilationStart, stored as instance field) |
Medium — if user changes alcops.json threshold without editing the method, cached result uses old threshold |
| CyclomaticComplexityAndMaintainabilityIndex |
LinterCop |
LC0060, LC0061 |
Settings threshold (loaded per-invocation inside CodeBlockAction) |
Low — settings read each time, purely per-method |
| IdentifiersInEventSubscribers |
LinterCop |
LC0049 |
None |
Low — purely local naming check |
| UseSequentialGuid |
PlatformCop |
PC0029 |
None |
Low — purely local pattern detection |
| PartialRecordOperations |
PlatformCop |
PC0030 |
None (per-method analysis of reads/writes) |
Low — purely local flow analysis |
CompilationStart → safe inner callback (not at risk, listed for completeness)
These use CompilationStart only to build compilation-wide indexes or load configuration, then register safe inner callbacks (RegisterSymbolAction):
- AllowInCustomizationsForOmittedFields (AC0026)
- FieldGroupsRequired (AC0013)
- InterfaceObjectNameGuide (LC0049)
- TranslatableTextShouldBeTranslated (LC0091)
- NamingPattern (LC0092)
Recommendations
-
CognitiveComplexity (LC0059): Consider moving settings loading into the CodeBlockAction itself (like CyclomaticComplexity does), or switching to RegisterSyntaxNodeAction on MethodDeclaration nodes. The current pattern means a threshold change in alcops.json may not take effect until the method is edited.
-
All CodeBlockAction analyzers: If any future changes add cross-method or cross-object dependencies, migrate to RegisterSyntaxNodeAction to avoid incremental skipping.
-
Guard rails: Add a code review checklist item: "Does this analyzer use RegisterCodeBlockAction? If so, does it depend on any state outside the code block?"
No action required now
This is a low-priority backlog item for awareness and future-proofing. The current analyzers using CodeBlockAction are mostly safe because they perform purely per-method analysis. The only actionable item is the CognitiveComplexity settings threshold staleness (medium risk, edge case).
Background
The NAV SDK
RegisterCodeBlockActioncallback can be skipped during incremental compilation when the SDK determines a declaration has not changed (viaAnalysisState.declarationAnalysisDataMapcaching). This was the root cause of AC0032 false positives (fixed in #253).While CodeBlockAction results are typically cached and replayed correctly for pure per-method analysis, analyzers that depend on external state (settings, compilation-wide indexes, other objects) risk producing stale diagnostics when that external state changes but the analyzed method does not.
Risky patterns
Safe patterns
RegisterSyntaxNodeAction— always fires, never skippedRegisterOperationAction— always fires, never skippedRegisterSymbolAction— fires per-symbol, safe for object-level analysisCompilationStart → RegisterSymbolAction— safe (used for pre-building indexes)Audit results
Analyzers using RegisterCodeBlockAction (5 total)
alcops.jsonthreshold without editing the method, cached result uses old thresholdCompilationStart → safe inner callback (not at risk, listed for completeness)
These use CompilationStart only to build compilation-wide indexes or load configuration, then register safe inner callbacks (RegisterSymbolAction):
Recommendations
CognitiveComplexity (LC0059): Consider moving settings loading into the CodeBlockAction itself (like CyclomaticComplexity does), or switching to RegisterSyntaxNodeAction on MethodDeclaration nodes. The current pattern means a threshold change in
alcops.jsonmay not take effect until the method is edited.All CodeBlockAction analyzers: If any future changes add cross-method or cross-object dependencies, migrate to RegisterSyntaxNodeAction to avoid incremental skipping.
Guard rails: Add a code review checklist item: "Does this analyzer use RegisterCodeBlockAction? If so, does it depend on any state outside the code block?"
No action required now
This is a low-priority backlog item for awareness and future-proofing. The current analyzers using CodeBlockAction are mostly safe because they perform purely per-method analysis. The only actionable item is the CognitiveComplexity settings threshold staleness (medium risk, edge case).