Blog
All Blog Posts | Next Post | Previous PostStatic code analysis for Delphi with TMS FixInsight v2021.10
Friday, October 8, 2021
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;
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;
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 can purchase a renewal at discount price.
If you haven't used TMS FixInsight before, download our trial version and see how it will offer tons of suggestions to improve your code.
Bruno Fierens
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post