sexta-feira, 16 de julho de 2010

Diretivas de Compilação - WARNINGS, HINTS e MESSAGES

$WARNINGS

Warnings são alertas emitidos durante a compilação que apontam para um potencial ou real problema no código fonte.
Algumas vezes, por exemplo, os warnings se referem a variáveis que foram declaradas mas que não estão sendo usadas. Esse é um caso onde não há um problema, mas mesmo assim vale a pena dar atenção para esse warning porque ele é um indício de que há espaço para tornar seu código fonte mais limpo/claro.
O ideal é nunca ter qualquer warning emitido durante a compilação.

Em certos casos o compilador emite alertas para um trecho de código do qual temos a certeza de estar correto, e que esse alerta poderia ser desconsiderado sem qualquer receio.
Para essa situação nós podemos usar a diretiva de compilação {$WARNINGS} para desabilitar a emisão dos warnings em um certo techo de código.

{$WARNINGS OFF}
// Seu código fonte
{$WARNINGS ON}

Uma outra abordagem mais recomendada para essa situação é desabilitar somente o warning específico a qual se tem ciência de não representar problema. Isso evita que outros warnings sejam desconsiderados não intencionalmente em decorrência de uma modificação futura nesse trecho de código, principalmente se o trecho de código for relativamente grande.

A sitaxe é:
{$WARN identifier OFF}
// Seu código fonte
{$WARN identifier ON}
onde "identifier" é o símbolo correspondente do warning.

Considere o exemplo abaixo:

unit uTest;

interface
  procedure MyTest; experimental;

implementation

procedure MyTest;
begin
  // Código fonte
end;

end.

Para quem não sabe "experimental" é uma palavra reservada que pode ser usada para métodos, funções, units e outros com a intenção clara de sinalizar que tal implementação está, como o próprio nome sugere, em face experimental e que deve ser cauteloso no seu uso.
Ao compilar esse exemplo será apresentado uma mensagem semelhante a essa:

[DCC Warning] Project2.dpr(13): W1003 Symbol 'MyTest' is experimental

O código de identificação desse warning, como mostra a mensagem, é 1003 e o correspondente símbolo é  SYMBOL_EXPERIMENTAL. Dessa forma, caso queira anular tal alerta em um trecho de código, basta usar:

{$WARN SYMBOL_EXPERIMENTAL OFF}
// trecho de código
{$WARN SYMBOL_EXPERIMENTAL ON}

Não tenho intenção de listar todos os símbolos pré-definidos que o Delphi possui, mas vou detalhar alguns poucos:
  • HIDING_MEMBER: Warning produzido quando uma descendente declara uma nova propriedade com o mesmo nome que uma propriedade do ancestral.
  • HIDDEN_VIRTUAL: Warning produzido quando um descendente declara um método, não especificado como override, e com o mesmo nome de um método virtual do ancestral.
  • HRESULT_COMPAT: Warning sobre o uso do tipo "Integer" no lugar de um HRESULT.
  • STRING_CONST_TRUNCED: Todos os warnings sobre instâncias na qual o compilador atribui um string literal ou um valor constante para um short string cujo tamanho é menor do que o suficiente.
  • SYMBOL_DEPRECATED: Habilita/desabilita todos os warnings sobre símbolos definidos como deprecated na unit corrente.
  • SYMBOL_EXPERIMENTAL: Habilita/desabilita todos os warnings sobre símbolos definidos como experimental na unit corrente.
  • SYMBOL_PLATFORM: Habilita/desabilita todos os warnings sobre símbolos definidos como platform na unit corrente.
  • SYMBOL_LIBRARY: Habilita/desabilita todos os warnings sobre símbolos definidos library na unit corrente.
  • UNIT_DEPRECATED: Habilita/desabilita todos os warnings relacionadas a units definidas como deprecated.
  • UNIT_EXPERIMENTAL: Habilita/desabilita todos os warnings relacionadas a units definidas como experimental.
  • UNIT_LIBRARY: Habilita/desabilita todos os warnings relacionadas a units definidas como library.
  • UNIT_PLATFORM: Habilita/desabilita todos os warnings relacionadas a units definidas como platform.
  • ZERO_NIL_COMPAT: Warnings sobre instâncias na qual o compilador converte o valor 0 como sendo um nil.
  • GARBAGE: Warnings produzidos quando há caracteres diferentes de espaços em branco após o marcador 'end.'.
Esses e todos os demais símbolos de alertas pode ser conferido na unit DCCStrs.pas, que faz parte da biblioteca do Delphi (provavelmente em %ProgramFiles%\...\sources\toolsapi\DCCStrs.pas).

Pontos importantes
Quando uma diretiva {$WARNINGS} ou {$WARN} é utilizada para alterar o estado padrão de um determinado tipo de alerta, esse estado permanece até que seja encontrada outra diretiva de mesmo tipo modificando seu estado ou até que seja encontrado o final da unit.
Uma diretiva de compilação só tem efeito dentro do contexto da unit a qual é utilizada e a partir do ponto onde estão definidas dentro do arquivo. Ao ser passado o contexto para outra unit, o estado da diretiva é revertido para sua condição padrão.

Mas se a intenção é habilitar/desabilitar um determinado warning para um projeto inteiro, como fazer?
Vejo duas formas de fazer isso. Uma usando um arquivo auxiliar e outra usando o IDE o Delphi para selecionar quais warnings devem ou não ser considerados.
A primeira solução consiste em você utilizar um arquivo contendo as opções desejadas e acrescentar uma diretiva {$INCLUDE filename} ou {$I filename} em todas as unit do projeto.
A diretiva {$INCLUDE} tem o objetivo de copiar o conteúdo de um determinado arquivo para o ponto onde ela está definida.
No entanto, essa solução não faz muito sentido em ser utilizada para um caso isolado. Faz mais sentido quando se tem um arquivo central com várias defines, constantes, ... onde este é incluído (com {$I}) em todos os arquivos do projeto.
Imagino que já devem ter visto em algum projeto, por exemplo, o uso de um arquivo Types.inc com todas as definições usadas. Esse é um bom ponto para aplicar esse caso.)

A segunda forma, mais recomendada e também mais fácil é marcar/desmarcar quais warnings deverão ou não ser emitidos no próprio IDE do Delphi.
Para isso acesse a opção do menu Project -> Options e vá até a aba "Hints and Warnings".
Bom, a partir daqui não há mais razão de detalhar os passos. O processo é bem intuitivo.


Caso queira conhecer um pouco mais sobre os tipos de mensagens de erros e warnings tratados pelo Delphi, acesse o link http://docwiki.embarcadero.com/RADStudio/en/Error_and_Warning_Messages_(Delphi)_Index.



Estados dos Alertas
Aqui está outro ponto muito importante e que nem sempre é mencionado.
O warning não possui somente dois estados (ON e OFF), mas sim três. Exatamente!
O terceiro estado é ERROR que instrui o compilador a tratar o warning como sendo um erro, ou seja, aumenta o nível de atenção daquele tipo de alerta.

{$WARN SYMBOL_EXPERIMENTAL OFF}
{$WARN SYMBOL_EXPERIMENTAL ON}
{$WARN SYMBOL_EXPERIMENTAL ERROR}

Essa opção pode ser bastante útil quando, por exemplo, há muitas ocorrências de warning no projeto e você quer dar atenção para um tipo específico.


$MESSAGES

O Delphi possui a diretiva de compilação $Message que nos permite instrumentar o código fonte de forma a salientar pontos importantes que devem ser observados quando o código for compilado.
Essa diretiva trabalha diretamente com o compilador o qual irá emitir o texto definido no corpo da definição tratando-a conforme seu nível atenção.

A sintaxe é a seguinte:

{$MESSAGE HINT|WARN|ERROR|FATAL 'Textstring'}

onde HINT|WARN|ERROR|FATAL é o nível de atenção/importância da mensagem e 'Textstring' é a mensagem que deve ser emitida pelo compilador.

O level da mensagem é opcional e, se não especificado, será assumido o valor padrão, ou seja, HINT. Já a sequência do testo é obrigatória e deve utilizar a sintaxe da string, ou seja, delimitada por aspas simples.
Destaco a importância de conhecer o significado que cada tipo de mensagem possui porque o compilador irá tratar essas mensagens da mesma forma como trata os alertas nativos.

HINT: Notificações quase sempre informativas e não incorrem risco

{$Message 'Essa mensagem é do tipo HINT'}
{$Message Hint 'Essa mensagem também é do tipo HINT'}

WARN: Notificação de alerta para um real ou potencial risco

{$Message Warn 'Essa mensagem é do tipo WARNING'}

Error: Falha de sintaxe ou semântica

{$Message Error 'Essa mensagem é do tipo ERROR'}

Fatal: Interrompe a compilação imediatamente

{$Message Fatal 'Essa mensagem é do tipo FATAL'}
 

$HINTS

Esse artigo tem explorado mais o lado técnico dos Warnings e Hints no Delphi do que propriamente sua utilização.
Esse é uma outra abordagem com ampla gama para exploração. Penso que poderia ser redigido um artigo enorme falando só das diversas formas de empregar, e de forma adequada, esse recurso que não é uma exclusividade do Delphi, muito pelo contrário.
Mas por enquanto iremos concluir esse texto com mais algumas notas sobre a diretiva {$HINT}.

O Delphi permite que a emissão de mensagens que são do tipo HINT possa ser habilita ou desabilitada através de:

{$HINTS ON}
// Trecho de código
{$HINTS OFF}

Vamos utilizar um exemplo simples.

procedure Teste;
var
  a, b: Integer;
begin
  {$HINTS ON}

  a := 1;
end;

Ao compilar, será apresentado duas mensagens do tipo hint.

[DCC Hint] uTest.pas(13): H2077 Value assigned to 'a' never used
[DCC Hint] uTest.pas(11): H2164 Variable 'b' is declared but never used in 'Teste'

Agora experimente substituir a linha onde aparece {$HINTS ON} por {$HINTS OFF} e recompile o código. Irá observar que ambas as mensagens não serão mais apresentadas.
Aqui a regra é a mesma. A diretiva é relevante apenas no contexto da unit e para as linhas abaixo.

Até a próxima.

3 comentários:

Anônimo disse...

Ótima dica! Sou bem preocupado com Warnings e hints. Show de bola o post.

Anônimo disse...

Artigo muito útil, além de bem explicado. Continue nos brindando com artigos dessa mesma categoria.

Unknown disse...

Sei que o poste é antigo mas tenho um dúvida, para desabilitar/habilitar determinado warning uso {$WARN SYMBOL_EXPERIMENTAL OFF} não tem como fazer isso para os Hints?
Obrigado