Rulesets in Business Central

Microsoft Learn: CodeCop Analyzer Rules

By default, when enabling the Code Analyzers, Visual Studio Code will give Information, Warnings and Errors when you are working with an object. The vast majority are warnings. Now while this might be useful when working on a new object, it rapidly becomes annoying when converting an existing C/AL project to AL with either the standard txt2al Microsoft tool or the ForNAV converting tool.

The Challange

The issue is that, to Microsoft, almost all warnings are equally important. That is obviously not the case.

Our priority is to focus on issues that potentially can give runtime errors and performance problems.

Enabling Code Analysis

So the idea is to enable Code Analysis and then disable the warnings that we can ignore for now. This also allows us to enable the warnings one by one.

settings.json

Find the settings.json file in the .vscode folder.

You configure the settings for project in this file. This is a complementary file to your personal settings.

{
    "al.enableCodeAnalysis": true,
    "al.codeAnalyzers": [
        "${UICop}",
        "${CodeCop}"
    ],
    "al.backgroundCodeAnalysis": "Project",
    "al.ruleSetPath": "./.vscode/AfterConversion.ruleset.json",
    "al.browser": "Edge"
}
  • al.enableCodeAnalysis: Set it to true to enable the code analysis.
  • al.codeAnalyzers: These options are enough unless you are making an app for the AppStore.
  • al.backgroundCodeAnalysis: Chose Project so that it analyses all files in the project.
  • al.ruleSetPath: Points to the RuleSet file.

You might also have other settings in this file.

RuleSet File

The ruleset files are also placed in the .vscode folder.

If you consider having multiple rulesets, then read on here: Advanced CodeCop Analyzer and Custom Rulesets

You can find more details on Microsoft Learn: Ruleset for the code analysis tool.

Clean-up strategy

Start by setting the action on all rules to "action": "None". This will suppress all warnings. Then change the setting for one rule at the time to "action": "Error" and analyse the code that is detected by the rule. Continue with this till all rules are enabled.

{
    "name": "After Conversion Ruleset",
    "description": "This allows us to fix the issues in a prioritized order.",
    "rules": [
        {
            "id": "AA0139",
            "action": "None",
            "justification": "Do not assign a text to a target with smaller size. POTENTIAL RUNTIME ERROR."
        },
        {
            "id": "AA0462",
            "action": "Error",
            "justification": "The CalcDate should only be used with DataFormula variables. Alternatively the string should be enclosed using the <> symbols. POTENTIAL RUNTIME ERROR."
        },
        ...
         
    ]
}

Converting with ForNAV

When converting an old C/AL project to AL you have two options: ForNAV and Microsoft.

ForNAV: Converting txt to AL

Microsoft Learn: The Txt2AL Conversion Tool

ForNAV does a good job, but will, currently, fail to convert all objects. I have experienced issues with objects containing dotNET variables. dotNET variables like XML Documents have been replaced by native datatypes in AL and you have to rewrite parts of your code.

However, if ForNAV fails to convert an object, you can always use Microsoft. The Microsoft conversion needs manual work afterwards. For example, replacing object numbers with object names.

When you use the ForNAV Text to AL converter, all objects get this line in the top of the file.

#pragma warning disable AA0005, AA0008, AA0018, AA0021, AA0072, 
AA0137, AA0201, AA0204, AA0206, AA0218, AA0228, AL0254, AL0424, 
AS0011, AW0006 // ForNAV settings

This disables a series of warnings, but what does it mean and what should we do about it?

Replace the warnings with a Ruleset file

I recommend that you delete the line in all the converted files and set up a Ruleset file instead.

Automatically fix some of the warnings

Before starting to fix all the warnings manually, you have to read the section Cleanup Your Project in this article: VS Code Extensions for AL.

Order to fix the warnings in

These warnings should be addressed to mitigate the risk of runtime errors, improve performance, enhancing the reliability and robustness of your Business Central code.

Potential Runtime Errors

        {
            "id": "AA0139",
            "action": "Error",
            "justification": "Do not assign a text to a target with smaller size."
        },
        {
            "id": "AA0462",
            "action": "Error",
            "justification": "The CalcDate should only be used with DataFormula variables. Alternatively the string should be enclosed using the <> symbols."
        },
        {
            "id": "AL0615",
            "action": "Error",
            "justification": "Field '{0}' is not specified as a source expression on page '{1}'. All fields specified in ODataKeyFields must be used as the source expression in a page control."
        },

Potential Performance Issues

        {
            "id": "AL0254",
            "action": "Error",
            "justification": "Sorting field '{0}' should be part of the keys for table '{1}'."
        },
        {
            "id": "AA0233",
            "action": "Error",
            "justification": "Use Get(), FindFirst() and FindLast() without Next() method"
        },
        {
            "id": "AA0181",
            "action": "Error",
            "justification": "The FindSet() or Find() methods must be used only in connection with the Next() method"
        },
        {
            "id": "AA0232",
            "action": "Error",
            "justification": "The FlowField of a table should be indexed"
        },
        {
            "id": "AA0210",
            "action": "Error",
            "justification": "Avoid non-indexed fields into filtering"
        },

Warnings that should be investigated

        {
            "id": "AA0205",
            "action": "None",
            "justification": "Variables must be initialized before usage."
        },
        {
            "id": "AA0175",
            "action": "None",
            "justification": "Do not write code that will never be hit."
        },
        {
            "id": "AA0136",
            "action": "None",
            "justification": "Do not write code that will never be hit."
        },
        {
            "id": "AW0006",
            "action": "None",
            "justification": "Pages and reports should use the UsageCategory and ApplicationArea properties to be searchable."
        },
        {
            "id": "AA0206",
            "action": "None",
            "justification": "The value assigned to a variable must be used."
        },
        {
            "id": "AA0244",
            "action": "None",
            "justification": "Do not use identical names for parameters and global variables."
        },
        {
            "id": "AA0198",
            "action": "None",
            "justification": "Do not use identical names for local and global variables."
        },
        {
            "id": "AA0137",
            "action": "None",
            "justification": "Do not declare variables that are unused."
        },

Improve the readability of the code

        {
            "id": "AA0021",
            "action": "None",
            "justification": "Variable declarations should be ordered by type."
        },
        {
            "id": "AA0005",
            "action": "None",
            "justification": "Only use BEGIN..END to enclose compound statements."
        },
        {
            "id": "AA0228",
            "action": "None",
            "justification": "The local method must be used; otherwise removed."
        },
        {
            "id": "AA0008",
            "action": "None",
            "justification": "Function calls should have parenthesis even if they do not have any parameters."
        },
        {
            "id": "AA0074",
            "action": "None",
            "justification": "TextConst and Label variable names should have an approved suffix."
        },
        {
            "id": "AA0215",
            "action": "None",
            "justification": "Follow the style guide about the best practices for naming."
        },
        {
            "id": "AA0470",
            "action": "None",
            "justification": "Placeholders should have a comment explaining their content."
        },
        {
            "id": "AA0073",
            "action": "None",
            "justification": "The name of temporary variable must be prefixed with Temp."
        },
        {
            "id": "AA0202",
            "action": "None",
            "justification": "To avoid confusion, do not give local variables the same name as fields, methods, or actions in the same scope."
        },
        {
            "id": "AA0241",
            "action": "None",
            "justification": "Use all lowercase letters for reserved language keywords."
        },
        {
            "id": "AA0018",
            "action": "None",
            "justification": "The END, IF, REPEAT, UNTIL, FOR, WHILE, and CASE statement should always start a line."
        },
        {
            "id": "AA0203",
            "action": "None",
            "justification": "To avoid confusion, do not give methods the same name as fields or actions in the same scope."
        },

Observe Best Codeing Practices

        {
            "id": "AA0201",
            "action": "None",
            "justification": "When ApplicationArea is set to 'Basic', you must also specify 'Suite'."
        },
        {
            "id": "AL0424",
            "action": "None",
            "justification": "The multilanguage syntax is being deprecated. Please update to the new syntax."
        },
        {
            "id": "AA0225",
            "action": "None",
            "justification": "You must specify a caption in the Caption property for Fields that exist on page objects."
        },
        {
            "id": "AA0072",
            "action": "None",
            "justification": "The name of variables and parameters must be suffixed with the type or object name."
        },
        {
            "id": "AA0218",
            "action": "None",
            "justification": "You must write a tooltip in the Tooltip property for all controls of type Action and Field that exist on page objects."
        },
        {
            "id": "AA0217",
            "action": "None",
            "justification": "Use a text constant or label for format string in StrSubstNo."
        },
        {
            "id": "AW0011",
            "action": "None",
            "justification": "Add PromotedOnly=true to some or all promoted actions to avoid identical actions from appearing in both the promoted and default sections of the command bar."
        },
        {
            "id": "AA0101",
            "action": "None",
            "justification": "Use camel case property values in pages of type API."
        },
        {
            "id": "AA0102",
            "action": "None",
            "justification": "Use camel case name for field controls in pages of type API."
        },

Clean AL Code Initiative