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 Out.str();
25 }
26 
27 TEST(TemplateName, PrintUsingTemplate) {
28   std::string Code = R"cpp(
29     namespace std {
30       template <typename> struct vector {};
31     }
32     namespace absl { using std::vector; }
33 
34     template<template <typename> class T> class X;
35 
36     using absl::vector;
37     using A = X<vector>;
38   )cpp";
39   auto AST = tooling::buildASTFromCode(Code);
40   ASTContext &Ctx = AST->getASTContext();
41   // Match the template argument vector in X<vector>.
42   auto MatchResults = match(templateArgumentLoc().bind("id"), Ctx);
43   const auto *Template = selectFirst<TemplateArgumentLoc>("id", MatchResults);
44   ASSERT_TRUE(Template);
45 
46   TemplateName TN = Template->getArgument().getAsTemplate();
47   EXPECT_EQ(TN.getKind(), TemplateName::UsingTemplate);
48   EXPECT_EQ(TN.getAsUsingShadowDecl()->getTargetDecl(), TN.getAsTemplateDecl());
49 
50   EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
51                               TemplateName::Qualified::Fully),
52             "std::vector");
53   EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
54                               TemplateName::Qualified::AsWritten),
55             "vector");
56   EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
57                               TemplateName::Qualified::None),
58             "vector");
59 }
60 
61 TEST(TemplateName, QualifiedUsingTemplate) {
62   std::string Code = R"cpp(
63     namespace std {
64       template <typename> struct vector {};
65     }
66     namespace absl { using std::vector; }
67 
68     template<template <typename> class T> class X;
69 
70     using A = X<absl::vector>; // QualifiedTemplateName in a template argument.
71   )cpp";
72   auto AST = tooling::buildASTFromCode(Code);
73   // Match the template argument absl::vector in X<absl::vector>.
74   auto Matcher = templateArgumentLoc().bind("id");
75   auto MatchResults = match(Matcher, AST->getASTContext());
76   const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>("id");
77   ASSERT_TRUE(TAL);
78   TemplateName TN = TAL->getArgument().getAsTemplate();
79   EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate);
80   const auto *QTN = TN.getAsQualifiedTemplateName();
81   // Verify that we have the Using template name in the QualifiedTemplateName.
82   const auto *USD = QTN->getUnderlyingTemplate().getAsUsingShadowDecl();
83   EXPECT_TRUE(USD);
84   EXPECT_EQ(USD->getTargetDecl(), TN.getAsTemplateDecl());
85 }
86 
87 TEST(TemplateName, UsingTemplate) {
88   auto AST = tooling::buildASTFromCode(R"cpp(
89     namespace std {
90       template <typename T> struct vector { vector(T); };
91     }
92     namespace absl { using std::vector; }
93     // The "absl::vector<int>" is an elaborated TemplateSpecializationType with
94     // an inner Using TemplateName (not a Qualified TemplateName, the qualifiers
95     // are rather part of the ElaboratedType)!
96     absl::vector<int> v(123);
97   )cpp");
98   auto Matcher = elaboratedTypeLoc(
99       hasNamedTypeLoc(loc(templateSpecializationType().bind("id"))));
100   auto MatchResults = match(Matcher, AST->getASTContext());
101   const auto *TST =
102       MatchResults.front().getNodeAs<TemplateSpecializationType>("id");
103   ASSERT_TRUE(TST);
104   EXPECT_EQ(TST->getTemplateName().getKind(), TemplateName::UsingTemplate);
105 
106   AST = tooling::buildASTFromCodeWithArgs(R"cpp(
107     namespace std {
108       template <typename T> struct vector { vector(T); };
109     }
110     namespace absl { using std::vector; }
111     // Similiar to the TemplateSpecializationType, absl::vector is an elaborated
112     // DeducedTemplateSpecializationType with an inner Using TemplateName!
113     absl::vector DTST(123);
114     )cpp",
115                                           {"-std=c++17"});
116   Matcher = elaboratedTypeLoc(
117       hasNamedTypeLoc(loc(deducedTemplateSpecializationType().bind("id"))));
118   MatchResults = match(Matcher, AST->getASTContext());
119   const auto *DTST =
120       MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>("id");
121   ASSERT_TRUE(DTST);
122   EXPECT_EQ(DTST->getTemplateName().getKind(), TemplateName::UsingTemplate);
123 }
124 
125 } // namespace
126 } // namespace clang
127