Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / AST / TypePrinterTest.cpp
blobf0a6eb7e9fd8c90073500150b7234475ea5fb02f
1 //===- unittests/AST/TypePrinterTest.cpp --- Type printer tests -----------===//
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 // This file contains tests for QualType::print() and related methods.
11 //===----------------------------------------------------------------------===//
13 #include "ASTPrint.h"
14 #include "clang/AST/ASTContext.h"
15 #include "clang/ASTMatchers/ASTMatchFinder.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "gtest/gtest.h"
20 using namespace clang;
21 using namespace ast_matchers;
22 using namespace tooling;
24 namespace {
26 static void PrintType(raw_ostream &Out, const ASTContext *Context,
27 const QualType *T,
28 PrintingPolicyAdjuster PolicyAdjuster) {
29 assert(T && !T->isNull() && "Expected non-null Type");
30 PrintingPolicy Policy = Context->getPrintingPolicy();
31 if (PolicyAdjuster)
32 PolicyAdjuster(Policy);
33 T->print(Out, Policy);
36 ::testing::AssertionResult
37 PrintedTypeMatches(StringRef Code, const std::vector<std::string> &Args,
38 const DeclarationMatcher &NodeMatch,
39 StringRef ExpectedPrinted,
40 PrintingPolicyAdjuster PolicyAdjuster) {
41 return PrintedNodeMatches<QualType>(Code, Args, NodeMatch, ExpectedPrinted,
42 "", PrintType, PolicyAdjuster);
45 } // unnamed namespace
47 TEST(TypePrinter, TemplateId) {
48 std::string Code = R"cpp(
49 namespace N {
50 template <typename> struct Type {};
52 template <typename T>
53 void Foo(const Type<T> &Param);
55 )cpp";
56 auto Matcher = parmVarDecl(hasType(qualType().bind("id")));
58 ASSERT_TRUE(PrintedTypeMatches(
59 Code, {}, Matcher, "const Type<T> &",
60 [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; }));
62 ASSERT_TRUE(PrintedTypeMatches(
63 Code, {}, Matcher, "const Type<T> &",
64 [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));
67 TEST(TypePrinter, TemplateId2) {
68 std::string Code = R"cpp(
69 template <template <typename ...> class TemplatedType>
70 void func(TemplatedType<int> Param);
71 )cpp";
72 auto Matcher = parmVarDecl(hasType(qualType().bind("id")));
74 // Regression test ensuring we do not segfault getting the QualType as a
75 // string.
76 ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "<int>",
77 [](PrintingPolicy &Policy) {
78 Policy.FullyQualifiedName = true;
79 Policy.PrintCanonicalTypes = true;
80 }));
83 TEST(TypePrinter, ParamsUglified) {
84 llvm::StringLiteral Code = R"cpp(
85 template <typename _Tp, template <typename> class __f>
86 const __f<_Tp&> *A = nullptr;
87 )cpp";
88 auto Clean = [](PrintingPolicy &Policy) {
89 Policy.CleanUglifiedParameters = true;
92 ASSERT_TRUE(PrintedTypeMatches(Code, {},
93 varDecl(hasType(qualType().bind("id"))),
94 "const __f<_Tp &> *", nullptr));
95 ASSERT_TRUE(PrintedTypeMatches(Code, {},
96 varDecl(hasType(qualType().bind("id"))),
97 "const f<Tp &> *", Clean));
100 TEST(TypePrinter, SuppressElaboration) {
101 llvm::StringLiteral Code = R"cpp(
102 namespace shared {
103 namespace a {
104 template <typename T>
105 struct S {};
106 } // namespace a
107 namespace b {
108 struct Foo {};
109 } // namespace b
110 using Alias = a::S<b::Foo>;
111 } // namespace shared
112 )cpp";
114 auto Matcher = typedefNameDecl(hasName("::shared::Alias"),
115 hasType(qualType().bind("id")));
116 ASSERT_TRUE(PrintedTypeMatches(
117 Code, {}, Matcher, "a::S<b::Foo>",
118 [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));
119 ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher,
120 "shared::a::S<shared::b::Foo>",
121 [](PrintingPolicy &Policy) {
122 Policy.SuppressElaboration = true;
123 Policy.FullyQualifiedName = true;
124 }));
127 TEST(TypePrinter, TemplateIdWithNTTP) {
128 constexpr char Code[] = R"cpp(
129 template <int N>
130 struct Str {
131 constexpr Str(char const (&s)[N]) { __builtin_memcpy(value, s, N); }
132 char value[N];
134 template <Str> class ASCII {};
136 ASCII<"this nontype template argument is too long to print"> x;
137 )cpp";
138 auto Matcher = classTemplateSpecializationDecl(
139 hasName("ASCII"), has(cxxConstructorDecl(
140 isMoveConstructor(),
141 has(parmVarDecl(hasType(qualType().bind("id")))))));
143 ASSERT_TRUE(PrintedTypeMatches(
144 Code, {"-std=c++20"}, Matcher,
145 R"(ASCII<Str<52>{"this nontype template argument is [...]"}> &&)",
146 [](PrintingPolicy &Policy) {
147 Policy.EntireContentsOfLargeArray = false;
148 }));
150 ASSERT_TRUE(PrintedTypeMatches(
151 Code, {"-std=c++20"}, Matcher,
152 R"(ASCII<Str<52>{"this nontype template argument is too long to print"}> &&)",
153 [](PrintingPolicy &Policy) {
154 Policy.EntireContentsOfLargeArray = true;
155 }));
158 TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
159 /// Tests clang::isSubstitutedDefaultArgument on TemplateArguments
160 /// that are of kind TemplateArgument::Expression
161 constexpr char Code[] = R"cpp(
162 constexpr bool func() { return true; }
164 template <typename T1 = int,
165 int T2 = 42,
166 T1 T3 = 43,
167 int T4 = sizeof(T1),
168 bool T5 = func()
170 struct Foo {
173 Foo<int, 40 + 2> X;
174 )cpp";
176 auto AST = tooling::buildASTFromCodeWithArgs(Code, /*Args=*/{"-std=c++20"});
177 ASTContext &Ctx = AST->getASTContext();
179 auto const *CTD = selectFirst<ClassTemplateDecl>(
180 "id", match(classTemplateDecl(hasName("Foo")).bind("id"), Ctx));
181 ASSERT_NE(CTD, nullptr);
182 auto const *CTSD = *CTD->specializations().begin();
183 ASSERT_NE(CTSD, nullptr);
184 auto const *Params = CTD->getTemplateParameters();
185 ASSERT_NE(Params, nullptr);
186 auto const &ArgList = CTSD->getTemplateArgs();
188 auto createBinOpExpr = [&](uint32_t LHS, uint32_t RHS,
189 uint32_t Result) -> ConstantExpr * {
190 const int numBits = 32;
191 clang::APValue ResultVal{llvm::APSInt(llvm::APInt(numBits, Result))};
192 auto *LHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, LHS),
193 Ctx.UnsignedIntTy, {});
194 auto *RHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, RHS),
195 Ctx.UnsignedIntTy, {});
196 auto *BinOp = BinaryOperator::Create(
197 Ctx, LHSInt, RHSInt, BinaryOperatorKind::BO_Add, Ctx.UnsignedIntTy,
198 ExprValueKind::VK_PRValue, ExprObjectKind::OK_Ordinary, {}, {});
199 return ConstantExpr::Create(Ctx, dyn_cast<Expr>(BinOp), ResultVal);
203 // Arg is an integral '42'
204 auto const &Arg = ArgList.get(1);
205 ASSERT_EQ(Arg.getKind(), TemplateArgument::Integral);
207 // Param has default expr which evaluates to '42'
208 auto const *Param = Params->getParam(1);
210 EXPECT_TRUE(clang::isSubstitutedDefaultArgument(
211 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
215 // Arg is an integral '41'
216 llvm::APInt Int(32, 41);
217 TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);
219 // Param has default expr which evaluates to '42'
220 auto const *Param = Params->getParam(1);
222 EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
223 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
227 // Arg is an integral '4'
228 llvm::APInt Int(32, 4);
229 TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);
231 // Param has is value-dependent expression (i.e., sizeof(T))
232 auto const *Param = Params->getParam(3);
234 EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
235 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
239 const int LHS = 40;
240 const int RHS = 2;
241 const int Result = 42;
242 auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
243 // Arg is instantiated with '40 + 2'
244 TemplateArgument Arg(ConstExpr);
246 // Param has default expr of '42'
247 auto const *Param = Params->getParam(1);
249 EXPECT_TRUE(clang::isSubstitutedDefaultArgument(
250 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
254 const int LHS = 40;
255 const int RHS = 1;
256 const int Result = 41;
257 auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
259 // Arg is instantiated with '40 + 1'
260 TemplateArgument Arg(ConstExpr);
262 // Param has default expr of '42'
263 auto const *Param = Params->getParam(1);
265 EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
266 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
270 const int LHS = 4;
271 const int RHS = 0;
272 const int Result = 4;
273 auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
275 // Arg is instantiated with '4 + 0'
276 TemplateArgument Arg(ConstExpr);
278 // Param has is value-dependent expression (i.e., sizeof(T))
279 auto const *Param = Params->getParam(3);
281 EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
282 Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));