Migrating from BusinessCentral.LinterCop

The BusinessCentral.LinterCop project has been the foundation for community-driven AL code analysis and it’s rules and diagnostics are now part of ALCops

  • ApplicationCop covers application conventions, labels, permissions, and UX standards.
  • DocumentationCop covers comments, XML documentation, and code documentation.
  • FormattingCop covers code style, formatting, and visual consistency.
  • LinterCop covers code quality metrics, complexity, and modern AL patterns.
  • PlatformCop covers platform-level correctness, runtime safety, and API constraints.
  • TestAutomationCop covers test code structure and correctness.

If you are currently using the BusinessCentral.LinterCop, use the mapping below to find where each diagnostic moved.

Diagnostic Mapping

LinterCopTitleAnalyzerALCops
LC0001FlowFields should not be editable.PlatformCopPC0001
LC0002Commit() needs a comment to justify its existence.DocumentationCopDC0001
LC0003Do not use an Object ID for properties or variable declarations.LinterCopLC0003
LC0004DrillDownPageId and LookupPageId must be filled in table when table is used in list page.ApplicationCopAC0001
LC0005The casing of variable/method usage must align with the definition.FormattingCopFC0002
LC0006Fields with property AutoIncrement cannot be used in temporary table (TableType = Temporary).PlatformCopPC0002
LC0007Every table needs to specify a value for the DataPerCompany property. Either true or false.ApplicationCopAC0008
LC0008Filter operators should not be used in SetRange.PlatformCopPC0003
LC0009Show info message about code metrics for each function or trigger.LinterCopLC0007 , LC0009
LC0010Show warning about code metrics for each function or trigger.LinterCopLC0008 , LC0010
LC0011Every object needs to specify a value for the Access property. Either true or false.PlatformCopPC0006
LC0012Using hardcoded IDs in functions like Codeunit.Run() is not allowed.LinterCopLC0003
LC0013Any table with a single field in the PK of type code or text, should have set NotBlank on the PK field.ApplicationCopAC0002
LC0014The Caption of permissionset objects should not exceed the maximum length.ApplicationCopAC0009
LC0015All application objects should be covered by at least one permission set in the extension.ApplicationCopAC0010
LC0016Caption is missing.ApplicationCopAC0011
LC0017Writing to a FlowField is not common. Add a comment to explain this.DocumentationCopDC0002
LC0018Events in internal codeunits are not accessible to extensions and should therefore be avoided.ApplicationCopAC0012
LC0019If Data Classification is set on the Table, fields do not need the same classification.LinterCopLC0019
LC0020If Application Area is set on the Page, controls do not need the same classification.LinterCopLC0020
LC0021Confirm() must be implemented through the Confirm Management codeunit from the System Application.ApplicationCopAC0004
LC0022GlobalLanguage() must be implemented through the Translation Helper codeunit from the Base Application.ApplicationCopAC0005
LC0023Always provide fieldgroups DropDown and Brick on tables.ApplicationCopAC0013
LC0024Procedure or Trigger declaration should not end with semicolon.FormattingCopFC0001
LC0025Procedure must be either local, internal or define a documentation comment.DocumentationCopDC0004
LC0026ToolTip must end with a dot.ApplicationCopAC0014
LC0027Utilize the Page Management codeunit for launching page.ApplicationCopAC0006
LC0028Event subscriber arguments now use identifier syntax instead of string literals.LinterCopLC0028
LC0029Use CompareDateTime method in Type Helper codeunit for DateTime variable comparisons.ApplicationCop
LC0030Set Access property to Internal for Install/Upgrade codeunits.ApplicationCopAC0007
LC0031Use ReadIsolation instead of LockTable.LinterCopLC0031
LC0032Clear(All) does not affect or change values for global variables in single instance codeunits.PlatformCopPC0016
LC0033The specified runtime version in app.json is falling behind.LinterCopLC0033
LC0034The property Extensible should be explicitly set for public objects.PlatformCopPC0005
LC0035Explicitly set AllowInCustomizations for fields omitted on pages.ApplicationCopAC0026
LC0036ToolTip must start with the verb “Specifies”.ApplicationCopAC0015
LC0037Do not use line breaks in ToolTip.ApplicationCopAC0016
LC0038Try to not exceed 200 characters (including spaces).ApplicationCopAC0017
LC0039The given argument has a different type from the one expected.PlatformCopPC0017
LC0040Explicitly set the RunTrigger parameter on built-in methods.LinterCopLC0040
LC0041Empty Captions should be Locked.ApplicationCopAC0018
LC0042AutoCalcFields should only be used for FlowFields or Blob fields.PlatformCopPC0007
LC0043Use SecretText type to protect credentials and sensitive textual values from being revealed.LinterCopLC0043
LC0044Tables coupled with TransferFields must have matching fields.PlatformCopPC0020 , PC0021
LC0045Zero (0) Enum value should be reserved for Empty Value.ApplicationCopAC0019
LC0046Label with suffix Tok must be locked.ApplicationCopAC0020
LC0047Locked Label must have a suffix Tok.ApplicationCopAC0021
LC0048Use Error with a ErrorInfo or Label variable to improve telemetry details.LinterCopLC0048
LC0049SourceTable property not defined on Page.PlatformCopPC0018
LC0050SetFilter with unsupported operator in filter expression.PlatformCopPC0008
LC0051Do not assign a text to a target with smaller size.PlatformCopPC0022
LC0052The internal procedure is declared but never used.LinterCopLC0052
LC0053The internal procedure is only used in the object in which it is declared. Consider making the procedure local.LinterCopLC0053
LC0054Interface name must start with the capital ‘I’ without any spaces following it.LinterCopLC0054
LC0055The suffix Tok is meant to be used when the value of the label matches the name.ApplicationCopAC0027
LC0056Empty Enum values should not have a specified Caption property.ApplicationCopAC0022
LC0057Enum values must have non-empty a Caption to be selectable in the client.ApplicationCopAC0023
LC0058PageVariable.SetRecord(): You cannot use a temporary record for the Record parameter.PlatformCop
LC0059Single quote escaping issue detected.PlatformCopPC0019
LC0060The ApplicationArea property is not applicable to API pages.PlatformCopPC0024
LC0061Pages of type API must have the ODataKeyFields property set to the SystemId field.PlatformCopPC0025
LC0062Mandatory field is missing on API page.PlatformCopPC0026
LC0063Consider naming field with a more descriptive name.LinterCopLC0063
LC0064Missing ToolTip property on table field.ApplicationCopAC0028
LC0065Event subscriber var keyword mismatch.PlatformCopPC0010
LC0066Duplicate ToolTip between page and table field.ApplicationCopAC0029
LC0067Set NotBlank property to false when ‘No. Series’ TableRelation exists.ApplicationCopAC0003
LC0068Informs the user that there are missing permission to access tabledata.ApplicationCopAC0031
LC0069Empty statements should be avoided or should have a comment explaining their use.DocumentationCopDC0003
LC0070Zero index access on 1-based List objects.PlatformCopPC0004
LC0071Incorrect ‘IsHandled’ parameter assignment.PlatformCopPC0023
LC0072The documentation comment must match the procedure syntax.DocumentationCopDC0005
LC0073Handled parameters in event signatures should be passed by var.PlatformCopPC0011
LC0074Set values for FlowFilter fields using filtering methods.PlatformCopPC0012
LC0075Incorrect number or type of arguments in .Get() method on Record object.PlatformCopPC0013
LC0076The field with table relation should have at least the same length as the referenced field.PlatformCopPC0028
LC0077Methods should always be called with parenthesis.FormattingCopFC0003
LC0078Temporary records should not trigger table triggers.PlatformCopPC0027
LC0079Event publishers should not be public.ApplicationCopAC0024
LC0080Replace double quotes in JPath expressions with two single quotes.PlatformCopPC0014
LC0081Use Rec.IsEmpty() for checking record existence.LinterCopLC0081
LC0082Consider using a Query or Rec.Find(’-’) with Rec.Next().LinterCopLC0082
LC0083Use new Date/Time/DateTime methods for extracting parts.LinterCopLC0083
LC0084Use return value for better error handling.ApplicationCopAC0030
LC0085Use the (CR)LFSeparator from the “Type Helper” codeunit.ApplicationCopAC0025
LC0086Use the new PageStyle datatype instead string literals.LinterCopLC0086
LC0087Use IsNullGuid() to check for empty GUID values.PlatformCopPC0015
LC0088Option types should be avoided, use enum if applicable.LinterCopLC0088
LC0089Show Cognitive Complexity diagnostics for all methods.LinterCopLC0089
LC0090Show Cognitive Complexity diagnostics for methods above threshold.LinterCopLC0090
LC0091Translatable texts should be translated.ApplicationCop
LC0092Names must match the allowed pattern and must not match the disallowed pattern.LinterCop
LC0093Global procedure in test codeunit requires test attribute.TestAutomationCopTA0001

Entries marked with do not have a new diagnostic ID assigned (yet).

Notable Changes

Rules split into multiple diagnostics. LC0009 and LC0010 each covered both cyclomatic complexity and maintainability index. In ALCops these are separate diagnostics (LC0007/LC0009 and LC0008/LC0010 respectively) so you can control each metric independently.

Rules merged. LC0003 and LC0012 both flagged the use of hardcoded object IDs. They are consolidated into LC0003 .

Rules split across analyzers. LC0044 (TransferFields matching) is now covered by two PlatformCop diagnostics: PC0020 and PC0021 .

Updating Your Ruleset

If you maintain a custom .ruleset.json that references LinterCop rule IDs, update the IDs to match the new analyzer prefixes. For example:

{
    "rules": [
        {
            "id": "PC0001",
            "action": "Warning",
            "justification": "Previously LC0001"
        },
        {
            "id": "AC0001",
            "action": "Warning",
            "justification": "Previously LC0004"
        }
    ]
}

Any pragma directives in your AL code (#pragma warning disable LCxxxx) need to be updated to the new diagnostic IDs as well.