108b28986SNathan Ridge //===- unittests/AST/TypePrinterTest.cpp --- Type printer tests -----------===//
208b28986SNathan Ridge //
308b28986SNathan Ridge // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
408b28986SNathan Ridge // See https://llvm.org/LICENSE.txt for license information.
508b28986SNathan Ridge // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
608b28986SNathan Ridge //
708b28986SNathan Ridge //===----------------------------------------------------------------------===//
808b28986SNathan Ridge //
908b28986SNathan Ridge // This file contains tests for QualType::print() and related methods.
1008b28986SNathan Ridge //
1108b28986SNathan Ridge //===----------------------------------------------------------------------===//
1208b28986SNathan Ridge
1308b28986SNathan Ridge #include "ASTPrint.h"
1408b28986SNathan Ridge #include "clang/AST/ASTContext.h"
1508b28986SNathan Ridge #include "clang/ASTMatchers/ASTMatchFinder.h"
1608b28986SNathan Ridge #include "clang/Tooling/Tooling.h"
1708b28986SNathan Ridge #include "llvm/ADT/SmallString.h"
1808b28986SNathan Ridge #include "gtest/gtest.h"
1908b28986SNathan Ridge
2008b28986SNathan Ridge using namespace clang;
2108b28986SNathan Ridge using namespace ast_matchers;
2208b28986SNathan Ridge using namespace tooling;
2308b28986SNathan Ridge
2408b28986SNathan Ridge namespace {
2508b28986SNathan Ridge
PrintType(raw_ostream & Out,const ASTContext * Context,const QualType * T,PrintingPolicyAdjuster PolicyAdjuster)2608b28986SNathan Ridge static void PrintType(raw_ostream &Out, const ASTContext *Context,
2708b28986SNathan Ridge const QualType *T,
2808b28986SNathan Ridge PrintingPolicyAdjuster PolicyAdjuster) {
2908b28986SNathan Ridge assert(T && !T->isNull() && "Expected non-null Type");
3008b28986SNathan Ridge PrintingPolicy Policy = Context->getPrintingPolicy();
3108b28986SNathan Ridge if (PolicyAdjuster)
3208b28986SNathan Ridge PolicyAdjuster(Policy);
3308b28986SNathan Ridge T->print(Out, Policy);
3408b28986SNathan Ridge }
3508b28986SNathan Ridge
3608b28986SNathan Ridge ::testing::AssertionResult
PrintedTypeMatches(StringRef Code,const std::vector<std::string> & Args,const DeclarationMatcher & NodeMatch,StringRef ExpectedPrinted,PrintingPolicyAdjuster PolicyAdjuster)3708b28986SNathan Ridge PrintedTypeMatches(StringRef Code, const std::vector<std::string> &Args,
3808b28986SNathan Ridge const DeclarationMatcher &NodeMatch,
3908b28986SNathan Ridge StringRef ExpectedPrinted,
4008b28986SNathan Ridge PrintingPolicyAdjuster PolicyAdjuster) {
4108b28986SNathan Ridge return PrintedNodeMatches<QualType>(Code, Args, NodeMatch, ExpectedPrinted,
4208b28986SNathan Ridge "", PrintType, PolicyAdjuster);
4308b28986SNathan Ridge }
4408b28986SNathan Ridge
4508b28986SNathan Ridge } // unnamed namespace
4608b28986SNathan Ridge
TEST(TypePrinter,TemplateId)4708b28986SNathan Ridge TEST(TypePrinter, TemplateId) {
4808b28986SNathan Ridge std::string Code = R"cpp(
4908b28986SNathan Ridge namespace N {
5008b28986SNathan Ridge template <typename> struct Type {};
5108b28986SNathan Ridge
5208b28986SNathan Ridge template <typename T>
5308b28986SNathan Ridge void Foo(const Type<T> &Param);
5408b28986SNathan Ridge }
5508b28986SNathan Ridge )cpp";
5608b28986SNathan Ridge auto Matcher = parmVarDecl(hasType(qualType().bind("id")));
5708b28986SNathan Ridge
5808b28986SNathan Ridge ASSERT_TRUE(PrintedTypeMatches(
5908b28986SNathan Ridge Code, {}, Matcher, "const Type<T> &",
6008b28986SNathan Ridge [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; }));
6108b28986SNathan Ridge
6208b28986SNathan Ridge ASSERT_TRUE(PrintedTypeMatches(
6315f3cd6bSMatheus Izvekov Code, {}, Matcher, "const Type<T> &",
6408b28986SNathan Ridge [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));
6508b28986SNathan Ridge }
6633c3ef2fSSam McCall
TEST(TypePrinter,TemplateId2)67225b91e6STom Eccles TEST(TypePrinter, TemplateId2) {
68225b91e6STom Eccles std::string Code = R"cpp(
69225b91e6STom Eccles template <template <typename ...> class TemplatedType>
70225b91e6STom Eccles void func(TemplatedType<int> Param);
71225b91e6STom Eccles )cpp";
72225b91e6STom Eccles auto Matcher = parmVarDecl(hasType(qualType().bind("id")));
73225b91e6STom Eccles
74225b91e6STom Eccles // Regression test ensuring we do not segfault getting the QualType as a
75225b91e6STom Eccles // string.
76225b91e6STom Eccles ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "<int>",
77225b91e6STom Eccles [](PrintingPolicy &Policy) {
78225b91e6STom Eccles Policy.FullyQualifiedName = true;
79225b91e6STom Eccles Policy.PrintCanonicalTypes = true;
80225b91e6STom Eccles }));
81225b91e6STom Eccles }
82225b91e6STom Eccles
TEST(TypePrinter,ParamsUglified)8333c3ef2fSSam McCall TEST(TypePrinter, ParamsUglified) {
8433c3ef2fSSam McCall llvm::StringLiteral Code = R"cpp(
8533c3ef2fSSam McCall template <typename _Tp, template <typename> class __f>
8633c3ef2fSSam McCall const __f<_Tp&> *A = nullptr;
8733c3ef2fSSam McCall )cpp";
8833c3ef2fSSam McCall auto Clean = [](PrintingPolicy &Policy) {
8933c3ef2fSSam McCall Policy.CleanUglifiedParameters = true;
9033c3ef2fSSam McCall };
9133c3ef2fSSam McCall
9233c3ef2fSSam McCall ASSERT_TRUE(PrintedTypeMatches(Code, {},
9333c3ef2fSSam McCall varDecl(hasType(qualType().bind("id"))),
9433c3ef2fSSam McCall "const __f<_Tp &> *", nullptr));
9533c3ef2fSSam McCall ASSERT_TRUE(PrintedTypeMatches(Code, {},
9633c3ef2fSSam McCall varDecl(hasType(qualType().bind("id"))),
9733c3ef2fSSam McCall "const f<Tp &> *", Clean));
9833c3ef2fSSam McCall }
9944eee659SZhihao Yuan
TEST(TypePrinter,SuppressElaboration)1003cb6ead7SEric Li TEST(TypePrinter, SuppressElaboration) {
1013cb6ead7SEric Li llvm::StringLiteral Code = R"cpp(
1023cb6ead7SEric Li namespace shared {
1033cb6ead7SEric Li namespace a {
1043cb6ead7SEric Li template <typename T>
1053cb6ead7SEric Li struct S {};
1063cb6ead7SEric Li } // namespace a
1073cb6ead7SEric Li namespace b {
1083cb6ead7SEric Li struct Foo {};
1093cb6ead7SEric Li } // namespace b
1103cb6ead7SEric Li using Alias = a::S<b::Foo>;
1113cb6ead7SEric Li } // namespace shared
1123cb6ead7SEric Li )cpp";
1133cb6ead7SEric Li
1143cb6ead7SEric Li auto Matcher = typedefNameDecl(hasName("::shared::Alias"),
1153cb6ead7SEric Li hasType(qualType().bind("id")));
1163cb6ead7SEric Li ASSERT_TRUE(PrintedTypeMatches(
1173cb6ead7SEric Li Code, {}, Matcher, "a::S<b::Foo>",
1183cb6ead7SEric Li [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));
1193cb6ead7SEric Li ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher,
1203cb6ead7SEric Li "shared::a::S<shared::b::Foo>",
1213cb6ead7SEric Li [](PrintingPolicy &Policy) {
1223cb6ead7SEric Li Policy.SuppressElaboration = true;
1233cb6ead7SEric Li Policy.FullyQualifiedName = true;
1243cb6ead7SEric Li }));
1253cb6ead7SEric Li }
1263cb6ead7SEric Li
TEST(TypePrinter,TemplateIdWithNTTP)12744eee659SZhihao Yuan TEST(TypePrinter, TemplateIdWithNTTP) {
12844eee659SZhihao Yuan constexpr char Code[] = R"cpp(
12944eee659SZhihao Yuan template <int N>
13044eee659SZhihao Yuan struct Str {
13144eee659SZhihao Yuan constexpr Str(char const (&s)[N]) { __builtin_memcpy(value, s, N); }
13244eee659SZhihao Yuan char value[N];
13344eee659SZhihao Yuan };
13444eee659SZhihao Yuan template <Str> class ASCII {};
13544eee659SZhihao Yuan
13644eee659SZhihao Yuan ASCII<"this nontype template argument is too long to print"> x;
13744eee659SZhihao Yuan )cpp";
13844eee659SZhihao Yuan auto Matcher = classTemplateSpecializationDecl(
13944eee659SZhihao Yuan hasName("ASCII"), has(cxxConstructorDecl(
14044eee659SZhihao Yuan isMoveConstructor(),
14144eee659SZhihao Yuan has(parmVarDecl(hasType(qualType().bind("id")))))));
14244eee659SZhihao Yuan
14344eee659SZhihao Yuan ASSERT_TRUE(PrintedTypeMatches(
14444eee659SZhihao Yuan Code, {"-std=c++20"}, Matcher,
145835b99e4SNenad Mikša R"(ASCII<Str<52>{"this nontype template argument is [...]"}> &&)",
14644eee659SZhihao Yuan [](PrintingPolicy &Policy) {
14744eee659SZhihao Yuan Policy.EntireContentsOfLargeArray = false;
14844eee659SZhihao Yuan }));
14944eee659SZhihao Yuan
15044eee659SZhihao Yuan ASSERT_TRUE(PrintedTypeMatches(
15144eee659SZhihao Yuan Code, {"-std=c++20"}, Matcher,
152835b99e4SNenad Mikša R"(ASCII<Str<52>{"this nontype template argument is too long to print"}> &&)",
15344eee659SZhihao Yuan [](PrintingPolicy &Policy) {
15444eee659SZhihao Yuan Policy.EntireContentsOfLargeArray = true;
15544eee659SZhihao Yuan }));
15644eee659SZhihao Yuan }
157798494edSMichael Buch
TEST(TypePrinter,TemplateArgumentsSubstitution)158*6503b015SZahira Ammarguellat TEST(TypePrinter, TemplateArgumentsSubstitution) {
159*6503b015SZahira Ammarguellat constexpr char Code[] = R"cpp(
160*6503b015SZahira Ammarguellat template <typename Y> class X {};
161*6503b015SZahira Ammarguellat typedef X<int> A;
162*6503b015SZahira Ammarguellat int foo() {
163*6503b015SZahira Ammarguellat return sizeof(A);
164*6503b015SZahira Ammarguellat }
165*6503b015SZahira Ammarguellat )cpp";
166*6503b015SZahira Ammarguellat auto Matcher = typedefNameDecl(hasName("A"), hasType(qualType().bind("id")));
167*6503b015SZahira Ammarguellat ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "X<int>",
168*6503b015SZahira Ammarguellat [](PrintingPolicy &Policy) {
169*6503b015SZahira Ammarguellat Policy.SuppressTagKeyword = false;
170*6503b015SZahira Ammarguellat Policy.SuppressScope = true;
171*6503b015SZahira Ammarguellat }));
172*6503b015SZahira Ammarguellat }
173*6503b015SZahira Ammarguellat
TEST(TypePrinter,TemplateArgumentsSubstitution_Expressions)174798494edSMichael Buch TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
175798494edSMichael Buch /// Tests clang::isSubstitutedDefaultArgument on TemplateArguments
176798494edSMichael Buch /// that are of kind TemplateArgument::Expression
177798494edSMichael Buch constexpr char Code[] = R"cpp(
178798494edSMichael Buch constexpr bool func() { return true; }
179798494edSMichael Buch
180798494edSMichael Buch template <typename T1 = int,
181798494edSMichael Buch int T2 = 42,
182798494edSMichael Buch T1 T3 = 43,
183798494edSMichael Buch int T4 = sizeof(T1),
184798494edSMichael Buch bool T5 = func()
185798494edSMichael Buch >
186798494edSMichael Buch struct Foo {
187798494edSMichael Buch };
188798494edSMichael Buch
189798494edSMichael Buch Foo<int, 40 + 2> X;
190798494edSMichael Buch )cpp";
191798494edSMichael Buch
192798494edSMichael Buch auto AST = tooling::buildASTFromCodeWithArgs(Code, /*Args=*/{"-std=c++20"});
193798494edSMichael Buch ASTContext &Ctx = AST->getASTContext();
194798494edSMichael Buch
195798494edSMichael Buch auto const *CTD = selectFirst<ClassTemplateDecl>(
196798494edSMichael Buch "id", match(classTemplateDecl(hasName("Foo")).bind("id"), Ctx));
197798494edSMichael Buch ASSERT_NE(CTD, nullptr);
198798494edSMichael Buch auto const *CTSD = *CTD->specializations().begin();
199798494edSMichael Buch ASSERT_NE(CTSD, nullptr);
200798494edSMichael Buch auto const *Params = CTD->getTemplateParameters();
201798494edSMichael Buch ASSERT_NE(Params, nullptr);
202798494edSMichael Buch auto const &ArgList = CTSD->getTemplateArgs();
203798494edSMichael Buch
204798494edSMichael Buch auto createBinOpExpr = [&](uint32_t LHS, uint32_t RHS,
205798494edSMichael Buch uint32_t Result) -> ConstantExpr * {
206798494edSMichael Buch const int numBits = 32;
207798494edSMichael Buch clang::APValue ResultVal{llvm::APSInt(llvm::APInt(numBits, Result))};
208798494edSMichael Buch auto *LHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, LHS),
209798494edSMichael Buch Ctx.UnsignedIntTy, {});
210798494edSMichael Buch auto *RHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, RHS),
211798494edSMichael Buch Ctx.UnsignedIntTy, {});
212798494edSMichael Buch auto *BinOp = BinaryOperator::Create(
213798494edSMichael Buch Ctx, LHSInt, RHSInt, BinaryOperatorKind::BO_Add, Ctx.UnsignedIntTy,
214798494edSMichael Buch ExprValueKind::VK_PRValue, ExprObjectKind::OK_Ordinary, {}, {});
215798494edSMichael Buch return ConstantExpr::Create(Ctx, dyn_cast<Expr>(BinOp), ResultVal);
216798494edSMichael Buch };
217798494edSMichael Buch
218798494edSMichael Buch {
219798494edSMichael Buch // Arg is an integral '42'
220798494edSMichael Buch auto const &Arg = ArgList.get(1);
221798494edSMichael Buch ASSERT_EQ(Arg.getKind(), TemplateArgument::Integral);
222798494edSMichael Buch
223798494edSMichael Buch // Param has default expr which evaluates to '42'
224798494edSMichael Buch auto const *Param = Params->getParam(1);
225798494edSMichael Buch
226798494edSMichael Buch EXPECT_TRUE(clang::isSubstitutedDefaultArgument(
227798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
228798494edSMichael Buch }
229798494edSMichael Buch
230798494edSMichael Buch {
231798494edSMichael Buch // Arg is an integral '41'
232798494edSMichael Buch llvm::APInt Int(32, 41);
233798494edSMichael Buch TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);
234798494edSMichael Buch
235798494edSMichael Buch // Param has default expr which evaluates to '42'
236798494edSMichael Buch auto const *Param = Params->getParam(1);
237798494edSMichael Buch
238798494edSMichael Buch EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
239798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
240798494edSMichael Buch }
241798494edSMichael Buch
242798494edSMichael Buch {
243798494edSMichael Buch // Arg is an integral '4'
244798494edSMichael Buch llvm::APInt Int(32, 4);
245798494edSMichael Buch TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);
246798494edSMichael Buch
247798494edSMichael Buch // Param has is value-dependent expression (i.e., sizeof(T))
248798494edSMichael Buch auto const *Param = Params->getParam(3);
249798494edSMichael Buch
250798494edSMichael Buch EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
251798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
252798494edSMichael Buch }
253798494edSMichael Buch
254798494edSMichael Buch {
255798494edSMichael Buch const int LHS = 40;
256798494edSMichael Buch const int RHS = 2;
257798494edSMichael Buch const int Result = 42;
258798494edSMichael Buch auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
259798494edSMichael Buch // Arg is instantiated with '40 + 2'
260798494edSMichael Buch TemplateArgument Arg(ConstExpr);
261798494edSMichael Buch
262798494edSMichael Buch // Param has default expr of '42'
263798494edSMichael Buch auto const *Param = Params->getParam(1);
264798494edSMichael Buch
265798494edSMichael Buch EXPECT_TRUE(clang::isSubstitutedDefaultArgument(
266798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
267798494edSMichael Buch }
268798494edSMichael Buch
269798494edSMichael Buch {
270798494edSMichael Buch const int LHS = 40;
271798494edSMichael Buch const int RHS = 1;
272798494edSMichael Buch const int Result = 41;
273798494edSMichael Buch auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
274798494edSMichael Buch
275798494edSMichael Buch // Arg is instantiated with '40 + 1'
276798494edSMichael Buch TemplateArgument Arg(ConstExpr);
277798494edSMichael Buch
278798494edSMichael Buch // Param has default expr of '42'
279798494edSMichael Buch auto const *Param = Params->getParam(1);
280798494edSMichael Buch
281798494edSMichael Buch EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
282798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
283798494edSMichael Buch }
284798494edSMichael Buch
285798494edSMichael Buch {
286798494edSMichael Buch const int LHS = 4;
287798494edSMichael Buch const int RHS = 0;
288798494edSMichael Buch const int Result = 4;
289798494edSMichael Buch auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
290798494edSMichael Buch
291798494edSMichael Buch // Arg is instantiated with '4 + 0'
292798494edSMichael Buch TemplateArgument Arg(ConstExpr);
293798494edSMichael Buch
294798494edSMichael Buch // Param has is value-dependent expression (i.e., sizeof(T))
295798494edSMichael Buch auto const *Param = Params->getParam(3);
296798494edSMichael Buch
297798494edSMichael Buch EXPECT_FALSE(clang::isSubstitutedDefaultArgument(
298798494edSMichael Buch Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
299798494edSMichael Buch }
300798494edSMichael Buch }
301