
FixInsight adiciona itens ao menu 'Project' do RAD Studio.
Para instalar o FixInsight:
Para desinstalar o FixInsight:
FixInsight suporta a versão RAD Studio 10.1 Berlin bem como as versões anteriores da IDE (2006—10 Seattle).
FixInsight adiciona itens ao menu 'Project' do RAD Studio.
No Delphi 2010 e superior ele também adiciona na barra do menu do project manager.
CLique em View->Toolbars->FixInsight para visualizar o FixInsight no toolbar.
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
É 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}
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
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.
Erros em potencial ou possíveis problema.
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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]);
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;
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;
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;
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;
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;
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;
Esta diretiva precisa ser atribuída, ou a chamada ao método Free nunca executará corretamente,porque o método Free chama o destrutor.
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'.
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;
Idêntico à regra W504, mas para construtores.
constructor TDataContainer.Create; begin FData := TList.Create; end;
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;
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;
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
Pequenos truques que tornam seu código mais limpo e rápido.
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;
Uma ResourceStringé declarada mas nunca utilizada. Significa que pode ser removida sem nenhum risco. Esta regra verifica somente constantes declaradas na seção implementation.
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.
Um método, função ou procedimento cresceu demais.
Uma lista de parâmetros muito longa em um procedimento ou função pode prejudicar a leitura do código.
Uma lista de variáveis muito longa em um procedimento ou função pode prejudicar a leitura do código.
De acordo com o Object Pascal Style Guide declaração de classes devem ser preferencialmente iniciadas pela letra "T".
De acordo com o Object Pascal Style Guide declaração de interfaces devem ser preferencialmente iniciadas pela letra "I".
De acordo com o Object Pascal Style Guidedeclaração de ponteiros devem ser preferencialmente iniciadas pela letra "P".
De acordo com o Object Pascal Style Guide declaração de campos de classes devem ser preferencialmente iniciadas pela letra "F".
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;
Comparação desnecessária. Não chega a ser um problema, mas uma atribuição simples seria mais natural.
Result := A <> True;
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;