diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -241,6 +241,11 @@ return true; } + bool VisitConceptReference(const ConceptReference *CR) { + report(CR->getConceptNameLoc(), CR->getFoundDecl()); + return true; + } + // Report a reference from explicit specializations to the specialized // template. Implicit ones are filtered out by RAV and explicit instantiations // are already traversed through typelocs. diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -528,5 +528,16 @@ const char* s = ""; auto sx = ^{s};)cpp"); } + +TEST(WalkAST, Concepts) { + std::string Concept = "template concept $explicit^Foo = true;"; + testWalk(Concept, "templateconcept Bar = ^Foo && true;"); + testWalk(Concept, "template<^Foo T>void func() {}"); + testWalk(Concept, "template requires ^Foo void func() {}"); + testWalk(Concept, "template void func() requires ^Foo {}"); + testWalk(Concept, "void func(^Foo auto x) {}"); + // FIXME: Foo should be explicitly referenced. + testWalk("template concept Foo = true;", "void func() { ^Foo auto x = 1; }"); +} } // namespace } // namespace clang::include_cleaner