728 lines · cpp
1//===- unittests/AST/DeclTest.cpp --- Declaration 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// Unit tests for Decl nodes in the AST.10//11//===----------------------------------------------------------------------===//12 13#include "clang/AST/Decl.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/DeclTemplate.h"17#include "clang/AST/Mangle.h"18#include "clang/ASTMatchers/ASTMatchFinder.h"19#include "clang/ASTMatchers/ASTMatchers.h"20#include "clang/Basic/ABI.h"21#include "clang/Basic/Diagnostic.h"22#include "clang/Basic/LLVM.h"23#include "clang/Basic/TargetInfo.h"24#include "clang/Lex/Lexer.h"25#include "clang/Tooling/Tooling.h"26#include "llvm/IR/DataLayout.h"27#include "llvm/Testing/Annotations/Annotations.h"28#include "gtest/gtest.h"29 30using namespace clang::ast_matchers;31using namespace clang::tooling;32using namespace clang;33 34TEST(Decl, CleansUpAPValues) {35 MatchFinder Finder;36 std::unique_ptr<FrontendActionFactory> Factory(37 newFrontendActionFactory(&Finder));38 39 // This is a regression test for a memory leak in APValues for structs that40 // allocate memory. This test only fails if run under valgrind with full leak41 // checking enabled.42 std::vector<std::string> Args(1, "-std=c++11");43 Args.push_back("-fno-ms-extensions");44 ASSERT_TRUE(runToolOnCodeWithArgs(45 Factory->create(),46 "struct X { int a; }; constexpr X x = { 42 };"47 "union Y { constexpr Y(int a) : a(a) {} int a; }; constexpr Y y = { 42 };"48 "constexpr int z[2] = { 42, 43 };"49 "constexpr int __attribute__((vector_size(16))) v1 = {};"50 "\n#ifdef __SIZEOF_INT128__\n"51 "constexpr __uint128_t large_int = 0xffffffffffffffff;"52 "constexpr __uint128_t small_int = 1;"53 "\n#endif\n"54 "constexpr double d1 = 42.42;"55 "constexpr long double d2 = 42.42;"56 "constexpr _Complex long double c1 = 42.0i;"57 "constexpr _Complex long double c2 = 42.0;"58 "template<int N> struct A : A<N-1> {};"59 "template<> struct A<0> { int n; }; A<50> a;"60 "constexpr int &r = a.n;"61 "constexpr int A<50>::*p = &A<50>::n;"62 "void f() { foo: bar: constexpr int k = __builtin_constant_p(0) ?"63 " (char*)&&foo - (char*)&&bar : 0; }",64 Args));65 66 // FIXME: Once this test starts breaking we can test APValue::needsCleanup67 // for ComplexInt.68 ASSERT_FALSE(runToolOnCodeWithArgs(69 Factory->create(),70 "constexpr _Complex __uint128_t c = 0xffffffffffffffff;",71 Args));72}73 74TEST(Decl, AsmLabelAttr) {75 // Create two method decls: `f` and `g`.76 StringRef Code = R"(77 struct S {78 void f() {}79 };80 )";81 auto AST =82 tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});83 ASTContext &Ctx = AST->getASTContext();84 assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&85 "Expected target to have a global prefix");86 DiagnosticsEngine &Diags = AST->getDiagnostics();87 88 const auto *DeclS =89 selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));90 NamedDecl *DeclF = *DeclS->method_begin();91 92 DeclF->addAttr(AsmLabelAttr::Create(Ctx, "foo"));93 94 // Mangle the decl names.95 std::string MangleF;96 std::unique_ptr<ItaniumMangleContext> MC(97 ItaniumMangleContext::create(Ctx, Diags));98 {99 llvm::raw_string_ostream OS_F(MangleF);100 MC->mangleName(DeclF, OS_F);101 }102 103 ASSERT_EQ(MangleF, "\x01"104 "foo");105}106 107TEST(Decl, AsmLabelAttr_LLDB) {108 StringRef Code = R"(109 struct S {110 void f() {}111 S() = default;112 ~S() = default;113 };114 )";115 auto AST =116 tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});117 ASTContext &Ctx = AST->getASTContext();118 assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&119 "Expected target to have a global prefix");120 DiagnosticsEngine &Diags = AST->getDiagnostics();121 122 const auto *DeclS =123 selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));124 125 auto *DeclF = *DeclS->method_begin();126 auto *Ctor = *DeclS->ctor_begin();127 auto *Dtor = DeclS->getDestructor();128 129 ASSERT_TRUE(DeclF);130 ASSERT_TRUE(Ctor);131 ASSERT_TRUE(Dtor);132 133 DeclF->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:_Z1fv"));134 Ctor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:S"));135 Dtor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:~S"));136 137 std::unique_ptr<ItaniumMangleContext> MC(138 ItaniumMangleContext::create(Ctx, Diags));139 140 {141 std::string Mangled;142 llvm::raw_string_ostream OS_Mangled(Mangled);143 MC->mangleName(DeclF, OS_Mangled);144 145 ASSERT_EQ(Mangled, "\x01$__lldb_func::123:123:_Z1fv");146 };147 148 {149 std::string Mangled;150 llvm::raw_string_ostream OS_Mangled(Mangled);151 MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);152 153 ASSERT_EQ(Mangled, "\x01$__lldb_func:C0:123:123:S");154 };155 156 {157 std::string Mangled;158 llvm::raw_string_ostream OS_Mangled(Mangled);159 MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);160 161 ASSERT_EQ(Mangled, "\x01$__lldb_func:C1:123:123:S");162 };163 164 {165 std::string Mangled;166 llvm::raw_string_ostream OS_Mangled(Mangled);167 MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Deleting), OS_Mangled);168 169 ASSERT_EQ(Mangled, "\x01$__lldb_func:D0:123:123:~S");170 };171 172 {173 std::string Mangled;174 llvm::raw_string_ostream OS_Mangled(Mangled);175 MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Base), OS_Mangled);176 177 ASSERT_EQ(Mangled, "\x01$__lldb_func:D2:123:123:~S");178 };179}180 181TEST(Decl, AsmLabelAttr_LLDB_Inherit) {182 StringRef Code = R"(183 struct Base {184 Base(int x) {}185 };186 187 struct Derived : Base {188 using Base::Base;189 } d(5);190 )";191 auto AST =192 tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});193 ASTContext &Ctx = AST->getASTContext();194 assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&195 "Expected target to have a global prefix");196 DiagnosticsEngine &Diags = AST->getDiagnostics();197 198 const auto *Ctor = selectFirst<CXXConstructorDecl>(199 "ctor",200 match(cxxConstructorDecl(isInheritingConstructor()).bind("ctor"), Ctx));201 202 const_cast<CXXConstructorDecl *>(Ctor)->addAttr(203 AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:Derived"));204 205 std::unique_ptr<ItaniumMangleContext> MC(206 ItaniumMangleContext::create(Ctx, Diags));207 208 {209 std::string Mangled;210 llvm::raw_string_ostream OS_Mangled(Mangled);211 MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);212 213 ASSERT_EQ(Mangled, "\x01$__lldb_func:CI0:123:123:Derived");214 };215 216 {217 std::string Mangled;218 llvm::raw_string_ostream OS_Mangled(Mangled);219 MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);220 221 ASSERT_EQ(Mangled, "\x01$__lldb_func:CI1:123:123:Derived");222 };223}224 225TEST(Decl, MangleDependentSizedArray) {226 StringRef Code = R"(227 template <int ...N>228 int A[] = {N...};229 230 template <typename T, int N>231 struct S {232 T B[N];233 };234 )";235 auto AST =236 tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});237 ASTContext &Ctx = AST->getASTContext();238 assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&239 "Expected target to have a global prefix");240 DiagnosticsEngine &Diags = AST->getDiagnostics();241 242 const auto *DeclA =243 selectFirst<VarDecl>("A", match(varDecl().bind("A"), Ctx));244 const auto *DeclB =245 selectFirst<FieldDecl>("B", match(fieldDecl().bind("B"), Ctx));246 247 std::string MangleA, MangleB;248 llvm::raw_string_ostream OS_A(MangleA), OS_B(MangleB);249 std::unique_ptr<ItaniumMangleContext> MC(250 ItaniumMangleContext::create(Ctx, Diags));251 252 MC->mangleCanonicalTypeName(DeclA->getType(), OS_A);253 MC->mangleCanonicalTypeName(DeclB->getType(), OS_B);254 255 ASSERT_EQ(MangleA, "_ZTSA_i");256 ASSERT_EQ(MangleB, "_ZTSAT0__T_");257}258 259TEST(Decl, ConceptDecl) {260 llvm::StringRef Code(R"(261 template<class T>262 concept integral = __is_integral(T);263 )");264 265 auto AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});266 ASTContext &Ctx = AST->getASTContext();267 268 const auto *Decl =269 selectFirst<ConceptDecl>("decl", match(conceptDecl().bind("decl"), Ctx));270 ASSERT_TRUE(Decl != nullptr);271 EXPECT_EQ(Decl->getName(), "integral");272}273 274TEST(Decl, EnumDeclRange) {275 llvm::Annotations Code(R"(276 typedef int Foo;277 [[enum Bar : Foo]];)");278 auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{});279 ASTContext &Ctx = AST->getASTContext();280 const auto &SM = Ctx.getSourceManager();281 282 const auto *Bar =283 selectFirst<TagDecl>("Bar", match(enumDecl().bind("Bar"), Ctx));284 auto BarRange =285 Lexer::getAsCharRange(Bar->getSourceRange(), SM, Ctx.getLangOpts());286 EXPECT_EQ(SM.getFileOffset(BarRange.getBegin()), Code.range().Begin);287 EXPECT_EQ(SM.getFileOffset(BarRange.getEnd()), Code.range().End);288}289 290TEST(Decl, IsInExportDeclContext) {291 llvm::Annotations Code(R"(292 export module m;293 export template <class T>294 void f() {})");295 auto AST =296 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});297 ASTContext &Ctx = AST->getASTContext();298 299 const auto *f =300 selectFirst<FunctionDecl>("f", match(functionDecl().bind("f"), Ctx));301 EXPECT_TRUE(f->isInExportDeclContext());302}303 304TEST(Decl, InConsistLinkageForTemplates) {305 llvm::Annotations Code(R"(306 export module m;307 export template <class T>308 void f() {}309 310 template <>311 void f<int>() {}312 313 export template <class T>314 class C {};315 316 template<>317 class C<int> {};318 )");319 320 auto AST =321 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});322 ASTContext &Ctx = AST->getASTContext();323 324 llvm::SmallVector<ast_matchers::BoundNodes, 2> Funcs =325 match(functionDecl().bind("f"), Ctx);326 327 EXPECT_EQ(Funcs.size(), 2U);328 const FunctionDecl *TemplateF = Funcs[0].getNodeAs<FunctionDecl>("f");329 const FunctionDecl *SpecializedF = Funcs[1].getNodeAs<FunctionDecl>("f");330 EXPECT_EQ(TemplateF->getLinkageInternal(),331 SpecializedF->getLinkageInternal());332 333 llvm::SmallVector<ast_matchers::BoundNodes, 1> ClassTemplates =334 match(classTemplateDecl().bind("C"), Ctx);335 llvm::SmallVector<ast_matchers::BoundNodes, 1> ClassSpecializations =336 match(classTemplateSpecializationDecl().bind("C"), Ctx);337 338 EXPECT_EQ(ClassTemplates.size(), 1U);339 EXPECT_EQ(ClassSpecializations.size(), 1U);340 const NamedDecl *TemplatedC = ClassTemplates[0].getNodeAs<NamedDecl>("C");341 const NamedDecl *SpecializedC = ClassSpecializations[0].getNodeAs<NamedDecl>("C");342 EXPECT_EQ(TemplatedC->getLinkageInternal(),343 SpecializedC->getLinkageInternal());344}345 346TEST(Decl, ModuleAndInternalLinkage) {347 llvm::Annotations Code(R"(348 export module M;349 static int a;350 static int f(int x);351 352 int b;353 int g(int x);)");354 355 auto AST =356 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});357 ASTContext &Ctx = AST->getASTContext();358 359 const auto *a =360 selectFirst<VarDecl>("a", match(varDecl(hasName("a")).bind("a"), Ctx));361 const auto *f = selectFirst<FunctionDecl>(362 "f", match(functionDecl(hasName("f")).bind("f"), Ctx));363 364 EXPECT_EQ(a->getFormalLinkage(), Linkage::Internal);365 EXPECT_EQ(f->getFormalLinkage(), Linkage::Internal);366 367 const auto *b =368 selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), Ctx));369 const auto *g = selectFirst<FunctionDecl>(370 "g", match(functionDecl(hasName("g")).bind("g"), Ctx));371 372 EXPECT_EQ(b->getFormalLinkage(), Linkage::Module);373 EXPECT_EQ(g->getFormalLinkage(), Linkage::Module);374}375 376TEST(Decl, GetNonTransparentDeclContext) {377 llvm::Annotations Code(R"(378 export module m3;379 export template <class> struct X {380 template <class Self> friend void f(Self &&self) {381 (Self&)self;382 }383 };)");384 385 auto AST =386 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});387 ASTContext &Ctx = AST->getASTContext();388 389 auto *f = selectFirst<FunctionDecl>(390 "f", match(functionDecl(hasName("f")).bind("f"), Ctx));391 392 EXPECT_TRUE(f->getNonTransparentDeclContext()->isFileContext());393}394 395TEST(Decl, MemberFunctionInModules) {396 llvm::Annotations Code(R"(397 module;398 class G {399 void bar() {}400 };401 export module M;402 class A {403 void foo() {}404 };405 )");406 407 auto AST =408 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});409 ASTContext &Ctx = AST->getASTContext();410 411 auto *foo = selectFirst<FunctionDecl>(412 "foo", match(functionDecl(hasName("foo")).bind("foo"), Ctx));413 414 // The function defined within a class definition is not implicitly inline415 // if it is not attached to global module416 EXPECT_FALSE(foo->isInlined());417 418 auto *bar = selectFirst<FunctionDecl>(419 "bar", match(functionDecl(hasName("bar")).bind("bar"), Ctx));420 421 // In global module, the function defined within a class definition is422 // implicitly inline.423 EXPECT_TRUE(bar->isInlined());424}425 426TEST(Decl, MemberFunctionInHeaderUnit) {427 llvm::Annotations Code(R"(428 class foo {429 public:430 int memFn() {431 return 43;432 }433 };434 )");435 436 auto AST = tooling::buildASTFromCodeWithArgs(437 Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});438 ASTContext &Ctx = AST->getASTContext();439 440 auto *memFn = selectFirst<FunctionDecl>(441 "memFn", match(functionDecl(hasName("memFn")).bind("memFn"), Ctx));442 443 EXPECT_TRUE(memFn->isInlined());444}445 446TEST(Decl, FriendFunctionWithinClassInHeaderUnit) {447 llvm::Annotations Code(R"(448 class foo {449 int value;450 public:451 foo(int v) : value(v) {}452 453 friend int getFooValue(foo f) {454 return f.value;455 }456 };457 )");458 459 auto AST = tooling::buildASTFromCodeWithArgs(460 Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});461 ASTContext &Ctx = AST->getASTContext();462 463 auto *getFooValue = selectFirst<FunctionDecl>(464 "getFooValue",465 match(functionDecl(hasName("getFooValue")).bind("getFooValue"), Ctx));466 467 EXPECT_TRUE(getFooValue->isInlined());468}469 470TEST(Decl, FunctionDeclBitsShouldNotOverlapWithCXXConstructorDeclBits) {471 llvm::Annotations Code(R"(472 struct A {473 A() : m() {}474 int m;475 };476 477 A f() { return A(); }478 )");479 480 auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), {"-std=c++14"});481 ASTContext &Ctx = AST->getASTContext();482 483 auto HasCtorInit =484 hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));485 auto ImpMoveCtor =486 cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit)487 .bind("MoveCtor");488 489 auto *ToImpMoveCtor =490 selectFirst<CXXConstructorDecl>("MoveCtor", match(ImpMoveCtor, Ctx));491 492 EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);493 EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());494}495 496TEST(Decl, NoProtoFunctionDeclAttributes) {497 llvm::Annotations Code(R"(498 void f();499 )");500 501 auto AST = tooling::buildASTFromCodeWithArgs(502 Code.code(),503 /*Args=*/{"-target", "i386-apple-darwin", "-x", "objective-c",504 "-std=c89"});505 ASTContext &Ctx = AST->getASTContext();506 507 auto *f = selectFirst<FunctionDecl>(508 "f", match(functionDecl(hasName("f")).bind("f"), Ctx));509 510 const auto *FPT = f->getType()->getAs<FunctionNoProtoType>();511 512 // Functions without prototypes always have 0 initialized qualifiers513 EXPECT_FALSE(FPT->isConst());514 EXPECT_FALSE(FPT->isVolatile());515 EXPECT_FALSE(FPT->isRestrict());516}517 518TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) {519 // C++ [basic.stc.dynamic.general]p2:520 // The library provides default definitions for the global allocation521 // and deallocation functions. Some global allocation and deallocation522 // functions are replaceable ([new.delete]); these are attached to the523 // global module ([module.unit]).524 525 llvm::Annotations Code(R"(526 export module base;527 528 export struct Base {529 virtual void hello() = 0;530 virtual ~Base() = default;531 };532 )");533 534 auto AST =535 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});536 ASTContext &Ctx = AST->getASTContext();537 538 // void* operator new(std::size_t);539 auto *SizedOperatorNew = selectFirst<FunctionDecl>(540 "operator new",541 match(functionDecl(hasName("operator new"), parameterCountIs(1),542 hasParameter(0, hasType(isUnsignedInteger())))543 .bind("operator new"),544 Ctx));545 ASSERT_TRUE(SizedOperatorNew->getOwningModule());546 EXPECT_TRUE(SizedOperatorNew->isFromExplicitGlobalModule());547 548 // void* operator new(std::size_t, std::align_val_t);549 auto *SizedAlignedOperatorNew = selectFirst<FunctionDecl>(550 "operator new",551 match(functionDecl(552 hasName("operator new"), parameterCountIs(2),553 hasParameter(0, hasType(isUnsignedInteger())),554 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))555 .bind("operator new"),556 Ctx));557 ASSERT_TRUE(SizedAlignedOperatorNew->getOwningModule());558 EXPECT_TRUE(SizedAlignedOperatorNew->isFromExplicitGlobalModule());559 560 // void* operator new[](std::size_t);561 auto *SizedArrayOperatorNew = selectFirst<FunctionDecl>(562 "operator new[]",563 match(functionDecl(hasName("operator new[]"), parameterCountIs(1),564 hasParameter(0, hasType(isUnsignedInteger())))565 .bind("operator new[]"),566 Ctx));567 ASSERT_TRUE(SizedArrayOperatorNew->getOwningModule());568 EXPECT_TRUE(SizedArrayOperatorNew->isFromExplicitGlobalModule());569 570 // void* operator new[](std::size_t, std::align_val_t);571 auto *SizedAlignedArrayOperatorNew = selectFirst<FunctionDecl>(572 "operator new[]",573 match(functionDecl(574 hasName("operator new[]"), parameterCountIs(2),575 hasParameter(0, hasType(isUnsignedInteger())),576 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))577 .bind("operator new[]"),578 Ctx));579 ASSERT_TRUE(SizedAlignedArrayOperatorNew->getOwningModule());580 EXPECT_TRUE(581 SizedAlignedArrayOperatorNew->isFromExplicitGlobalModule());582 583 // void operator delete(void*) noexcept;584 auto *Delete = selectFirst<FunctionDecl>(585 "operator delete",586 match(functionDecl(587 hasName("operator delete"), parameterCountIs(1),588 hasParameter(0, hasType(pointerType(pointee(voidType())))))589 .bind("operator delete"),590 Ctx));591 ASSERT_TRUE(Delete->getOwningModule());592 EXPECT_TRUE(Delete->isFromExplicitGlobalModule());593 594 // void operator delete(void*, std::align_val_t) noexcept;595 auto *AlignedDelete = selectFirst<FunctionDecl>(596 "operator delete",597 match(functionDecl(598 hasName("operator delete"), parameterCountIs(2),599 hasParameter(0, hasType(pointerType(pointee(voidType())))),600 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))601 .bind("operator delete"),602 Ctx));603 ASSERT_TRUE(AlignedDelete->getOwningModule());604 EXPECT_TRUE(AlignedDelete->isFromExplicitGlobalModule());605 606 // Sized deallocation is not enabled by default. So we skip it here.607 608 // void operator delete[](void*) noexcept;609 auto *ArrayDelete = selectFirst<FunctionDecl>(610 "operator delete[]",611 match(functionDecl(612 hasName("operator delete[]"), parameterCountIs(1),613 hasParameter(0, hasType(pointerType(pointee(voidType())))))614 .bind("operator delete[]"),615 Ctx));616 ASSERT_TRUE(ArrayDelete->getOwningModule());617 EXPECT_TRUE(ArrayDelete->isFromExplicitGlobalModule());618 619 // void operator delete[](void*, std::align_val_t) noexcept;620 auto *AlignedArrayDelete = selectFirst<FunctionDecl>(621 "operator delete[]",622 match(functionDecl(623 hasName("operator delete[]"), parameterCountIs(2),624 hasParameter(0, hasType(pointerType(pointee(voidType())))),625 hasParameter(1, hasType(enumDecl(hasName("std::align_val_t")))))626 .bind("operator delete[]"),627 Ctx));628 ASSERT_TRUE(AlignedArrayDelete->getOwningModule());629 EXPECT_TRUE(AlignedArrayDelete->isFromExplicitGlobalModule());630}631 632TEST(Decl, TemplateArgumentDefaulted) {633 llvm::Annotations Code(R"cpp(634 template<typename T1, typename T2>635 struct Alloc {};636 637 template <typename T1,638 typename T2 = double,639 int T3 = 42,640 typename T4 = Alloc<T1, T2>>641 struct Foo {642 };643 644 Foo<char, int, 42, Alloc<char, int>> X;645 )cpp");646 647 auto AST =648 tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{"-std=c++20"});649 ASTContext &Ctx = AST->getASTContext();650 651 auto const *CTSD = selectFirst<ClassTemplateSpecializationDecl>(652 "id",653 match(classTemplateSpecializationDecl(hasName("Foo")).bind("id"), Ctx));654 ASSERT_NE(CTSD, nullptr);655 auto const &ArgList = CTSD->getTemplateArgs();656 657 EXPECT_FALSE(ArgList.get(0).getIsDefaulted());658 EXPECT_FALSE(ArgList.get(1).getIsDefaulted());659 EXPECT_TRUE(ArgList.get(2).getIsDefaulted());660 EXPECT_TRUE(ArgList.get(3).getIsDefaulted());661}662 663TEST(Decl, CXXDestructorDeclsShouldHaveWellFormedNameInfoRanges) {664 // GH71161665 llvm::Annotations Code(R"cpp(666template <typename T> struct Resource {667 ~Resource(); // 1668};669template <typename T>670Resource<T>::~Resource() {} // 2,3671 672void instantiate_template() {673 Resource<int> x;674}675)cpp");676 677 auto AST = tooling::buildASTFromCode(Code.code());678 ASTContext &Ctx = AST->getASTContext();679 680 const auto &SM = Ctx.getSourceManager();681 auto GetNameInfoRange = [&SM](const BoundNodes &Match) {682 const auto *D = Match.getNodeAs<CXXDestructorDecl>("dtor");683 return D->getNameInfo().getSourceRange().printToString(SM);684 };685 686 auto Matches = match(findAll(cxxDestructorDecl().bind("dtor")),687 *Ctx.getTranslationUnitDecl(), Ctx);688 ASSERT_EQ(Matches.size(), 3U);689 EXPECT_EQ(GetNameInfoRange(Matches[0]), "<input.cc:3:3, col:4>");690 EXPECT_EQ(GetNameInfoRange(Matches[1]), "<input.cc:6:14, col:15>");691 EXPECT_EQ(GetNameInfoRange(Matches[2]), "<input.cc:6:14, col:15>");692}693 694TEST(Decl, getQualifiedNameAsString) {695 llvm::Annotations Code(R"cpp(696namespace x::y {697 template <class T> class Foo { Foo() {} };698}699)cpp");700 701 auto AST = tooling::buildASTFromCode(Code.code());702 ASTContext &Ctx = AST->getASTContext();703 704 auto const *FD = selectFirst<CXXConstructorDecl>(705 "ctor", match(cxxConstructorDecl().bind("ctor"), Ctx));706 ASSERT_NE(FD, nullptr);707 ASSERT_EQ(FD->getQualifiedNameAsString(), "x::y::Foo::Foo<T>");708}709 710TEST(Decl, NoWrittenArgsInImplicitlyInstantiatedVarSpec) {711 const char *Code = R"cpp(712 template <typename>713 int VarTpl;714 715 void fn() {716 (void)VarTpl<char>;717 }718 )cpp";719 720 auto AST = tooling::buildASTFromCode(Code);721 ASTContext &Ctx = AST->getASTContext();722 723 const auto *VTSD = selectFirst<VarTemplateSpecializationDecl>(724 "id", match(varDecl(isTemplateInstantiation()).bind("id"), Ctx));725 ASSERT_NE(VTSD, nullptr);726 EXPECT_EQ(VTSD->getTemplateArgsAsWritten(), nullptr);727}728