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" |
11 | using namespace clang; |
12 | |
13 | namespace { |
14 | struct TypeNameVisitor : TestVisitor<TypeNameVisitor> { |
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(const ValueDecl *VD) { |
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 | |
45 | TEST(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 | Code: "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 | L: TypeNameVisitor::Lang_CXX11); |
173 | } |
174 | |
175 | TEST(QualTypeNameTest, Complex) { |
176 | TypeNameVisitor Complex; |
177 | Complex.ExpectedQualTypeNames["CheckTX" ] = "B::TX" ; |
178 | Complex.runOver( |
179 | Code: "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 | |
194 | TEST(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(Code: 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 | |
215 | TEST(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 | Code: "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 | |
255 | TEST(QualTypeNameTest, InlineNamespace) { |
256 | TypeNameVisitor InlineNamespace; |
257 | InlineNamespace.ExpectedQualTypeNames["c" ] = "B::C" ; |
258 | InlineNamespace.runOver(Code: "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 | L: TypeNameVisitor::Lang_CXX11); |
266 | } |
267 | |
268 | TEST(QualTypeNameTest, AnonStrucs) { |
269 | TypeNameVisitor AnonStrucs; |
270 | AnonStrucs.ExpectedQualTypeNames["a" ] = "short" ; |
271 | AnonStrucs.ExpectedQualTypeNames["un_in_st_1" ] = |
272 | "union (unnamed struct at input.cc:1:1)::(unnamed union at " |
273 | "input.cc:2:27)" ; |
274 | AnonStrucs.ExpectedQualTypeNames["b" ] = "short" ; |
275 | AnonStrucs.ExpectedQualTypeNames["un_in_st_2" ] = |
276 | "union (unnamed struct at input.cc:1:1)::(unnamed union at " |
277 | "input.cc:5:27)" ; |
278 | AnonStrucs.ExpectedQualTypeNames["anon_st" ] = |
279 | "struct (unnamed struct at input.cc:1:1)" ; |
280 | AnonStrucs.runOver(Code: R"(struct { |
281 | union { |
282 | short a; |
283 | } un_in_st_1; |
284 | union { |
285 | short b; |
286 | } un_in_st_2; |
287 | } anon_st;)" ); |
288 | } |
289 | |
290 | TEST(QualTypeNameTest, ConstUsing) { |
291 | TypeNameVisitor ConstUsing; |
292 | ConstUsing.ExpectedQualTypeNames["param1" ] = "const A::S &" ; |
293 | ConstUsing.ExpectedQualTypeNames["param2" ] = "const A::S" ; |
294 | ConstUsing.runOver(Code: R"(namespace A { |
295 | class S {}; |
296 | } |
297 | using ::A::S; |
298 | void foo(const S& param1, const S param2);)" ); |
299 | } |
300 | } // end anonymous namespace |
301 | |