I'm trying to prototype a clang-tidy
matcher with clang-query
to find using namespace
directive with a certain name like using namespace ns1::ns2;
.
With clang-query
I tried these variants but none is matching anything:
clang-query> match usingDirectiveDecl(hasName("ns1")).bind("changeNamespaceName")
0 matches.
clang-query> match usingDirectiveDecl(hasName("ns2")).bind("changeNamespaceName")
0 matches.
clang-query> match usingDirectiveDecl(hasName("ns1::ns2")).bind("changeNamespaceName")
0 matches.
Is usingDirectiveDecl
the right matcher for this task?
What is the right way to find a using namespace
directive with a specific name?
Unfortunately, it appears to be impossible to do this with a clang-query
AST matcher alone. usingDirectiveDecl
matches using namespace
declarations, but further restriction based on the nominated namespace is incomplete.
While UsingDirectiveDecl
does have a name, it is simply the placeholder string ::<using-directive>
:
clang-query> m usingDirectiveDecl(matchesName("^::<using-directive>$"))
Match #1:
/home/scott/wrk/learn/clang/using-namespace/un1.cc:22:3: note: "root" binds here
using namespace ns1;
^~~~~~~~~~~~~~~~~~~
Match #2:
/home/scott/wrk/learn/clang/using-namespace/un1.cc:28:3: note: "root" binds here
using namespace ns1::ns2;
^~~~~~~~~~~~~~~~~~~~~~~~
2 matches.
It turns out we can use hasDescendant
to filter based on a namespace qualifier if one is present:
clang-query> m usingDirectiveDecl(hasDescendant(nestedNameSpecifier(specifiesNamespace(matchesName("ns1")))))
Match #1:
/home/scott/wrk/learn/clang/using-namespace/un1.cc:28:3: note: "root" binds here
using namespace ns1::ns2;
^~~~~~~~~~~~~~~~~~~~~~~~
1 match.
This is filtering using the QualifierLoc
member of UsingDirectiveDecl
. But there's no way to filter on what comes after the qualifier, nor if there is no qualifier at all. The reason appears to be simply the absence of an AST matcher that would restrict UsingDirectiveDecl
based on its NominatedNamespace
field.
Consequently, within a clang-tidy
check, the best you can do is use a matcher to find all using namespace
declarations, then (in subsequent C++ code) inspect the result of calling getNominatedNamespace()
.