Skip to content

fix(fc0007,pc0038,lc0089,lc0090) Inconsistent handling of AL built-in methods that unconditionally end execution - #464

Closed
MODUSCarstenScholling wants to merge 6 commits into
ALCops:release/v1.1.0from
MODUSCarstenScholling:dev-fix-terminating-methods
Closed

fix(fc0007,pc0038,lc0089,lc0090) Inconsistent handling of AL built-in methods that unconditionally end execution#464
MODUSCarstenScholling wants to merge 6 commits into
ALCops:release/v1.1.0from
MODUSCarstenScholling:dev-fix-terminating-methods

Conversation

@MODUSCarstenScholling

Copy link
Copy Markdown
Contributor

Fixes the inconsistent handling of AL built-in methods that unconditionally end execution.

  • Adds FlowTerminatingBuiltIns as the shared semantic classifier for built-in Error and FieldError.
  • Updates PC0038 to treat Record.FieldError and FieldRef.FieldError as terminating return paths.
  • Updates FC0007 to handle FieldError consistently with Error.
  • Updates LC0089/LC0090 guard-clause handling to resolve calls semantically, preserving complexity increments for user-defined procedures named Error or FieldError.
  • Supports the valid AL syntax without parentheses for parameterless FieldRef.FieldError.
  • Uses AL case-insensitive name comparison and removes the obsolete ThrowError entry.
  • Adds focused regression coverage and records the LC0089/LC0090 semantic-resolution design decision.

Validation

  • CognitiveComplexity: 18 passed
  • Affected PC0038, FC0007, and Cognitive Complexity tests: 77 passed
  • CI-style multi-target build (netstandard2.1, net8.0, net10.0): 0 errors

Fixes #463

Resolve Error and FieldError calls semantically across PC0038, FC0007,
and LC0089/LC0090. This preserves cognitive-complexity increments for
user-defined methods with the same names, supports case-insensitive AL
method names, and removes the obsolete ThrowError terminator.

Add focused regression coverage and document the LC0089/LC0090 design.

Fixes ALCops#463
@MODUSCarstenScholling MODUSCarstenScholling changed the title fix(pc0007,pc0038,lc0089,lc0090) Inconsistent handling of AL built-in methods that unconditionally end execution fix(fc0007,pc0038,lc0089,lc0090) Inconsistent handling of AL built-in methods that unconditionally end execution Aug 25, 2026
Arthurvdv added a commit to Arthurvdv/Analyzers that referenced this pull request Aug 25, 2026
…ail to bind

PR ALCops#464 moved guard-clause detection for Error/FieldError from the lexical
guardClauseExitCommands set to FlowTerminatingBuiltIns, which requires
MethodKind.BuiltInMethod. When an argument does not bind (undefined
variable, wrong arity, mid-edit), Binder.CreateBadCall takes the
methods.Length != 1 branch for the two-overload built-ins Dialog.Error,
Table.FieldError and FieldRef.FieldError and returns an ErrorMethodSymbol
with MethodKind.Method. The classifier rejected it, the guard scored +1
and LC0089/LC0090 flickered while typing.

IsGuardExpression now runs in four stages: lexical exit commands, a
syntactic callee-name pre-filter (only Error/FieldError reach the binder),
semantic resolution, and an unbound fallback that keeps the guard unless
the call positively binds to a user-defined procedure
(DeclaringSyntaxReference != null) or the receiver is typed as a user
application object.

- Add error-tolerant fixtures proving Error(UndefinedVar) and
  Rec.FieldError(UndefinedField) stay guards, and Handler.Error(UndefinedVar)
  on a user codeunit still does not.
- Fix stale comment in IsGuardInvocation.
- Sync lc0089-cognitive-complexity instructions (design decisions, known
  issues, roadmap, test coverage).

Refs ALCops#464, ALCops#463

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Arthurvdv and others added 2 commits August 25, 2026 14:39
…ail to bind

PR ALCops#464 moved guard-clause detection for Error/FieldError from the lexical
guardClauseExitCommands set to FlowTerminatingBuiltIns, which requires
MethodKind.BuiltInMethod. When an argument does not bind (undefined
variable, wrong arity, mid-edit), Binder.CreateBadCall takes the
methods.Length != 1 branch for the two-overload built-ins Dialog.Error,
Table.FieldError and FieldRef.FieldError and returns an ErrorMethodSymbol
with MethodKind.Method. The classifier rejected it, the guard scored +1
and LC0089/LC0090 flickered while typing.

IsGuardExpression now accepts an invocation target whose name is in
FlowTerminatingBuiltIns.MethodNames and has no DeclaringSyntaxReference.
Built-ins and the synthesized ErrorMethodSymbol both satisfy this; only
user-defined procedures carry a DeclaringSyntaxReference, and since AL has
no user overloads a user procedure with bad arguments still binds to its
own symbol and stays demoted.

- Add error-tolerant fixtures proving Error(UndefinedVar) and
  Rec.FieldError(UndefinedField) stay guards, and Handler.Error(UndefinedVar)
  on a user codeunit still does not.
- Fix stale comment in IsGuardInvocation.
- Sync lc0089-cognitive-complexity instructions (design decisions, known
  issues, roadmap, test coverage).

Refs ALCops#464, ALCops#463

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…anticModel

The AL SDK's Compilation.GetSemanticModel is not cached: it returns
new SyntaxTreeSemanticModel(this, syntaxTree) on every call
(Compilation.cs:957). Calling it once per analyzed code block therefore
re-bound each procedure from scratch. CodeBlockAnalysisContext already
carries the semantic model for its tree, and the analyzer uses
context.SemanticModel elsewhere in the same file.

- Drop the Compilation parameter from AnalyzeCognitiveComplexity.
- Sync lc0089-cognitive-complexity instructions (design decision,
  architecture, remove the roadmap entry).

Refs ALCops#464, ALCops#463

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Arthurvdv

Copy link
Copy Markdown
Member

Thank you for creating a PR for this.

Instead of letting Claude write a review comment I wanted to experiment with letting it create a PR, so it created four (stacked) PR's based on the code review. Would love to hear if this works for you.

perf(LC0089): use context.SemanticModel instead of Compilation.GetSemanticModel
…-context-semantic-model

Revert "perf(LC0089): use context.SemanticModel instead of Compilation.GetSemanticModel"
@MODUSCarstenScholling

Copy link
Copy Markdown
Contributor Author

Thanks for trying this out, Arthur. I’m sorry, but I’m going to close the PR for now. My own review didn’t confirm all of the findings and found gaps, and I also accidentally merged the PRs in the wrong order. Unfortunately, I don’t have enough time at the moment to explore this workflow further, but I appreciate the experiment and the effort you put into it.

@MODUSCarstenScholling
MODUSCarstenScholling deleted the dev-fix-terminating-methods branch August 26, 2026 03:34
@Arthurvdv

Copy link
Copy Markdown
Member

I’m sorry, this wasn’t the outcome I was expecting. I’ll reach out to you directly so we can align and make sure we’re on the same page for future PRs.

@MODUSCarstenScholling

Copy link
Copy Markdown
Contributor Author

Looking forward to it. But the only issue here is that directly the first PR was wrong in my opinion. Like an AI suggesting the following 10 steps where step 1 already contains errors and changes all steps after.

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.

2 participants