The constant attribute on a metavariable declaration will only match an explicit literal value. For instance constant int matches a literal that is considered to have int type.
@r@ int E1; constant int C; @@ E1 = C
Because in Linux constant defined using #define are commonly written using only capital letters, an identifier written using only capital letters is considered to be a constant as well. For example, consider the following semantic patch:
@@ identifier C; @@ + an_identifier( C + ) @@ constant int C; @@ + an_int_constant( C + ) @@ constant C; @@ + a_constant( C + )
and the following C file:
int f() {
return 1 + SOMETHING;
}
the result is:
int f() {
return an_int_constant(a_constant(1)) + an_identifier(a_constant(SOMETHING));
}
because 1 is both a constant and an integer constant, while SOMETHING is both an identifier and a constant, but not an integer constant, because its type is not known. On the other hand, if the C file also contains:
#define SOMETHING 1
then SOMETHING is also considered to be an integer constant.
While there is a constant attribute, there is no attribute to indicate that a metavariable should not match a constant. This can be done using a disjunction, ( | ), in the pattern, as illustrated by the following example:
@r@ int E; constant int C; long E1; @@ E1 = ( C | - E + f(E) )
This semantic patch wraps a call to f around the right-hand side of an assignment, unless the right-hand side is a constant.
The “fresh” attribute on an identifier metavariable declaration allows creating new identifiers to be used in the generated (+) code. The declaration of a fresh identifier x has three possible forms, which determine how the new identifier is chosen:
Metavariable of identifier can not only be used to match any identifier, or exactly the ones defined in a list, but also match according to a regular expression. Some examples are provided below:
@anyid@
type t;
identifier id;
@@
t id () {
...
}
@script:python@
x << anyid.id;
@@
print "Identifier: %s" % x
@contains@
type t;
identifier foo ~= ".*foo";
@@
t foo () {
...
}
@script:python@
x << contains.foo;
@@
print "Contains foo: %s" % x
@nocontain@
type t;
identifier foo !~= ".*foo";
@@
t foo () {
...
}
@script:python@
x << nocontain.foo;
@@
print "Does not contain foo: %s" % x
@endsby@
type t;
identifier foo ~= ".*foo$";
@@
t foo () {
...
}
@script:python@
x << endsby.foo;
@@
print "Ends by foo: %s" % x
@beginsby@
type t;
identifier foo ~= "^foo";
@@
t foo () {
...
}
@script:python@
x << beginsby.foo;
@@
print "Begins by foo: %s" % x
Group, alternative and optional element can be used in the regexp, as illustrated by the following example:
@@ identifier SPAM ~= "\(WINE_\)?\(ERR\|FIXME\|WARN\)"; @@ -SPAM +bar
An identifier metavariable can be constrained to be different from either a concrete identifier or an identifier metavariable inherited from a previous rule. Examples of such metavariable declarations are as follows, where some previous rule r has declared an identifier metavariable id.
identifier a != foo;
identifier b != {foo,r.id};
identifier c != r.id;
In the second and third cases, the constraint is that the declared metavariable is different from some binding of r.id, and not that it is different from every binding of r.id, which is somewhat unfortunate and should be fixed at some point. This kind of constraint is thus only useful in practice when r.id has only one possible binding.
The constraint
<=
on the declaration of an expression metavariable allows declaring a metavariable that matches a subexpression of another one. This is particularly useful in checking that the value of the expression matching an expression metavariable has not changed from one matching instance to another one. An example is as follows:
@r@ expression E; @@ f(E); @@ expression subE <= r.E; expression E1; @@ f(E); ... when != subE = E1 return E;