Mark Bradford
Mark Bradford

Reputation: 85

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

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

Upvotes: 6

Views: 4447

Answers (4)

mj2008
mj2008

Reputation: 6747

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.

Upvotes: 3

Toon Krijthe
Toon Krijthe

Reputation: 53366

If there is no such tool and you have some patience, I'm building a Delphi analysis and repair tool. And removal of unused symbols is on the list. It is a low proirity project so I can't give an estimate on when its ready.

Just to explain why this isn't a trivial task:

  1. read the source
  2. create a model that contains enough information for each symbol usage.
  3. mark all unused symbols.
  4. rewrite the source without the unneeded symbols.

Task 1 and 2 are hard (luckily for me those are already done). The Delphi language is quite complex. And you need all language elements to be able to recreate the source.

Task 3 is simple. Just flag all symbols that are unused. But beware of symbols in the interface section of a unit. They are possibly not used but needed later (or by some other project).

Task 4 depends.

Aproach A uses an intermediate format (for example a stringlist), you can then use the model to find the declaration of each unused symbol (bottom up else you possibly change the line numbers). You delete all not needed. And don't forget to delete the var keyword if it's the last var in the list!

Aproach B completely rewrites the source file. In this case, you must preserve all comments which is not really fun to do (but my model needs that too). You just removes the unused symbols from the model and rewrite it. Always be sure to create a backup, because this can end up in disaster.

Upvotes: 2

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391326

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.

Upvotes: 3

jpfollenius
jpfollenius

Reputation: 16612

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.

Upvotes: 5

Related Questions