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 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(Matcher: templateArgumentLoc().bind(ID: "id" ), Context&: Ctx); |
43 | const auto *Template = selectFirst<TemplateArgumentLoc>(BoundTo: "id" , Results: 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: "id" ); |
75 | auto MatchResults = match(Matcher, Context&: AST->getASTContext()); |
76 | const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>(ID: "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 | EXPECT_EQ(TN.getAsUsingShadowDecl(), USD); |
86 | } |
87 | |
88 | TEST(TemplateName, UsingTemplate) { |
89 | auto AST = tooling::buildASTFromCode(Code: R"cpp( |
90 | namespace std { |
91 | template <typename T> struct vector { vector(T); }; |
92 | } |
93 | namespace absl { using std::vector; } |
94 | // The "absl::vector<int>" is an elaborated TemplateSpecializationType with |
95 | // an inner Using TemplateName (not a Qualified TemplateName, the qualifiers |
96 | // are rather part of the ElaboratedType)! |
97 | absl::vector<int> v(123); |
98 | )cpp" ); |
99 | auto Matcher = elaboratedTypeLoc( |
100 | hasNamedTypeLoc(InnerMatcher: loc(InnerMatcher: templateSpecializationType().bind(ID: "id" )))); |
101 | auto MatchResults = match(Matcher, Context&: AST->getASTContext()); |
102 | const auto *TST = |
103 | MatchResults.front().getNodeAs<TemplateSpecializationType>(ID: "id" ); |
104 | ASSERT_TRUE(TST); |
105 | EXPECT_EQ(TST->getTemplateName().getKind(), TemplateName::UsingTemplate); |
106 | |
107 | AST = tooling::buildASTFromCodeWithArgs(Code: R"cpp( |
108 | namespace std { |
109 | template <typename T> struct vector { vector(T); }; |
110 | } |
111 | namespace absl { using std::vector; } |
112 | // Similiar to the TemplateSpecializationType, absl::vector is an elaborated |
113 | // DeducedTemplateSpecializationType with an inner Using TemplateName! |
114 | absl::vector DTST(123); |
115 | )cpp" , |
116 | Args: {"-std=c++17" }); |
117 | Matcher = elaboratedTypeLoc( |
118 | hasNamedTypeLoc(InnerMatcher: loc(InnerMatcher: deducedTemplateSpecializationType().bind(ID: "id" )))); |
119 | MatchResults = match(Matcher, Context&: AST->getASTContext()); |
120 | const auto *DTST = |
121 | MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>(ID: "id" ); |
122 | ASSERT_TRUE(DTST); |
123 | EXPECT_EQ(DTST->getTemplateName().getKind(), TemplateName::UsingTemplate); |
124 | } |
125 | |
126 | } // namespace |
127 | } // namespace clang |
128 | |