Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find assignments with no effect?

In the process of automatically renaming many variables in a big project I may have created a lot of things like these:

class Foo {
    int Par;
    void Bar(int Par) {
        Par = Par;       // Nonsense
    }
};

Now I need to identify those locations to correct them. E.g. into "this->Par = Par;". Unfortunately the Visual C++ Compiler des not give me any comment about it even with all warnings on. I remember there once was a warning about it. It said "Code has no effect" or something. But it seems to be gone maybe because some people used that practice to avoid "unreferenced parameter" warnings. Is there a way to re-activate that warning? Does GCC warn here? Any Idea?

like image 857
Ole Dittmann Avatar asked Sep 23 '10 17:09

Ole Dittmann


2 Answers

A couple of compilers can generate warnings on this:

  • GCC and Clang can warn on code like this if you add the -Wshadow option. (Specifically, while they don't warn about the meaningless assignment, they do warn about the local variable Par shadowing the member variable Par - you may or may not like this.)
  • Embarcadero C++Builder does not warn that Par = Par is useless, but it can warn that Par isn't used after it's assigned to, which should meet your needs.

I suspect a tool like PC-Lint could also identify code like this.

Another solution is to mark your parameters as const:

class Foo {
    int Par;
    void Bar(const int Par) {
        Par = Par;       // Compiler error!
    }
};

const on pass-by-value parameters is not part of the function signature, so you only need to add it to the function definitions within your .cpp file, not your function declarations within your .h file. In other words, it's legal to do this:

// foo.h
class Foo {
    int Par;
    void Bar(int Par);
};

// foo.cpp
void Foo::Bar(const int Par) { ... }
like image 67
Josh Kelley Avatar answered Oct 20 '22 08:10

Josh Kelley


As kaptnole pointed out, the regex I crafted could be used directly in visual studio. Your pattern is:

^[\s\t]*([a-zA-Z_0-9])[\s\t]=[\s\t]\1[\s\t];[\s\t]*$

Follow the directions listed here:
http://msdn.microsoft.com/en-us/library/2k3te2cs%28VS.80%29.aspx
...and happy finding (without ever touching Perl!).


This perl one liner will do it for you:

perl -n -e'/^[\s\t]*([a-zA-Z_0-9]*)[\s\t]*=[\s\t]*\1[\s\t]*;[\s\t]*$/&&print "$. $_"' test_me && echo

I tested it on a file containing the following and it correctly detected all matches:

hi = hi; 
hi= hi ;
  hi=hi   ;

Output....

xxxxx@yyyy% perl -n -e'/[\s\t]*([a-zA-Z_0-9]*)[\s\t]*=[\s\t]*\1[\s\t]*;[\s\t]*$/&&print "$. $_"' test_me && echo
1 hi = hi; 
2 hi= hi ;
3   hi=hi   ;
xxxxx@yyyy%

My first thought was to do it in Awk, but apparently Awk doesn't store its matches! :(

But hey, this Perl script is pretty snazzy itself... it even prints the line numbers of the find!


EDIT 1

And to answer your other question, I compiled a simple test program with such an assignment inside main with the "-pedantic" and "-Wall" flags using gcc and g++ and received no warnings in either... so I guess it doesn't warn you of this kind of redundancy.

Here's my test program:

int main (int argc, char *argv[]) {
  int bob=5;
  bob=bob;
  return 0;
}

EDIT 2

Please note my above perl script does NOT check to see if there's a local variable of an identical name inside a function. In that case the statement might be valid, but poor style (still might be good to warn about).

And as Josh points out, the flag "-Wshadow" WILL warn about this in gcc/g++ in this specialized case.

I would suggest following Josh's advice about using const for static function arguments. In fact, any variable not passed by reference should generally be const

e.g.

void hello_world_print_numbers(int number_1, int number_2, int number_3) {
   ...
}

is a misassignment waiting to happen, so instead use:

void hello_world_print_numbers(const int number_1, const int number_2, const int number_3) {
   ...
}

...likewise in general with pointers, except in the case of passed pointers to arrays (and be careful there to pass in proper array bounds!).

void hello_world_print_numbers(const int * number_1, const int * number_2, const int * number_3) {
   ...
}

EDIT 3

I forgot my ^ at the start of my regex. While seemingly trivial this causes it to improperly tag assignments of type my_class->name=name;. This was wisely pointed out by RC. The regex is now fixed and should no longer have this issue. Thanks RC!

like image 38
Jason R. Mick Avatar answered Oct 20 '22 07:10

Jason R. Mick