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.
10 //
11 //===----------------------------------------------------------------------===//
12
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"
19
20 using namespace clang;
21 using namespace ast_matchers;
22 using namespace tooling;
23
24 namespace {
25
PrintType(raw_ostream & Out,const ASTContext * Context,const QualType * T,PrintingPolicyAdjuster PolicyAdjuster)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);
34 }
35
36 ::testing::AssertionResult
PrintedTypeMatches(StringRef Code,const std::vector<std::string> & Args,const DeclarationMatcher & NodeMatch,StringRef ExpectedPrinted,PrintingPolicyAdjuster PolicyAdjuster)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);
43 }
44
45 } // unnamed namespace
46
TEST(TypePrinter,TemplateId)47 TEST(TypePrinter, TemplateId) {
48 std::string Code = R"cpp(
49 namespace N {
50 template <typename> struct Type {};
51
52 template <typename T>
53 void Foo(const Type<T> &Param);
54 }
55 )cpp";
56 auto Matcher = parmVarDecl(hasType(qualType().bind("id")));
57
58 ASSERT_TRUE(PrintedTypeMatches(
59 Code, {}, Matcher, "const Type<T> &",
60 [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; }));
61
62 ASSERT_TRUE(PrintedTypeMatches(
63 Code, {}, Matcher, "const N::Type<T> &",
64 [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));
65 }
66
TEST(TypePrinter,TemplateId2)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")));
73
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 }));
81 }
82
TEST(TypePrinter,ParamsUglified)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;
90 };
91
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));
98 }
99
TEST(TypePrinter,TemplateIdWithNTTP)100 TEST(TypePrinter, TemplateIdWithNTTP) {
101 constexpr char Code[] = R"cpp(
102 template <int N>
103 struct Str {
104 constexpr Str(char const (&s)[N]) { __builtin_memcpy(value, s, N); }
105 char value[N];
106 };
107 template <Str> class ASCII {};
108
109 ASCII<"this nontype template argument is too long to print"> x;
110 )cpp";
111 auto Matcher = classTemplateSpecializationDecl(
112 hasName("ASCII"), has(cxxConstructorDecl(
113 isMoveConstructor(),
114 has(parmVarDecl(hasType(qualType().bind("id")))))));
115
116 ASSERT_TRUE(PrintedTypeMatches(
117 Code, {"-std=c++20"}, Matcher,
118 R"(ASCII<{"this nontype template argument is [...]"}> &&)",
119 [](PrintingPolicy &Policy) {
120 Policy.EntireContentsOfLargeArray = false;
121 }));
122
123 ASSERT_TRUE(PrintedTypeMatches(
124 Code, {"-std=c++20"}, Matcher,
125 R"(ASCII<{"this nontype template argument is too long to print"}> &&)",
126 [](PrintingPolicy &Policy) {
127 Policy.EntireContentsOfLargeArray = true;
128 }));
129 }
130