117 lines
4.1 KiB
C++
117 lines
4.1 KiB
C++
//===- unittest/Tooling/RecursiveASTVisitorTests/Concept.cpp----------------==//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TestVisitor.h"
|
|
#include "clang/AST/ASTConcept.h"
|
|
#include "clang/AST/DeclTemplate.h"
|
|
#include "clang/AST/ExprConcepts.h"
|
|
#include "clang/AST/Type.h"
|
|
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
|
|
struct ConceptVisitor : ExpectedLocationVisitor<ConceptVisitor> {
|
|
bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
|
|
++ConceptSpecializationExprsVisited;
|
|
return true;
|
|
}
|
|
bool TraverseTypeConstraint(const TypeConstraint *C) {
|
|
++TypeConstraintsTraversed;
|
|
return ExpectedLocationVisitor::TraverseTypeConstraint(C);
|
|
}
|
|
bool TraverseConceptRequirement(concepts::Requirement *R) {
|
|
++ConceptRequirementsTraversed;
|
|
return ExpectedLocationVisitor::TraverseConceptRequirement(R);
|
|
}
|
|
|
|
bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; }
|
|
|
|
int ConceptSpecializationExprsVisited = 0;
|
|
int TypeConstraintsTraversed = 0;
|
|
int ConceptRequirementsTraversed = 0;
|
|
bool ShouldVisitImplicitCode = false;
|
|
};
|
|
|
|
TEST(RecursiveASTVisitor, Concepts) {
|
|
ConceptVisitor Visitor;
|
|
Visitor.ShouldVisitImplicitCode = true;
|
|
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
|
|
"template <Fooable T> void bar(T);",
|
|
ConceptVisitor::Lang_CXX2a));
|
|
// Check that we traverse the "Fooable T" template parameter's
|
|
// TypeConstraint's ImmediatelyDeclaredConstraint, which is a
|
|
// ConceptSpecializationExpr.
|
|
EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
|
|
// Also check we traversed the TypeConstraint that produced the expr.
|
|
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
|
|
|
|
Visitor = {}; // Don't visit implicit code now.
|
|
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
|
|
"template <Fooable T> void bar(T);",
|
|
ConceptVisitor::Lang_CXX2a));
|
|
// Check that we only visit the TypeConstraint, but not the implicitly
|
|
// generated immediately declared expression.
|
|
EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited);
|
|
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
|
|
|
|
Visitor = {};
|
|
EXPECT_TRUE(Visitor.runOver("template <class T> concept A = true;\n"
|
|
"template <class T> struct vector {};\n"
|
|
"template <class T> concept B = requires(T x) {\n"
|
|
" typename vector<T*>;\n"
|
|
" {x} -> A;\n"
|
|
" requires true;\n"
|
|
"};",
|
|
ConceptVisitor::Lang_CXX2a));
|
|
EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed);
|
|
}
|
|
|
|
struct VisitDeclOnlyOnce : ExpectedLocationVisitor<VisitDeclOnlyOnce> {
|
|
bool VisitConceptDecl(ConceptDecl *D) {
|
|
++ConceptDeclsVisited;
|
|
return true;
|
|
}
|
|
|
|
bool VisitAutoType(AutoType *) {
|
|
++AutoTypeVisited;
|
|
return true;
|
|
}
|
|
bool VisitAutoTypeLoc(AutoTypeLoc) {
|
|
++AutoTypeLocVisited;
|
|
return true;
|
|
}
|
|
|
|
bool TraverseVarDecl(VarDecl *V) {
|
|
// The base traversal visits only the `TypeLoc`.
|
|
// However, in the test we also validate the underlying `QualType`.
|
|
TraverseType(V->getType());
|
|
return ExpectedLocationVisitor::TraverseVarDecl(V);
|
|
}
|
|
|
|
bool shouldWalkTypesOfTypeLocs() { return false; }
|
|
|
|
int ConceptDeclsVisited = 0;
|
|
int AutoTypeVisited = 0;
|
|
int AutoTypeLocVisited = 0;
|
|
};
|
|
|
|
TEST(RecursiveASTVisitor, ConceptDeclInAutoType) {
|
|
// Check `AutoType` and `AutoTypeLoc` do not repeatedly traverse the
|
|
// underlying concept.
|
|
VisitDeclOnlyOnce Visitor;
|
|
Visitor.runOver("template <class T> concept A = true;\n"
|
|
"A auto i = 0;\n",
|
|
VisitDeclOnlyOnce::Lang_CXX2a);
|
|
EXPECT_EQ(1, Visitor.AutoTypeVisited);
|
|
EXPECT_EQ(1, Visitor.AutoTypeLocVisited);
|
|
EXPECT_EQ(1, Visitor.ConceptDeclsVisited);
|
|
}
|
|
|
|
} // end anonymous namespace
|