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 | bool TraverseConceptReference(ConceptReference *CR) { |
33 | ++ConceptReferencesTraversed; |
34 | return ExpectedLocationVisitor::TraverseConceptReference(CR); |
35 | } |
36 | bool VisitConceptReference(ConceptReference *CR) { |
37 | ++ConceptReferencesVisited; |
38 | return true; |
39 | } |
40 | |
41 | bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; } |
42 | |
43 | int ConceptSpecializationExprsVisited = 0; |
44 | int TypeConstraintsTraversed = 0; |
45 | int ConceptRequirementsTraversed = 0; |
46 | int ConceptReferencesTraversed = 0; |
47 | int ConceptReferencesVisited = 0; |
48 | bool ShouldVisitImplicitCode = false; |
49 | }; |
50 | |
51 | TEST(RecursiveASTVisitor, Concepts) { |
52 | ConceptVisitor Visitor; |
53 | Visitor.ShouldVisitImplicitCode = true; |
54 | EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n" |
55 | "template <Fooable T> void bar(T);" , |
56 | ConceptVisitor::Lang_CXX2a)); |
57 | // Check that we traverse the "Fooable T" template parameter's |
58 | // TypeConstraint's ImmediatelyDeclaredConstraint, which is a |
59 | // ConceptSpecializationExpr. |
60 | EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited); |
61 | // Also check we traversed the TypeConstraint that produced the expr. |
62 | EXPECT_EQ(1, Visitor.TypeConstraintsTraversed); |
63 | EXPECT_EQ(1, Visitor.ConceptReferencesTraversed); |
64 | EXPECT_EQ(1, Visitor.ConceptReferencesVisited); |
65 | |
66 | Visitor = {}; // Don't visit implicit code now. |
67 | EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n" |
68 | "template <Fooable T> void bar(T);" , |
69 | ConceptVisitor::Lang_CXX2a)); |
70 | // Check that we only visit the TypeConstraint, but not the implicitly |
71 | // generated immediately declared expression. |
72 | EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited); |
73 | EXPECT_EQ(1, Visitor.TypeConstraintsTraversed); |
74 | EXPECT_EQ(1, Visitor.ConceptReferencesTraversed); |
75 | EXPECT_EQ(1, Visitor.ConceptReferencesVisited); |
76 | |
77 | Visitor = {}; |
78 | EXPECT_TRUE(Visitor.runOver("template <class T> concept A = true;\n" |
79 | "template <class T> struct vector {};\n" |
80 | "template <class T> concept B = requires(T x) {\n" |
81 | " typename vector<T*>;\n" |
82 | " {x} -> A;\n" |
83 | " requires true;\n" |
84 | "};" , |
85 | ConceptVisitor::Lang_CXX2a)); |
86 | EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed); |
87 | EXPECT_EQ(1, Visitor.ConceptReferencesTraversed); |
88 | EXPECT_EQ(1, Visitor.ConceptReferencesVisited); |
89 | |
90 | Visitor = {}; |
91 | llvm::StringRef Code = |
92 | R"cpp( |
93 | template<typename T> concept True = false; |
94 | template <typename F> struct Foo {}; |
95 | |
96 | template <typename F> |
97 | requires requires { requires True<F>; } |
98 | struct Foo<F> {}; |
99 | |
100 | template <typename F> requires True<F> |
101 | struct Foo<F> {}; |
102 | )cpp" ; |
103 | EXPECT_TRUE(Visitor.runOver(Code, ConceptVisitor::Lang_CXX2a)); |
104 | // Check that the concept references from the partial specializations are |
105 | // visited. |
106 | EXPECT_EQ(2, Visitor.ConceptReferencesTraversed); |
107 | EXPECT_EQ(2, Visitor.ConceptReferencesVisited); |
108 | } |
109 | |
110 | struct VisitDeclOnlyOnce : ExpectedLocationVisitor<VisitDeclOnlyOnce> { |
111 | bool VisitConceptDecl(ConceptDecl *D) { |
112 | ++ConceptDeclsVisited; |
113 | return true; |
114 | } |
115 | |
116 | bool VisitAutoType(AutoType *) { |
117 | ++AutoTypeVisited; |
118 | return true; |
119 | } |
120 | bool VisitAutoTypeLoc(AutoTypeLoc) { |
121 | ++AutoTypeLocVisited; |
122 | return true; |
123 | } |
124 | bool VisitConceptReference(ConceptReference *) { |
125 | ++ConceptReferencesVisited; |
126 | return true; |
127 | } |
128 | |
129 | bool TraverseVarDecl(VarDecl *V) { |
130 | // The base traversal visits only the `TypeLoc`. |
131 | // However, in the test we also validate the underlying `QualType`. |
132 | TraverseType(T: V->getType()); |
133 | return ExpectedLocationVisitor::TraverseVarDecl(V); |
134 | } |
135 | |
136 | bool shouldWalkTypesOfTypeLocs() { return false; } |
137 | |
138 | int ConceptDeclsVisited = 0; |
139 | int AutoTypeVisited = 0; |
140 | int AutoTypeLocVisited = 0; |
141 | int ConceptReferencesVisited = 0; |
142 | }; |
143 | |
144 | TEST(RecursiveASTVisitor, ConceptDeclInAutoType) { |
145 | // Check `AutoType` and `AutoTypeLoc` do not repeatedly traverse the |
146 | // underlying concept. |
147 | VisitDeclOnlyOnce Visitor; |
148 | Visitor.runOver(Code: "template <class T> concept A = true;\n" |
149 | "A auto i = 0;\n" , |
150 | L: VisitDeclOnlyOnce::Lang_CXX2a); |
151 | EXPECT_EQ(1, Visitor.AutoTypeVisited); |
152 | EXPECT_EQ(1, Visitor.AutoTypeLocVisited); |
153 | EXPECT_EQ(1, Visitor.ConceptDeclsVisited); |
154 | EXPECT_EQ(1, Visitor.ConceptReferencesVisited); |
155 | } |
156 | |
157 | } // end anonymous namespace |
158 | |