Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: how to automatically remove unused vars ("Variable 'x' is declared but never used" hint)

Tags:

syntax

delphi

Is there any tool (preferably freeware) that can analyze Pascal/Delphi syntax and automatically remove unused vars?

In my case, I'm working with a very large Delphi code base, and the compiler hints report over one thousand cases of "Variable 'x' is declared but never used".

I would take hours to remove them by hand, and I might make errors, but the right tool should be able to do that safely and automatically.

I searched online but didn't find one... does anybody here know of such a tool?

Thanks...

Mark Brarford

like image 563
Mark Bradford Avatar asked Feb 10 '09 11:02

Mark Bradford


3 Answers

I see your point and totally agree that such a tool would be useful when working with legacy code. Unfortunately I don't know of any existing tool (I should add freeware tool here, static analyis tools should of course be able to do it easily, but I don't know of any free static code analysis tool) that is capable doing that.

But I guess you could easily write such a tool in a few minutes. A small GUI with a memo and a button should be enough. Then just copy the compiler hints to the memo and press the button. The tool then parses every line. It can easily check if the line contains the hint you are looking for and each such line has the same structure, so parsing should be relatively easy. It can then extract the file name and the line number, open the file and remove the variable declaration. This can be a bit tricky in case of multiple variable declarations in one line but I think it is doable.

I don't know if that's too much effort for you compared to the task of removing all variable declarations yourself. But I would like to see such a tool, so feel free to write it :)

Hope that helped at least a bit.

Okay, I really can't see any problems here. For the parsing part:

function ParseHint (const HintText : String; out HintInfo : THintInfo) : Boolean;
var
  I, J     : Integer;
  HintName : String;
begin
  Result := False;
  for I := 1 to Length (HintText) do
  begin
    if (HintText [I] = '(') then
    begin
      J := I + 1;
      while (HintText [J] <> ')') do Inc (J);
      HintInfo.LineNumber := StrToInt (MidStr (HintText, I+1, J-(I+1)));
      HintInfo.SourceFile := MidStr (HintText, 12, I-12);
      HintName := MidStr (HintText, J+3, 5);
      if (HintName <> 'H2164') then Exit (False);
    end;
    if (HintText [I] = '''') then
    begin
      J := I + 1;
      while (HintText [J] <> '''') do Inc (J);
      HintInfo.VarName := MidStr (HintText, I+1, J-(I+1));
      Exit (True);
    end;
  end;
end;

Well, reading the source file should be easy, so the only remaing part is removing the variable from its line of declaration. We can simply search for occurences of HintInfo.VarName in the line and check if the character before and after the occurence are no letters but only ' ', ',' or ':'. If this is the case we can just remove it. This covers all these cases:

var UnusedVar : Integer;
var
  UnusedVar,
  AnotherVar : Integer;
var
  UnusedVar, AnotherVar : Integer;

Tell me if I'm wrong or if I forgot any cases but I think this would work and woulde solve the problem of removing unused variables from delphi source files using the compiler-generated hints.

like image 139
jpfollenius Avatar answered Oct 27 '22 05:10

jpfollenius


The solution is simple, but requires those hours to be sure you don't make a mistake. First off, You can use Alt-F8 to step through each report one after the other (and Alt-F7 to step backwards). That makes locating them very easy. The cursor is put on the line for you. Then just press the '/' key twice to comment it out. Don't delete it, comment it. This way if you make a mistake you haven't lost any information. The presence of the variable and its data type is still recorded. You can tidy it up later at some point.

One caveat to all this: Conditional compilation may render some variables unused when built different ways. If this happens, then just uncomment the variable again, and put the condition around the declaration too.

like image 3
mj2008 Avatar answered Oct 27 '22 07:10

mj2008


Are you sure the variables shouldn't be used? I know the compiler figures out that they aren't used right now, but is that correct, perhaps many of these should be used, but a developer used x2 instead of x1 for instance, copy and paste?

While you might want to remove all those variables unscrutinized, I wouldn't be so hasty, they might be indications of bugs in your code that you'd like to fix.

Example:

procedure PlotPixelAtCenter(rect: Rectangle)
var
    x, y: Integer;
begin
    x := (rect.Left + rect.Right) div 2;
    x := (rect.Top + rect.Bottom) div 2; // <-- bug here, should be y :=
    PlotPixel(x, y);
end;

In this example you'll get an error about an unused variable, but this is a bug lurking. Of course, in this example the bug should be easy to find since the plotting will probably be off, but other similar bugs might be harder to spot.

like image 2
Lasse V. Karlsen Avatar answered Oct 27 '22 06:10

Lasse V. Karlsen