1 //===- unittest/Tooling/RecursiveASTVisitorTests/Concept.cpp----------------==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "TestVisitor.h" 10 #include "clang/AST/ASTConcept.h" 11 #include "clang/AST/DeclTemplate.h" 12 #include "clang/AST/ExprConcepts.h" 13 #include "clang/AST/Type.h" 14 15 using namespace clang; 16 17 namespace { 18 19 struct ConceptVisitor : ExpectedLocationVisitor<ConceptVisitor> { 20 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { 21 ++ConceptSpecializationExprsVisited; 22 return true; 23 } 24 bool TraverseTypeConstraint(const TypeConstraint *C) { 25 ++TypeConstraintsTraversed; 26 return ExpectedLocationVisitor::TraverseTypeConstraint(C); 27 } 28 bool TraverseConceptRequirement(concepts::Requirement *R) { 29 ++ConceptRequirementsTraversed; 30 return ExpectedLocationVisitor::TraverseConceptRequirement(R); 31 } 32 33 bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; } 34 35 int ConceptSpecializationExprsVisited = 0; 36 int TypeConstraintsTraversed = 0; 37 int ConceptRequirementsTraversed = 0; 38 bool ShouldVisitImplicitCode = false; 39 }; 40 41 TEST(RecursiveASTVisitor, Concepts) { 42 ConceptVisitor Visitor; 43 Visitor.ShouldVisitImplicitCode = true; 44 EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n" 45 "template <Fooable T> void bar(T);", 46 ConceptVisitor::Lang_CXX2a)); 47 // Check that we traverse the "Fooable T" template parameter's 48 // TypeConstraint's ImmediatelyDeclaredConstraint, which is a 49 // ConceptSpecializationExpr. 50 EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited); 51 // Also check we traversed the TypeConstraint that produced the expr. 52 EXPECT_EQ(1, Visitor.TypeConstraintsTraversed); 53 54 Visitor = {}; // Don't visit implicit code now. 55 EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n" 56 "template <Fooable T> void bar(T);", 57 ConceptVisitor::Lang_CXX2a)); 58 // Check that we only visit the TypeConstraint, but not the implicitly 59 // generated immediately declared expression. 60 EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited); 61 EXPECT_EQ(1, Visitor.TypeConstraintsTraversed); 62 63 Visitor = {}; 64 EXPECT_TRUE(Visitor.runOver("template <class T> concept A = true;\n" 65 "template <class T> struct vector {};\n" 66 "template <class T> concept B = requires(T x) {\n" 67 " typename vector<T*>;\n" 68 " {x} -> A;\n" 69 " requires true;\n" 70 "};", 71 ConceptVisitor::Lang_CXX2a)); 72 EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed); 73 } 74 75 struct VisitDeclOnlyOnce : ExpectedLocationVisitor<VisitDeclOnlyOnce> { 76 bool VisitConceptDecl(ConceptDecl *D) { 77 ++ConceptDeclsVisited; 78 return true; 79 } 80 81 bool VisitAutoType(AutoType *) { 82 ++AutoTypeVisited; 83 return true; 84 } 85 bool VisitAutoTypeLoc(AutoTypeLoc) { 86 ++AutoTypeLocVisited; 87 return true; 88 } 89 90 bool TraverseVarDecl(VarDecl *V) { 91 // The base traversal visits only the `TypeLoc`. 92 // However, in the test we also validate the underlying `QualType`. 93 TraverseType(V->getType()); 94 return ExpectedLocationVisitor::TraverseVarDecl(V); 95 } 96 97 bool shouldWalkTypesOfTypeLocs() { return false; } 98 99 int ConceptDeclsVisited = 0; 100 int AutoTypeVisited = 0; 101 int AutoTypeLocVisited = 0; 102 }; 103 104 TEST(RecursiveASTVisitor, ConceptDeclInAutoType) { 105 // Check `AutoType` and `AutoTypeLoc` do not repeatedly traverse the 106 // underlying concept. 107 VisitDeclOnlyOnce Visitor; 108 Visitor.runOver("template <class T> concept A = true;\n" 109 "A auto i = 0;\n", 110 VisitDeclOnlyOnce::Lang_CXX2a); 111 EXPECT_EQ(1, Visitor.AutoTypeVisited); 112 EXPECT_EQ(1, Visitor.AutoTypeLocVisited); 113 EXPECT_EQ(1, Visitor.ConceptDeclsVisited); 114 } 115 116 } // end anonymous namespace 117