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 @@ -249,6 +249,11 @@ return true; } + bool VisitConceptReference(const ConceptReference *CR) { + report(CR->getConceptNameLoc(), CR->getNamedConcept()); + return true; + } + // TypeLoc visitors. void reportType(SourceLocation RefLoc, NamedDecl *ND) { // Reporting explicit references to types nested inside classes can cause @@ -279,6 +284,13 @@ return true; } + bool VisitAutoTypeLoc(AutoTypeLoc ATL) { + // FIXME: RAV should call VisitConceptReference here, but doesn't! + if (ATL.isConstrained()) + report(ATL.getConceptNameLoc(), ATL.getNamedConcept()); + return true; + } + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { reportType(TL.getTemplateNameLoc(), getMostRelevantTemplatePattern(TL.getTypePtr())); 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 @@ -50,7 +50,7 @@ Inputs.ExtraFiles["target.h"] = Target.code().str(); Inputs.ExtraArgs.push_back("-include"); Inputs.ExtraArgs.push_back("target.h"); - Inputs.ExtraArgs.push_back("-std=c++17"); + Inputs.ExtraArgs.push_back("-std=c++20"); TestAST AST(Inputs); const auto &SM = AST.sourceManager(); @@ -510,5 +510,17 @@ testWalk("enum class E : int {};", "enum class ^E : int ;"); } +TEST(WalkAST, Concepts) { + testWalk("template concept $explicit^C = true;", "^C auto x = 1;"); + testWalk("template concept $explicit^C = true;", "bool x = ^C;"); + testWalk("template concept $explicit^C = true;", "void X(^C auto);"); + testWalk("template concept $explicit^C = true;", + "template <^C T> int X;"); + testWalk("template concept $explicit^C = true;", + "template <^C auto T> int X;"); + testWalk("template concept $explicit^C = true;", + "template requires(^C) int X;"); +} + } // namespace } // namespace clang::include_cleaner diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -457,6 +457,9 @@ DEF_TRAVERSE_TMPL_INST(Function) #undef DEF_TRAVERSE_TMPL_INST + // FIXME: we should also provide VisitTypeConstraint. + // FIXME: VisitConceptReference is not yet called in constrained AutoTypeLoc. + bool VisitConceptReference(const ConceptReference *C) { return true; } bool TraverseTypeConstraint(const TypeConstraint *C); bool TraverseConceptRequirement(concepts::Requirement *R); @@ -543,6 +546,7 @@ template bool RecursiveASTVisitor::TraverseConceptReferenceHelper( const ConceptReference &C) { + TRY_TO(VisitConceptReference(&C)); TRY_TO(TraverseNestedNameSpecifierLoc(C.getNestedNameSpecifierLoc())); TRY_TO(TraverseDeclarationNameInfo(C.getConceptNameInfo())); if (C.hasExplicitTemplateArgs()) @@ -1356,6 +1360,8 @@ DEF_TRAVERSE_TYPELOC(AutoType, { TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); if (TL.isConstrained()) { + // FIXME: should VisitConceptReference instead. + // We don't store that node in the AST today. TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc())); TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo())); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)