Skip to content

fix(LC0091): align obsolete handling with compiler XLIFF generation - #563

Merged
Arthurvdv merged 4 commits into
mainfrom
fix/lc0091-obsolete-compiler-parity
Sep 27, 2026
Merged

Arthurvdv merged 4 commits into
mainfrom
fix/lc0091-obsolete-compiler-parity

Conversation

@Arthurvdv

@Arthurvdv Arthurvdv commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Problem

LC0091 reads source symbols, computes each trans-unit id and looks it up in the translated .xlf files, so it has to replicate the compiler's decision of which units are locked or dropped. It gated every callback on the general IsObsolete() check (Pending, Removed, Moved, PendingMove, on the symbol and its containing object) and additionally dropped labels and report labels whenever their containing object was obsolete. The compiler is narrower, which left false negatives: Pending captions and tooltips, and labels left behind in obsolete objects, were never reported although the XLIFF still carries their units.

Compiler behaviour (nav-sdk-source, identical from SDK 12 to 30)

Translation/LabelWriterVisitor.cs:

  • IsObsolete locks a field when it or its containing table is IsObsoleteRemoved, and any other symbol only when it is IsObsoleteRemoved itself. IsObsoletePending is never read.
  • Only FieldSymbol, KeySymbol, TableTypeSymbol, TableExtensionTypeSymbol (forwarding to its target) and RecordTypeSymbol override IsObsoleteRemoved; pages, controls, actions, enums, reports and the other object kinds can never be Removed.
  • ShouldSymbolBeVisited skips a Moved table or field and its whole subtree. PendingMove is neither skipped nor locked.
  • VisitVariable and VisitReportLabel pass no lock flag; a label is locked only by its own Locked = true.
  • XliffOutputter.WriteLabel drops locked units (or writes translate="no" under GenerateLockedTranslations).

Change

Element Compiler LC0091 before LC0091 after
Caption on Removed table/field, field in Removed table, tableextension field on Removed target dropped skipped skipped
Anything inside a Moved object, Moved field not visited skipped skipped
Caption/ToolTip on Pending or PendingMove element emitted skipped reported
Label or report label inside a Removed/Pending object, not Locked emitted skipped reported
Label with Locked = true dropped skipped skipped
  • TranslatableTextShouldBeTranslated: the IsObsolete() gate becomes a Moved-container check; property lock decisions go through IsLockedByCompiler, a mirror of the visitor's IsObsolete built on the existing IsRemoved(); the containing-object check on report labels is gone; controls, actions and analysis views use IsRemoved().
  • ALCops.Common: IsMoved() next to IsRemoved(), reusing the existing reflection accessor.
  • Fixtures: six HasDiagnostic cases (all failing before the change) and four NoDiagnostic regression guards for the Removed paths.
  • .claude docs: rule doc design decision, non-reports, SDK facts and test notes; compiler-parity exception on the IsObsolete()-first rule in analyzer-development.md and REVIEW.md.

Verification

  • LC0091 filter 29/29, LinterCop 396/396, dotnet test ALCops.sln 1895 passed.
  • dotnet format --verify-no-changes clean; Common and all six cops build for netstandard2.1;net8.0;net10.0 with 0 warnings.
  • Validate-Rules.ps1 passes.
  • Independent /code-review at effort high: one finding on the helper comment, addressed in the last commit.

Companion docs PR: ALCops/alcops.dev#191

Closes #385

🤖 Generated with Claude Code

Arthurvdv and others added 4 commits September 27, 2026 06:56
…cking

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ymbols

The helper comment described only the Removed case while IsRemoved()
also returns true for Moved, which mirrors ShouldSymbolBeVisited
skipping a Moved table or field. The rule doc now lists Moved fields
among the deliberate non-reports.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Arthurvdv
Arthurvdv merged commit 591e4a1 into main Sep 27, 2026
40 checks passed
@Arthurvdv
Arthurvdv deleted the fix/lc0091-obsolete-compiler-parity branch September 27, 2026 05:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LC0091: verify & align obsolete/removed handling with compiler XLIFF generation

1 participant