In the following example, the variable a defined in line 1 is hidden
in the scope from line 5 to 9. The problem is thus to write a semantic patch
that transforms only one of the two variables.
1. extern int a;
2.
3. void foo()
4. {
5. {
6. int a;
7. a = bar() + 3;
8. ...
9. }
10.
11 a = bar1() + bar2();
12. }
Since we only want to distinguish between local and global, there is
a simple solution using the local attribute.
@@ local idexpression x; expression E; @@ ( x = E | -a = E +a = 12 // whatever change you want to make )
A local idexpression metavariable only matches an identifier that is
declared as a local variable. The | gives precedence to the first
pattern, so the only assignments to a that will get transformed are the
global ones.
We could also have a rule to find extern variables:
@r@ type T; identifier a; @@ extern T a;
And then in the rule above, we could have a metavariable declaration:
identifier r.a;
On the other hand, if you want all global variables, not just extern ones,
then it is more complicated, because global declarations and local
declarations look the same. You also can't use the local idexpression
trick, because that is for expressions, and a variable name in a
declaration is an identifier. In this case, you could first match the
identifiers that are declared locally:
@locally@
type T;
identifier a;
position p;
@@
{
<...
T a@p;
...>
}
TOCHECK: I'm also not sure whether that would match a function body. You might need another rule for variables that are declared at the top level of a program.
Then the global variables are the ones that match the following rule:
@globally@ type T; identifier a; position p!=locally.p; @@ T a@p;