Skip to content

feat(LC0101,LC0102): Report database modifications inside TryFunctions - #590

Open
tkroes wants to merge 1 commit into
ALCops:mainfrom
tkroes:feat/lc0101-tryfunction-database-modifications
Open

tkroes wants to merge 1 commit into
ALCops:mainfrom
tkroes:feat/lc0101-tryfunction-database-modifications

Conversation

@tkroes

@tkroes tkroes commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds two LinterCop rules that flag database modifications inside a [TryFunction].

A TryFunction swallows runtime errors, but it does not roll back database writes made before the error. Code that writes inside a TryFunction can therefore leave the database half-updated while the caller carries on as if the call had failed cleanly.

ID Name Severity Category
LC0101 TryFunctionDatabaseModificationDisallowed Error Usage
LC0102 TryFunctionPotentialDatabaseModification Warning Usage

Both are enabled by default. Neither has a CodeFix, a setting or a version gate.

What is reported

LC0101 (Error) is raised on built-in methods that always write:
Insert, Modify, ModifyAll, Delete, DeleteAll, Rename, Truncate, AddLink, CopyLinks, DeleteLink, DeleteLinks.

LC0102 (Warning) is raised on calls that may write, depending on the target:

  • Validate, since field triggers may modify data
  • Run and Codeunit.Run
  • calls to custom procedures and other non-built-in methods

Deliberate limits

  • Only calls written directly in the TryFunction body are analyzed. The call graph is not followed, because walking it for every procedure is too expensive. LC0102 is a warning so it can be dismissed with a pragma once the callee is known to be safe.
  • Matching is by method name, so FieldRef.Validate is covered by the same rule as Record.Validate.
  • Obsolete TryFunctions and declarations without a body are skipped.
  • Calls in nested code blocks inside the TryFunction are all reported.

Implementation notes

  • One analyzer, TryFunctionDatabaseModification, registered with RegisterCodeBlockAction. It reports both diagnostics in the same callback and carries no state between callbacks.
  • TryFunctions are detected with the syntax helper MethodDeclarationSyntax.IsTryFunction(), because IMethodSymbol.IsTryFunction is not available on netstandard2.1.
  • The Insert, Modify and Delete method names come from ALCops.Common.RecordMethodClassification, and the remaining names are listed in the analyzer.

Tests

5 new fixture-based tests:

  • HasDiagnostic: all 11 direct modification methods, and the potential-modification cases.
  • NoDiagnostic: read-only methods, the same calls outside a TryFunction, and an obsolete TryFunction.

Validation:

  • LinterCop tests: 401 passing.
  • Release build with ContinuousIntegrationBuild=true: succeeds on netstandard2.1, net8.0 and net10.0.
  • dotnet format --verify-no-changes: clean.
  • Validate-Rules.ps1: passes.

Documentation

  • Rule doc added at .claude/rules/diagnostics/lc0101-lc0102-tryfunction-database-modification.md.
  • The docs-site pages in alcops.dev (content/docs/analyzers/lintercop/LC0101.md and LC0102.md) still need to be written.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant