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