Skip to content

Audit all rules for the four receiver forms on fields and methods, TableNo OnRun Rec, page Rec and namespaces #545

Description

@Arthurvdv

Why

While fixing PC0029 (#544) three false negatives turned out to be gaps in how rules reach a record: a bare-self field write inside a table trigger, a namespaced fully qualified Record variable, and Rec."Field" inside the OnRun trigger of a codeunit with TableNo. Only PC0029 was fixed. Every rule that touches record fields, record methods or user procedures can have the same gaps, and #509 audited only the method receiver axis on 18 rules. This issue asks for a second, broader audit.

The constructs every rule must handle

AL reaches a receiver in four forms, and they apply to fields (IFieldAccess.Instance) and methods (IInvocationExpression.Instance, built-in record methods and user procedures alike):

Form Example Bound Instance
Named variable MyTable."No.", MyTable.Modify(), Helper.MyProc() variable or parameter reference
Implicit Rec Rec."No.", Rec.Modify() the synthesized Rec (see below)
Bare self "No.", Modify(), MyProc() null inside tables and tableextensions; a Rec reference elsewhere
this (runtime 14.0+) this."No.", this.Modify(), this.MyProc() OperationKind.ThisReference

Rec itself has several origins (verified in the decompiled SDK, Microsoft.Dynamics.Nav.CodeAnalysis):

Object Rec Bare access binds as xRec this
table, tableextension synthesized global flagged as the object's own instance (TableObjectMembers, TableExtensionObjectMembers) Instance == null, triggers and procedures alike yes the record type
page, pageextension, requestpage, report, xmlport synthesized global of the SourceTable (report/xmlport: the request page's) (PageObjectMembers and siblings) binder inserts Rec: IGlobalReferenceExpression, gated on #pragma implicitwith yes the object
codeunit with TableNo, only in trigger OnRun synthesized local variable of the trigger (SourceMethodOrTriggerSymbol) ILocalReferenceExpression over that local (InMethodBinder) no the codeunit; this."Field" does not compile
report / query dataitem triggers none IReportDataItemAccess / query dataitem access no the object

TableNo is a codeunit-only property (ObjectParser.GetCodeunitProperties). A namespaced Record Pub.Ext.Domain.Table binds to the same RecordTypeSymbol as the unqualified spelling, but a misspelled namespace yields an error type that still reports NavTypeKind.Record while not being an IRecordTypeSymbol.

Full write-up with SDK file references: .claude/rules/receiver-forms.md (renamed and expanded from record-receiver-forms.md in #544); fixture conventions in .claude/rules/testing.md rule 6 and 7; reviewer rows in REVIEW.md.

What to do

For every rule that reads a record receiver, a field access or a method invocation (in all six cops, analyzers and code fixes):

  1. Add the fixture set from testing.md rule 6: {Scenario}NamedVariable, RecSelf, BareSelf, ThisSelf (gated on 14.0), the InTableExtension variants, {Scenario}OnRunRec for a TableNo codeunit, {Scenario}PageRec where the rule can apply to pages or request pages, and one namespaced fixture with a fully qualified object reference (rule 7). Where a code fix exists, add HasFix cases for bare self and this.
  2. Fix what fails. Prefer GetReceiverTableType (Common) for table resolution; a Rec check must accept both the global and the OnRun local (test IsSynthesized and the name, not SymbolKind.GlobalVariable).
  3. Record a per-form verdict in the rule's .claude/rules/diagnostics/{id}-{slug}.md (fixed / by design / known limitation), as fix: handle all four record-method receiver forms across analyzers (#348) #509 did for the method axis; pin every deliberate non-report with a NoDiagnostic fixture.

Related: #509 (method receiver audit), #544 (PC0029 fixes and the guide), and #546 (implicit primary key audit).

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