mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2024-12-26 03:32:45 +00:00
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}
|
||||
TermHeader; {make sure the compiled header file is closed}
|
||||
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.pcount := 14;
|
||||
ffDCBGS.pathName := @includeFileGS.theString;
|
||||
|
@ -93,6 +93,7 @@ const
|
||||
lintOverflow = $0020; {check for overflows}
|
||||
lintC99Syntax = $0040; {check for syntax that C99 disallows}
|
||||
lintReturn = $0080; {flag issues with how functions return}
|
||||
lintUnused = $0100; {check for unused variables}
|
||||
|
||||
{bit masks for GetLInfo flags}
|
||||
{----------------------------}
|
||||
@ -375,6 +376,7 @@ type
|
||||
iPtr: initializerPtr; {pointer to the first initializer}
|
||||
isForwardDeclared: boolean; {does this var use a forward declared type?}
|
||||
class: tokenEnum; {storage class}
|
||||
used: boolean; {is this identifier used?}
|
||||
case storage: storageType of
|
||||
stackFrame: (lln: integer; {local label #}
|
||||
clnext: identPtr); {next compound literal}
|
||||
|
@ -986,6 +986,7 @@ var
|
||||
stack^.token.class := longlongConstant;
|
||||
stack^.token.kind := longlongconst;
|
||||
stack^.token.qval := longlong0;
|
||||
id := nil;
|
||||
end {if}
|
||||
|
||||
{if the id is not declared, create a function returning integer}
|
||||
@ -1022,6 +1023,9 @@ var
|
||||
stack^.token.kind := intconst;
|
||||
stack^.token.ival := id^.itype^.eval;
|
||||
end; {else if}
|
||||
|
||||
if id <> nil then
|
||||
id^.used := true;
|
||||
stack^.id := id; {save the identifier}
|
||||
ComplexTerm; {handle subscripts, selection, etc.}
|
||||
1:
|
||||
|
@ -1810,6 +1810,7 @@ var
|
||||
sp^.isForwardDeclared := boolean(ReadByte);
|
||||
sp^.class := tokenEnum(ReadByte);
|
||||
sp^.storage := storageType(ReadByte);
|
||||
sp^.used := false;
|
||||
if sp^.storage = none then
|
||||
sp^.anonMemberField := false
|
||||
else if sp^.storage = external then
|
||||
|
@ -4115,6 +4115,7 @@ if isFunction then begin
|
||||
lp := NewSymbol(@'__orcac_va_info', vaInfoPtr, autosy,
|
||||
variableSpace, declared, false);
|
||||
lp^.lln := GetLocalLabel;
|
||||
lp^.used := true;
|
||||
Gen2(dc_loc, lp^.lln, ord(vaInfoPtr^.size));
|
||||
Gen2(pc_lda, lastParameterLLN, lastParameterSize);
|
||||
Gen2t(pc_cop, lp^.lln, 0, cgULong);
|
||||
|
44
Scanner.pas
44
Scanner.pas
@ -114,6 +114,18 @@ procedure Error (err: integer);
|
||||
{ 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}
|
||||
|
||||
{ flag an error }
|
||||
@ -190,13 +202,14 @@ const
|
||||
{----}
|
||||
defaultName = '13:ORCACDefs:Defaults.h'; {default include file name}
|
||||
maxErr = 10; {max errors on one line}
|
||||
maxLint = 170; {maximum lint error code}
|
||||
maxLint = 185; {maximum lint error code}
|
||||
|
||||
type
|
||||
errorType = record {record of a single error}
|
||||
num: integer; {error number}
|
||||
line: longint; {line number}
|
||||
col: integer; {column number}
|
||||
extraStr: stringPtr; {extra text to include in message}
|
||||
end;
|
||||
|
||||
{file inclusion}
|
||||
@ -787,8 +800,13 @@ if list or (numErr <> 0) then begin
|
||||
182: msg := @'''='' expected';
|
||||
183: msg := @'array index out of bounds';
|
||||
184: msg := @'segment exceeds bank size';
|
||||
185: msg := @'lint: unused variable: ';
|
||||
otherwise: Error(57);
|
||||
end; {case}
|
||||
if extraStr <> nil then begin
|
||||
extraStr^ := concat(msg^,extraStr^);
|
||||
msg := extraStr;
|
||||
end; {if}
|
||||
writeln(msg^);
|
||||
if terminalErrors and (numErrors <> 0)
|
||||
and (lintIsError or not (num in lintErrors)) then begin
|
||||
@ -803,6 +821,8 @@ if list or (numErr <> 0) then begin
|
||||
else
|
||||
TermError(0);
|
||||
end; {if}
|
||||
if extraStr <> nil then
|
||||
dispose(extraStr);
|
||||
end; {with}
|
||||
{handle pauses}
|
||||
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}
|
||||
line := tokenLine;
|
||||
col := tokenColumn;
|
||||
extraStr := nil;
|
||||
end; {with}
|
||||
if numErrors <> 0 then
|
||||
codeGeneration := false; {inhibit code generation}
|
||||
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}
|
||||
|
||||
{ flag an error }
|
||||
@ -4490,7 +4529,8 @@ strictMode := false; {...with extensions}
|
||||
|
||||
{error codes for lint messages}
|
||||
{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}
|
||||
quoteStr := '"';
|
||||
|
49
Symbol.pas
49
Symbol.pas
@ -100,6 +100,11 @@ procedure CheckStaticFunctions;
|
||||
{ check for undefined functions }
|
||||
|
||||
|
||||
procedure CheckUnused (tPtr: symbolTablePtr);
|
||||
|
||||
{ check for unused variables in symbol table }
|
||||
|
||||
|
||||
function CompTypes (t1, t2: typePtr): boolean;
|
||||
|
||||
{ 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^.name := name; {record the name}
|
||||
{p^.next := nil;}
|
||||
{p^.used := false;} {unused for now}
|
||||
if space <> fieldListSpace then {insert the symbol in the hash bucket}
|
||||
begin
|
||||
if itype = nil then
|
||||
@ -2389,6 +2395,47 @@ useGlobalPool := lUseGlobalPool; {restore the useGlobalPool variable}
|
||||
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;
|
||||
|
||||
{ Pop a symbol table (remove definitions local to a block) }
|
||||
@ -2400,6 +2447,8 @@ begin {PopTable}
|
||||
tPtr := table;
|
||||
{if printSymbols then {debug}
|
||||
{ PrintTable(tPtr); {debug}
|
||||
if (lint & lintUnused) <> 0 then
|
||||
CheckUnused(tPtr);
|
||||
if tPtr^.next <> nil then begin
|
||||
table := table^.next;
|
||||
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.
|
||||
|
||||
* 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
|
||||
------------------
|
||||
|
Loading…
Reference in New Issue
Block a user