Unused permission declared

Properties
AC0032 Info Design Code Fix Ignore Obsolete

The Permissions property declares which table data operations the object performs. When an entry references a table the object never accesses, or grants broader access than the code requires, the extra declarations mislead anyone auditing the object: a reviewer reading Permissions = tabledata "G/L Entry" = rimd trusts that the object modifies and deletes general ledger entries, when in fact it only reads them. Remove unused entries and reduce overly broad chars to match actual usage.

This rule is the inverse of AC0031 . Where AC0031 detects missing permissions, AC0032 detects permissions that are declared but not backed by any code.

Example

Entire entry unused. When a Permissions entry references a table that no code in the object accesses at all:

codeunit 50100 "Post Sales Invoice"
{
    Permissions = tabledata "Sales Header" = rimd; // Unused permission declared [AC0032]

    procedure Post()
    begin
        // No code accesses "Sales Header"
    end;
}

Remove the unused entry:

codeunit 50100 "Post Sales Invoice"
{
    procedure Post()
    begin
    end;
}

Partial chars unused. When the declared permission chars exceed what the code actually needs:

codeunit 50100 "Post Sales Invoice"
{
    Permissions = tabledata "Sales Header" = rimd; // Unused permission declared [AC0032]

    procedure Post()
    var
        SalesHeader: Record "Sales Header";
    begin
        SalesHeader.FindFirst();
    end;
}

Reduce the permission to match actual usage:

codeunit 50100 "Post Sales Invoice"
{
    Permissions = tabledata "Sales Header" = r;

    procedure Post()
    var
        SalesHeader: Record "Sales Header";
    begin
        SalesHeader.FindFirst();
    end;
}

Code fix

The ALCops: Remove unused permission code fix handles both variants:

  • Entire entry unused: removes the entry from the list. If it is the last entry, the entire Permissions property is removed.
  • Partial chars unused: reduces the permission string to only the chars that are actually used, in canonical rimd order.

Exception

The diagnostic is suppressed when any of the following conditions apply:

  • The target table is a system table (ID > 2,000,000,000)
  • The containing symbol is obsolete
  • The codeunit is a test codeunit with TestPermissions = Disabled
  • The containing object is a permissionset or permissionsetextension (these declare permissions structurally, not for access control)

Temporary tables

Access through a temporary table does not count as using a permission. Temporary tables never touch the database, so a Permissions entry for a table that is accessed only through temporary records is dead code and is reported as unused. This applies to every way a temporary table can be implemented: the temporary keyword on a record variable, a table object with TableType = Temporary, a page with SourceTableTemporary = true, and report data items or XMLPort table elements with UseTemporary = true.

Temporary tables don’t require the user to have permissions on the underlying table. Because temporary table data is held only in memory and never read from or written to the database, the permission system doesn’t apply. […] This behavior applies regardless of how the temporary table is implemented—whether by using the TableType property, a temporary record variable, or the SourceTableTemporary property on a page.

Temporary tables on Microsoft Learn

See also