brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.8 KiB · 3cadf9b Raw
363 lines · cpp
1//===- unittests/AST/TypePrinterTest.cpp --- Type printer tests -----------===//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// This file contains tests for QualType::print() and related methods.10//11//===----------------------------------------------------------------------===//12 13#include "ASTPrint.h"14#include "clang/AST/ASTContext.h"15#include "clang/ASTMatchers/ASTMatchFinder.h"16#include "clang/Tooling/Tooling.h"17#include "llvm/ADT/SmallString.h"18#include "gtest/gtest.h"19 20using namespace clang;21using namespace ast_matchers;22using namespace tooling;23 24namespace {25 26static void PrintType(raw_ostream &Out, const ASTContext *Context,27                      const QualType *T,28                      PrintingPolicyAdjuster PolicyAdjuster) {29  assert(T && !T->isNull() && "Expected non-null Type");30  PrintingPolicy Policy = Context->getPrintingPolicy();31  if (PolicyAdjuster)32    PolicyAdjuster(Policy);33  T->print(Out, Policy);34}35 36::testing::AssertionResult37PrintedTypeMatches(StringRef Code, const std::vector<std::string> &Args,38                   const DeclarationMatcher &NodeMatch,39                   StringRef ExpectedPrinted,40                   PrintingPolicyAdjuster PolicyAdjuster) {41  return PrintedNodeMatches<QualType>(Code, Args, NodeMatch, ExpectedPrinted,42                                      "", PrintType, PolicyAdjuster);43}44 45} // unnamed namespace46 47TEST(TypePrinter, TemplateId) {48  std::string Code = R"cpp(49    namespace N {50      template <typename> struct Type {};51 52      template <typename T>53      void Foo(const Type<T> &Param);54    }55  )cpp";56  auto Matcher = parmVarDecl(hasType(qualType().bind("id")));57 58  ASSERT_TRUE(PrintedTypeMatches(59      Code, {}, Matcher, "const Type<T> &",60      [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; }));61 62  ASSERT_TRUE(PrintedTypeMatches(63      Code, {}, Matcher, "const N::Type<T> &",64      [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));65}66 67TEST(TypePrinter, TemplateId2) {68  std::string Code = R"cpp(69      template <template <typename ...> class TemplatedType>70      void func(TemplatedType<int> Param);71    )cpp";72  auto Matcher = parmVarDecl(hasType(qualType().bind("id")));73 74  // Regression test ensuring we do not segfault getting the QualType as a75  // string.76  ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "<int>",77                                 [](PrintingPolicy &Policy) {78                                   Policy.FullyQualifiedName = true;79                                   Policy.PrintAsCanonical = true;80                                 }));81}82 83TEST(TypePrinter, ParamsUglified) {84  llvm::StringLiteral Code = R"cpp(85    template <typename _Tp, template <typename> class __f>86    const __f<_Tp&> *A = nullptr;87  )cpp";88  auto Clean = [](PrintingPolicy &Policy) {89    Policy.CleanUglifiedParameters = true;90  };91 92  ASSERT_TRUE(PrintedTypeMatches(Code, {},93                                 varDecl(hasType(qualType().bind("id"))),94                                 "const __f<_Tp &> *", nullptr));95  ASSERT_TRUE(PrintedTypeMatches(Code, {},96                                 varDecl(hasType(qualType().bind("id"))),97                                 "const f<Tp &> *", Clean));98}99 100TEST(TypePrinter, TemplateSpecializationFullyQualified) {101  llvm::StringLiteral Code = R"cpp(102    namespace shared {103    namespace a {104    template <typename T>105    struct S {};106    }  // namespace a107    namespace b {108    struct Foo {};109    }  // namespace b110    using Alias = a::S<b::Foo>;111    }  // namespace shared112  )cpp";113 114  auto Matcher = typedefNameDecl(hasName("::shared::Alias"),115                                 hasType(qualType().bind("id")));116  ASSERT_TRUE(PrintedTypeMatches(117      Code, {}, Matcher, "a::S<b::Foo>",118      [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; }));119  ASSERT_TRUE(PrintedTypeMatches(120      Code, {}, Matcher, "shared::a::S<shared::b::Foo>",121      [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; }));122}123 124TEST(TypePrinter, TemplateIdWithNTTP) {125  constexpr char Code[] = R"cpp(126    template <int N>127    struct Str {128      constexpr Str(char const (&s)[N]) { __builtin_memcpy(value, s, N); }129      char value[N];130    };131    template <Str> class ASCII {};132 133    ASCII<"this nontype template argument is too long to print"> x;134  )cpp";135  auto Matcher = classTemplateSpecializationDecl(136      hasName("ASCII"), has(cxxConstructorDecl(137                            isMoveConstructor(),138                            has(parmVarDecl(hasType(qualType().bind("id")))))));139 140  ASSERT_TRUE(PrintedTypeMatches(141      Code, {"-std=c++20"}, Matcher,142      R"(ASCII<Str<52>{"this nontype template argument is [...]"}> &&)",143      [](PrintingPolicy &Policy) {144        Policy.EntireContentsOfLargeArray = false;145      }));146 147  ASSERT_TRUE(PrintedTypeMatches(148      Code, {"-std=c++20"}, Matcher,149      R"(ASCII<Str<52>{"this nontype template argument is too long to print"}> &&)",150      [](PrintingPolicy &Policy) {151        Policy.EntireContentsOfLargeArray = true;152      }));153}154 155TEST(TypePrinter, TemplateArgumentsSubstitution) {156  constexpr char Code[] = R"cpp(157       template <typename Y> class X {};158       typedef X<int> A;159       int foo() {160          return sizeof(A);161       }162  )cpp";163  auto Matcher = typedefNameDecl(hasName("A"), hasType(qualType().bind("id")));164  ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "X<int>",165                                 [](PrintingPolicy &Policy) {166                                   Policy.SuppressTagKeyword = false;167                                   Policy.SuppressScope = true;168                                 }));169}170 171TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {172  /// Tests clang::isSubstitutedDefaultArgument on TemplateArguments173  /// that are of kind TemplateArgument::Expression174  constexpr char Code[] = R"cpp(175    constexpr bool func() { return true; }176 177    template <typename T1 = int,178              int      T2 = 42,179              T1       T3 = 43,180              int      T4 = sizeof(T1),181              bool     T5 = func()182              >183    struct Foo {184    };185 186    Foo<int, 40 + 2> X;187  )cpp";188 189  auto AST = tooling::buildASTFromCodeWithArgs(Code, /*Args=*/{"-std=c++20"});190  ASTContext &Ctx = AST->getASTContext();191 192  auto const *CTD = selectFirst<ClassTemplateDecl>(193      "id", match(classTemplateDecl(hasName("Foo")).bind("id"), Ctx));194  ASSERT_NE(CTD, nullptr);195  auto const *CTSD = *CTD->specializations().begin();196  ASSERT_NE(CTSD, nullptr);197  auto const *Params = CTD->getTemplateParameters();198  ASSERT_NE(Params, nullptr);199  auto const &ArgList = CTSD->getTemplateArgs();200 201  auto createBinOpExpr = [&](uint32_t LHS, uint32_t RHS,202                             uint32_t Result) -> ConstantExpr * {203    const int numBits = 32;204    clang::APValue ResultVal{llvm::APSInt(llvm::APInt(numBits, Result))};205    auto *LHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, LHS),206                                          Ctx.UnsignedIntTy, {});207    auto *RHSInt = IntegerLiteral::Create(Ctx, llvm::APInt(numBits, RHS),208                                          Ctx.UnsignedIntTy, {});209    auto *BinOp = BinaryOperator::Create(210        Ctx, LHSInt, RHSInt, BinaryOperatorKind::BO_Add, Ctx.UnsignedIntTy,211        ExprValueKind::VK_PRValue, ExprObjectKind::OK_Ordinary, {}, {});212    return ConstantExpr::Create(Ctx, dyn_cast<Expr>(BinOp), ResultVal);213  };214 215  {216    // Arg is an integral '42'217    auto const &Arg = ArgList.get(1);218    ASSERT_EQ(Arg.getKind(), TemplateArgument::Integral);219 220    // Param has default expr which evaluates to '42'221    auto const *Param = Params->getParam(1);222 223    EXPECT_TRUE(clang::isSubstitutedDefaultArgument(224        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));225  }226 227  {228    // Arg is an integral '41'229    llvm::APInt Int(32, 41);230    TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);231 232    // Param has default expr which evaluates to '42'233    auto const *Param = Params->getParam(1);234 235    EXPECT_FALSE(clang::isSubstitutedDefaultArgument(236        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));237  }238 239  {240    // Arg is an integral '4'241    llvm::APInt Int(32, 4);242    TemplateArgument Arg(Ctx, llvm::APSInt(Int), Ctx.UnsignedIntTy);243 244    // Param has is value-dependent expression (i.e., sizeof(T))245    auto const *Param = Params->getParam(3);246 247    EXPECT_FALSE(clang::isSubstitutedDefaultArgument(248        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));249  }250 251  {252    const int LHS = 40;253    const int RHS = 2;254    const int Result = 42;255    auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);256    // Arg is instantiated with '40 + 2'257    TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);258 259    // Param has default expr of '42'260    auto const *Param = Params->getParam(1);261 262    EXPECT_TRUE(clang::isSubstitutedDefaultArgument(263        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));264  }265 266  {267    const int LHS = 40;268    const int RHS = 1;269    const int Result = 41;270    auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);271 272    // Arg is instantiated with '40 + 1'273    TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);274 275    // Param has default expr of '42'276    auto const *Param = Params->getParam(1);277 278    EXPECT_FALSE(clang::isSubstitutedDefaultArgument(279        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));280  }281 282  {283    const int LHS = 4;284    const int RHS = 0;285    const int Result = 4;286    auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);287 288    // Arg is instantiated with '4 + 0'289    TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);290 291    // Param has is value-dependent expression (i.e., sizeof(T))292    auto const *Param = Params->getParam(3);293 294    EXPECT_FALSE(clang::isSubstitutedDefaultArgument(295        Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));296  }297}298 299TEST(TypePrinter, NestedNameSpecifiers) {300  constexpr char Code[] = R"cpp(301    void level1() {302      struct Inner {303        Inner(int) {304          struct {305            union {} u;306          } imem;307        }308      };309    }310  )cpp";311 312  // Types scoped immediately inside a function don't print the function name in313  // their scope.314  ASSERT_TRUE(PrintedTypeMatches(315      Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),316      "struct (unnamed)", [](PrintingPolicy &Policy) {317        Policy.FullyQualifiedName = true;318        Policy.AnonymousTagLocations = false;319      }));320 321  ASSERT_TRUE(PrintedTypeMatches(322      Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),323      "struct (unnamed)", [](PrintingPolicy &Policy) {324        Policy.FullyQualifiedName = false;325        Policy.AnonymousTagLocations = false;326      }));327 328  // Further levels of nesting print the entire scope.329  ASSERT_TRUE(PrintedTypeMatches(330      Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),331      "union level1()::Inner::Inner(int)::(anonymous struct)::(unnamed)",332      [](PrintingPolicy &Policy) {333        Policy.FullyQualifiedName = true;334        Policy.AnonymousTagLocations = false;335      }));336 337  ASSERT_TRUE(PrintedTypeMatches(338      Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),339      "union (unnamed)", [](PrintingPolicy &Policy) {340        Policy.FullyQualifiedName = false;341        Policy.AnonymousTagLocations = false;342      }));343}344 345TEST(TypePrinter, NestedNameSpecifiersTypedef) {346  constexpr char Code[] = R"cpp(347    typedef union {348      struct {349        struct {350          unsigned int baz;351        } bar;352      };353    } foo;354  )cpp";355 356  ASSERT_TRUE(PrintedTypeMatches(357      Code, {}, fieldDecl(hasName("bar"), hasType(qualType().bind("id"))),358      "struct foo::(anonymous struct)::(unnamed)", [](PrintingPolicy &Policy) {359        Policy.FullyQualifiedName = true;360        Policy.AnonymousTagLocations = false;361      }));362}363