diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index dff0c711f04c5..ba6eff49e9c98 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -321,6 +321,11 @@ class ASTWalker : public RecursiveASTVisitor { return true; } + bool VisitCleanupAttr(CleanupAttr *attr) { + report(attr->getLocation(), attr->getFunctionDecl()); + return true; + } + // TypeLoc visitors. void reportType(SourceLocation RefLoc, NamedDecl *ND) { // Reporting explicit references to types nested inside classes can cause diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index e45ea36f7938e..19695a34bd63e 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -570,5 +570,11 @@ TEST(WalkAST, OperatorNewDelete) { testWalk("struct A { static void $ambiguous^operator delete(void*); };", "void foo() { A a; ^delete &a; }"); } + +TEST(WalkAST, CleanupAttr) { + testWalk("void* $explicit^freep(void *p);", + "void foo() { __attribute__((^__cleanup__(freep))) char* x = 0; }"); +} + } // namespace } // namespace clang::include_cleaner