1//===- unittest/Tooling/QualTypeNameTest.cpp ------------------------------===//
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 "clang/AST/QualTypeNames.h"
10#include "TestVisitor.h"
11using namespace clang;
12
13namespace {
14struct TypeNameVisitor : TestVisitor {
15 llvm::StringMap<std::string> ExpectedQualTypeNames;
16 bool WithGlobalNsPrefix = false;
17
18 // ValueDecls are the least-derived decl with both a qualtype and a name.
19 bool VisitValueDecl(ValueDecl *VD) override {
20 std::string ExpectedName =
21 ExpectedQualTypeNames.lookup(Key: VD->getNameAsString());
22 if (ExpectedName != "") {
23 PrintingPolicy Policy(Context->getPrintingPolicy());
24 Policy.SuppressScope = false;
25 Policy.AnonymousTagLocations = true;
26 Policy.PolishForDeclaration = true;
27 Policy.SuppressUnwrittenScope = true;
28 std::string ActualName = TypeName::getFullyQualifiedName(
29 QT: VD->getType(), Ctx: *Context, Policy, WithGlobalNsPrefix);
30 if (ExpectedName != ActualName) {
31 // A custom message makes it much easier to see what declaration
32 // failed compared to EXPECT_EQ.
33 ADD_FAILURE() << "Typename::getFullyQualifiedName failed for "
34 << VD->getQualifiedNameAsString() << std::endl
35 << " Actual: " << ActualName << std::endl
36 << " Expected: " << ExpectedName;
37 }
38 }
39 return true;
40 }
41};
42
43// named namespaces inside anonymous namespaces
44
45TEST(QualTypeNameTest, Simple) {
46 TypeNameVisitor Visitor;
47 // Simple case to test the test framework itself.
48 Visitor.ExpectedQualTypeNames["CheckInt"] = "int";
49
50 // Keeping the names of the variables whose types we check unique
51 // within the entire test--regardless of their own scope--makes it
52 // easier to diagnose test failures.
53
54 // Simple namespace qualifier
55 Visitor.ExpectedQualTypeNames["CheckA"] = "A::B::Class0";
56 // Lookup up the enclosing scopes, then down another one. (These
57 // appear as elaborated type in the AST. In that case--even if
58 // policy.SuppressScope = 0--qual_type.getAsString(policy) only
59 // gives the name as it appears in the source, not the full name.
60 Visitor.ExpectedQualTypeNames["CheckB"] = "A::B::C::Class1";
61 // Template parameter expansion.
62 Visitor.ExpectedQualTypeNames["CheckC"] =
63 "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>";
64 // Recursive template parameter expansion.
65 Visitor.ExpectedQualTypeNames["CheckD"] =
66 "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, "
67 "A::B::Template0<int, long>>";
68 // Variadic Template expansion.
69 Visitor.ExpectedQualTypeNames["CheckE"] =
70 "A::Variadic<int, A::B::Template0<int, char>, "
71 "A::B::Template1<int, long>, A::B::C::MyInt>";
72 // Using declarations should be fully expanded.
73 Visitor.ExpectedQualTypeNames["CheckF"] = "A::B::Class0";
74 // Elements found within "using namespace foo;" should be fully
75 // expanded.
76 Visitor.ExpectedQualTypeNames["CheckG"] = "A::B::C::MyInt";
77 // Type inside function
78 Visitor.ExpectedQualTypeNames["CheckH"] = "struct X";
79 // Anonymous Namespaces
80 Visitor.ExpectedQualTypeNames["CheckI"] = "aClass";
81 // Keyword inclusion with namespaces
82 Visitor.ExpectedQualTypeNames["CheckJ"] = "struct A::aStruct";
83 // Anonymous Namespaces nested in named namespaces and vice-versa.
84 Visitor.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
85 // Namespace alias
86 Visitor.ExpectedQualTypeNames["CheckL"] = "A::B::C::MyInt";
87 Visitor.ExpectedQualTypeNames["non_dependent_type_var"] =
88 "Foo<X>::non_dependent_type";
89 Visitor.ExpectedQualTypeNames["AnEnumVar"] = "EnumScopeClass::AnEnum";
90 Visitor.ExpectedQualTypeNames["AliasTypeVal"] = "A::B::C::InnerAlias<int>";
91 Visitor.ExpectedQualTypeNames["AliasInnerTypeVal"] =
92 "OuterTemplateClass<A::B::Class0>::Inner";
93 Visitor.ExpectedQualTypeNames["CheckM"] = "const A::B::Class0 *";
94 Visitor.ExpectedQualTypeNames["CheckN"] = "const X *";
95 Visitor.ExpectedQualTypeNames["ttp_using"] =
96 "OuterTemplateClass<A::B::Class0>";
97 Visitor.ExpectedQualTypeNames["alias_of_template"] = "ABTemplate0IntInt";
98 Visitor.runOver(
99 "int CheckInt;\n"
100 "template <typename T>\n"
101 "class OuterTemplateClass { public: struct Inner {}; };\n"
102 "namespace A {\n"
103 " namespace B {\n"
104 " class Class0 { };\n"
105 " namespace C {\n"
106 " typedef int MyInt;"
107 " template <typename T>\n"
108 " using InnerAlias = OuterTemplateClass<T>;\n"
109 " InnerAlias<int> AliasTypeVal;\n"
110 " InnerAlias<Class0>::Inner AliasInnerTypeVal;\n"
111 " }\n"
112 " template<class X, class Y> class Template0;"
113 " template<class X, class Y> class Template1;"
114 " typedef B::Class0 AnotherClass;\n"
115 " void Function1(Template0<C::MyInt,\n"
116 " AnotherClass> CheckC);\n"
117 " void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n"
118 " Template0<int, long> > CheckD);\n"
119 " void Function3(const B::Class0* CheckM);\n"
120 " }\n"
121 "template<typename... Values> class Variadic {};\n"
122 "Variadic<int, B::Template0<int, char>, "
123 " B::Template1<int, long>, "
124 " B::C::MyInt > CheckE;\n"
125 " namespace BC = B::C;\n"
126 " BC::MyInt CheckL;\n"
127 "}\n"
128 "using A::B::Class0;\n"
129 "void Function(Class0 CheckF);\n"
130 "OuterTemplateClass<Class0> ttp_using;\n"
131 "using ABTemplate0IntInt = A::B::Template0<int, int>;\n"
132 "void Function(ABTemplate0IntInt alias_of_template);\n"
133 "using namespace A::B::C;\n"
134 "void Function(MyInt CheckG);\n"
135 "void f() {\n"
136 " struct X {} CheckH;\n"
137 "}\n"
138 "struct X;\n"
139 "void f(const ::X* CheckN) {}\n"
140 "namespace {\n"
141 " class aClass {};\n"
142 " aClass CheckI;\n"
143 "}\n"
144 "namespace A {\n"
145 " struct aStruct {} CheckJ;\n"
146 "}\n"
147 "namespace {\n"
148 " namespace D {\n"
149 " namespace {\n"
150 " class aStruct {};\n"
151 " aStruct CheckK;\n"
152 " }\n"
153 " }\n"
154 "}\n"
155 "template<class T> struct Foo {\n"
156 " typedef typename T::A dependent_type;\n"
157 " typedef int non_dependent_type;\n"
158 " dependent_type dependent_type_var;\n"
159 " non_dependent_type non_dependent_type_var;\n"
160 "};\n"
161 "struct X { typedef int A; };"
162 "Foo<X> var;"
163 "void F() {\n"
164 " var.dependent_type_var = 0;\n"
165 "var.non_dependent_type_var = 0;\n"
166 "}\n"
167 "class EnumScopeClass {\n"
168 "public:\n"
169 " enum AnEnum { ZERO, ONE };\n"
170 "};\n"
171 "EnumScopeClass::AnEnum AnEnumVar;\n",
172 TypeNameVisitor::Lang_CXX11);
173}
174
175TEST(QualTypeNameTest, Complex) {
176 TypeNameVisitor Complex;
177 Complex.ExpectedQualTypeNames["CheckTX"] = "B::TX";
178 Complex.runOver(
179 "namespace A {"
180 " struct X {};"
181 "}"
182 "using A::X;"
183 "namespace fake_std {"
184 " template<class... Types > class tuple {};"
185 "}"
186 "namespace B {"
187 " using fake_std::tuple;"
188 " typedef tuple<X> TX;"
189 " TX CheckTX;"
190 " struct A { typedef int X; };"
191 "}");
192}
193
194TEST(QualTypeNameTest, DoubleUsing) {
195 TypeNameVisitor DoubleUsing;
196 DoubleUsing.ExpectedQualTypeNames["direct"] = "a::A<0>";
197 DoubleUsing.ExpectedQualTypeNames["indirect"] = "b::B";
198 DoubleUsing.ExpectedQualTypeNames["double_indirect"] = "b::B";
199 DoubleUsing.runOver(R"cpp(
200 namespace a {
201 template<int> class A {};
202 A<0> direct;
203 }
204 namespace b {
205 using B = ::a::A<0>;
206 B indirect;
207 }
208 namespace b {
209 using ::b::B;
210 B double_indirect;
211 }
212 )cpp");
213}
214
215TEST(QualTypeNameTest, GlobalNsPrefix) {
216 TypeNameVisitor GlobalNsPrefix;
217 GlobalNsPrefix.WithGlobalNsPrefix = true;
218 GlobalNsPrefix.ExpectedQualTypeNames["IntVal"] = "int";
219 GlobalNsPrefix.ExpectedQualTypeNames["BoolVal"] = "bool";
220 GlobalNsPrefix.ExpectedQualTypeNames["XVal"] = "::A::B::X";
221 GlobalNsPrefix.ExpectedQualTypeNames["IntAliasVal"] = "::A::B::Alias<int>";
222 GlobalNsPrefix.ExpectedQualTypeNames["ZVal"] = "::A::B::Y::Z";
223 GlobalNsPrefix.ExpectedQualTypeNames["GlobalZVal"] = "::Z";
224 GlobalNsPrefix.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
225 GlobalNsPrefix.ExpectedQualTypeNames["YZMPtr"] = "::A::B::X ::A::B::Y::Z::*";
226 GlobalNsPrefix.runOver(
227 "namespace A {\n"
228 " namespace B {\n"
229 " int IntVal;\n"
230 " bool BoolVal;\n"
231 " struct X {};\n"
232 " X XVal;\n"
233 " template <typename T> class CCC { };\n"
234 " template <typename T>\n"
235 " using Alias = CCC<T>;\n"
236 " Alias<int> IntAliasVal;\n"
237 " struct Y { struct Z { X YZIPtr; }; };\n"
238 " Y::Z ZVal;\n"
239 " X Y::Z::*YZMPtr;\n"
240 " }\n"
241 "}\n"
242 "struct Z {};\n"
243 "Z GlobalZVal;\n"
244 "namespace {\n"
245 " namespace D {\n"
246 " namespace {\n"
247 " class aStruct {};\n"
248 " aStruct CheckK;\n"
249 " }\n"
250 " }\n"
251 "}\n"
252 );
253}
254
255TEST(QualTypeNameTest, InlineNamespace) {
256 TypeNameVisitor InlineNamespace;
257 InlineNamespace.ExpectedQualTypeNames["c"] = "B::C";
258 InlineNamespace.runOver("inline namespace A {\n"
259 " namespace B {\n"
260 " class C {};\n"
261 " }\n"
262 "}\n"
263 "using namespace A::B;\n"
264 "C c;\n",
265 TypeNameVisitor::Lang_CXX11);
266}
267
268TEST(QualTypeNameTest, TemplatedClass) {
269 std::unique_ptr<ASTUnit> AST =
270 tooling::buildASTFromCode(Code: "template <unsigned U1> struct A {\n"
271 " template <unsigned U2> struct B {};\n"
272 "};\n"
273 "template struct A<1>;\n"
274 "template struct A<2u>;\n"
275 "template struct A<1>::B<3>;\n"
276 "template struct A<2u>::B<4u>;\n");
277
278 auto &Context = AST->getASTContext();
279 auto &Policy = Context.getPrintingPolicy();
280 auto getFullyQualifiedName = [&](QualType QT) {
281 return TypeName::getFullyQualifiedName(QT, Ctx: Context, Policy);
282 };
283
284 auto *A = Context.getTranslationUnitDecl()
285 ->lookup(&Context.Idents.get(Name: "A"))
286 .find_first<ClassTemplateDecl>();
287 ASSERT_NE(A, nullptr);
288
289 // A has two explicit instantiations: A<1> and A<2u>
290 auto ASpec = A->spec_begin();
291 ASSERT_NE(ASpec, A->spec_end());
292 auto *A1 = *ASpec;
293 ASpec++;
294 ASSERT_NE(ASpec, A->spec_end());
295 auto *A2 = *ASpec;
296
297 // Their type names follow the records.
298 QualType A1RecordTy = Context.getRecordType(Decl: A1);
299 EXPECT_EQ(getFullyQualifiedName(A1RecordTy), "A<1>");
300 QualType A2RecordTy = Context.getRecordType(Decl: A2);
301 EXPECT_EQ(getFullyQualifiedName(A2RecordTy), "A<2U>");
302
303 // getTemplateSpecializationType() gives types that print the integral
304 // argument directly.
305 TemplateArgument Args1[] = {
306 {Context, llvm::APSInt::getUnsigned(X: 1u), Context.UnsignedIntTy}};
307 QualType A1TemplateSpecTy = Context.getTemplateSpecializationType(
308 TemplateName(A), Args1, Args1, A1RecordTy);
309 EXPECT_EQ(A1TemplateSpecTy.getAsString(), "A<1>");
310
311 TemplateArgument Args2[] = {
312 {Context, llvm::APSInt::getUnsigned(X: 2u), Context.UnsignedIntTy}};
313 QualType A2TemplateSpecTy = Context.getTemplateSpecializationType(
314 TemplateName(A), Args2, Args2, A2RecordTy);
315 EXPECT_EQ(A2TemplateSpecTy.getAsString(), "A<2>");
316
317 // Find A<1>::B and its specialization B<3>.
318 auto *A1B =
319 A1->lookup(&Context.Idents.get(Name: "B")).find_first<ClassTemplateDecl>();
320 ASSERT_NE(A1B, nullptr);
321 auto A1BSpec = A1B->spec_begin();
322 ASSERT_NE(A1BSpec, A1B->spec_end());
323 auto *A1B3 = *A1BSpec;
324 QualType A1B3RecordTy = Context.getRecordType(Decl: A1B3);
325 EXPECT_EQ(getFullyQualifiedName(A1B3RecordTy), "A<1>::B<3>");
326
327 // Construct A<1>::B<3> and check name.
328 TemplateArgument Args3[] = {
329 {Context, llvm::APSInt::getUnsigned(X: 3u), Context.UnsignedIntTy}};
330 QualType A1B3TemplateSpecTy = Context.getTemplateSpecializationType(
331 TemplateName(A1B), Args3, Args3, A1B3RecordTy);
332 EXPECT_EQ(A1B3TemplateSpecTy.getAsString(), "B<3>");
333
334 NestedNameSpecifier *A1Nested = NestedNameSpecifier::Create(
335 Context, Prefix: nullptr, T: A1TemplateSpecTy.getTypePtr());
336 QualType A1B3ElaboratedTy = Context.getElaboratedType(
337 Keyword: ElaboratedTypeKeyword::None, NNS: A1Nested, NamedType: A1B3TemplateSpecTy);
338 EXPECT_EQ(A1B3ElaboratedTy.getAsString(), "A<1>::B<3>");
339
340 // Find A<2u>::B and its specialization B<4u>.
341 auto *A2B =
342 A2->lookup(&Context.Idents.get(Name: "B")).find_first<ClassTemplateDecl>();
343 ASSERT_NE(A2B, nullptr);
344 auto A2BSpec = A2B->spec_begin();
345 ASSERT_NE(A2BSpec, A2B->spec_end());
346 auto *A2B4 = *A2BSpec;
347 QualType A2B4RecordTy = Context.getRecordType(Decl: A2B4);
348 EXPECT_EQ(getFullyQualifiedName(A2B4RecordTy), "A<2U>::B<4U>");
349
350 // Construct A<2>::B<4> and check name.
351 TemplateArgument Args4[] = {
352 {Context, llvm::APSInt::getUnsigned(X: 4u), Context.UnsignedIntTy}};
353 QualType A2B4TemplateSpecTy = Context.getTemplateSpecializationType(
354 TemplateName(A2B), Args4, Args4, A2B4RecordTy);
355 EXPECT_EQ(A2B4TemplateSpecTy.getAsString(), "B<4>");
356
357 NestedNameSpecifier *A2Nested = NestedNameSpecifier::Create(
358 Context, Prefix: nullptr, T: A2TemplateSpecTy.getTypePtr());
359 QualType A2B4ElaboratedTy = Context.getElaboratedType(
360 Keyword: ElaboratedTypeKeyword::None, NNS: A2Nested, NamedType: A2B4TemplateSpecTy);
361 EXPECT_EQ(A2B4ElaboratedTy.getAsString(), "A<2>::B<4>");
362}
363
364TEST(QualTypeNameTest, AnonStrucs) {
365 TypeNameVisitor AnonStrucs;
366 AnonStrucs.ExpectedQualTypeNames["a"] = "short";
367 AnonStrucs.ExpectedQualTypeNames["un_in_st_1"] =
368 "union (unnamed struct at input.cc:1:1)::(unnamed union at "
369 "input.cc:2:27)";
370 AnonStrucs.ExpectedQualTypeNames["b"] = "short";
371 AnonStrucs.ExpectedQualTypeNames["un_in_st_2"] =
372 "union (unnamed struct at input.cc:1:1)::(unnamed union at "
373 "input.cc:5:27)";
374 AnonStrucs.ExpectedQualTypeNames["anon_st"] =
375 "struct (unnamed struct at input.cc:1:1)";
376 AnonStrucs.runOver(R"(struct {
377 union {
378 short a;
379 } un_in_st_1;
380 union {
381 short b;
382 } un_in_st_2;
383 } anon_st;)");
384}
385
386TEST(QualTypeNameTest, ConstUsing) {
387 TypeNameVisitor ConstUsing;
388 ConstUsing.ExpectedQualTypeNames["param1"] = "const A::S &";
389 ConstUsing.ExpectedQualTypeNames["param2"] = "const A::S";
390 ConstUsing.runOver(R"(namespace A {
391 class S {};
392 }
393 using ::A::S;
394 void foo(const S& param1, const S param2);)");
395}
396
397TEST(QualTypeNameTest, NullableAttributesWithGlobalNs) {
398 TypeNameVisitor Visitor;
399 Visitor.WithGlobalNsPrefix = true;
400 Visitor.ExpectedQualTypeNames["param1"] = "::std::unique_ptr<int> _Nullable";
401 Visitor.ExpectedQualTypeNames["param2"] = "::std::unique_ptr<int> _Nonnull";
402 Visitor.ExpectedQualTypeNames["param3"] =
403 "::std::unique_ptr< ::std::unique_ptr<int> _Nullable> _Nonnull";
404 Visitor.ExpectedQualTypeNames["param4"] =
405 "::std::unique_ptr<int> _Nullable const *";
406 Visitor.ExpectedQualTypeNames["param5"] =
407 "::std::unique_ptr<int> _Nullable const *";
408 Visitor.ExpectedQualTypeNames["param6"] =
409 "::std::unique_ptr<int> _Nullable const *";
410 Visitor.runOver(R"(namespace std {
411 template<class T> class unique_ptr {};
412 }
413 void foo(
414 std::unique_ptr<int> _Nullable param1,
415 _Nonnull std::unique_ptr<int> param2,
416 std::unique_ptr<std::unique_ptr<int> _Nullable> _Nonnull param3,
417 const std::unique_ptr<int> _Nullable *param4,
418 _Nullable std::unique_ptr<int> const *param5,
419 std::unique_ptr<int> _Nullable const *param6
420 );
421 )");
422}
423} // end anonymous namespace
424

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/unittests/Tooling/QualTypeNamesTest.cpp