brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.9 KiB · 1139392 Raw
420 lines · cpp
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-exception6//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(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 declaration32        // failed compared to EXPECT_EQ.33        ADD_FAILURE() << "Typename::getFullyQualifiedName failed for "34                      << VD->getQualifiedNameAsString() << std::endl35                      << "   Actual: " << ActualName << std::endl36                      << " Expected: " << ExpectedName;37      }38    }39    return true;40  }41};42 43// named namespaces inside anonymous namespaces44 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 unique51  // within the entire test--regardless of their own scope--makes it52  // easier to diagnose test failures.53 54  // Simple namespace qualifier55  Visitor.ExpectedQualTypeNames["CheckA"] = "A::B::Class0";56  // Lookup up the enclosing scopes, then down another one. (These57  // appear as elaborated type in the AST. In that case--even if58  // policy.SuppressScope = 0--qual_type.getAsString(policy) only59  // 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 fully75  // expanded.76  Visitor.ExpectedQualTypeNames["CheckG"] = "A::B::C::MyInt";77  // Type inside function78  Visitor.ExpectedQualTypeNames["CheckH"] = "struct X";79  // Anonymous Namespaces80  Visitor.ExpectedQualTypeNames["CheckI"] = "aClass";81  // Keyword inclusion with namespaces82  Visitor.ExpectedQualTypeNames["CheckJ"] = "struct A::aStruct";83  // Anonymous Namespaces nested in named namespaces and vice-versa.84  Visitor.ExpectedQualTypeNames["CheckK"] = "D::aStruct";85  // Namespace alias86  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("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, Context, Policy);282  };283 284  auto *A = Context.getTranslationUnitDecl()285                ->lookup(&Context.Idents.get("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  CanQualType A1RecordTy = Context.getCanonicalTagType(A1);299  EXPECT_EQ(getFullyQualifiedName(A1RecordTy), "A<1>");300  CanQualType A2RecordTy = Context.getCanonicalTagType(A2);301  EXPECT_EQ(getFullyQualifiedName(A2RecordTy), "A<2U>");302 303  // getTemplateSpecializationType() gives types that print the integral304  // argument directly.305  TemplateArgument Args1[] = {306      {Context, llvm::APSInt::getUnsigned(1u), Context.UnsignedIntTy}};307  QualType A1TemplateSpecTy = Context.getTemplateSpecializationType(308      ElaboratedTypeKeyword::None, TemplateName(A), Args1, Args1, A1RecordTy);309  EXPECT_EQ(A1TemplateSpecTy.getAsString(), "A<1>");310 311  TemplateArgument Args2[] = {312      {Context, llvm::APSInt::getUnsigned(2u), Context.UnsignedIntTy}};313  QualType A2TemplateSpecTy = Context.getTemplateSpecializationType(314      ElaboratedTypeKeyword::None, 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("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  CanQualType A1B3RecordTy = Context.getCanonicalTagType(A1B3);325  EXPECT_EQ(getFullyQualifiedName(A1B3RecordTy), "A<1>::B<3>");326 327  // Construct A<1>::B<3> and check name.328  NestedNameSpecifier A1Nested(A1TemplateSpecTy.getTypePtr());329  TemplateName A1B3Name = Context.getQualifiedTemplateName(330      A1Nested, /*TemplateKeyword=*/false, TemplateName(A1B));331 332  TemplateArgument Args3[] = {333      {Context, llvm::APSInt::getUnsigned(3u), Context.UnsignedIntTy}};334  QualType A1B3TemplateSpecTy = Context.getTemplateSpecializationType(335      ElaboratedTypeKeyword::None, A1B3Name, Args3, Args3, A1B3RecordTy);336  EXPECT_EQ(A1B3TemplateSpecTy.getAsString(), "A<1>::B<3>");337 338  // Find A<2u>::B and its specialization B<4u>.339  auto *A2B =340      A2->lookup(&Context.Idents.get("B")).find_first<ClassTemplateDecl>();341  ASSERT_NE(A2B, nullptr);342  auto A2BSpec = A2B->spec_begin();343  ASSERT_NE(A2BSpec, A2B->spec_end());344  auto *A2B4 = *A2BSpec;345  CanQualType A2B4RecordTy = Context.getCanonicalTagType(A2B4);346  EXPECT_EQ(getFullyQualifiedName(A2B4RecordTy), "A<2U>::B<4U>");347 348  // Construct A<2>::B<4> and check name.349  NestedNameSpecifier A2Nested(A2TemplateSpecTy.getTypePtr());350  TemplateName A2B4Name = Context.getQualifiedTemplateName(351      A2Nested, /*TemplateKeyword=*/false, TemplateName(A2B));352 353  TemplateArgument Args4[] = {354      {Context, llvm::APSInt::getUnsigned(4u), Context.UnsignedIntTy}};355  QualType A2B4TemplateSpecTy = Context.getTemplateSpecializationType(356      ElaboratedTypeKeyword::None, A2B4Name, Args4, Args4, A2B4RecordTy);357  EXPECT_EQ(A2B4TemplateSpecTy.getAsString(), "A<2>::B<4>");358}359 360TEST(QualTypeNameTest, AnonStrucs) {361  TypeNameVisitor AnonStrucs;362  AnonStrucs.ExpectedQualTypeNames["a"] = "short";363  AnonStrucs.ExpectedQualTypeNames["un_in_st_1"] =364      "union (unnamed struct at input.cc:1:1)::(unnamed union at "365      "input.cc:2:27)";366  AnonStrucs.ExpectedQualTypeNames["b"] = "short";367  AnonStrucs.ExpectedQualTypeNames["un_in_st_2"] =368      "union (unnamed struct at input.cc:1:1)::(unnamed union at "369      "input.cc:5:27)";370  AnonStrucs.ExpectedQualTypeNames["anon_st"] =371      "struct (unnamed struct at input.cc:1:1)";372  AnonStrucs.runOver(R"(struct {373                          union {374                            short a;375                          } un_in_st_1;376                          union {377                            short b;378                          } un_in_st_2;379                        } anon_st;)");380}381 382TEST(QualTypeNameTest, ConstUsing) {383  TypeNameVisitor ConstUsing;384  ConstUsing.ExpectedQualTypeNames["param1"] = "const A::S &";385  ConstUsing.ExpectedQualTypeNames["param2"] = "const A::S";386  ConstUsing.runOver(R"(namespace A {387                          class S {};388                        }389                        using ::A::S;390                        void foo(const S& param1, const S param2);)");391}392 393TEST(QualTypeNameTest, NullableAttributesWithGlobalNs) {394  TypeNameVisitor Visitor;395  Visitor.WithGlobalNsPrefix = true;396  Visitor.ExpectedQualTypeNames["param1"] = "::std::unique_ptr<int> _Nullable";397  Visitor.ExpectedQualTypeNames["param2"] = "::std::unique_ptr<int> _Nonnull";398  Visitor.ExpectedQualTypeNames["param3"] =399      "::std::unique_ptr< ::std::unique_ptr<int> _Nullable> _Nonnull";400  Visitor.ExpectedQualTypeNames["param4"] =401      "::std::unique_ptr<int>  _Nullable const *";402  Visitor.ExpectedQualTypeNames["param5"] =403      "::std::unique_ptr<int>  _Nullable const *";404  Visitor.ExpectedQualTypeNames["param6"] =405      "::std::unique_ptr<int>  _Nullable const *";406  Visitor.runOver(R"(namespace std {407                        template<class T> class unique_ptr {};408                     }409                     void foo(410                      std::unique_ptr<int> _Nullable param1,411                      _Nonnull std::unique_ptr<int> param2,412                      std::unique_ptr<std::unique_ptr<int> _Nullable> _Nonnull param3,413                      const std::unique_ptr<int> _Nullable *param4,414                      _Nullable std::unique_ptr<int> const *param5,415                      std::unique_ptr<int> _Nullable const *param6416                      );417                     )");418}419}  // end anonymous namespace420