Skip to content

Audit: Analyzers using RegisterCodeBlockAction (incremental compilation risk) #254

Description

@Arthurvdv

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

  1. RegisterCodeBlockAction — can be skipped entirely for unchanged declarations during incremental compilation in VS Code
  2. 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

  1. 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.

  2. All CodeBlockAction analyzers: If any future changes add cross-method or cross-object dependencies, migrate to RegisterSyntaxNodeAction to avoid incremental skipping.

  3. 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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions