Static code analysis for Delphi with TMS FixInsight v2021.10
We are pleased to announce the immediate availability of the new TMS FixInsight version v2021.10! Highlights of this new release are: Delphi 11 support Better type resolving Improved & more robust code parser 5 New code analysis rules added The first three highlights are quite obvious, but let’s have a deeper look at the 5 new code analysis rules that have been added and that will enable you to detect possible code issues faster. W537 Format parameter type mismatch The Delphi compiler is not able to check data types used in Format() function. The example below will compile, but will never work properly. FixInsight is able to catch that. var StringTypeParameter: string; begin Result := Format(‘String type parameter value = %d’, [StringTypeParameter]); end; W539 Interface method call passing the same interface reference as out parameter In the example below access violation will be raised because Delphi compiler cleans up Node variable before the actual Node.GetParent() function call. type INode = interface [‘{39EE5CA9-C4C1-46E1-B326-BAA2D004A5CD}’] function GetParent(out Parent: INode): Boolean; end; TNode = class(TInterfacedObject, INode) strict private // INode. function GetParent(out Parent: INode): Boolean; end; { TNode } function TNode.GetParent(out Parent: INode): Boolean; begin Parent := TNode.Create; Result := True; end; procedure InterfaceErrorSample; var Node: INode; begin Node := TNode.Create; // Before calling Node GetParent, the compiler generates code that clears the Node variable // because the GetParent parameter is declared with the out parameters. // Thus calling Node.GetParent will result in AV. while Node.GetParent(Node) do // Getting root node. ; // Do somthing with root node. end; W540 String variable used twice in a call both as an output and an input parameter In the example below Str parameter in IsStringSliceNotEmpty() function will always be an empty string if you pass the same variable twice. Because the variable will be cleaned up by Delphi compiler. function IsStringSliceNotEmpty(const Str: string; out Slice: string; Index, Count: Integer): Boolean; begin Slice := Copy(Str, Index, Count); Result := Slice ”; end; procedure StringErrorSample; var Str: string; begin Str := ‘qwerty’; if IsStringSliceNotEmpty(Str, Str, 1, Length(Str)) and (Str[Length(Str)] = ‘y’) then ShowMessage(Str); // ShowMessage never run because Str was cleared before the SliceString call. end; W541 Type-casting from Pointer to Integer type (or vice versa) Type casting from Pointer to Integer and Integer to Pointer is often used in legacy code. But it is not safe on some platforms, because types size are differ. For instance, Pointer is 8 byte on x64, and the code below will lead to data loss. procedure TypecastSample(A: Pointer); var B: Integer; begin B := Integer(A); //… end; W542 Direct floating-point comparison There are several not obvious problems with comparing floating-point numbers. They are perfectly explained in DocWiki https://docwiki.embarcadero.com/RADStudio/Sydney/en/Floating-Point_Comparison_Routines In short, you should never use equal sign to compare two floating-point numbers, but rather use special comparison routines. var X:Single; Y:Double; begin X:=0.1; Y:=0.1; if X=Y then Writeln(‘Equal’) else Writeln(‘Not equal’); ReadLn; end. The program outputs: Not equal Get the update & increase the quality of your code! If you have an active license for TMS FixInsight, the update is available for you free. Users with an expired license […]
