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(OS&: 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(Matcher: templateArgumentLoc().bind(ID: "id" ), Context&: Ctx); |
39 | const auto *Template = selectFirst<TemplateArgumentLoc>(BoundTo: "id" , Results: 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(Matcher: templateArgumentLoc().bind(ID: "id" ), Context&: Ctx); |
68 | const auto *Template = selectFirst<TemplateArgumentLoc>(BoundTo: "id" , Results: 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: "id" ); |
99 | auto MatchResults = match(Matcher, Context&: AST->getASTContext()); |
100 | const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>(ID: "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(Code: 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(InnerMatcher: loc(InnerMatcher: templateSpecializationType().bind(ID: "id" )))); |
125 | auto MatchResults = match(Matcher, Context&: AST->getASTContext()); |
126 | const auto *TST = |
127 | MatchResults.front().getNodeAs<TemplateSpecializationType>(ID: "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(Code: 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 | Args: {"-std=c++17" }); |
142 | Matcher = elaboratedTypeLoc( |
143 | hasNamedTypeLoc(InnerMatcher: loc(InnerMatcher: deducedTemplateSpecializationType().bind(ID: "id" )))); |
144 | MatchResults = match(Matcher, Context&: AST->getASTContext()); |
145 | const auto *DTST = |
146 | MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>(ID: "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 | |