Suppress Compile and Best Practice Warnings in D365FO

One of the X++ compiler features is the ability to analyze the code we write and the artifacts we add to the solution and check them against a predefined set of rules, providing us with compile and best practice warnings when the code and metadata are not fully up to coding standards. When conforming to these rules, we are able to provide a better and more efficient solution to both our developer colleagues and the client that will be using it. However, there are some cases when we are forced not to follow these rules. We then have two options: to leave them as is or to suppress them.

Suppressing compile and best practice warnings contributes to code hygiene, because we’ll only be suppressing warnings when it’s strictly necessary, we’ll do it in a controlled manner and we’ll have a clearer image when new warnings appear during further development.

In this article, we will explain how to suppress compile and best practice warnings while developing in X++. You will learn how to create suppression files for your models, suppress different types of warnings, where to find monikers for the suppressing warnings and how to populate your CAR report with the proper justifications automatically.

This might not be so straightforward, so let us jump in and have a look.

Basic terms

When compiling the X++ code, the compiler checks for errors (which prevent your code from compiling at all) and warnings that indicate a potential problem (but still let your code compile). Additionally, you can make the compiler run the best practice checks by turning on Run Best Practice Checks on the Options tab when building your model:

You can notice that are other options as well on this form, two of which also help us with code hygiene and best practices. Those options are:

  • Run Appchecker Rules
  • Run Socratex Checks

App checker is used to analyze X++ code and apply different rules as to what a correct code structure or logic should look like. There is a predefined set of rules that come with App checker, but you can also create your own rules if needed. When this option is enabled, the compiler will generate either code errors or warnings, depending on the severity of the implemented rule. You can check out some examples in Ariste’s article.

Socratex is the natural successor of App checker. During the code analysis, it generates Abstract Syntax Trees (ASTs), which are actually an XML representation of your X++ code. It uses a BaseX database to store the created XML structures, which can subsequently be used to easily query the code as you would query data in a database, and this way enables you to better understand and analyze your code. This is a great tool for improving the code quality and best practices handling. More information about Socratex can be found here.

Now back to our main mission for this article. In general, we can state that compiler warnings are treated as more severe than best practice warnings. You will get a compile warning for example if you use an obsolete artifact or invoke a method that is only meant for internal use by Microsoft. However, it is not impossible that at some time in the future Microsoft promotes some of them into compile errors causing you unpleasant feelings and additional work 😊, so we should be cautious when dealing with compile warnings. You might not have been aware, but at the early beginning the X++ compiler emitted almost zero compile warnings and Microsoft was adding them over time while developing the D365FO platform.

On the other hand, the best practice warnings that we know since AX 2012 typically refer to broken naming conventions (Pascal case for class names, camel case for methods), use of “ ” instead of ‘ ’ with strings, missing summaries/comments for classes and class methods, nested loops, etc. Their main intention is to improve the code presentation and performance as well as to provide a uniform codebase experience.

In most of the cases we should follow along with the warnings and correct them. However, sometimes we are forced to make an exception to be able to achieve our requirements, simply because there is no other way! As said, for the sake of code hygiene, we suppress such warnings. Let’s see how!

I need to suppress some warnings…

Let us create an example solution that we can use to demonstrate how to suppress compile and best practice warnings. This example will consist of a class named DocentricSuppressWarningsDemo which will contain two methods. The first one will be the method named getCurrentUserDirPartyName() which performs a call to an InternalUseOnly method, thus generating a compile warning, while the second one will be an event handler method, producing a best practice warning. This is how our test code example looks like:

When we compile this class in Visual Studio, we can see that we get the best practice and compile warnings in the Warnings tab:

We can see that for our test code example we are getting two compile warnings – in regard to using the SysWorkflowHelper class and the getDirPartyNameFromUserId() method, which are both decorated with the Microsoft.Dynamics.BusinessPlatform.SharedTypes.InternalUseOnlyAttribute attribute, and one best practice warning for not using the parameter e in the event handler method.

Perhaps this example is not such a case, but sometimes you might be hard pressed to use the InternalUseOnly classes and methods because they are either tightly coupled into the built-in frameworks or, if this is not the case, completely new classes should be recreated, with copying over the needed methods and readjusting them to work with your solution, which can lead to unnecessary increase in project artifacts and code complexity.

The best practice warning on the other hand refers to the e parameter, which is not being used in our event handler method. This is correct; however, in our case we have no need to use it. We also cannot remove it from the method parameters as it is defined as mandatory by the DataEventHandler attribute. Thus, we remain stuck with the best practice warning and without a very productive way to fix it.

Let us see how we can mitigate these warnings in our demo class.

Create a suppression file for your model

To create a new suppression for a best practice warning, first we need to locate the best practice suppression file for our model. However, when a new model has been created (as in our case), the suppression file is not created by default and needs to be created manually.

We can check this by right clicking on our project in Visual Studio and then clicking on Edit Best Practice Suppressions:

 

As we can see from the message we are getting, Visual Studio is looking for the Docentric Suppress Warnings Demo_BPSuppressions.xml file in the AxIgnoreDiagnosticList folder for our model. The name of the suppression file derives from the name of our model with the addition of the _BPSuppressions suffix, and Visual Studio will always look for and open only this file when clicking the Edit Best Practice Suppressions button for a model.

To create the suppression file for our model, we will create a new XML file in the location specified in the alert message and add the following initial XML structure:

The inline XSD schema is not necessary as a part of the suppression file, but it is a good practice to follow to avoid incorrect entries.

After doing this, we can now open the suppression file in Visual Studio by clicking the Edit Best Practice Suppressions button and without getting a warning message that the file does not exist.

Create a suppression for your warning

Now that we have the suppression file ready, we will need to insert suppression entries for all the warnings we want to suppress. The suppression entries are in a 1:1 relationship to the warnings we get when compiling the code, which means that we will need to create a separate entry for every warning line that we get in Visual Studio. In our case, that means one entry for our best practice warning and two entries for our compile warnings.

The structure of the entry should be the same as described in the diagnostic item template code that we have already included in the suppression file and the new entries should be added between the tags

Therefore, when adding a new suppression, you will need to fill in the following elements: 

  • DiagnosticType– a diagnostic type that can have a value of BestPracticesCompiler, CodeAnalysis, etc. 
  • Severity– a severity level of the message, which will always be Warning. 
  • Path– a path to the object from which the message originated. 
  • Moniker– a unique identification of a compiler or BP rule that was violated. 
  • Message– an warning message. 
  • Justification– a reason why the warning should be ignored.

The suppression file with our entries should then look something like this:

Where to find monikers for your warnings?

As you might notice from our suppression entries, we have quite a bit of information included for the different tags and you might be wondering where this data comes from. In fact, the data for the tags is mostly generated by Visual Studio when it is running the best practice and compile warnings checks when the Visual Studio project/model is compiled. This data is then shown in the Error List tab in Visual Studio (that we have already seen) but it is also saved in an XML file named BuildProjectResult.xml located in the root folder for the model (in our case C:\AOSService\PackagesLocalDirectory\DocentricSuppressWarningsDemo).

Best practice and compiler warnings can also be found in the BPCheck.xml file (when we are compiling the model with the Run Best Practice Checks turned on) and in the BuildModelResult.xml file (when we compile a model instead of a project).

If we open the BuildProjectResult.xml file, we can notice the following data inside it:

As you can see, a <Diagnostic> node in this file is similar in structure to the entries we have created in the suppression file. This means that we can copy over the <Diagnostic> nodes we need from this file to our suppression file, remove the tags that are not necessary for the suppression file (ElementType, Line, Column, EndLine, EndColumn) and add the <Justification> tag that explains the reason for suppressing the warning. Thus, we have a correct entry created for our suppression file that significantly eases our work.

Which file to use for different types of warnings?

Another option that X++ compiler offers is that we can use multiple files for the suppression of warnings. Why would we like to do that you ask? Well, to organize and separate the different type of warnings of course. In the previous example, we have put both compile and best practice warnings together in a single file. This works without any issues, but from a user perspective it might be more user friendly and productive to have the two types of warnings divided in to two separate files.

Thus, if we split the original suppression file into two separate files we will get the following two XML files:

We will need to maintain one file with the original name that will be accessible through Visual Studio (Docentric Suppress Warnings Demo_BPSuppressions.xml) and a second file for the compile warnings that we can name as we see fit. The only caveat here is that the second file we have created will not be accessible through the Edit Best Practice Suppressions button in Visual Studio and we will have to open it directly from the AxIgnoreDiagnosticList folder of our model. Both files should be placed in the AxIgnoreDiagnosticList folder to be taken into consideration when compiling the project.

Automate CAR using suppressions

The positive side to the suppression files is that they are also picked up by the CAR report (Customization Analysis Report) automatically, meaning that you can consolidate your warnings suppression and creating the CAR report procedures into a single job.

We wish you successful suppressing warnings but with the premise that you will suppress only as much as you have to 😊.

Leave a Reply

Your email address will not be published.

*

Docentric respects your privacy. Learn how your comment data is processed >>

Docentric respects your privacy. Learn how your comment data is processed >>