brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.6 KiB · 6dd28e2 Raw
167 lines · cpp
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-exception6//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's60    // TypeConstraint's ImmediatelyDeclaredConstraint, which is a61    // 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 implicitly76    // 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 are114  // 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 the155  // 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 namespace167