I am trying to write a clang-tidy check to rename struct members.
For this, I need to match MemberExpr
nodes that access a certain member, from certain structs.
In the following code, it should only match all uses of member
on types S1
and S2
(8 matches in total).
typedef struct S1 { int member; int v; } S1; typedef struct MS1 {S1 s1; } MS1;
typedef struct S2 { int member; int v; } S2; typedef struct MS2 {S2 s2; } MS2;
typedef struct S3 { int member; int v; } S3; typedef struct MS3 {S2 s3; } MS3;
void f() {
S1 *s1a, s1b; MS1 *ms1a, ms1b;
S2 *s2a, s2b; MS2 *ms2a, ms2b;
S3 *s3a, s3b; MS3 *ms3a, ms3b;
(void)s1a->member; (void)s1b.member; (void)ms1a->s1.member; (void)ms1b.s1.member;
(void)s2a->member; (void)s2b.member; (void)ms2a->s2.member; (void)ms2b.s2.member;
(void)s3a->member; (void)s3b.member; (void)ms3a->s3.member; (void)ms3b.s3.member;
(void)s1a->v; (void)s1b.v; (void)ms1a->s1.v; (void)ms1b.s1.v;
(void)s2a->v; (void)s2b.v; (void)ms2a->s2.v; (void)ms2b.s2.v;
(void)s3a->v; (void)s3b.v; (void)ms3a->s3.v; (void)ms3b.s3.v;
}
The matcher memberExpr(member(hasName("member")))
is too broad and also includes type S3
.
How can I limit the matcher to only return those member accesses of S1
and S2
?
Thanks.
Perhaps surprisingly, the hasName
selector can be used to restrict the member's containing class or namespace as well as its simple identifier name. Quoting the linked documentation:
Matches NamedDecl nodes that have the specified name.
Supports specifying enclosing namespaces or classes by prefixing the name
with '<enclosing>::'.
Does not match typedefs of an underlying type with the given name.
Example matches X (Name == "X")
class X;
Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
namespace a { namespace b { class X; } }
This means we can match S1::member
and S2::member
like this:
memberExpr(member(anyOf(hasName("S1::member"),hasName("S2::member"))))
We can also use matchesName
to express the conditionality using a regular expression:
memberExpr(member(matchesName("S[12]::member")))
With either of the above, I get eight matches on your testcase, but only after fixing the apparent typo in this line:
typedef struct S3 { int member; int v; } S3; typedef struct MS3 {S2 s3; } MS3;
which I think should be:
typedef struct S3 { int member; int v; } S3; typedef struct MS3 {S3 s3; } MS3;
^