Add lint option to check for unused variables.
This commit is contained in:
parent
44499bdddb
commit
fe62f70d51
2
CC.pas
2
CC.pas
|
@ -140,6 +140,8 @@ DoGlobals; {create the ~GLOBALS and ~ARRAYS segment
|
||||||
{shut down the compiler}
|
{shut down the compiler}
|
||||||
TermHeader; {make sure the compiled header file is closed}
|
TermHeader; {make sure the compiled header file is closed}
|
||||||
CheckStaticFunctions; {check for undefined functions}
|
CheckStaticFunctions; {check for undefined functions}
|
||||||
|
if (lint & lintUnused) <> 0 then {check for unused static vars}
|
||||||
|
CheckUnused(globalTable);
|
||||||
ffDCBGS.action := 7; {purge the source file}
|
ffDCBGS.action := 7; {purge the source file}
|
||||||
ffDCBGS.pcount := 14;
|
ffDCBGS.pcount := 14;
|
||||||
ffDCBGS.pathName := @includeFileGS.theString;
|
ffDCBGS.pathName := @includeFileGS.theString;
|
||||||
|
|
|
@ -93,6 +93,7 @@ const
|
||||||
lintOverflow = $0020; {check for overflows}
|
lintOverflow = $0020; {check for overflows}
|
||||||
lintC99Syntax = $0040; {check for syntax that C99 disallows}
|
lintC99Syntax = $0040; {check for syntax that C99 disallows}
|
||||||
lintReturn = $0080; {flag issues with how functions return}
|
lintReturn = $0080; {flag issues with how functions return}
|
||||||
|
lintUnused = $0100; {check for unused variables}
|
||||||
|
|
||||||
{bit masks for GetLInfo flags}
|
{bit masks for GetLInfo flags}
|
||||||
{----------------------------}
|
{----------------------------}
|
||||||
|
@ -375,6 +376,7 @@ type
|
||||||
iPtr: initializerPtr; {pointer to the first initializer}
|
iPtr: initializerPtr; {pointer to the first initializer}
|
||||||
isForwardDeclared: boolean; {does this var use a forward declared type?}
|
isForwardDeclared: boolean; {does this var use a forward declared type?}
|
||||||
class: tokenEnum; {storage class}
|
class: tokenEnum; {storage class}
|
||||||
|
used: boolean; {is this identifier used?}
|
||||||
case storage: storageType of
|
case storage: storageType of
|
||||||
stackFrame: (lln: integer; {local label #}
|
stackFrame: (lln: integer; {local label #}
|
||||||
clnext: identPtr); {next compound literal}
|
clnext: identPtr); {next compound literal}
|
||||||
|
|
|
@ -986,6 +986,7 @@ var
|
||||||
stack^.token.class := longlongConstant;
|
stack^.token.class := longlongConstant;
|
||||||
stack^.token.kind := longlongconst;
|
stack^.token.kind := longlongconst;
|
||||||
stack^.token.qval := longlong0;
|
stack^.token.qval := longlong0;
|
||||||
|
id := nil;
|
||||||
end {if}
|
end {if}
|
||||||
|
|
||||||
{if the id is not declared, create a function returning integer}
|
{if the id is not declared, create a function returning integer}
|
||||||
|
@ -1022,6 +1023,9 @@ var
|
||||||
stack^.token.kind := intconst;
|
stack^.token.kind := intconst;
|
||||||
stack^.token.ival := id^.itype^.eval;
|
stack^.token.ival := id^.itype^.eval;
|
||||||
end; {else if}
|
end; {else if}
|
||||||
|
|
||||||
|
if id <> nil then
|
||||||
|
id^.used := true;
|
||||||
stack^.id := id; {save the identifier}
|
stack^.id := id; {save the identifier}
|
||||||
ComplexTerm; {handle subscripts, selection, etc.}
|
ComplexTerm; {handle subscripts, selection, etc.}
|
||||||
1:
|
1:
|
||||||
|
|
|
@ -1810,6 +1810,7 @@ var
|
||||||
sp^.isForwardDeclared := boolean(ReadByte);
|
sp^.isForwardDeclared := boolean(ReadByte);
|
||||||
sp^.class := tokenEnum(ReadByte);
|
sp^.class := tokenEnum(ReadByte);
|
||||||
sp^.storage := storageType(ReadByte);
|
sp^.storage := storageType(ReadByte);
|
||||||
|
sp^.used := false;
|
||||||
if sp^.storage = none then
|
if sp^.storage = none then
|
||||||
sp^.anonMemberField := false
|
sp^.anonMemberField := false
|
||||||
else if sp^.storage = external then
|
else if sp^.storage = external then
|
||||||
|
|
|
@ -4115,6 +4115,7 @@ if isFunction then begin
|
||||||
lp := NewSymbol(@'__orcac_va_info', vaInfoPtr, autosy,
|
lp := NewSymbol(@'__orcac_va_info', vaInfoPtr, autosy,
|
||||||
variableSpace, declared, false);
|
variableSpace, declared, false);
|
||||||
lp^.lln := GetLocalLabel;
|
lp^.lln := GetLocalLabel;
|
||||||
|
lp^.used := true;
|
||||||
Gen2(dc_loc, lp^.lln, ord(vaInfoPtr^.size));
|
Gen2(dc_loc, lp^.lln, ord(vaInfoPtr^.size));
|
||||||
Gen2(pc_lda, lastParameterLLN, lastParameterSize);
|
Gen2(pc_lda, lastParameterLLN, lastParameterSize);
|
||||||
Gen2t(pc_cop, lp^.lln, 0, cgULong);
|
Gen2t(pc_cop, lp^.lln, 0, cgULong);
|
||||||
|
|
44
Scanner.pas
44
Scanner.pas
|
@ -114,6 +114,18 @@ procedure Error (err: integer);
|
||||||
{ err - error number }
|
{ err - error number }
|
||||||
|
|
||||||
|
|
||||||
|
procedure ErrorWithExtraString (err:integer; extraStr: stringPtr);
|
||||||
|
|
||||||
|
{ flag an error, with an extra string to be attached to it }
|
||||||
|
{ }
|
||||||
|
{ err - error number }
|
||||||
|
{ extraStr - extra string to include in error message }
|
||||||
|
{ }
|
||||||
|
{ Note: }
|
||||||
|
{ extraStr must point to a pString allocated with new. }
|
||||||
|
{ This call transfers ownership of it. }
|
||||||
|
|
||||||
|
|
||||||
{procedure Error2 (loc, err: integer); {debug}
|
{procedure Error2 (loc, err: integer); {debug}
|
||||||
|
|
||||||
{ flag an error }
|
{ flag an error }
|
||||||
|
@ -190,13 +202,14 @@ const
|
||||||
{----}
|
{----}
|
||||||
defaultName = '13:ORCACDefs:Defaults.h'; {default include file name}
|
defaultName = '13:ORCACDefs:Defaults.h'; {default include file name}
|
||||||
maxErr = 10; {max errors on one line}
|
maxErr = 10; {max errors on one line}
|
||||||
maxLint = 170; {maximum lint error code}
|
maxLint = 185; {maximum lint error code}
|
||||||
|
|
||||||
type
|
type
|
||||||
errorType = record {record of a single error}
|
errorType = record {record of a single error}
|
||||||
num: integer; {error number}
|
num: integer; {error number}
|
||||||
line: longint; {line number}
|
line: longint; {line number}
|
||||||
col: integer; {column number}
|
col: integer; {column number}
|
||||||
|
extraStr: stringPtr; {extra text to include in message}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{file inclusion}
|
{file inclusion}
|
||||||
|
@ -787,8 +800,13 @@ if list or (numErr <> 0) then begin
|
||||||
182: msg := @'''='' expected';
|
182: msg := @'''='' expected';
|
||||||
183: msg := @'array index out of bounds';
|
183: msg := @'array index out of bounds';
|
||||||
184: msg := @'segment exceeds bank size';
|
184: msg := @'segment exceeds bank size';
|
||||||
|
185: msg := @'lint: unused variable: ';
|
||||||
otherwise: Error(57);
|
otherwise: Error(57);
|
||||||
end; {case}
|
end; {case}
|
||||||
|
if extraStr <> nil then begin
|
||||||
|
extraStr^ := concat(msg^,extraStr^);
|
||||||
|
msg := extraStr;
|
||||||
|
end; {if}
|
||||||
writeln(msg^);
|
writeln(msg^);
|
||||||
if terminalErrors and (numErrors <> 0)
|
if terminalErrors and (numErrors <> 0)
|
||||||
and (lintIsError or not (num in lintErrors)) then begin
|
and (lintIsError or not (num in lintErrors)) then begin
|
||||||
|
@ -803,6 +821,8 @@ if list or (numErr <> 0) then begin
|
||||||
else
|
else
|
||||||
TermError(0);
|
TermError(0);
|
||||||
end; {if}
|
end; {if}
|
||||||
|
if extraStr <> nil then
|
||||||
|
dispose(extraStr);
|
||||||
end; {with}
|
end; {with}
|
||||||
{handle pauses}
|
{handle pauses}
|
||||||
if ((numErr <> 0) and wait) or KeyPress then begin
|
if ((numErr <> 0) and wait) or KeyPress then begin
|
||||||
|
@ -3767,12 +3787,31 @@ else begin
|
||||||
with errors[numErr] do begin {record the position of the error}
|
with errors[numErr] do begin {record the position of the error}
|
||||||
line := tokenLine;
|
line := tokenLine;
|
||||||
col := tokenColumn;
|
col := tokenColumn;
|
||||||
|
extraStr := nil;
|
||||||
end; {with}
|
end; {with}
|
||||||
if numErrors <> 0 then
|
if numErrors <> 0 then
|
||||||
codeGeneration := false; {inhibit code generation}
|
codeGeneration := false; {inhibit code generation}
|
||||||
end; {Error}
|
end; {Error}
|
||||||
|
|
||||||
|
|
||||||
|
procedure ErrorWithExtraString {err:integer; extraStr: stringPtr};
|
||||||
|
|
||||||
|
{ flag an error, with an extra string to be attached to it }
|
||||||
|
{ }
|
||||||
|
{ err - error number }
|
||||||
|
{ extraStr - extra string to include in error message }
|
||||||
|
{ }
|
||||||
|
{ Note: }
|
||||||
|
{ extraStr must point to a pString allocated with new. }
|
||||||
|
{ This call transfers ownership of it. }
|
||||||
|
|
||||||
|
begin {ErrorWithExtraString}
|
||||||
|
Error(err);
|
||||||
|
if errors[numErr].num <> 4 then
|
||||||
|
errors[numErr].extraStr := extraStr;
|
||||||
|
end; {ErrorWithExtraString}
|
||||||
|
|
||||||
|
|
||||||
{procedure Error2 {loc, err: integer} {debug}
|
{procedure Error2 {loc, err: integer} {debug}
|
||||||
|
|
||||||
{ flag an error }
|
{ flag an error }
|
||||||
|
@ -4490,7 +4529,8 @@ strictMode := false; {...with extensions}
|
||||||
|
|
||||||
{error codes for lint messages}
|
{error codes for lint messages}
|
||||||
{if changed, also change maxLint}
|
{if changed, also change maxLint}
|
||||||
lintErrors := [51,104,105,110,124,125,128,129,130,147,151,152,153,154,155,170];
|
lintErrors :=
|
||||||
|
[51,104,105,110,124,125,128,129,130,147,151,152,153,154,155,170,185];
|
||||||
|
|
||||||
spaceStr := ' '; {strings used in stringization}
|
spaceStr := ' '; {strings used in stringization}
|
||||||
quoteStr := '"';
|
quoteStr := '"';
|
||||||
|
|
49
Symbol.pas
49
Symbol.pas
|
@ -100,6 +100,11 @@ procedure CheckStaticFunctions;
|
||||||
{ check for undefined functions }
|
{ check for undefined functions }
|
||||||
|
|
||||||
|
|
||||||
|
procedure CheckUnused (tPtr: symbolTablePtr);
|
||||||
|
|
||||||
|
{ check for unused variables in symbol table }
|
||||||
|
|
||||||
|
|
||||||
function CompTypes (t1, t2: typePtr): boolean;
|
function CompTypes (t1, t2: typePtr): boolean;
|
||||||
|
|
||||||
{ Determine if the two types are compatible }
|
{ Determine if the two types are compatible }
|
||||||
|
@ -2339,6 +2344,7 @@ if needSymbol then begin
|
||||||
{p^.isForwardDeclared := false;} {assume no forward declarations are used}
|
{p^.isForwardDeclared := false;} {assume no forward declarations are used}
|
||||||
p^.name := name; {record the name}
|
p^.name := name; {record the name}
|
||||||
{p^.next := nil;}
|
{p^.next := nil;}
|
||||||
|
{p^.used := false;} {unused for now}
|
||||||
if space <> fieldListSpace then {insert the symbol in the hash bucket}
|
if space <> fieldListSpace then {insert the symbol in the hash bucket}
|
||||||
begin
|
begin
|
||||||
if itype = nil then
|
if itype = nil then
|
||||||
|
@ -2389,6 +2395,47 @@ useGlobalPool := lUseGlobalPool; {restore the useGlobalPool variable}
|
||||||
end; {NewSymbol}
|
end; {NewSymbol}
|
||||||
|
|
||||||
|
|
||||||
|
procedure CheckUnused {tPtr: symbolTablePtr};
|
||||||
|
|
||||||
|
{ check for unused variables in symbol table }
|
||||||
|
|
||||||
|
var
|
||||||
|
i: integer; {loop variable}
|
||||||
|
ip: identPtr; {current symbol}
|
||||||
|
nameStr: stringPtr;
|
||||||
|
|
||||||
|
begin {CheckUnused}
|
||||||
|
for i := 0 to hashSize do begin {loop over all hash buckets}
|
||||||
|
ip := tPtr^.buckets[i]; {trace through non-static symbols}
|
||||||
|
while ip <> nil do begin
|
||||||
|
if not ip^.used then
|
||||||
|
if ip^.itype <> nil then
|
||||||
|
if not (ip^.itype^.kind in [functionType,enumConst]) then
|
||||||
|
if ip^.storage in [stackFrame,private] then
|
||||||
|
if not (ip^.name^[1] in ['~','@']) then begin
|
||||||
|
new(nameStr);
|
||||||
|
nameStr^ := ip^.name^;
|
||||||
|
ErrorWithExtraString(185, nameStr);
|
||||||
|
end; {if}
|
||||||
|
ip := ip^.next;
|
||||||
|
end; {while}
|
||||||
|
ip := globalTable^.buckets[i]; {trace through static symbols}
|
||||||
|
while ip <> nil do begin
|
||||||
|
if not ip^.used then
|
||||||
|
if ip^.itype <> nil then
|
||||||
|
if not (ip^.itype^.kind in [functionType,enumConst]) then
|
||||||
|
if ip^.storage = private then
|
||||||
|
if copy(ip^.name^,1,5) = tPtr^.staticNum then begin
|
||||||
|
new(nameStr);
|
||||||
|
nameStr^ := copy(ip^.name^, 6, maxint);
|
||||||
|
ErrorWithExtraString(185, nameStr);
|
||||||
|
end; {if}
|
||||||
|
ip := ip^.next;
|
||||||
|
end; {while}
|
||||||
|
end; {for}
|
||||||
|
end; {CheckUnused}
|
||||||
|
|
||||||
|
|
||||||
procedure PopTable;
|
procedure PopTable;
|
||||||
|
|
||||||
{ Pop a symbol table (remove definitions local to a block) }
|
{ Pop a symbol table (remove definitions local to a block) }
|
||||||
|
@ -2400,6 +2447,8 @@ begin {PopTable}
|
||||||
tPtr := table;
|
tPtr := table;
|
||||||
{if printSymbols then {debug}
|
{if printSymbols then {debug}
|
||||||
{ PrintTable(tPtr); {debug}
|
{ PrintTable(tPtr); {debug}
|
||||||
|
if (lint & lintUnused) <> 0 then
|
||||||
|
CheckUnused(tPtr);
|
||||||
if tPtr^.next <> nil then begin
|
if tPtr^.next <> nil then begin
|
||||||
table := table^.next;
|
table := table^.next;
|
||||||
dispose(tPtr);
|
dispose(tPtr);
|
||||||
|
|
4
cc.notes
4
cc.notes
|
@ -757,6 +757,10 @@ ORCA/C can now detect several elements of C syntax that were allowed in C89 but
|
||||||
|
|
||||||
If #pragma lint bit 7 (a value of 128) is set, ORCA/C detects some situations where a function with a non-void return type may return an unpredictable value, either by executing a return statement with no value or by executing to the end of the function with no return statement. (The former case is also detected by #pragma lint bit 6.) It also detects some situations where a _Noreturn function could return. Note that these checks only detect some cases of these problems, not all of them. Also, they may report a potential problem in some situations where the code at the end of a function is not actually reachable.
|
If #pragma lint bit 7 (a value of 128) is set, ORCA/C detects some situations where a function with a non-void return type may return an unpredictable value, either by executing a return statement with no value or by executing to the end of the function with no return statement. (The former case is also detected by #pragma lint bit 6.) It also detects some situations where a _Noreturn function could return. Note that these checks only detect some cases of these problems, not all of them. Also, they may report a potential problem in some situations where the code at the end of a function is not actually reachable.
|
||||||
|
|
||||||
|
* Checking for unused variables:
|
||||||
|
|
||||||
|
If #pragma lint bit 8 (a value of 256) is set, ORCA/C checks for variables that are declared but never subsequently used. This covers local variables in functions, as well as file-scope static variables.
|
||||||
|
|
||||||
|
|
||||||
#pragma extensions
|
#pragma extensions
|
||||||
------------------
|
------------------
|
||||||
|
|
Loading…
Reference in New Issue