Unused permission declared
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
Permissionsproperty is removed. - Partial chars unused: reduces the permission string to only the chars that are actually used, in canonical
rimdorder.
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
permissionsetorpermissionsetextension(these declare permissions structurally, not for access control) - The object contains a database operation on a
RecordRef(see below)
RecordRef operations
A RecordRef can point to any table, and which table it targets is only known at runtime. When an object contains any database operation on a RecordRef receiver (Find, FindFirst, FindLast, FindSet, Get, GetBySystemId, IsEmpty, Count, Insert, Modify, ModifyAll, Rename, Delete, or DeleteAll), the rule cannot determine which declared permission that operation consumes. AC0032 is therefore disabled for the entire object: no unused-permission diagnostics are reported, and the code fix is not offered.
codeunit 50100 "Ledger Entry Management"
{
// No AC0032 diagnostics: the RecordRef.Modify call below may target any of these tables at runtime
Permissions =
tabledata "G/L Entry" = md,
tabledata "Cust. Ledger Entry" = md;
procedure DoModify(var RecordRefToModify: RecordRef; RunTrigger: Boolean)
begin
RecordRefToModify.Modify(RunTrigger);
end;
}Note that this also suppresses genuinely unused entries in the same object. This trade-off is deliberate: a false “unused” report combined with the code fix would remove permissions that are required at runtime.
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
TableTypeproperty, a temporary record variable, or theSourceTableTemporaryproperty on a page.
— Temporary tables on Microsoft Learn
See also
- Permissions on database objects on Microsoft Learn