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 { 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(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 VD->getType(), *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 "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 175 TEST(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 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(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 "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("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 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(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(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