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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp