xref: /llvm-project/clang/unittests/AST/TemplateNameTest.cpp (revision 918972bded27de6a2bfacc15b4ad3edebd81f405)
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