_WARNING Warnings Report

Top  Previous  Next

 

[BP7,D1,D2,D3,D4,D5,D6,D7,D8, D2005W, D2005N, D2006W, D2006N, D2007W]

 

This report contains several sections that present different types of warnings. These warnings point to possible anomalies or errors in your source code. Because PAL may not have full access to all source code, some of these warnings may however turn out to be just false.

__________________________________________________

 

Interfaced identifiers that are used, but not outside of unit

 

This section lists all identifiers that are declared in the interface section of a unit, and that are used in the unit, but not outside the unit. You should declare these identifiers in the implementation section of the unit instead.

 

This section is also generated for multi-projects.

 

Restrictions:

Interfaced identifiers that are not used at all are not listed. These identifiers are already listed in the “Identifiers never used” section in the Code Reduction Report.

 

Recommendation:

Declare these identifiers in the implementation section of the unit, to avoid unnecessary exposure.

 

__________________________________________________

 

Interfaced class identifiers that are public/published, but not used outside of unit

 

This section lists all identifiers that are members of a class, and are declared with the public/published directive, but not used outside of the unit.

 

This section is also generated for multi-projects.

 

Recommentation:

Declare these identifiers with the private/protected directive instead.

 

__________________________________________________

 

Variables that are referenced, but never set

 

This section lists all declared and referenced variables that never are set. Possibly this is an error, but the reason could also be that the variable is set in code that is not seen by the parser.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, and are changed whenever the other variable changes.

 

Recommendation:

Examine why these variables are referenced, but never set. False warnings may be generated in some cases for null-terminated strings, where the actual pointer (PChar) is not set, but when the contents of the buffer pointed to is indeed changed.

 

__________________________________________________

 

Variables that are referenced, but possibly never set (ref/set by unknown subprograms)

 

This section lists all variables that are declared and referenced but never set. They are referenced in unknown fashion, and the parser is unable to determine whether they are set or just referenced in these locations.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, and are changed whenever the other variable changes.

 

Recommendation:

Examine why these variables are referenced, but never set. False warnings may be generated in some cases for null-terminated strings, where the actual pointer (PChar) is not set, but when the contents of the buffer pointed to is indeed changed.

 

__________________________________________________

 

Variables that are set, but never referenced

 

This is a list of all variables that are set but never referenced. Either these variables are unnecessary or something is missing in the code, because it is meaningless to set a variable and then never reference, or use it.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, and are changed whenever the other variable changes.

 

Recommendation:

Examine why these variables are set, but never referenced.
 

__________________________________________________

 

Variables that are set, but possibly never referenced (ref/set by unknown subprograms)

 

This is a list of all variables that are set but never referenced. The variables are referenced in unknown fashion, and the parser cannot determine whether they are set or just referenced in these locations. They are either unnecessary or something is missing in the code, because it is meaningless to set a variable and then never reference, or use it.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, they are changed whenever the other variable changes.

 

Recommendation:

Examine why these variables are set, but never referenced. Also, try to make more source code available to PAL.
 

__________________________________________________

 

Local variables that are referenced before they are set

 

This is a list of all local variables that are referenced before they are set. Probably this is an error, because the values of these identifiers are undefined before they are set. An exception is long strings that are not examined, because they are implicitly initialized upon creation.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, they are changed whenever the other variable changes.

 

Recommendation:

Examine why these variables are referenced before they are set.

 

Example:

 

procedure MyProc;

var

I : integer;

begin

if I = 55 then // !! I is undefined

begin

   ..

end;

 

I := 55;

..

end;

 

Pascal Analyzer also examines local subprograms that are called. Consider this scenario:

 

Example:

 

procedure Proc;

var

I : integer;

 

procedure InnerProc;

begin

   if Condition then

     if I < 5 then

       ..

end;

 

begin

InnerProc;  

..

I := 55;

end;

 

This code triggers a warning, because the local variable I is first referenced by InnerProc. The call to InnerProc occurs before I is set in the main body of Proc. Even if I is only referenced when Condition evaluates to True (in InnerProc), this must happen at some occasion, otherwise that check would be pointless.

 

__________________________________________________

 

Local variables that may be referenced by unknown subprogram before they are set

 

This is a list of all local variables that are referenced before they are set. They are referenced in unknown fashion, and the parser cannot determine whether they are set or just referenced in these locations. Probably this is an error because the values of these identifiers are undefined before they are set. An exception is long strings that are not examined, because they are implicitly initialized to empty strings when created.

 

Restrictions:

Variables marked with the absolute directive are not examined. These identifiers shadow another variable in memory, they are changed whenever the other variable changes.

 

 

Example:

 

procedure MyProc;

var

I : integer;

begin

UnknownProc(I);

 

if I = 55 then // !! I may be undefined

begin

   ..

end;

 

I := 55;

..

end;

 

__________________________________________________

 

Var parameters that are used, but never set

 

This is a list of all var parameters that are used but never set in the subprogram they belong to. Although this is not an error, it may be an indication that something is wrong with your code. Otherwise, you may omit the var keyword, or change it to a const parameter.

 

Example:

 

procedure MyProc(var I : integer);

begin

..

if I = 5 then // !! I is not set

begin

   ..

end;

..

end;

 

Restrictions:

Parameters to event handlers are not reported. 

 

__________________________________________________

 

Var parameters that are used, but possibly never set (ref/set by unknown subprograms

 

This is a list of all var parameters that are used but never set in the subprogram they belong to. They are referenced in unknown fashion, and the parser cannot determine whether they are set or just referenced in these locations. Although this is not an error, it may be an indication that something is wrong with your code. Otherwise, you may omit the var keyword, or change it to a const parameter.

 

Example:

 

procedure MyProc(var I : integer);

begin

..

UnknownProc(I);

..

if I = 5 then // !! I may not be set

begin

   ..

end;

..

end;

 

Restrictions:

Parameters to event handlers are not reported. 

__________________________________________________

 

Value parameters that are set

 

This is a list of all value parameters that are set in the subprogram they belong to. Although this is permitted by the compiler, it may not be what you intended. If you want to really change the variable, use the var directive instead.

 

Example:

 

procedure MyProc(I : integer);

begin

..

I := 5; // !! I is changed

..

end;

 

__________________________________________________

 

Value parameters that are possibly set (ref/set by unknown subprogram)

 

This is a list of all value parameters that are set in the subprogram they belong to. They are referenced in unknown fashion, and the parser cannot determine whether they are set or just referenced in these locations. Although this is permitted by the compiler, it may not be what you intended. If your intention is to really change the variable, use the var directive instead.

 

Example:

 

procedure MyProc(I : integer);

begin

..

UnknownProc(I); // !! I may be changed

..

end;

 

__________________________________________________

 

Variables with absolute directive

 

[BP7,D1,D2,D3,D4,D5,D6]

This is a list of all variables that are declared with the absolute directive keyword. You should watch these variables carefully, since they may potentially overwrite memory.

 

Example:

 

procedure MyProc;

var

I : byte;

K : integer absolute I;

begin

..

K := MaxInt; // !! I is overwritten

end;

 

Recommendation:

Examine absolute variables carefully, and make sure that they do not overwrite memory. 
 

__________________________________________________

 

Constructors/destructors without calls to inherited

 

This is a list of all constructors and destructors that never call their inherited constructor/destructor. This call is often required. so that the object can be correctly created or destroyed. For a class descending directly from TObject, the inherited call in the constructor is not needed, since the constructor in TObject does not actually do anything. There is no guarantee though that the constructor will be empty in future versions.

 

Recommendation:

Call the inherited constructor as the first statement in the constructor, and as the last statement in the destructor.

 

__________________________________________________

 

Destructors without override directive

 

This is a list of all destructors that miss the override directive keyword. Normally this directive must be set, or a call to the Free method would never be successful. This is because Free calls the destructor.

 

Limitation:

Not examined for Borland Pascal 7. For other targets, old-style objects are never reported, because in this case the override keyword is not allowed.

 

__________________________________________________

 

Classes with more than one destructor

 

This is a list of all classes that have more than one destructor declared. To declare more than one destructor is usually pointless and should be avoided.
 

__________________________________________________

 

Function result not set

 

This is a list of all functions where the result value never is set. Although this is acceptable for the compiler, it implies an error in the code. Maybe the function could be implemented as a procedure instead, if the result value is not needed.

 

Recommendation:

Check these functions and examine if they should be implemented as procedures instead.
 

__________________________________________________

 

Recursive subprograms

 

This is a list of all subprograms (procedures and functions) that are recursive (call themselves). Recursive subprograms are difficult to implement, and should be given extra attention.

 

Recommendation:

Check these subprograms and make sure that they cannot fall into infinite recursion.
 

__________________________________________________

 

Dangerous Exit-statements

 

This is a list of all locations with dangerous Exit-statements. These Exit-statements may leave a whole block of code that is never executed (dead code). Every unconditional (not within an if-statement) Exit-statement is considered dangerous in this respect. Exit-statements within except-blocks are considered as safe, however.

 

There are situations when a developer inserts Exit-commands just for testing purposes, for example to quit a function without executing a block of code. This report section catches those locations where the Exit-commands have not been removed.

 

Example:

 

procedure MyProc;

begin

..

Exit;

 

Proc(X); // !! never executed

..

end;

__________________________________________________

 

Dangerous Raise

 

This is a list of all locations with dangerous raise commands. These raise-commands may leave a whole block of code that is never executed (dead code). Every unconditional (not within an if-statement) raise-command is considered dangerous in this respect. Raise-commands within except-blocks are considered as safe, however.

 

There are situations when a developer inserts raise-commands just for testing purposes, for example to quit a function without executing a block of code. This report section catches those locations where raise-commands have not been removed.

 

Example:

 

procedure MyProc;

begin

..

raise Exception.Create(‘Leave here’);

 

Proc(X); // !! never executed

..

end;

__________________________________________________

 

Dangerous Label-locations inside for-loops

 

This is a list of all locations with dangerous goto-labels. These labels are located inside for-loops. In the case of a for-loop, this is especially dangerous, since the loop variable has an undefined value in the code following the loop.

 

Example:

 

procedure MyProc;

label

MyLabel;

..

begin

..

for I := 0 to NumItems-1 do

begin

..

MyLabel:

..

end;

..

if Cond then

   goto MyLabel; // !! dangerous 

..

end;

 

__________________________________________________

 

Dangerous Label-locations inside repeat/while-loops

 

This is a list of all locations with dangerous goto-labels. These labels are located inside repeat/while-loops. If the loop counter is considered, this may work just fine, but these labels should be given extra attention. 

 

Example:

 

procedure MyProc;

label

MyLabel;

..

begin

..

while I < NumItems-1 do

begin

..

MyLabel:

..

end;

..

if Cond then

   goto MyLabel; // !! dangerous 

..

end;

 

__________________________________________________

 

Possible bad object creation

 

This is a list of all locations in the code where an object possibly is created in a bad fashion.

 

Example:

 

procedure Proc;

var

Bmp : TBitmap;

begin

..

Bmp.Create // !! Bmp := TBitmap.Create  

..

end;

 

This is an error!

 

Example:

 

procedure Proc2;

begin

TNode.Create(Parent)

end;

 

PAL reports this as an error, since the reference to the new object is not assigned to a variable. It could possibly be a mistake. However, in a situation where the object is inserted into a list managed by “Parent”, it is not a mistake. This is the case for the common TTreeView control.

 

Limitation:

Not examined for Borland Pascal 7. For other targets, old-style objects are never reported, because in this case the override keyword is not allowed.

 

__________________________________________________

 

Bad thread-local variables

 

This is a list of all thread-local variables (declared with the “threadvar” keyword) with bad declarations. Reference-counted variables (such as long strings, dynamic arrays, or interfaces) are not thread-safe and should not be declared with “threadvar”. Also, do not create pointer- or procedural-type thread variables. 

 

Limitation:

Not examined for Borland Pascal 7 and Delphi 1

 

 

Example:

 

threadvar

S : string;           // !! these are all bad thread-local variables     

P : pointer;

R : array of integer;

X : IMyInterface;

W : TProcedure;

 

__________________________________________________

 

Instance created of class with abstract methods
 

This is a list of all locations where instances of classes with abstract methods are created. Such classes should serve as ancestor classes only.

 

Example:

 

type

TAbstractClass = class

    procedure AbstractMethod; virtual; abstract;

    ..

end;

..

var

  Obj : TAbstractClass;

 

begin

Obj := TAbstractClass.Create; // triggers a warning

..

end;

__________________________________________________

 

Empty code blocks and short-circuited statements

 

This is a list of all empty code blocks and short-circuited statements. Short-circuited statements are of these kinds:

 

Example:

 

if x then;

for I := 0 to 5 do;

while x do;

 

These statements may be mistakes.

 

__________________________________________________

 

Forward directive in interface

 

Even if a forward directive is allowed by at least some versions of the Pascal/Delphi compiler, they are unnecessary and should be avoided.

 

________________________________________________

 

Empty subprogram parameter list

 

Surprisingly, this code is accepted by at least some versions of the Pascal/Delphi  compiler:

 

Example:

 

procedure Proc();

begin

..

end;

 

________________________________________________

 

Ambiguous references in with-blocks

 

This section reports locations where a valid references to an identifier inside a with-block could be mixed up with another identifier declared in the same scope. It is not an error, but just means that you should check that the code does what you intended.

 

Example:

 

..

var

Title : string;

 

type

TMyRec = record

   Title : string;

end;  

 

var

Rec : TMyRec;

begin

..

with Rec do

begin

   ..

   Title := ´Hello’;

end;  

end;

 

The record field referenced in the with-block could be mixed up with the global Title.

Maybe the programmer instead intended to set the global Title identifier.

 

________________________________________________

 

Classes without overrides of abstract methods

 

This section lists classes that do not override abstract methods in ancestor classes. If a method is declared abstract in an ancestor class, it must be overridden in descendant classes. Otherwise, calling the method for the descendant class will result in a runtime error.

 

________________________________________________

 

Local for-loop variables read after loop

This section lists for-loop variables that are read in code after the loop. Their values are undefined, and thus it is not recommended to use their values.

________________________________________________

 

Local for-loop variables possibly read after loop

This section lists for-loop variables that possibly are read in code after the loop. Their values are undefined, and thus it is not recommended to use their values.

________________________________________________

 

For-loop variables not used in loop

When a for-loop variable is not used in the loop, it may be a coding error.

________________________________________________

 

Non-public constructors/destructors

This section lists constructors/destructors that are non-public.

________________________________________________

 

Functions called as procedures

This section lists locations in the source code where functions are called as procedures, that is without using the result value. Maybe this is a coding error, and the function should really be called as a function instead.

________________________________________________

 

Mismatch property read/write specifiers

This section lists property declarations with mismatch between read/write specifiers, like

 

property IntValue2 : integer read IntValue2 write IntValue3;

 

This is probably a coding error.

 

 

See also:

 

R_GEN General Reports