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
19   // name.
20   bool TraverseDecl(Decl *D) {
21     return true;  // Always continue
22   }
23 
24   bool VisitValueDecl(const ValueDecl *VD) {
25     std::string ExpectedName =
26         ExpectedQualTypeNames.lookup(VD->getNameAsString());
27     if (ExpectedName != "") {
28       PrintingPolicy Policy(Context->getPrintingPolicy());
29       Policy.SuppressScope = false;
30       Policy.AnonymousTagLocations = true;
31       Policy.PolishForDeclaration = true;
32       Policy.SuppressUnwrittenScope = true;
33       std::string ActualName = TypeName::getFullyQualifiedName(
34           VD->getType(), *Context, Policy, WithGlobalNsPrefix);
35       if (ExpectedName != ActualName) {
36         // A custom message makes it much easier to see what declaration
37         // failed compared to EXPECT_EQ.
38         EXPECT_TRUE(false) << "Typename::getFullyQualifiedName failed for "
39                            << VD->getQualifiedNameAsString() << std::endl
40                            << "   Actual: " << ActualName << std::endl
41                            << " Exepcted: " << ExpectedName;
42       }
43     }
44     return true;
45   }
46 };
47 
48 // named namespaces inside anonymous namespaces
49 
50 TEST(QualTypeNameTest, getFullyQualifiedName) {
51   TypeNameVisitor Visitor;
52   // Simple case to test the test framework itself.
53   Visitor.ExpectedQualTypeNames["CheckInt"] = "int";
54 
55   // Keeping the names of the variables whose types we check unique
56   // within the entire test--regardless of their own scope--makes it
57   // easier to diagnose test failures.
58 
59   // Simple namespace qualifier
60   Visitor.ExpectedQualTypeNames["CheckA"] = "A::B::Class0";
61   // Lookup up the enclosing scopes, then down another one. (These
62   // appear as elaborated type in the AST. In that case--even if
63   // policy.SuppressScope = 0--qual_type.getAsString(policy) only
64   // gives the name as it appears in the source, not the full name.
65   Visitor.ExpectedQualTypeNames["CheckB"] = "A::B::C::Class1";
66   // Template parameter expansion.
67   Visitor.ExpectedQualTypeNames["CheckC"] =
68       "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>";
69   // Recursive template parameter expansion.
70   Visitor.ExpectedQualTypeNames["CheckD"] =
71       "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, "
72       "A::B::Template0<int, long> >";
73   // Variadic Template expansion.
74   Visitor.ExpectedQualTypeNames["CheckE"] =
75       "A::Variadic<int, A::B::Template0<int, char>, "
76       "A::B::Template1<int, long>, A::B::C::MyInt>";
77   // Using declarations should be fully expanded.
78   Visitor.ExpectedQualTypeNames["CheckF"] = "A::B::Class0";
79   // Elements found within "using namespace foo;" should be fully
80   // expanded.
81   Visitor.ExpectedQualTypeNames["CheckG"] = "A::B::C::MyInt";
82   // Type inside function
83   Visitor.ExpectedQualTypeNames["CheckH"] = "struct X";
84   // Anonymous Namespaces
85   Visitor.ExpectedQualTypeNames["CheckI"] = "aClass";
86   // Keyword inclusion with namespaces
87   Visitor.ExpectedQualTypeNames["CheckJ"] = "struct A::aStruct";
88   // Anonymous Namespaces nested in named namespaces and vice-versa.
89   Visitor.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
90   // Namespace alias
91   Visitor.ExpectedQualTypeNames["CheckL"] = "A::B::C::MyInt";
92   Visitor.ExpectedQualTypeNames["non_dependent_type_var"] =
93       "Foo<X>::non_dependent_type";
94   Visitor.ExpectedQualTypeNames["AnEnumVar"] = "EnumScopeClass::AnEnum";
95   Visitor.ExpectedQualTypeNames["AliasTypeVal"] = "A::B::C::InnerAlias<int>";
96   Visitor.ExpectedQualTypeNames["AliasInnerTypeVal"] =
97       "OuterTemplateClass<A::B::Class0>::Inner";
98   Visitor.ExpectedQualTypeNames["CheckM"] = "const A::B::Class0 *";
99   Visitor.ExpectedQualTypeNames["CheckN"] = "const X *";
100   Visitor.runOver(
101       "int CheckInt;\n"
102       "template <typename T>\n"
103       "class OuterTemplateClass { public: struct Inner {}; };\n"
104       "namespace A {\n"
105       " namespace B {\n"
106       "   class Class0 { };\n"
107       "   namespace C {\n"
108       "     typedef int MyInt;"
109       "     template <typename T>\n"
110       "     using InnerAlias = OuterTemplateClass<T>;\n"
111       "     InnerAlias<int> AliasTypeVal;\n"
112       "     InnerAlias<Class0>::Inner AliasInnerTypeVal;\n"
113       "   }\n"
114       "   template<class X, class Y> class Template0;"
115       "   template<class X, class Y> class Template1;"
116       "   typedef B::Class0 AnotherClass;\n"
117       "   void Function1(Template0<C::MyInt,\n"
118       "                  AnotherClass> CheckC);\n"
119       "   void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n"
120       "                            Template0<int, long> > CheckD);\n"
121       "   void Function3(const B::Class0* CheckM);\n"
122       "  }\n"
123       "template<typename... Values> class Variadic {};\n"
124       "Variadic<int, B::Template0<int, char>, "
125       "         B::Template1<int, long>, "
126       "         B::C::MyInt > CheckE;\n"
127       " namespace BC = B::C;\n"
128       " BC::MyInt CheckL;\n"
129       "}\n"
130       "using A::B::Class0;\n"
131       "void Function(Class0 CheckF);\n"
132       "using namespace A::B::C;\n"
133       "void Function(MyInt CheckG);\n"
134       "void f() {\n"
135       "  struct X {} CheckH;\n"
136       "}\n"
137       "struct X;\n"
138       "void f(const ::X* CheckN) {}\n"
139       "namespace {\n"
140       "  class aClass {};\n"
141       "   aClass CheckI;\n"
142       "}\n"
143       "namespace A {\n"
144       "  struct aStruct {} CheckJ;\n"
145       "}\n"
146       "namespace {\n"
147       "  namespace D {\n"
148       "    namespace {\n"
149       "      class aStruct {};\n"
150       "      aStruct CheckK;\n"
151       "    }\n"
152       "  }\n"
153       "}\n"
154       "template<class T> struct Foo {\n"
155       "  typedef typename T::A dependent_type;\n"
156       "  typedef int non_dependent_type;\n"
157       "  dependent_type dependent_type_var;\n"
158       "  non_dependent_type non_dependent_type_var;\n"
159       "};\n"
160       "struct X { typedef int A; };"
161       "Foo<X> var;"
162       "void F() {\n"
163       "  var.dependent_type_var = 0;\n"
164       "var.non_dependent_type_var = 0;\n"
165       "}\n"
166       "class EnumScopeClass {\n"
167       "public:\n"
168       "  enum AnEnum { ZERO, ONE };\n"
169       "};\n"
170       "EnumScopeClass::AnEnum AnEnumVar;\n",
171       TypeNameVisitor::Lang_CXX11);
172 
173   TypeNameVisitor Complex;
174   Complex.ExpectedQualTypeNames["CheckTX"] = "B::TX";
175   Complex.runOver(
176       "namespace A {"
177       "  struct X {};"
178       "}"
179       "using A::X;"
180       "namespace fake_std {"
181       "  template<class... Types > class tuple {};"
182       "}"
183       "namespace B {"
184       "  using fake_std::tuple;"
185       "  typedef tuple<X> TX;"
186       "  TX CheckTX;"
187       "  struct A { typedef int X; };"
188       "}");
189 
190   TypeNameVisitor GlobalNsPrefix;
191   GlobalNsPrefix.WithGlobalNsPrefix = true;
192   GlobalNsPrefix.ExpectedQualTypeNames["IntVal"] = "int";
193   GlobalNsPrefix.ExpectedQualTypeNames["BoolVal"] = "bool";
194   GlobalNsPrefix.ExpectedQualTypeNames["XVal"] = "::A::B::X";
195   GlobalNsPrefix.ExpectedQualTypeNames["IntAliasVal"] = "::A::B::Alias<int>";
196   GlobalNsPrefix.ExpectedQualTypeNames["ZVal"] = "::A::B::Y::Z";
197   GlobalNsPrefix.ExpectedQualTypeNames["GlobalZVal"] = "::Z";
198   GlobalNsPrefix.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
199   GlobalNsPrefix.ExpectedQualTypeNames["YZMPtr"] = "::A::B::X ::A::B::Y::Z::*";
200   GlobalNsPrefix.runOver(
201       "namespace A {\n"
202       "  namespace B {\n"
203       "    int IntVal;\n"
204       "    bool BoolVal;\n"
205       "    struct X {};\n"
206       "    X XVal;\n"
207       "    template <typename T> class CCC { };\n"
208       "    template <typename T>\n"
209       "    using Alias = CCC<T>;\n"
210       "    Alias<int> IntAliasVal;\n"
211       "    struct Y { struct Z { X YZIPtr; }; };\n"
212       "    Y::Z ZVal;\n"
213       "    X Y::Z::*YZMPtr;\n"
214       "  }\n"
215       "}\n"
216       "struct Z {};\n"
217       "Z GlobalZVal;\n"
218       "namespace {\n"
219       "  namespace D {\n"
220       "    namespace {\n"
221       "      class aStruct {};\n"
222       "      aStruct CheckK;\n"
223       "    }\n"
224       "  }\n"
225       "}\n"
226   );
227 
228   TypeNameVisitor InlineNamespace;
229   InlineNamespace.ExpectedQualTypeNames["c"] = "B::C";
230   InlineNamespace.runOver("inline namespace A {\n"
231                           "  namespace B {\n"
232                           "    class C {};\n"
233                           "  }\n"
234                           "}\n"
235                           "using namespace A::B;\n"
236                           "C c;\n",
237                           TypeNameVisitor::Lang_CXX11);
238 
239   TypeNameVisitor AnonStrucs;
240   AnonStrucs.ExpectedQualTypeNames["a"] = "short";
241   AnonStrucs.ExpectedQualTypeNames["un_in_st_1"] =
242       "union (anonymous struct at input.cc:1:1)::(anonymous union at "
243       "input.cc:2:27)";
244   AnonStrucs.ExpectedQualTypeNames["b"] = "short";
245   AnonStrucs.ExpectedQualTypeNames["un_in_st_2"] =
246       "union (anonymous struct at input.cc:1:1)::(anonymous union at "
247       "input.cc:5:27)";
248   AnonStrucs.ExpectedQualTypeNames["anon_st"] =
249       "struct (anonymous struct at input.cc:1:1)";
250   AnonStrucs.runOver(R"(struct {
251                           union {
252                             short a;
253                           } un_in_st_1;
254                           union {
255                             short b;
256                           } un_in_st_2;
257                         } anon_st;)");
258 }
259 
260 }  // end anonymous namespace
261