[cfe-dev] [AST Matcher API] How to match against a subtree?
Gábor Márton via cfe-dev
cfe-dev at lists.llvm.org
Thu Jul 26 02:52:19 PDT 2018
Hi Stephen,
Thanks for pointing out to findAll and it's weaknesses.
I went on and created a phabricator review:
https://reviews.llvm.org/D49840
Cheers,
GaborOn Thu, Jul 26, 2018 at 12:00 AM Stephen Kelly via cfe-dev
<cfe-dev at lists.llvm.org> wrote:
>
> Gábor Márton via cfe-dev wrote:
>
> > Hi,
> >
> > I'd like to do a traversal on a subtree rooted on a specific node, but
> > not on the whole tree rooted at the TranslataionUnitDecl. My
> > understanding is this is not possible today, or is it? I wonder why
> > this was not missing for anybody.
>
> Hi Gabor,
>
> I encountered the same issue, and wrote a similar solution. However, then I
> realized the ast_matchers::match documentation says:
>
> /// If you want to find all matches on the sub-tree rooted at \c Node
> (rather
> /// than only the matches on \c Node itself), surround the \c Matcher with a
> /// \c findAll().
>
> So, we should be able to do something like
>
> Decl* someRootDeclContext = ...;
>
> clang::ast_matchers::match(
> decl(findAll(callExpr()))
> , *someRootDeclContext, *Result.Context);
>
>
> However, that does not work because findAll is implemented with eachOf and
>
> decl(eachOf(callExpr(), expr()))
>
> doesn't work for the same reason
>
> decl(callExpr())
>
> doesn't work - a decl is never a callExpr.
>
> I filed a bug for this: https://bugs.llvm.org/show_bug.cgi?id=38318
>
> Meanwhile, findAll might work for your specific case, or you might be able
> to write a replacement or use something more specific.
>
> A case I encountered involved replacing the type of certain varDecl nodes in
> the source code, but porting them if they are passed by reference in a
> function call (a case I handled separately).
>
> Given
>
> void takeRef(int&)
> {
>
> }
>
> void takeConstRef(int const&)
> {
>
> }
>
> void takeVal(int)
> {
>
> }
>
> struct IntWrapper
> {
> IntWrapper(int i) : m_i(i) {}
>
> operator int() { return m_i; }
>
> private:
> int m_i;
> };
>
> int main()
> {
> int a = 42;
> int b = 7;
>
> takeVal(a);
> takeConstRef(a);
>
> takeVal(b);
> takeRef(b);
> }
>
> the goal is to replace
>
> int a = 42;
>
> with
>
> IntWrapper a = 42;
>
> but leave
>
> int b = 7;
>
> untouched because
>
> takeRef(b);
>
> would not compile if the varDecl is ported.
>
>
> Here is my solution which uses match(). You should be able to do something
> similar for your case without the additional API.
>
> Thanks,
>
> Stephen.
>
>
> #include "PortToIntwrapperCheck.h"
> #include "clang/AST/ASTContext.h"
> #include "clang/ASTMatchers/ASTMatchFinder.h"
>
> using namespace clang::ast_matchers;
>
> namespace clang {
> namespace tidy {
> namespace misc {
>
> void PortToIntwrapperCheck::registerMatchers(MatchFinder *Finder) {
>
> Finder->addMatcher(
> varDecl(
> hasType(asString("int")),
> unless(parmVarDecl()),
> hasDeclContext(decl().bind("varDeclContext"))
> ).bind("portToIntWrapperIfPossible")
> , this);
> }
>
> void PortToIntwrapperCheck::check(const MatchFinder::MatchResult
> &Result) {
>
> if (const auto *portToIntWrapper =
> Result.Nodes.getNodeAs<VarDecl>("portToIntWrapperIfPossible"))
> {
> const auto *varDeclContext =
> Result.Nodes.getNodeAs<Decl>("varDeclContext");
>
> // Got a match for a particular var.
> // Check if it is passed by reference in any calls
> // within the context it is defined in
>
> auto usesByReference = clang::ast_matchers::match(
> decl(forEachDescendant(
> callExpr(forEachArgumentWithParam(
> declRefExpr(
> to(varDecl(equalsNode(portToIntWrapper)))
> ).bind("arg"),
> parmVarDecl(
> hasType(lValueReferenceType(
> unless(pointee(isConstQualified()))
> ))
> )
> ))
> ))
> , *varDeclContext, *Result.Context);
>
> if (usesByReference.empty())
> {
> // All uses are safe to port to IntWrapper
>
> auto tInfo = portToIntWrapper->getTypeSourceInfo();
> auto tLoc = tInfo->getTypeLoc();
>
> SourceRange typeRange = tLoc.getSourceRange();
>
> diag(typeRange.getBegin(), "type of %0 should be IntWrapper")
> << portToIntWrapper
> << FixItHint::CreateReplacement(typeRange, "IntWrapper");
> }
> }
> }
>
> } // namespace misc
> } // namespace tidy
> } // namespace clang
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
More information about the cfe-dev
mailing list