FixInsight adiciona itens ao menu 'Project' do RAD Studio.
Documentação
Contents
- Instalando e Desinstalando
- Utilizando o sistema
- Ferramenta de linha de comando
- Regras
- Warnings
- W501 Empty EXCEPT block
- W502 Empty FINALLY block
- W503 Assignment right hand side is equal to its left hand side
- W504 Missing INHERITED call in destructor
- W505 Empty THEN block
- W506 Empty ELSE block
- W507 THEN statement is equal to ELSE statement
- W508 Variable is assigned twice successively
- W509 Unreachable code
- W510 Values on both sides of the operator are equal
- W511 Object 'Foo' created in TRY block
- W512 Odd ELSE-IF condition
- W513 Format parameter count mismatch
- W514 Loop iterator could be out of range (missing -1?)
- W515 Suspect Free call
- W517 Variable 'Foo' hides a class field, method or property
- W519 Method 'Foo' is empty
- W520 Parenthesis might be missing around IN operand
- W521 Return value of function 'Foo' might be undefined
- W522 Destructor without an override directive
- W523 Interface 'Foo' declared without a GUID
- W524 Generic interface 'Foo' declared with a GUID
- W525 Missing INHERITED call in constructor
- W526 Pointer to a nested method
- W527 Property is referenced directly in its getter or setter
- W528 Loop variable is not used in FOR-loop
- Otimizações
- Convenções de Código
- C101 Method 'Foo' is too long (N lines)
- C102 Too many parameters in 'Foo' (N parameters)
- C103 Too many variables in 'Foo' (N variables)
- C104 Class name should start with 'T'
- C105 Interface name should start with 'I'
- C106 Pointer type name should start with 'P'
- C107 Class field name should start with 'F'
- C108 Nested WITH statement
- C109 Unneeded boolean comparison
- C110 Getter or setter name is different from property declaration
- Warnings
Instalando e Desinstalando
Para instalar o FixInsight:
- Faça o download do instalador. No link a seguir clique no botão de download: http://sourceoddity.com/br/fixinsight/download.html
- Execute o instalador e siga as instruções
Para desinstalar o FixInsight:
- Abara o Painel de Controle do Windows
- Selecione a opção 'Desinstalar um programa'
- Localize o FixInsightna lista de programar e dê um duplo clique nele
- 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).
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.
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;