Documentação

Contents

  1. Instalando e Desinstalando
  2. Utilizando o sistema
    1. Excluindo Units da análise
    2. Suprimindo Warnings
  3. Ferramenta de linha de comando
  4. Regras
    1. Warnings
    2. Otimizações
    3. Convenções de Código

Instalando e Desinstalando

Para instalar o FixInsight:

  1. Faça o download do instalador. No link a seguir clique no botão de download: http://sourceoddity.com/br/fixinsight/download.html
  2. Execute o instalador e siga as instruções

Para desinstalar o FixInsight:

  1. Abara o Painel de Controle do Windows
  2. Selecione a opção 'Desinstalar um programa'
  3. Localize o FixInsightna lista de programar e dê um duplo clique nele
  4. Clique no botão 'Sim' para desinstalar o FixInsight

Utilizando o sistema

FixInsight suporta a versão RAD Studio 10.1 Berlin bem como as versões anteriores da IDE (2006—10 Seattle).


Excluindo Units da análise

Você pode excluir Units especificas do seu projeto da análise realizada pelo FixInsight para isso basta incluir o nome das units desejadas (uma por linha) na janela de configurações.

Uma outra opção é adicionar um comentário "FI:ignore" na primeira linha da Unit que você deseja ignorar.

A exemplo ,

      unit Unit1; //FI:ignore
    

Suprimindo warnings

É possível utilizar um comentário especial "FI:<RULENUMBER>" para suprimir mensagens de warning em uma determinada linha. É preciso colocar este comentário na linha onde o warning ocorre.

A exemplo,

      procedure RestartTimer;
      begin
        FTimer.Enabled := False;
        FTimer.Enabled := True; //FI:W508 - this warning will be ignored.
      end;
    

Uma segunda opção é utilizar a diretiva de compilação _FIXINSIGHT_ para suprimir warnings. Funcionar como uma diretiva de compilação comum. Certifique-se de que seu código continua válido quando a diretiva for desabilitada e o segmento de código excluído.

For instance,

      {$IFNDEF _FIXINSIGHT_}
      procedure RestartTimer; // this code will be ignored
      begin 
        FTimer.Enabled := False;
        FTimer.Enabled := True;
      end;
     {$ENDIF}
    

Ferramenta de linha de comando

A ferramenta d elinha de código do FixInsight (FixInsightCL.exe) pode ser utilizada em processos de build automatizados ou integração contínua.

Parâmetros:
  --project=XXX.dpr (a project to analyze)
  --defines=XXX;YYY;ZZZ (compiler defines separated by semicolon)
  --output=XXX (write output to a file)
  --searchpath=XXX (unit directories)
  --settings=XXX.ficfg (override project settings)
  --silent (produce no output if no issues were found)
  --xml (format output as xml)

A --project parameter is mandatory, other parameters are optional.

  Exemplo de uso:
    FixInsightCL --project=c:\source\example.dpr


Code patterns suportados pelo FixInsight

A ferramenta gera uma lista de warnings quando possíveis problemas são encontrados. Ela também verifica seu código para garantir atendimento a determinadas convenções de código.

Warnings

Erros em potencial ou possíveis problema.

W501 Empty EXCEPT block

Este warning indica que a exceção é capturada mas não é tratada corretamente, o que significa dizer que a causa da exceção no bloco de try ainda está lá afetando a execução do aplicativo. Você que produzir uma reação em cadeia de erros que serão impossíveis de identificar? Um block de except vazio é a maneira perfeita de fazer isso!

       try
         Result := GetSomeData;
       except
         // nothing
       end;
      

W502 Empty FINALLY block

O block de finally block permite sua aplicação limpar a memória e finalizar corretamente todos os processos em execução. Um bloco de finally vazio significa dizer que sua aplicação não se preocupa com isso e por isso pode se tornar uma fonte fértil para erros misteriosos e mau uso de memória.

       try
         Result := GetSomeData;
       finally
         // nothing
       end;
      

W503 Assignment right hand side is equal to its left hand side

Apesar de não gerar problemas de performe ou erros, uma atribuição como esta pode ser potencialmente perigosa se uma expressão diferente era esperada do lado direito e por acado o desenvolvedor tenha se passado no momento de escreve-la. Erros como este acontecem tipicamente por conta de copiar e colar feitos de forma desatenta.

       RowCount := RowCount;
      

W504 Missing INHERITED call in destructor

Esquecer de chamar um destrutor do tipo inherited significa pode não ser destruido completamente uma vez que os destrutores das classes ancestrais não são chamados, resultados em leaks de memório ou outros comportamentos indesajados.

       destructor TDataContainer.Destroy;
       begin
         FData.Free;
       end;
      

W505 Empty THEN block

Um simples ponto e vírgula torna todo o seu IF inútil. O bloco DoSomething sempre será executado.

       if Param > 3 then;
       begin
         DoSomething;
       end;
      

W506 Empty ELSE block

De forma semelhante ao warning anterior , o bloco ELSE executa independente do valor de Param. Um simples ponto e vírgula colocado no local errado pode gerar um erro extremamente dificil de localizar.

       if Param > 3 then
         DoSomething
       else;
       begin
         Flag := -1;
         ShowMessage('Wrong param value');
       end;
      

W507 THEN statement is equal to ELSE statement

Blocos de IF e ELSE idênticos não causam nenhum problema caso você tenha feito isso intencionalmente (para debugar sua aplicação por exemplo). O mesmo código será executado independente do valor de Param. Este warning pode indicar problemas na sua lógica, muito provavelmente por falta de atenção do desenvolvedor no momento de copiar e colar partes do código.

       if Param > 3 then
         DoSomething
       else
         DoSomething;
      

W508 Variable is assigned twice successively

Um erro simples e difícil de localizar . A variável Value simplesmente perde seu valor original. Perceba que estas duas linhas podem estar separadas por 200 ou mais linhas de código tornando a detecção deste bug bastante complicada.

       Value := GetValue;
       Value := 505;
      

W509 Unreachable code

A última linha deste bloco nunca é executada. O comando Exit pode estar disposto em um bloco grande de lógica mais complexa tornando este problema menos evidente e mais difícil de localizar.

       begin
         Value := GetValue;
         Exit;
         ProcessValue(Value);
       end;
      

W510 Values on both sides of the operator are equal

Copiar e colar ou a simples falta de atenção do desenvolvedor pode resultar em fragmentos de código que não geram erros de imediato mas que podem na verdade estar incorretos do ponto de vista da lógica final desejada. Aqui os dois operadores são iguais resultando em 0 sendo atribuido a Result.

       Result := X - X;
      

W511 Object 'Foo' created in TRY block

Um erro comum para desenvolvedores inexperientes. Quando um objeto é criado dentro de um bloco TRY, e a aplicação disparar uma exceção antes da instancia do objeto ser atribuida para a variável Foo, por exemplo se o construtor causar um erro, Foo permanece não atribuido e a chamada a Free no bloco de FINALLY causará uma nova exceção ao tentar liberar um ponteiro nulo.

       try
         Foo := TFooObject.Create;
         Foo.CallMethod;
       finally
         Foo.Free;
       end;
      

W512 Odd ELSE-IF condition

Por que isso está aqui ? O que isso faz? O bloco de ELSE é realmente necessário? Talvez você saiba a resposta, mas é provável que algo esteja errado e talvez os valores testados não devessem ser os mesmos e talvez este seja um motivo de erros na sua aplicação.

       if Param = 1 then
         ProcA
       else if Param = 1 then
         ProcB;
      

W513 Format parameter count mismatch

O número de parâmetros informados não corresponde com o número de parâmetros da String formatada. Esta linha compila mas não funciona corretamente!

       Result := Format('%s = %d', [Name]);
      

W514 Loop iterator could be out of range (missing -1?)

No Delphi os arrays dinâmicos são indexados de 0 até Length – 1, o que significa dizer que este código está incorreto.

       var
         I: Integer;
         Arr: array of Char;
       begin
         Arr := GetArr;
         for I := 0 to Length(Arr) do
           ProcessChar(Arr[I]);
       end;
      

W515 Suspect Free call

O comando Free parece suspeito neste contexto. É possível que deveria ser utilzado um "with" que eventualmente pode estar faltando, ou o bloco foi copiado de outra parte de código e então modificado de forma incorreta. De qualquer forma este warning indica que um o Free pode estar sendo executado em um objeto incorreto. No código abaixo o a instância de THelloObject executa o Free ao invés do da instância de TStringList.

       procedure THelloObject.SaveToFile(const FileName: string);
       var
         StringList: TStringList;
       begin
         StringList := TStringList.Create;
         try
           StringList.Add('Hello world');
           StringList.SaveToFile(FileName);
         finally
           Free;
         end;
       end;
      

W517 Variable 'Foo' hides a class field, method or property

Viu que a variável local Foo está no método GetFoo? Esconde o método de classe privada de mesmo nome, tornando o campo de classe inacessível a partir do método. No exemplo a seguir o método GetFoo sempre vai retornar o valor da variável local Foo, e não o campo Foo.

       type
         TMyClass = class
         private
           Foo: Integer;
         public
           function GetFoo: Integer;
         end;

       function TMyClass.GetFoo: Integer;
       var
         Foo: Integer;
       begin
         Result := Foo;
       end;
      

W519 Method 'Foo' is empty

Métodos vazios não fazem nada. Isso é ruim? Não, a não ser que você quisesse que o método fizesse algo. Tipicamente métodos vazios não deveriam existir e podem ter sido remanecessentes de refatoração ou alguma falta de atenção do desenvolvedor.

       procedure TMyClass.Foo;
       begin
         // nothing
       end;
      

W520 Parenthesis might be missing around IN operand

Se Value é um integer ele será considerado como "(not Value) in [set]", quando usualmente o desejado seria "not (Value in [set])". Um parênteses pode fazer toda a diferença em sua lógica!

       procedure TMyClass.Foo;
       var
         Value: Integer; 
       begin
         if not Value in [1,2,3] then
           Bar;
       end; 
      

W521 Return value of function 'Foo' might be undefined

O compilador do Delphi gera um warning se uma função não tiver seu resultado inicializado, mas somente para tipos simples, exemplo Integer. No entanto, para tipos de mais complexos como Strings e Interfaces nenhum warning é gerado.

       function TMyClass.Foo(Param: Boolean): string;
       begin
         if Param then
           Result := 'OK'
         else
           DoNotAssignResult;
       end; 
      

W522 Destructor without an override directive

Esta diretiva precisa ser atribuída, ou a chamada ao método Free nunca executará corretamente,porque o método Free chama o destrutor.

W523 Interface 'Foo' declared without a GUID

Se uma interface não tem um GUID, ela não pode ser utilizada com funções do tipo Supports ou com o operador 'as'.

W524 Generic interface 'Foo' declared with a GUID

Significa que qualquer instância genérica desta interface genérica vai compartilhar o mesmo GUID. Como interfaces devem ter um GUID único, e GUIDs são usados para conversões, isso pode causar problemas sérios.

        IFoo<T> = interface
          ['{E7B8DF46-3B3D-46D3-916A-6A6008DD5B68}']
          procedure DoWork; 
        end;
      

W525 Missing INHERITED call in constructor

Idêntico à regra W504, mas para construtores.

       constructor TDataContainer.Create;
       begin
         FData := TList.Create;
       end;
      

W526 Pointer to a nested method

Quando um método aninhado está sendo chamado de foram do seu método "parent", um empilhamento incorreto geralmente resultará em um erro dificil de localizar.

       procedure TMyClass.DoWork;

         procedure NestedMethod(List: TObjectList);
         var
           I: Integer;
         begin
           for I := 0 to List.Count - 1 do
             Foo(Self, List[I]);
         end;

       begin
         SetCallback(@NestedMethod);
       end;
      

W527 Property is referenced directly in its getter or setter

Acessar uma propriedade no seu método de Get ou St pode levar a recursão infinita.

       type
         TTestClass = class
         private
           FProp: Integer;
           procedure SetProp(const Value: Integer);
           function GetProp: Integer;
         published
           property Prop: Integer read GetProp write SetProp;
         end;
              
       // ...
              
       procedure TTestClass.SetProp(const Value: Integer);
       begin
         Prop := Value; // cannot assign to Prop here
       end;
              
       function TTestClass.GetProp: Integer;
       begin
         Result := Prop; // cannot get Prop value here
       end;
      

W528 Loop variable is not used in FOR-loop

Uma variável de loop não é usada no interior do loop. Isto pode indicar erros no código.

       for I := 0 to 9 do
         for J := 0 to 9 do
           Matrix[I, I] := 0; // J is not used
      

Otimizações

Pequenos truques que tornam seu código mais limpo e rápido.

O801 CONST missing for unmodified string parameter 'Foo'

Parâmetro String não é modificado em um método. Se você declarar este parâmetro como um 'const' resultará em uma melhor performance. .

       procedure Output(S: string);
       begin
         ShowMessage('The message is "' + S + '"');
       end;
      

O802 ResourceString 'Foo' is declared but never used

Uma ResourceStringé declarada mas nunca utilizada. Significa que pode ser removida sem nenhum risco. Esta regra verifica somente constantes declaradas na seção implementation.

Convenções de Código

Violações de convenções de código tecnicamente não resultam em erros mas podem atrasar o processo de desenvolvimento ou aumentar a probabilidade de surgimento de bugs no futuro.

C101 Method 'Foo' is too long (N lines)

Um método, função ou procedimento cresceu demais.

C102 Too many parameters in 'Foo' (N parameters)

Uma lista de parâmetros muito longa em um procedimento ou função pode prejudicar a leitura do código.

C103 Too many variables in 'Foo' (N variables)

Uma lista de variáveis muito longa em um procedimento ou função pode prejudicar a leitura do código.

C104 Class name should start with 'T'

De acordo com o Object Pascal Style Guide declaração de classes devem ser preferencialmente iniciadas pela letra "T".

C105 Interface name should start with 'I'

De acordo com o Object Pascal Style Guide declaração de interfaces devem ser preferencialmente iniciadas pela letra "I".

C106 Pointer type name should start with 'P'

De acordo com o Object Pascal Style Guidedeclaração de ponteiros devem ser preferencialmente iniciadas pela letra "P".

C107 Class field name should start with 'F'

De acordo com o Object Pascal Style Guide declaração de campos de classes devem ser preferencialmente iniciadas pela letra "F".

C108 Nested WITH statement

Se uma interface de classe muda, o comportamento do código usando ‘with’ pode mudar de forma silenciosa e sem nenhuma indicação. Pode criar semânticas imprecisas e isso é sempre ruim.

       with Obj1 do
         with Obj2 do
           DoSomething;
      

C109 Unneeded boolean comparison

Comparação desnecessária. Não chega a ser um problema, mas uma atribuição simples seria mais natural.

       Result := A <> True;
      

C110 Getter or setter name is different from property declaration

Nomes dos métodos de Get ou Set são tipicamente o nome da propriedade com um prefixo 'Get' ou 'Set'.

       property Caption: string read GetName write SetName;