Creating Custom Best Practices Checks In Dynamics AX

Microsoft Dynamics AX development environment includes Best Practice Tools which check the code for best practices and generate the error, warning, and information messages according to severity. Microsoft Dynamics AX for ERP ecosystem is more popular. The Best Practices tool runs with the compiler, and we can see the results on the Best Practices tab of the Compiler Output dialog box.

You can define the best practice rules that you want to run, in the Best Practice Parameters dialog box. From the Microsoft Dynamics AX drop-down menu, click Tools\Options\Development and then the "Best Practices" button.


Also, you need to set the error level of compiler to 4 from Tools\Options\Development\Compiler if you want Best Practice errors to be reported.

The X++ Best Practices tool allows us to create our own set of rules. The classes used to check for rules are named SysBPCheck<ElementKind>. You call the init, check, and dispose methods once for each node in the AOT for the element being compiled.

If you want your custom BP check to work for all the X++ code like class method, macro, or form method, you have to use class SysBPCheckMemberFunction.

Steps

In this scenario, we will see how to create a custom best practice which will check if nested while select is used in any class methods or in form methods and then generate a BP warning for that. 

  1. Go to AOT > Data Dictionary > Table SysBPParameters

    Add CheckNestedWhile field of Enum Type NoYes

  2. Go to AOT > Forms > SysBPsetup

    In method buildSelectionTree add the below written code at specific node
    1. element.addNode(tmpNode, fieldNum(SysBPParameters, CheckNestedWhile), parameter.CheckNestedWhile);  

Here, I have added the code under Classes node.

To verify, go to Tools > Options. Then, go to the Best Practices button in the Development section.

 

Now, define a Macro for Nested While Select.

Go to AOT > Macros > SysBPCheck

#define.BPErrorNestedWhileSelect(10) // Use Join instead of nested While loops.

You can change the error number accordingly. Here, I am using 10.

Now, go to AOT > Classes > SysBPCheckMemberFunction and add a new method checkNestedWhile.

Our pattern is a nested while select statement, so we can use a Regular Expression to match the pattern.

[Ww]hile\s*[Ss]elect[^\{^\;]*\{\s*[Ww]hile\s*[Ss]elect

Code
  1. <code style="color: #000000;"></code>  
  2. <pre><code style="color: #000000;"protected void checkNestedWhile()    
  3.  {    
  4.      #SysBPCheck    
  5.      TextBuffer  textBuffer;    
  6.      str matchPattern = @"[Ww]hile\s*[Ss]elect[^\{^\;]*\{\s*[Ww]hile\s*[Ss]elect";    
  7.      System.Text.RegularExpressions.Match whileSelectMatch;    
  8.      int startPos;    
  9.      int matchPosLine;    
  10.      int matchPosColumn;    
  11.      int cntChar;    
  12.      void setMatchPosLineAndColumn(int startPosition) //method for getting line number    
  13.      {    
  14.          cntChar = 0;    
  15.          matchPosLine = 0;    
  16.          if (scanner.lines())    
  17.          {    
  18.              while ((matchPosLine <= scanner.lines()) && (cntChar <= startPosition))    
  19.              {    
  20.                  matchPosLine ++;    
  21.                  if ((cntChar + strLen(scanner.sourceLine(matchPosLine)) <startPosition))    
  22.                  {    
  23.                      cntChar += strLen(scanner.sourceLine(matchPosLine));    
  24.                  }    
  25.                  else    
  26.                  {    
  27.                      matchPosColumn = startPosition - cntChar;    
  28.                      break;    
  29.                  }    
  30.              }    
  31.          }    
  32.      }    
  33.      textBuffer = new TextBuffer();    
  34.      textBuffer.regularExpressions(true);    
  35.      textBuffer.setText(scanner.source());    
  36.      whileSelectMatch = System.Text.RegularExpressions.Regex::Match(textBuffer.getText(), matchPattern);    
  37.      while (whileSelectMatch.get_Success())    
  38.      {    
  39.          startPos=whileSelectMatch.get_Index();    
  40.          setMatchPosLineAndColumn(startPos);    
  41.          sysBPCheck.addWarning(#BPErrorNestedWhileSelect,matchPosLine, matchPosCol  
  42. umn, strFmt("Use Join instead of nested while loops"));    
  43.          whileSelectMatch = whileSelectMatch.NextMatch();    
  44.      }    
  45.  }</code></pre>  

Now, in check method of the same class (SysBPCheckMemberFunction), add this code.

  1. <pre><code style="color: #000000;"if(parameters.CheckNestedWhile)    
  2.  {    
  3.       this.checkNestedWhile();    
  4.  }    
  5. </code></pre>  

Now, when you will compile any class which has nested while select loops, you will get Best Practice warning like this.

 

Conclusion

In the same way, you can create different custom checks which are not part of Standard Dynamics AX development, like the class name should start with some particular prefix, the maximum number of fields that can be added to a table etc. Also, you can check or uncheck these in Best Practice parameters form depending on the coding standard you are following.