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> {
VisitConceptSpecializationExpr__anon0eba5fef0111::ConceptVisitor20 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
21 ++ConceptSpecializationExprsVisited;
22 return true;
23 }
TraverseTypeConstraint__anon0eba5fef0111::ConceptVisitor24 bool TraverseTypeConstraint(const TypeConstraint *C) {
25 ++TypeConstraintsTraversed;
26 return ExpectedLocationVisitor::TraverseTypeConstraint(C);
27 }
TraverseConceptRequirement__anon0eba5fef0111::ConceptVisitor28 bool TraverseConceptRequirement(concepts::Requirement *R) {
29 ++ConceptRequirementsTraversed;
30 return ExpectedLocationVisitor::TraverseConceptRequirement(R);
31 }
32
shouldVisitImplicitCode__anon0eba5fef0111::ConceptVisitor33 bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; }
34
35 int ConceptSpecializationExprsVisited = 0;
36 int TypeConstraintsTraversed = 0;
37 int ConceptRequirementsTraversed = 0;
38 bool ShouldVisitImplicitCode = false;
39 };
40
TEST(RecursiveASTVisitor,Concepts)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> {
VisitConceptDecl__anon0eba5fef0111::VisitDeclOnlyOnce76 bool VisitConceptDecl(ConceptDecl *D) {
77 ++ConceptDeclsVisited;
78 return true;
79 }
80
VisitAutoType__anon0eba5fef0111::VisitDeclOnlyOnce81 bool VisitAutoType(AutoType *) {
82 ++AutoTypeVisited;
83 return true;
84 }
VisitAutoTypeLoc__anon0eba5fef0111::VisitDeclOnlyOnce85 bool VisitAutoTypeLoc(AutoTypeLoc) {
86 ++AutoTypeLocVisited;
87 return true;
88 }
89
TraverseVarDecl__anon0eba5fef0111::VisitDeclOnlyOnce90 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
shouldWalkTypesOfTypeLocs__anon0eba5fef0111::VisitDeclOnlyOnce97 bool shouldWalkTypesOfTypeLocs() { return false; }
98
99 int ConceptDeclsVisited = 0;
100 int AutoTypeVisited = 0;
101 int AutoTypeLocVisited = 0;
102 };
103
TEST(RecursiveASTVisitor,ConceptDeclInAutoType)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