1 //===- unittests/AST/TemplateNameTest.cpp --- Tests for TemplateName ------===// 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 "ASTPrint.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchers.h" 12 #include "llvm/Support/raw_ostream.h" 13 #include "gtest/gtest.h" 14 15 namespace clang { 16 namespace { 17 using namespace ast_matchers; 18 19 std::string printTemplateName(TemplateName TN, const PrintingPolicy &Policy, 20 TemplateName::Qualified Qual) { 21 std::string Result; 22 llvm::raw_string_ostream Out(Result); 23 TN.print(Out, Policy, Qual); 24 return Result; 25 } 26 27 TEST(TemplateName, PrintTemplate) { 28 std::string Code = R"cpp( 29 namespace std { 30 template <typename> struct vector {}; 31 } 32 template<template <typename> class T> class X; 33 using A = X<std::vector>; 34 )cpp"; 35 auto AST = tooling::buildASTFromCode(Code); 36 ASTContext &Ctx = AST->getASTContext(); 37 // Match the template argument vector in X<std::vector>. 38 auto MatchResults = match(templateArgumentLoc().bind("id"), Ctx); 39 const auto *Template = selectFirst<TemplateArgumentLoc>("id", MatchResults); 40 ASSERT_TRUE(Template); 41 42 TemplateName TN = Template->getArgument().getAsTemplate(); 43 EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate); 44 EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(), 45 TemplateName::Qualified::AsWritten), 46 "std::vector"); 47 EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(), 48 TemplateName::Qualified::None), 49 "vector"); 50 } 51 52 TEST(TemplateName, PrintUsingTemplate) { 53 std::string Code = R"cpp( 54 namespace std { 55 template <typename> struct vector {}; 56 } 57 namespace absl { using std::vector; } 58 59 template<template <typename> class T> class X; 60 61 using absl::vector; 62 using A = X<vector>; 63 )cpp"; 64 auto AST = tooling::buildASTFromCode(Code); 65 ASTContext &Ctx = AST->getASTContext(); 66 // Match the template argument vector in X<vector>. 67 auto MatchResults = match(templateArgumentLoc().bind("id"), Ctx); 68 const auto *Template = selectFirst<TemplateArgumentLoc>("id", MatchResults); 69 ASSERT_TRUE(Template); 70 71 TemplateName TN = Template->getArgument().getAsTemplate(); 72 EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate); 73 UsingShadowDecl *USD = TN.getAsUsingShadowDecl(); 74 EXPECT_TRUE(USD != nullptr); 75 EXPECT_EQ(USD->getTargetDecl(), TN.getAsTemplateDecl()); 76 77 EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(), 78 TemplateName::Qualified::AsWritten), 79 "vector"); 80 EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(), 81 TemplateName::Qualified::None), 82 "vector"); 83 } 84 85 TEST(TemplateName, QualifiedUsingTemplate) { 86 std::string Code = R"cpp( 87 namespace std { 88 template <typename> struct vector {}; 89 } 90 namespace absl { using std::vector; } 91 92 template<template <typename> class T> class X; 93 94 using A = X<absl::vector>; // QualifiedTemplateName in a template argument. 95 )cpp"; 96 auto AST = tooling::buildASTFromCode(Code); 97 // Match the template argument absl::vector in X<absl::vector>. 98 auto Matcher = templateArgumentLoc().bind("id"); 99 auto MatchResults = match(Matcher, AST->getASTContext()); 100 const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>("id"); 101 ASSERT_TRUE(TAL); 102 TemplateName TN = TAL->getArgument().getAsTemplate(); 103 EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate); 104 const auto *QTN = TN.getAsQualifiedTemplateName(); 105 // Verify that we have the Using template name in the QualifiedTemplateName. 106 const auto *USD = QTN->getUnderlyingTemplate().getAsUsingShadowDecl(); 107 EXPECT_TRUE(USD); 108 EXPECT_EQ(USD->getTargetDecl(), TN.getAsTemplateDecl()); 109 EXPECT_EQ(TN.getAsUsingShadowDecl(), USD); 110 } 111 112 TEST(TemplateName, UsingTemplate) { 113 auto AST = tooling::buildASTFromCode(R"cpp( 114 namespace std { 115 template <typename T> struct vector { vector(T); }; 116 } 117 namespace absl { using std::vector; } 118 // The "absl::vector<int>" is an elaborated TemplateSpecializationType with 119 // an inner Using TemplateName (not a Qualified TemplateName, the qualifiers 120 // are rather part of the ElaboratedType)! 121 absl::vector<int> v(123); 122 )cpp"); 123 auto Matcher = elaboratedTypeLoc( 124 hasNamedTypeLoc(loc(templateSpecializationType().bind("id")))); 125 auto MatchResults = match(Matcher, AST->getASTContext()); 126 const auto *TST = 127 MatchResults.front().getNodeAs<TemplateSpecializationType>("id"); 128 ASSERT_TRUE(TST); 129 EXPECT_EQ(TST->getTemplateName().getKind(), TemplateName::QualifiedTemplate); 130 EXPECT_TRUE(TST->getTemplateName().getAsUsingShadowDecl() != nullptr); 131 132 AST = tooling::buildASTFromCodeWithArgs(R"cpp( 133 namespace std { 134 template <typename T> struct vector { vector(T); }; 135 } 136 namespace absl { using std::vector; } 137 // Similiar to the TemplateSpecializationType, absl::vector is an elaborated 138 // DeducedTemplateSpecializationType with an inner Using TemplateName! 139 absl::vector DTST(123); 140 )cpp", 141 {"-std=c++17"}); 142 Matcher = elaboratedTypeLoc( 143 hasNamedTypeLoc(loc(deducedTemplateSpecializationType().bind("id")))); 144 MatchResults = match(Matcher, AST->getASTContext()); 145 const auto *DTST = 146 MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>("id"); 147 ASSERT_TRUE(DTST); 148 EXPECT_EQ(DTST->getTemplateName().getKind(), TemplateName::QualifiedTemplate); 149 EXPECT_TRUE(DTST->getTemplateName().getAsUsingShadowDecl() != nullptr); 150 } 151 152 } // namespace 153 } // namespace clang 154