llvm-project

Форк
0
/
ASTTraverserTest.cpp 
1935 строк · 42.5 Кб
1
//===- unittests/AST/ASTTraverserTest.h------------------------------------===//
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/ASTContext.h"
10
#include "clang/AST/ASTNodeTraverser.h"
11
#include "clang/AST/TextNodeDumper.h"
12
#include "clang/ASTMatchers/ASTMatchFinder.h"
13
#include "clang/ASTMatchers/ASTMatchers.h"
14
#include "clang/Tooling/Tooling.h"
15
#include "gmock/gmock.h"
16
#include "gtest/gtest.h"
17

18
using namespace clang::tooling;
19
using namespace clang::ast_matchers;
20

21
namespace clang {
22

23
class NodeTreePrinter : public TextTreeStructure {
24
  llvm::raw_ostream &OS;
25

26
public:
27
  NodeTreePrinter(llvm::raw_ostream &OS)
28
      : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
29

30
  void Visit(const Decl *D) {
31
    OS << D->getDeclKindName() << "Decl";
32
    if (auto *ND = dyn_cast<NamedDecl>(D)) {
33
      OS << " '" << ND->getDeclName() << "'";
34
    }
35
  }
36

37
  void Visit(const Stmt *S) {
38
    if (!S) {
39
      OS << "<<<NULL>>>";
40
      return;
41
    }
42
    OS << S->getStmtClassName();
43
    if (auto *E = dyn_cast<DeclRefExpr>(S)) {
44
      OS << " '" << E->getDecl()->getDeclName() << "'";
45
    }
46
  }
47

48
  void Visit(QualType QT) {
49
    OS << "QualType " << QT.split().Quals.getAsString();
50
  }
51

52
  void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }
53

54
  void Visit(const comments::Comment *C, const comments::FullComment *FC) {
55
    OS << C->getCommentKindName();
56
  }
57

58
  void Visit(const CXXCtorInitializer *Init) {
59
    OS << "CXXCtorInitializer";
60
    if (const auto *F = Init->getAnyMember()) {
61
      OS << " '" << F->getNameAsString() << "'";
62
    } else if (auto const *TSI = Init->getTypeSourceInfo()) {
63
      OS << " '" << TSI->getType() << "'";
64
    }
65
  }
66

67
  void Visit(const Attr *A) {
68
    switch (A->getKind()) {
69
#define ATTR(X)                                                                \
70
  case attr::X:                                                                \
71
    OS << #X;                                                                  \
72
    break;
73
#include "clang/Basic/AttrList.inc"
74
    }
75
    OS << "Attr";
76
  }
77

78
  void Visit(const OMPClause *C) { OS << "OMPClause"; }
79
  void Visit(const TemplateArgument &A, SourceRange R = {},
80
             const Decl *From = nullptr, const char *Label = nullptr) {
81
    OS << "TemplateArgument";
82
    switch (A.getKind()) {
83
    case TemplateArgument::Type: {
84
      OS << " type " << A.getAsType();
85
      break;
86
    }
87
    default:
88
      break;
89
    }
90
  }
91

92
  template <typename... T> void Visit(T...) {}
93
};
94

95
class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {
96

97
  NodeTreePrinter MyNodeRecorder;
98

99
public:
100
  TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}
101
  NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }
102
};
103

104
template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {
105
  std::string Buffer;
106
  llvm::raw_string_ostream OS(Buffer);
107

108
  TestASTDumper Dumper(OS);
109

110
  OS << "\n";
111

112
  Dumper.Visit(std::forward<NodeType &&>(N)...);
113

114
  return Buffer;
115
}
116

117
template <typename... NodeType>
118
std::string dumpASTString(TraversalKind TK, NodeType &&... N) {
119
  std::string Buffer;
120
  llvm::raw_string_ostream OS(Buffer);
121

122
  TestASTDumper Dumper(OS);
123
  Dumper.SetTraversalKind(TK);
124

125
  OS << "\n";
126

127
  Dumper.Visit(std::forward<NodeType &&>(N)...);
128

129
  return Buffer;
130
}
131

132
const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
133
                                    const std::string &Name) {
134
  auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),
135
                                    AST->getASTContext());
136
  EXPECT_EQ(Result.size(), 1u);
137
  return Result[0].getNodeAs<FunctionDecl>("fn");
138
}
139

140
template <typename T> struct Verifier {
141
  static void withDynNode(T Node, const std::string &DumpString) {
142
    EXPECT_EQ(dumpASTString(DynTypedNode::create(Node)), DumpString);
143
  }
144
};
145

146
template <typename T> struct Verifier<T *> {
147
  static void withDynNode(T *Node, const std::string &DumpString) {
148
    EXPECT_EQ(dumpASTString(DynTypedNode::create(*Node)), DumpString);
149
  }
150
};
151

152
template <typename T>
153
void verifyWithDynNode(T Node, const std::string &DumpString) {
154
  EXPECT_EQ(dumpASTString(Node), DumpString);
155

156
  Verifier<T>::withDynNode(Node, DumpString);
157
}
158

159
TEST(Traverse, Dump) {
160

161
  auto AST = buildASTFromCode(R"cpp(
162
struct A {
163
  int m_number;
164

165
  /// CTor
166
  A() : m_number(42) {}
167

168
  [[nodiscard]] const int func() {
169
    return 42;
170
  }
171

172
};
173

174
template<typename T>
175
struct templ
176
{
177
};
178

179
template<>
180
struct templ<int>
181
{
182
};
183

184
void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
185

186
)cpp");
187

188
  const FunctionDecl *Func = getFunctionNode(AST.get(), "func");
189

190
  verifyWithDynNode(Func,
191
                    R"cpp(
192
CXXMethodDecl 'func'
193
|-CompoundStmt
194
| `-ReturnStmt
195
|   `-IntegerLiteral
196
`-WarnUnusedResultAttr
197
)cpp");
198

199
  Stmt *Body = Func->getBody();
200

201
  verifyWithDynNode(Body,
202
                    R"cpp(
203
CompoundStmt
204
`-ReturnStmt
205
  `-IntegerLiteral
206
)cpp");
207

208
  QualType QT = Func->getType();
209

210
  verifyWithDynNode(QT,
211
                    R"cpp(
212
FunctionProtoType
213
`-QualType const
214
  `-BuiltinType
215
)cpp");
216

217
  const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");
218

219
  verifyWithDynNode(CTorFunc->getType(),
220
                    R"cpp(
221
FunctionProtoType
222
`-BuiltinType
223
)cpp");
224

225
  Attr *A = *Func->attr_begin();
226

227
  {
228
    std::string expectedString = R"cpp(
229
WarnUnusedResultAttr
230
)cpp";
231

232
    EXPECT_EQ(dumpASTString(A), expectedString);
233
  }
234

235
  auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);
236
  const CXXCtorInitializer *Init = *CTor->init_begin();
237

238
  verifyWithDynNode(Init,
239
                    R"cpp(
240
CXXCtorInitializer 'm_number'
241
`-IntegerLiteral
242
)cpp");
243

244
  const comments::FullComment *Comment =
245
      AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);
246
  {
247
    std::string expectedString = R"cpp(
248
FullComment
249
`-ParagraphComment
250
  `-TextComment
251
)cpp";
252
    EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);
253
  }
254

255
  auto Result = ast_matchers::match(
256
      classTemplateSpecializationDecl(hasName("templ")).bind("fn"),
257
      AST->getASTContext());
258
  EXPECT_EQ(Result.size(), 1u);
259
  auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");
260

261
  TemplateArgument TA = Templ->getTemplateArgs()[0];
262

263
  verifyWithDynNode(TA,
264
                    R"cpp(
265
TemplateArgument type int
266
`-BuiltinType
267
)cpp");
268

269
  Func = getFunctionNode(AST.get(), "parmvardecl_attr");
270

271
  const auto *Parm = Func->getParamDecl(0);
272
  const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();
273
  ASSERT_TRUE(TL.getType()->isPointerType());
274

275
  const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>();
276
  const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr());
277
  EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())),
278
            19u);
279
}
280

281
TEST(Traverse, IgnoreUnlessSpelledInSourceVars) {
282

283
  auto AST = buildASTFromCodeWithArgs(R"cpp(
284

285
struct String
286
{
287
    String(const char*, int = -1) {}
288

289
    int overloaded() const;
290
    int& overloaded();
291
};
292

293
void stringConstruct()
294
{
295
    String s = "foo";
296
    s = "bar";
297
}
298

299
void overloadCall()
300
{
301
   String s = "foo";
302
   (s).overloaded();
303
}
304

305
struct C1 {};
306
struct C2 { operator C1(); };
307

308
void conversionOperator()
309
{
310
    C2* c2;
311
    C1 c1 = (*c2);
312
}
313

314
template <unsigned alignment>
315
void template_test() {
316
  static_assert(alignment, "");
317
}
318
void actual_template_test() {
319
  template_test<4>();
320
}
321

322
struct OneParamCtor {
323
  explicit OneParamCtor(int);
324
};
325
struct TwoParamCtor {
326
  explicit TwoParamCtor(int, int);
327
};
328

329
void varDeclCtors() {
330
  {
331
  auto var1 = OneParamCtor(5);
332
  auto var2 = TwoParamCtor(6, 7);
333
  }
334
  {
335
  OneParamCtor var3(5);
336
  TwoParamCtor var4(6, 7);
337
  }
338
  int i = 0;
339
  {
340
  auto var5 = OneParamCtor(i);
341
  auto var6 = TwoParamCtor(i, 7);
342
  }
343
  {
344
  OneParamCtor var7(i);
345
  TwoParamCtor var8(i, 7);
346
  }
347
}
348

349
)cpp", {"-std=c++14"});
350

351
  {
352
    auto FN =
353
        ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"),
354
                            AST->getASTContext());
355
    EXPECT_EQ(FN.size(), 1u);
356

357
    EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),
358
              R"cpp(
359
FunctionDecl 'stringConstruct'
360
`-CompoundStmt
361
  |-DeclStmt
362
  | `-VarDecl 's'
363
  |   `-ExprWithCleanups
364
  |     `-CXXConstructExpr
365
  |       `-MaterializeTemporaryExpr
366
  |         `-ImplicitCastExpr
367
  |           `-CXXConstructExpr
368
  |             |-ImplicitCastExpr
369
  |             | `-StringLiteral
370
  |             `-CXXDefaultArgExpr
371
  |               `-UnaryOperator
372
  |                 `-IntegerLiteral
373
  `-ExprWithCleanups
374
    `-CXXOperatorCallExpr
375
      |-ImplicitCastExpr
376
      | `-DeclRefExpr 'operator='
377
      |-DeclRefExpr 's'
378
      `-MaterializeTemporaryExpr
379
        `-CXXConstructExpr
380
          |-ImplicitCastExpr
381
          | `-StringLiteral
382
          `-CXXDefaultArgExpr
383
            `-UnaryOperator
384
              `-IntegerLiteral
385
)cpp");
386

387
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
388
                            FN[0].getNodeAs<Decl>("fn")),
389
              R"cpp(
390
FunctionDecl 'stringConstruct'
391
`-CompoundStmt
392
  |-DeclStmt
393
  | `-VarDecl 's'
394
  |   `-StringLiteral
395
  `-CXXOperatorCallExpr
396
    |-DeclRefExpr 'operator='
397
    |-DeclRefExpr 's'
398
    `-StringLiteral
399
)cpp");
400
  }
401

402
  {
403
    auto FN =
404
        ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),
405
                            AST->getASTContext());
406
    EXPECT_EQ(FN.size(), 1u);
407

408
    EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),
409
              R"cpp(
410
FunctionDecl 'overloadCall'
411
`-CompoundStmt
412
  |-DeclStmt
413
  | `-VarDecl 's'
414
  |   `-ExprWithCleanups
415
  |     `-CXXConstructExpr
416
  |       `-MaterializeTemporaryExpr
417
  |         `-ImplicitCastExpr
418
  |           `-CXXConstructExpr
419
  |             |-ImplicitCastExpr
420
  |             | `-StringLiteral
421
  |             `-CXXDefaultArgExpr
422
  |               `-UnaryOperator
423
  |                 `-IntegerLiteral
424
  `-CXXMemberCallExpr
425
    `-MemberExpr
426
      `-ParenExpr
427
        `-DeclRefExpr 's'
428
)cpp");
429

430
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
431
                            FN[0].getNodeAs<Decl>("fn")),
432
              R"cpp(
433
FunctionDecl 'overloadCall'
434
`-CompoundStmt
435
  |-DeclStmt
436
  | `-VarDecl 's'
437
  |   `-StringLiteral
438
  `-CXXMemberCallExpr
439
    `-MemberExpr
440
      `-DeclRefExpr 's'
441
)cpp");
442
  }
443

444
  {
445
    auto FN = ast_matchers::match(
446
        functionDecl(hasName("conversionOperator"),
447
                     hasDescendant(varDecl(hasName("c1")).bind("var"))),
448
        AST->getASTContext());
449
    EXPECT_EQ(FN.size(), 1u);
450

451
    EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("var")),
452
              R"cpp(
453
VarDecl 'c1'
454
`-ExprWithCleanups
455
  `-CXXConstructExpr
456
    `-MaterializeTemporaryExpr
457
      `-ImplicitCastExpr
458
        `-CXXMemberCallExpr
459
          `-MemberExpr
460
            `-ParenExpr
461
              `-UnaryOperator
462
                `-ImplicitCastExpr
463
                  `-DeclRefExpr 'c2'
464
)cpp");
465

466
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
467
                            FN[0].getNodeAs<Decl>("var")),
468
              R"cpp(
469
VarDecl 'c1'
470
`-UnaryOperator
471
  `-DeclRefExpr 'c2'
472
)cpp");
473
  }
474

475
  {
476
    auto FN = ast_matchers::match(
477
        functionDecl(hasName("template_test"),
478
                     hasDescendant(staticAssertDecl().bind("staticAssert"))),
479
        AST->getASTContext());
480
    EXPECT_EQ(FN.size(), 2u);
481

482
    EXPECT_EQ(dumpASTString(TK_AsIs, FN[1].getNodeAs<Decl>("staticAssert")),
483
              R"cpp(
484
StaticAssertDecl
485
|-ImplicitCastExpr
486
| `-SubstNonTypeTemplateParmExpr
487
|   |-NonTypeTemplateParmDecl 'alignment'
488
|   `-IntegerLiteral
489
`-StringLiteral
490
)cpp");
491

492
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
493
                            FN[1].getNodeAs<Decl>("staticAssert")),
494
              R"cpp(
495
StaticAssertDecl
496
|-IntegerLiteral
497
`-StringLiteral
498
)cpp");
499
  }
500

501
  auto varChecker = [&AST](StringRef varName, StringRef SemanticDump,
502
                           StringRef SyntacticDump) {
503
    auto FN = ast_matchers::match(
504
        functionDecl(
505
            hasName("varDeclCtors"),
506
            forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))),
507
        AST->getASTContext());
508
    EXPECT_EQ(FN.size(), 1u);
509

510
    EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")),
511
              SemanticDump);
512

513
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
514
                            FN[0].getNodeAs<Decl>("varDeclCtor")),
515
              SyntacticDump);
516
  };
517

518
  varChecker("var1",
519
             R"cpp(
520
VarDecl 'var1'
521
`-ExprWithCleanups
522
  `-CXXConstructExpr
523
    `-MaterializeTemporaryExpr
524
      `-CXXFunctionalCastExpr
525
        `-CXXConstructExpr
526
          `-IntegerLiteral
527
)cpp",
528
             R"cpp(
529
VarDecl 'var1'
530
`-CXXConstructExpr
531
  `-IntegerLiteral
532
)cpp");
533

534
  varChecker("var2",
535
             R"cpp(
536
VarDecl 'var2'
537
`-ExprWithCleanups
538
  `-CXXConstructExpr
539
    `-MaterializeTemporaryExpr
540
      `-CXXTemporaryObjectExpr
541
        |-IntegerLiteral
542
        `-IntegerLiteral
543
)cpp",
544
             R"cpp(
545
VarDecl 'var2'
546
`-CXXTemporaryObjectExpr
547
  |-IntegerLiteral
548
  `-IntegerLiteral
549
)cpp");
550

551
  varChecker("var3",
552
             R"cpp(
553
VarDecl 'var3'
554
`-CXXConstructExpr
555
  `-IntegerLiteral
556
)cpp",
557
             R"cpp(
558
VarDecl 'var3'
559
`-CXXConstructExpr
560
  `-IntegerLiteral
561
)cpp");
562

563
  varChecker("var4",
564
             R"cpp(
565
VarDecl 'var4'
566
`-CXXConstructExpr
567
  |-IntegerLiteral
568
  `-IntegerLiteral
569
)cpp",
570
             R"cpp(
571
VarDecl 'var4'
572
`-CXXConstructExpr
573
  |-IntegerLiteral
574
  `-IntegerLiteral
575
)cpp");
576

577
  varChecker("var5",
578
             R"cpp(
579
VarDecl 'var5'
580
`-ExprWithCleanups
581
  `-CXXConstructExpr
582
    `-MaterializeTemporaryExpr
583
      `-CXXFunctionalCastExpr
584
        `-CXXConstructExpr
585
          `-ImplicitCastExpr
586
            `-DeclRefExpr 'i'
587
)cpp",
588
             R"cpp(
589
VarDecl 'var5'
590
`-CXXConstructExpr
591
  `-DeclRefExpr 'i'
592
)cpp");
593

594
  varChecker("var6",
595
             R"cpp(
596
VarDecl 'var6'
597
`-ExprWithCleanups
598
  `-CXXConstructExpr
599
    `-MaterializeTemporaryExpr
600
      `-CXXTemporaryObjectExpr
601
        |-ImplicitCastExpr
602
        | `-DeclRefExpr 'i'
603
        `-IntegerLiteral
604
)cpp",
605
             R"cpp(
606
VarDecl 'var6'
607
`-CXXTemporaryObjectExpr
608
  |-DeclRefExpr 'i'
609
  `-IntegerLiteral
610
)cpp");
611

612
  varChecker("var7",
613
             R"cpp(
614
VarDecl 'var7'
615
`-CXXConstructExpr
616
  `-ImplicitCastExpr
617
    `-DeclRefExpr 'i'
618
)cpp",
619
             R"cpp(
620
VarDecl 'var7'
621
`-CXXConstructExpr
622
  `-DeclRefExpr 'i'
623
)cpp");
624

625
  varChecker("var8",
626
             R"cpp(
627
VarDecl 'var8'
628
`-CXXConstructExpr
629
  |-ImplicitCastExpr
630
  | `-DeclRefExpr 'i'
631
  `-IntegerLiteral
632
)cpp",
633
             R"cpp(
634
VarDecl 'var8'
635
`-CXXConstructExpr
636
  |-DeclRefExpr 'i'
637
  `-IntegerLiteral
638
)cpp");
639
}
640

641
TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) {
642
  auto AST = buildASTFromCode(R"cpp(
643

644
struct MyStruct {
645
  MyStruct();
646
  MyStruct(int i) {
647
    MyStruct();
648
  }
649
  ~MyStruct();
650
};
651

652
)cpp");
653

654
  auto BN = ast_matchers::match(
655
      cxxConstructorDecl(hasName("MyStruct"),
656
                         hasParameter(0, parmVarDecl(hasType(isInteger()))))
657
          .bind("ctor"),
658
      AST->getASTContext());
659
  EXPECT_EQ(BN.size(), 1u);
660

661
  EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
662
                          BN[0].getNodeAs<Decl>("ctor")),
663
            R"cpp(
664
CXXConstructorDecl 'MyStruct'
665
|-ParmVarDecl 'i'
666
`-CompoundStmt
667
  `-CXXTemporaryObjectExpr
668
)cpp");
669

670
  EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("ctor")),
671
            R"cpp(
672
CXXConstructorDecl 'MyStruct'
673
|-ParmVarDecl 'i'
674
`-CompoundStmt
675
  `-ExprWithCleanups
676
    `-CXXBindTemporaryExpr
677
      `-CXXTemporaryObjectExpr
678
)cpp");
679
}
680

681
TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) {
682

683
  auto AST = buildASTFromCode(R"cpp(
684
struct Retval {
685
  Retval() {}
686
  ~Retval() {}
687
};
688

689
Retval someFun();
690

691
void foo()
692
{
693
    someFun();
694
}
695
)cpp");
696

697
  auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),
698
                                AST->getASTContext());
699
  EXPECT_EQ(BN.size(), 1u);
700

701
  EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
702
                          BN[0].getNodeAs<Decl>("fn")),
703
            R"cpp(
704
FunctionDecl 'foo'
705
`-CompoundStmt
706
  `-CallExpr
707
    `-DeclRefExpr 'someFun'
708
)cpp");
709

710
  EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
711
            R"cpp(
712
FunctionDecl 'foo'
713
`-CompoundStmt
714
  `-ExprWithCleanups
715
    `-CXXBindTemporaryExpr
716
      `-CallExpr
717
        `-ImplicitCastExpr
718
          `-DeclRefExpr 'someFun'
719
)cpp");
720
}
721

722
TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) {
723

724
  auto AST = buildASTFromCodeWithArgs(R"cpp(
725

726
struct A
727
{
728
};
729

730
struct B
731
{
732
  B(int);
733
  B(A const& a);
734
  B();
735
};
736

737
struct C
738
{
739
  operator B();
740
};
741

742
B func1() {
743
  return 42;
744
}
745

746
B func2() {
747
  return B{42};
748
}
749

750
B func3() {
751
  return B(42);
752
}
753

754
B func4() {
755
  return B();
756
}
757

758
B func5() {
759
  return B{};
760
}
761

762
B func6() {
763
  return C();
764
}
765

766
B func7() {
767
  return A();
768
}
769

770
B func8() {
771
  return C{};
772
}
773

774
B func9() {
775
  return A{};
776
}
777

778
B func10() {
779
  A a;
780
  return a;
781
}
782

783
B func11() {
784
  B b;
785
  return b;
786
}
787

788
B func12() {
789
  C c;
790
  return c;
791
}
792

793
)cpp", {"-std=c++14"});
794

795
  auto getFunctionNode = [&AST](const std::string &name) {
796
    auto BN = ast_matchers::match(functionDecl(hasName(name)).bind("fn"),
797
                                  AST->getASTContext());
798
    EXPECT_EQ(BN.size(), 1u);
799
    return BN[0].getNodeAs<Decl>("fn");
800
  };
801

802
  {
803
    auto FN = getFunctionNode("func1");
804
    llvm::StringRef Expected = R"cpp(
805
FunctionDecl 'func1'
806
`-CompoundStmt
807
  `-ReturnStmt
808
    `-ExprWithCleanups
809
      `-CXXConstructExpr
810
        `-MaterializeTemporaryExpr
811
          `-ImplicitCastExpr
812
            `-CXXConstructExpr
813
              `-IntegerLiteral
814
)cpp";
815

816
    EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected);
817

818
    Expected = R"cpp(
819
FunctionDecl 'func1'
820
`-CompoundStmt
821
  `-ReturnStmt
822
    `-IntegerLiteral
823
)cpp";
824
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected);
825
  }
826

827
  llvm::StringRef Expected = R"cpp(
828
FunctionDecl 'func2'
829
`-CompoundStmt
830
  `-ReturnStmt
831
    `-CXXTemporaryObjectExpr
832
      `-IntegerLiteral
833
)cpp";
834
  EXPECT_EQ(
835
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func2")),
836
      Expected);
837

838
  Expected = R"cpp(
839
FunctionDecl 'func3'
840
`-CompoundStmt
841
  `-ReturnStmt
842
    `-CXXConstructExpr
843
      `-IntegerLiteral
844
)cpp";
845
  EXPECT_EQ(
846
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func3")),
847
      Expected);
848

849
  Expected = R"cpp(
850
FunctionDecl 'func4'
851
`-CompoundStmt
852
  `-ReturnStmt
853
    `-CXXTemporaryObjectExpr
854
)cpp";
855
  EXPECT_EQ(
856
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func4")),
857
      Expected);
858

859
  Expected = R"cpp(
860
FunctionDecl 'func5'
861
`-CompoundStmt
862
  `-ReturnStmt
863
    `-CXXTemporaryObjectExpr
864
)cpp";
865
  EXPECT_EQ(
866
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func5")),
867
      Expected);
868

869
  Expected = R"cpp(
870
FunctionDecl 'func6'
871
`-CompoundStmt
872
  `-ReturnStmt
873
    `-CXXTemporaryObjectExpr
874
)cpp";
875
  EXPECT_EQ(
876
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func6")),
877
      Expected);
878

879
  Expected = R"cpp(
880
FunctionDecl 'func7'
881
`-CompoundStmt
882
  `-ReturnStmt
883
    `-CXXTemporaryObjectExpr
884
)cpp";
885
  EXPECT_EQ(
886
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func7")),
887
      Expected);
888

889
  Expected = R"cpp(
890
FunctionDecl 'func8'
891
`-CompoundStmt
892
  `-ReturnStmt
893
    `-CXXFunctionalCastExpr
894
      `-InitListExpr
895
)cpp";
896
  EXPECT_EQ(
897
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func8")),
898
      Expected);
899

900
  Expected = R"cpp(
901
FunctionDecl 'func9'
902
`-CompoundStmt
903
  `-ReturnStmt
904
    `-CXXFunctionalCastExpr
905
      `-InitListExpr
906
)cpp";
907
  EXPECT_EQ(
908
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func9")),
909
      Expected);
910

911
  Expected = R"cpp(
912
FunctionDecl 'func10'
913
`-CompoundStmt
914
  |-DeclStmt
915
  | `-VarDecl 'a'
916
  |   `-CXXConstructExpr
917
  `-ReturnStmt
918
    `-DeclRefExpr 'a'
919
)cpp";
920
  EXPECT_EQ(
921
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func10")),
922
      Expected);
923

924
  Expected = R"cpp(
925
FunctionDecl 'func11'
926
`-CompoundStmt
927
  |-DeclStmt
928
  | `-VarDecl 'b'
929
  |   `-CXXConstructExpr
930
  `-ReturnStmt
931
    `-DeclRefExpr 'b'
932
)cpp";
933
  EXPECT_EQ(
934
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func11")),
935
      Expected);
936

937
  Expected = R"cpp(
938
FunctionDecl 'func12'
939
`-CompoundStmt
940
  |-DeclStmt
941
  | `-VarDecl 'c'
942
  |   `-CXXConstructExpr
943
  `-ReturnStmt
944
    `-DeclRefExpr 'c'
945
)cpp";
946
  EXPECT_EQ(
947
      dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func12")),
948
      Expected);
949
}
950

951
TEST(Traverse, LambdaUnlessSpelledInSource) {
952

953
  auto AST =
954
      buildASTFromCodeWithArgs(R"cpp(
955

956
void captures() {
957
  int a = 0;
958
  int b = 0;
959
  int d = 0;
960
  int f = 0;
961

962
  [a, &b, c = d, &e = f](int g, int h = 42) {};
963
}
964

965
void templated() {
966
  int a = 0;
967
  [a]<typename T>(T t) {};
968
}
969

970
struct SomeStruct {
971
    int a = 0;
972
    void capture_this() {
973
        [this]() {};
974
    }
975
    void capture_this_copy() {
976
        [self = *this]() {};
977
    }
978
};
979
)cpp",
980
                               {"-Wno-unused-value", "-Wno-c++2a-extensions"});
981

982
  auto getLambdaNode = [&AST](const std::string &name) {
983
    auto BN = ast_matchers::match(
984
        lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),
985
        AST->getASTContext());
986
    EXPECT_EQ(BN.size(), 1u);
987
    return BN[0].getNodeAs<LambdaExpr>("lambda");
988
  };
989

990
  {
991
    auto L = getLambdaNode("captures");
992

993
    llvm::StringRef Expected = R"cpp(
994
LambdaExpr
995
|-DeclRefExpr 'a'
996
|-DeclRefExpr 'b'
997
|-VarDecl 'c'
998
| `-DeclRefExpr 'd'
999
|-VarDecl 'e'
1000
| `-DeclRefExpr 'f'
1001
|-ParmVarDecl 'g'
1002
|-ParmVarDecl 'h'
1003
| `-IntegerLiteral
1004
`-CompoundStmt
1005
)cpp";
1006
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1007

1008
    Expected = R"cpp(
1009
LambdaExpr
1010
|-CXXRecordDecl ''
1011
| |-CXXMethodDecl 'operator()'
1012
| | |-ParmVarDecl 'g'
1013
| | |-ParmVarDecl 'h'
1014
| | | `-IntegerLiteral
1015
| | `-CompoundStmt
1016
| |-FieldDecl ''
1017
| |-FieldDecl ''
1018
| |-FieldDecl ''
1019
| |-FieldDecl ''
1020
| `-CXXDestructorDecl '~(lambda at input.cc:9:3)'
1021
|-ImplicitCastExpr
1022
| `-DeclRefExpr 'a'
1023
|-DeclRefExpr 'b'
1024
|-ImplicitCastExpr
1025
| `-DeclRefExpr 'd'
1026
|-DeclRefExpr 'f'
1027
`-CompoundStmt
1028
)cpp";
1029
    EXPECT_EQ(dumpASTString(TK_AsIs, L), Expected);
1030
  }
1031

1032
  {
1033
    auto L = getLambdaNode("templated");
1034

1035
    llvm::StringRef Expected = R"cpp(
1036
LambdaExpr
1037
|-DeclRefExpr 'a'
1038
|-TemplateTypeParmDecl 'T'
1039
|-ParmVarDecl 't'
1040
`-CompoundStmt
1041
)cpp";
1042
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1043
  }
1044

1045
  {
1046
    auto L = getLambdaNode("capture_this");
1047

1048
    llvm::StringRef Expected = R"cpp(
1049
LambdaExpr
1050
|-CXXThisExpr
1051
`-CompoundStmt
1052
)cpp";
1053
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1054
  }
1055

1056
  {
1057
    auto L = getLambdaNode("capture_this_copy");
1058

1059
    llvm::StringRef Expected = R"cpp(
1060
LambdaExpr
1061
|-VarDecl 'self'
1062
| `-UnaryOperator
1063
|   `-CXXThisExpr
1064
`-CompoundStmt
1065
)cpp";
1066
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1067
  }
1068
}
1069

1070
TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {
1071
  {
1072
    auto AST = buildASTFromCode(R"cpp(
1073
int i = 0;
1074
)cpp");
1075
    const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();
1076

1077
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),
1078
              R"cpp(
1079
TranslationUnitDecl
1080
`-VarDecl 'i'
1081
  `-IntegerLiteral
1082
)cpp");
1083
  }
1084

1085
  auto AST2 = buildASTFromCodeWithArgs(R"cpp(
1086
struct Simple {
1087
};
1088
struct Other {
1089
};
1090

1091
struct Record : Simple, Other {
1092
  Record() : Simple(), m_i(42) {}
1093
private:
1094
  int m_i;
1095
  int m_i2 = 42;
1096
  Simple m_s;
1097
};
1098

1099
struct NonTrivial {
1100
    NonTrivial() {}
1101
    NonTrivial(NonTrivial&) {}
1102
    NonTrivial& operator=(NonTrivial&) { return *this; }
1103

1104
    ~NonTrivial() {}
1105
};
1106

1107
struct ContainsArray {
1108
    NonTrivial arr[2];
1109
    int irr[2];
1110
    ContainsArray& operator=(ContainsArray &) = default;
1111
};
1112

1113
void copyIt()
1114
{
1115
    ContainsArray ca;
1116
    ContainsArray ca2;
1117
    ca2 = ca;
1118
}
1119

1120
void forLoop()
1121
{
1122
    int arr[2];
1123
    for (auto i : arr)
1124
    {
1125

1126
    }
1127
    for (auto& a = arr; auto i : a)
1128
    {
1129

1130
    }
1131
}
1132

1133
struct DefaultedAndDeleted {
1134
  NonTrivial nt;
1135
  DefaultedAndDeleted() = default;
1136
  ~DefaultedAndDeleted() = default;
1137
  DefaultedAndDeleted(DefaultedAndDeleted &) = default;
1138
  DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
1139
  DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
1140
  DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
1141
};
1142

1143
void copyIt2()
1144
{
1145
    DefaultedAndDeleted ca;
1146
    DefaultedAndDeleted ca2;
1147
    ca2 = ca;
1148
}
1149

1150
void hasDefaultArg(int i, int j = 0)
1151
{
1152
}
1153
void callDefaultArg()
1154
{
1155
  hasDefaultArg(42);
1156
}
1157

1158
void decomposition()
1159
{
1160
    int arr[3];
1161
    auto &[f, s, t] = arr;
1162

1163
    f = 42;
1164
}
1165

1166
typedef __typeof(sizeof(int)) size_t;
1167

1168
struct Pair
1169
{
1170
    int x, y;
1171
};
1172

1173
// Note: these utilities are required to force binding to tuple like structure
1174
namespace std
1175
{
1176
    template <typename E>
1177
    struct tuple_size
1178
    {
1179
    };
1180

1181
    template <>
1182
    struct tuple_size<Pair>
1183
    {
1184
        static constexpr size_t value = 2;
1185
    };
1186

1187
    template <size_t I, class T>
1188
    struct tuple_element
1189
    {
1190
        using type = int;
1191
    };
1192

1193
};
1194

1195
template <size_t I>
1196
int &&get(Pair &&p);
1197

1198
void decompTuple()
1199
{
1200
    Pair p{1, 2};
1201
    auto [a, b] = p;
1202

1203
    a = 3;
1204
}
1205

1206
)cpp",
1207
                                       {"-std=c++20"});
1208

1209
  {
1210
    auto BN = ast_matchers::match(
1211
        cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1212
        AST2->getASTContext());
1213
    EXPECT_EQ(BN.size(), 1u);
1214

1215
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1216
              R"cpp(
1217
CXXRecordDecl 'Record'
1218
|-CXXRecordDecl 'Record'
1219
|-CXXConstructorDecl 'Record'
1220
| |-CXXCtorInitializer 'Simple'
1221
| | `-CXXConstructExpr
1222
| |-CXXCtorInitializer 'Other'
1223
| | `-CXXConstructExpr
1224
| |-CXXCtorInitializer 'm_i'
1225
| | `-IntegerLiteral
1226
| |-CXXCtorInitializer 'm_i2'
1227
| | `-CXXDefaultInitExpr
1228
| |   `-IntegerLiteral
1229
| |-CXXCtorInitializer 'm_s'
1230
| | `-CXXConstructExpr
1231
| `-CompoundStmt
1232
|-AccessSpecDecl
1233
|-FieldDecl 'm_i'
1234
|-FieldDecl 'm_i2'
1235
| `-IntegerLiteral
1236
`-FieldDecl 'm_s'
1237
)cpp");
1238

1239
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1240
                            BN[0].getNodeAs<Decl>("rec")),
1241
              R"cpp(
1242
CXXRecordDecl 'Record'
1243
|-CXXConstructorDecl 'Record'
1244
| |-CXXCtorInitializer 'Simple'
1245
| | `-CXXConstructExpr
1246
| |-CXXCtorInitializer 'm_i'
1247
| | `-IntegerLiteral
1248
| `-CompoundStmt
1249
|-AccessSpecDecl
1250
|-FieldDecl 'm_i'
1251
|-FieldDecl 'm_i2'
1252
| `-IntegerLiteral
1253
`-FieldDecl 'm_s'
1254
)cpp");
1255
  }
1256
  {
1257
    auto BN = ast_matchers::match(
1258
        cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1259
            .bind("rec"),
1260
        AST2->getASTContext());
1261
    EXPECT_EQ(BN.size(), 1u);
1262

1263
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1264
              R"cpp(
1265
CXXRecordDecl 'ContainsArray'
1266
|-CXXRecordDecl 'ContainsArray'
1267
|-FieldDecl 'arr'
1268
|-FieldDecl 'irr'
1269
|-CXXMethodDecl 'operator='
1270
| |-ParmVarDecl ''
1271
| `-CompoundStmt
1272
|   |-ForStmt
1273
|   | |-DeclStmt
1274
|   | | `-VarDecl '__i0'
1275
|   | |   `-IntegerLiteral
1276
|   | |-<<<NULL>>>
1277
|   | |-BinaryOperator
1278
|   | | |-ImplicitCastExpr
1279
|   | | | `-DeclRefExpr '__i0'
1280
|   | | `-IntegerLiteral
1281
|   | |-UnaryOperator
1282
|   | | `-DeclRefExpr '__i0'
1283
|   | `-CXXMemberCallExpr
1284
|   |   |-MemberExpr
1285
|   |   | `-ArraySubscriptExpr
1286
|   |   |   |-ImplicitCastExpr
1287
|   |   |   | `-MemberExpr
1288
|   |   |   |   `-CXXThisExpr
1289
|   |   |   `-ImplicitCastExpr
1290
|   |   |     `-DeclRefExpr '__i0'
1291
|   |   `-ArraySubscriptExpr
1292
|   |     |-ImplicitCastExpr
1293
|   |     | `-MemberExpr
1294
|   |     |   `-DeclRefExpr ''
1295
|   |     `-ImplicitCastExpr
1296
|   |       `-DeclRefExpr '__i0'
1297
|   |-CallExpr
1298
|   | |-ImplicitCastExpr
1299
|   | | `-DeclRefExpr '__builtin_memcpy'
1300
|   | |-ImplicitCastExpr
1301
|   | | `-UnaryOperator
1302
|   | |   `-MemberExpr
1303
|   | |     `-CXXThisExpr
1304
|   | |-ImplicitCastExpr
1305
|   | | `-UnaryOperator
1306
|   | |   `-MemberExpr
1307
|   | |     `-DeclRefExpr ''
1308
|   | `-IntegerLiteral
1309
|   `-ReturnStmt
1310
|     `-UnaryOperator
1311
|       `-CXXThisExpr
1312
|-CXXConstructorDecl 'ContainsArray'
1313
| `-ParmVarDecl ''
1314
|-CXXDestructorDecl '~ContainsArray'
1315
| `-CompoundStmt
1316
`-CXXConstructorDecl 'ContainsArray'
1317
  |-CXXCtorInitializer 'arr'
1318
  | `-CXXConstructExpr
1319
  `-CompoundStmt
1320
)cpp");
1321

1322
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1323
                            BN[0].getNodeAs<Decl>("rec")),
1324
              R"cpp(
1325
CXXRecordDecl 'ContainsArray'
1326
|-FieldDecl 'arr'
1327
|-FieldDecl 'irr'
1328
`-CXXMethodDecl 'operator='
1329
  `-ParmVarDecl ''
1330
)cpp");
1331
  }
1332
  {
1333
    auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1334
                                  AST2->getASTContext());
1335
    EXPECT_EQ(BN.size(), 1u);
1336

1337
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),
1338
              R"cpp(
1339
FunctionDecl 'forLoop'
1340
`-CompoundStmt
1341
  |-DeclStmt
1342
  | `-VarDecl 'arr'
1343
  |-CXXForRangeStmt
1344
  | |-<<<NULL>>>
1345
  | |-DeclStmt
1346
  | | `-VarDecl '__range1'
1347
  | |   `-DeclRefExpr 'arr'
1348
  | |-DeclStmt
1349
  | | `-VarDecl '__begin1'
1350
  | |   `-ImplicitCastExpr
1351
  | |     `-DeclRefExpr '__range1'
1352
  | |-DeclStmt
1353
  | | `-VarDecl '__end1'
1354
  | |   `-BinaryOperator
1355
  | |     |-ImplicitCastExpr
1356
  | |     | `-DeclRefExpr '__range1'
1357
  | |     `-IntegerLiteral
1358
  | |-BinaryOperator
1359
  | | |-ImplicitCastExpr
1360
  | | | `-DeclRefExpr '__begin1'
1361
  | | `-ImplicitCastExpr
1362
  | |   `-DeclRefExpr '__end1'
1363
  | |-UnaryOperator
1364
  | | `-DeclRefExpr '__begin1'
1365
  | |-DeclStmt
1366
  | | `-VarDecl 'i'
1367
  | |   `-ImplicitCastExpr
1368
  | |     `-UnaryOperator
1369
  | |       `-ImplicitCastExpr
1370
  | |         `-DeclRefExpr '__begin1'
1371
  | `-CompoundStmt
1372
  `-CXXForRangeStmt
1373
    |-DeclStmt
1374
    | `-VarDecl 'a'
1375
    |   `-DeclRefExpr 'arr'
1376
    |-DeclStmt
1377
    | `-VarDecl '__range1'
1378
    |   `-DeclRefExpr 'a'
1379
    |-DeclStmt
1380
    | `-VarDecl '__begin1'
1381
    |   `-ImplicitCastExpr
1382
    |     `-DeclRefExpr '__range1'
1383
    |-DeclStmt
1384
    | `-VarDecl '__end1'
1385
    |   `-BinaryOperator
1386
    |     |-ImplicitCastExpr
1387
    |     | `-DeclRefExpr '__range1'
1388
    |     `-IntegerLiteral
1389
    |-BinaryOperator
1390
    | |-ImplicitCastExpr
1391
    | | `-DeclRefExpr '__begin1'
1392
    | `-ImplicitCastExpr
1393
    |   `-DeclRefExpr '__end1'
1394
    |-UnaryOperator
1395
    | `-DeclRefExpr '__begin1'
1396
    |-DeclStmt
1397
    | `-VarDecl 'i'
1398
    |   `-ImplicitCastExpr
1399
    |     `-UnaryOperator
1400
    |       `-ImplicitCastExpr
1401
    |         `-DeclRefExpr '__begin1'
1402
    `-CompoundStmt
1403
)cpp");
1404

1405
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1406
                            BN[0].getNodeAs<Decl>("func")),
1407
              R"cpp(
1408
FunctionDecl 'forLoop'
1409
`-CompoundStmt
1410
  |-DeclStmt
1411
  | `-VarDecl 'arr'
1412
  |-CXXForRangeStmt
1413
  | |-<<<NULL>>>
1414
  | |-VarDecl 'i'
1415
  | |-DeclRefExpr 'arr'
1416
  | `-CompoundStmt
1417
  `-CXXForRangeStmt
1418
    |-DeclStmt
1419
    | `-VarDecl 'a'
1420
    |   `-DeclRefExpr 'arr'
1421
    |-VarDecl 'i'
1422
    |-DeclRefExpr 'a'
1423
    `-CompoundStmt
1424
)cpp");
1425
  }
1426
  {
1427
    auto BN = ast_matchers::match(
1428
        cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1429
            .bind("rec"),
1430
        AST2->getASTContext());
1431
    EXPECT_EQ(BN.size(), 1u);
1432

1433
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1434
              R"cpp(
1435
CXXRecordDecl 'DefaultedAndDeleted'
1436
|-CXXRecordDecl 'DefaultedAndDeleted'
1437
|-FieldDecl 'nt'
1438
|-CXXConstructorDecl 'DefaultedAndDeleted'
1439
| |-CXXCtorInitializer 'nt'
1440
| | `-CXXConstructExpr
1441
| `-CompoundStmt
1442
|-CXXDestructorDecl '~DefaultedAndDeleted'
1443
| `-CompoundStmt
1444
|-CXXConstructorDecl 'DefaultedAndDeleted'
1445
| `-ParmVarDecl ''
1446
|-CXXMethodDecl 'operator='
1447
| |-ParmVarDecl ''
1448
| `-CompoundStmt
1449
|   |-CXXMemberCallExpr
1450
|   | |-MemberExpr
1451
|   | | `-MemberExpr
1452
|   | |   `-CXXThisExpr
1453
|   | `-MemberExpr
1454
|   |   `-DeclRefExpr ''
1455
|   `-ReturnStmt
1456
|     `-UnaryOperator
1457
|       `-CXXThisExpr
1458
|-CXXConstructorDecl 'DefaultedAndDeleted'
1459
| `-ParmVarDecl ''
1460
`-CXXMethodDecl 'operator='
1461
  `-ParmVarDecl ''
1462
)cpp");
1463

1464
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1465
                            BN[0].getNodeAs<Decl>("rec")),
1466
              R"cpp(
1467
CXXRecordDecl 'DefaultedAndDeleted'
1468
|-FieldDecl 'nt'
1469
|-CXXConstructorDecl 'DefaultedAndDeleted'
1470
|-CXXDestructorDecl '~DefaultedAndDeleted'
1471
|-CXXConstructorDecl 'DefaultedAndDeleted'
1472
| `-ParmVarDecl ''
1473
|-CXXMethodDecl 'operator='
1474
| `-ParmVarDecl ''
1475
|-CXXConstructorDecl 'DefaultedAndDeleted'
1476
| `-ParmVarDecl ''
1477
`-CXXMethodDecl 'operator='
1478
  `-ParmVarDecl ''
1479
)cpp");
1480
  }
1481
  {
1482
    auto BN = ast_matchers::match(
1483
        callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1484
            .bind("funcCall"),
1485
        AST2->getASTContext());
1486
    EXPECT_EQ(BN.size(), 1u);
1487

1488
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),
1489
              R"cpp(
1490
CallExpr
1491
|-ImplicitCastExpr
1492
| `-DeclRefExpr 'hasDefaultArg'
1493
|-IntegerLiteral
1494
`-CXXDefaultArgExpr
1495
  `-IntegerLiteral
1496
)cpp");
1497
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1498
                            BN[0].getNodeAs<CallExpr>("funcCall")),
1499
              R"cpp(
1500
CallExpr
1501
|-DeclRefExpr 'hasDefaultArg'
1502
`-IntegerLiteral
1503
)cpp");
1504
  }
1505

1506
  {
1507
    auto FN = ast_matchers::match(
1508
        functionDecl(hasName("decomposition"),
1509
                     hasDescendant(decompositionDecl().bind("decomp"))),
1510
        AST2->getASTContext());
1511
    EXPECT_EQ(FN.size(), 1u);
1512

1513
    EXPECT_EQ(
1514
        dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),
1515
        R"cpp(
1516
DecompositionDecl ''
1517
|-DeclRefExpr 'arr'
1518
|-BindingDecl 'f'
1519
| `-ArraySubscriptExpr
1520
|   |-ImplicitCastExpr
1521
|   | `-DeclRefExpr ''
1522
|   `-IntegerLiteral
1523
|-BindingDecl 's'
1524
| `-ArraySubscriptExpr
1525
|   |-ImplicitCastExpr
1526
|   | `-DeclRefExpr ''
1527
|   `-IntegerLiteral
1528
`-BindingDecl 't'
1529
  `-ArraySubscriptExpr
1530
    |-ImplicitCastExpr
1531
    | `-DeclRefExpr ''
1532
    `-IntegerLiteral
1533
)cpp");
1534

1535
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1536
                            FN[0].getNodeAs<DecompositionDecl>("decomp")),
1537
              R"cpp(
1538
DecompositionDecl ''
1539
|-DeclRefExpr 'arr'
1540
|-BindingDecl 'f'
1541
|-BindingDecl 's'
1542
`-BindingDecl 't'
1543
)cpp");
1544
  }
1545

1546
  {
1547
    auto FN = ast_matchers::match(
1548
        functionDecl(hasName("decompTuple"),
1549
                     hasDescendant(decompositionDecl().bind("decomp"))),
1550
        AST2->getASTContext());
1551
    EXPECT_EQ(FN.size(), 1u);
1552

1553
    EXPECT_EQ(
1554
        dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),
1555
        R"cpp(
1556
DecompositionDecl ''
1557
|-CXXConstructExpr
1558
| `-ImplicitCastExpr
1559
|   `-DeclRefExpr 'p'
1560
|-BindingDecl 'a'
1561
| |-VarDecl 'a'
1562
| | `-CallExpr
1563
| |   |-ImplicitCastExpr
1564
| |   | `-DeclRefExpr 'get'
1565
| |   `-ImplicitCastExpr
1566
| |     `-DeclRefExpr ''
1567
| `-DeclRefExpr 'a'
1568
`-BindingDecl 'b'
1569
  |-VarDecl 'b'
1570
  | `-CallExpr
1571
  |   |-ImplicitCastExpr
1572
  |   | `-DeclRefExpr 'get'
1573
  |   `-ImplicitCastExpr
1574
  |     `-DeclRefExpr ''
1575
  `-DeclRefExpr 'b'
1576
)cpp");
1577

1578
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1579
                            FN[0].getNodeAs<DecompositionDecl>("decomp")),
1580
              R"cpp(
1581
DecompositionDecl ''
1582
|-DeclRefExpr 'p'
1583
|-BindingDecl 'a'
1584
`-BindingDecl 'b'
1585
)cpp");
1586
  }
1587
}
1588

1589
TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
1590

1591
  auto AST = buildASTFromCode(R"cpp(
1592
template<typename T>
1593
struct TemplStruct {
1594
  TemplStruct() {}
1595
  ~TemplStruct() {}
1596

1597
private:
1598
  T m_t;
1599
};
1600

1601
template<typename T>
1602
T timesTwo(T input)
1603
{
1604
  return input * 2;
1605
}
1606

1607
void instantiate()
1608
{
1609
  TemplStruct<int> ti;
1610
  TemplStruct<double> td;
1611
  (void)timesTwo<int>(2);
1612
  (void)timesTwo<double>(2);
1613
}
1614

1615
template class TemplStruct<float>;
1616

1617
extern template class TemplStruct<long>;
1618

1619
template<> class TemplStruct<bool> {
1620
  TemplStruct() {}
1621
  ~TemplStruct() {}
1622

1623
  void foo() {}
1624
private:
1625
  bool m_t;
1626
};
1627

1628
// Explicit instantiation of template functions do not appear in the AST
1629
template float timesTwo(float);
1630

1631
template<> bool timesTwo<bool>(bool) {
1632
  return true;
1633
}
1634
)cpp");
1635
  {
1636
    auto BN = ast_matchers::match(
1637
        classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1638
        AST->getASTContext());
1639
    EXPECT_EQ(BN.size(), 1u);
1640

1641
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1642
                            BN[0].getNodeAs<Decl>("rec")),
1643
              R"cpp(
1644
ClassTemplateDecl 'TemplStruct'
1645
|-TemplateTypeParmDecl 'T'
1646
`-CXXRecordDecl 'TemplStruct'
1647
  |-CXXConstructorDecl 'TemplStruct<T>'
1648
  | `-CompoundStmt
1649
  |-CXXDestructorDecl '~TemplStruct<T>'
1650
  | `-CompoundStmt
1651
  |-AccessSpecDecl
1652
  `-FieldDecl 'm_t'
1653
)cpp");
1654

1655
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1656
              R"cpp(
1657
ClassTemplateDecl 'TemplStruct'
1658
|-TemplateTypeParmDecl 'T'
1659
|-CXXRecordDecl 'TemplStruct'
1660
| |-CXXRecordDecl 'TemplStruct'
1661
| |-CXXConstructorDecl 'TemplStruct<T>'
1662
| | `-CompoundStmt
1663
| |-CXXDestructorDecl '~TemplStruct<T>'
1664
| | `-CompoundStmt
1665
| |-AccessSpecDecl
1666
| `-FieldDecl 'm_t'
1667
|-ClassTemplateSpecializationDecl 'TemplStruct'
1668
| |-TemplateArgument type int
1669
| | `-BuiltinType
1670
| |-CXXRecordDecl 'TemplStruct'
1671
| |-CXXConstructorDecl 'TemplStruct'
1672
| | `-CompoundStmt
1673
| |-CXXDestructorDecl '~TemplStruct'
1674
| | `-CompoundStmt
1675
| |-AccessSpecDecl
1676
| |-FieldDecl 'm_t'
1677
| `-CXXConstructorDecl 'TemplStruct'
1678
|   `-ParmVarDecl ''
1679
|-ClassTemplateSpecializationDecl 'TemplStruct'
1680
| |-TemplateArgument type double
1681
| | `-BuiltinType
1682
| |-CXXRecordDecl 'TemplStruct'
1683
| |-CXXConstructorDecl 'TemplStruct'
1684
| | `-CompoundStmt
1685
| |-CXXDestructorDecl '~TemplStruct'
1686
| | `-CompoundStmt
1687
| |-AccessSpecDecl
1688
| |-FieldDecl 'm_t'
1689
| `-CXXConstructorDecl 'TemplStruct'
1690
|   `-ParmVarDecl ''
1691
|-ClassTemplateSpecializationDecl 'TemplStruct'
1692
| |-TemplateArgument type float
1693
| | `-BuiltinType
1694
| |-CXXRecordDecl 'TemplStruct'
1695
| |-CXXConstructorDecl 'TemplStruct'
1696
| | `-CompoundStmt
1697
| |-CXXDestructorDecl '~TemplStruct'
1698
| | `-CompoundStmt
1699
| |-AccessSpecDecl
1700
| `-FieldDecl 'm_t'
1701
|-ClassTemplateSpecializationDecl 'TemplStruct'
1702
| |-TemplateArgument type long
1703
| | `-BuiltinType
1704
| |-CXXRecordDecl 'TemplStruct'
1705
| |-CXXConstructorDecl 'TemplStruct'
1706
| |-CXXDestructorDecl '~TemplStruct'
1707
| |-AccessSpecDecl
1708
| `-FieldDecl 'm_t'
1709
`-ClassTemplateSpecializationDecl 'TemplStruct'
1710
  |-TemplateArgument type _Bool
1711
  | `-BuiltinType
1712
  |-CXXRecordDecl 'TemplStruct'
1713
  |-CXXConstructorDecl 'TemplStruct'
1714
  | `-CompoundStmt
1715
  |-CXXDestructorDecl '~TemplStruct'
1716
  | `-CompoundStmt
1717
  |-CXXMethodDecl 'foo'
1718
  | `-CompoundStmt
1719
  |-AccessSpecDecl
1720
  `-FieldDecl 'm_t'
1721
)cpp");
1722
  }
1723
  {
1724
    auto BN = ast_matchers::match(
1725
        classTemplateSpecializationDecl(
1726
            hasTemplateArgument(
1727
                0, templateArgument(refersToType(asString("_Bool")))))
1728
            .bind("templSpec"),
1729
        AST->getASTContext());
1730
    EXPECT_EQ(BN.size(), 1u);
1731

1732
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")),
1733
              R"cpp(
1734
ClassTemplateSpecializationDecl 'TemplStruct'
1735
|-TemplateArgument type _Bool
1736
| `-BuiltinType
1737
|-CXXRecordDecl 'TemplStruct'
1738
|-CXXConstructorDecl 'TemplStruct'
1739
| `-CompoundStmt
1740
|-CXXDestructorDecl '~TemplStruct'
1741
| `-CompoundStmt
1742
|-CXXMethodDecl 'foo'
1743
| `-CompoundStmt
1744
|-AccessSpecDecl
1745
`-FieldDecl 'm_t'
1746
)cpp");
1747

1748
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1749
                            BN[0].getNodeAs<Decl>("templSpec")),
1750
              R"cpp(
1751
ClassTemplateSpecializationDecl 'TemplStruct'
1752
|-TemplateArgument type _Bool
1753
| `-BuiltinType
1754
|-CXXConstructorDecl 'TemplStruct'
1755
| `-CompoundStmt
1756
|-CXXDestructorDecl '~TemplStruct'
1757
| `-CompoundStmt
1758
|-CXXMethodDecl 'foo'
1759
| `-CompoundStmt
1760
|-AccessSpecDecl
1761
`-FieldDecl 'm_t'
1762
)cpp");
1763
  }
1764
  {
1765
    auto BN = ast_matchers::match(
1766
        functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1767
        AST->getASTContext());
1768
    EXPECT_EQ(BN.size(), 1u);
1769

1770
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1771
                            BN[0].getNodeAs<Decl>("fn")),
1772
              R"cpp(
1773
FunctionTemplateDecl 'timesTwo'
1774
|-TemplateTypeParmDecl 'T'
1775
`-FunctionDecl 'timesTwo'
1776
  |-ParmVarDecl 'input'
1777
  `-CompoundStmt
1778
    `-ReturnStmt
1779
      `-BinaryOperator
1780
        |-DeclRefExpr 'input'
1781
        `-IntegerLiteral
1782
)cpp");
1783

1784
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
1785
              R"cpp(
1786
FunctionTemplateDecl 'timesTwo'
1787
|-TemplateTypeParmDecl 'T'
1788
|-FunctionDecl 'timesTwo'
1789
| |-ParmVarDecl 'input'
1790
| `-CompoundStmt
1791
|   `-ReturnStmt
1792
|     `-BinaryOperator
1793
|       |-DeclRefExpr 'input'
1794
|       `-IntegerLiteral
1795
|-FunctionDecl 'timesTwo'
1796
| |-TemplateArgument type int
1797
| | `-BuiltinType
1798
| |-ParmVarDecl 'input'
1799
| `-CompoundStmt
1800
|   `-ReturnStmt
1801
|     `-BinaryOperator
1802
|       |-ImplicitCastExpr
1803
|       | `-DeclRefExpr 'input'
1804
|       `-IntegerLiteral
1805
|-FunctionDecl 'timesTwo'
1806
| |-TemplateArgument type double
1807
| | `-BuiltinType
1808
| |-ParmVarDecl 'input'
1809
| `-CompoundStmt
1810
|   `-ReturnStmt
1811
|     `-BinaryOperator
1812
|       |-ImplicitCastExpr
1813
|       | `-DeclRefExpr 'input'
1814
|       `-ImplicitCastExpr
1815
|         `-IntegerLiteral
1816
|-FunctionDecl 'timesTwo'
1817
| |-TemplateArgument type float
1818
| | `-BuiltinType
1819
| |-ParmVarDecl 'input'
1820
| `-CompoundStmt
1821
|   `-ReturnStmt
1822
|     `-BinaryOperator
1823
|       |-ImplicitCastExpr
1824
|       | `-DeclRefExpr 'input'
1825
|       `-ImplicitCastExpr
1826
|         `-IntegerLiteral
1827
|-FunctionDecl 'timesTwo'
1828
| |-TemplateArgument type _Bool
1829
| | `-BuiltinType
1830
| |-ParmVarDecl ''
1831
| `-CompoundStmt
1832
|   `-ReturnStmt
1833
|     `-CXXBoolLiteralExpr
1834
`-FunctionDecl 'timesTwo'
1835
  |-TemplateArgument type _Bool
1836
  | `-BuiltinType
1837
  `-ParmVarDecl 'input'
1838
)cpp");
1839
  }
1840
  {
1841
    auto BN = ast_matchers::match(
1842
        classTemplateSpecializationDecl(
1843
            hasName("TemplStruct"),
1844
            hasTemplateArgument(
1845
                0, templateArgument(refersToType(asString("float")))),
1846
            hasParent(translationUnitDecl()))
1847
            .bind("rec"),
1848
        AST->getASTContext());
1849
    EXPECT_EQ(BN.size(), 1u);
1850

1851
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1852
                            BN[0].getNodeAs<Decl>("rec")),
1853
              R"cpp(
1854
ClassTemplateSpecializationDecl 'TemplStruct'
1855
`-TemplateArgument type float
1856
  `-BuiltinType
1857
)cpp");
1858

1859
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1860
              R"cpp(
1861
ClassTemplateSpecializationDecl 'TemplStruct'
1862
|-TemplateArgument type float
1863
| `-BuiltinType
1864
|-CXXRecordDecl 'TemplStruct'
1865
|-CXXConstructorDecl 'TemplStruct'
1866
| `-CompoundStmt
1867
|-CXXDestructorDecl '~TemplStruct'
1868
| `-CompoundStmt
1869
|-AccessSpecDecl
1870
`-FieldDecl 'm_t'
1871
)cpp");
1872
  }
1873
}
1874

1875
TEST(Traverse, CXXRewrittenBinaryOperator) {
1876

1877
  auto AST = buildASTFromCodeWithArgs(R"cpp(
1878
namespace std {
1879
struct strong_ordering {
1880
  int n;
1881
  constexpr operator int() const { return n; }
1882
  static const strong_ordering equal, greater, less;
1883
};
1884
constexpr strong_ordering strong_ordering::equal = {0};
1885
constexpr strong_ordering strong_ordering::greater = {1};
1886
constexpr strong_ordering strong_ordering::less = {-1};
1887
}
1888

1889
struct HasSpaceshipMem {
1890
  int a;
1891
  constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1892
};
1893

1894
void binop()
1895
{
1896
    HasSpaceshipMem hs1, hs2;
1897
    if (hs1 < hs2)
1898
        return;
1899
}
1900
)cpp",
1901
                                      {"-std=c++20"});
1902
  {
1903
    auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1904
                                  AST->getASTContext());
1905
    EXPECT_EQ(BN.size(), 1u);
1906

1907
    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")),
1908
              R"cpp(
1909
CXXRewrittenBinaryOperator
1910
`-BinaryOperator
1911
  |-ImplicitCastExpr
1912
  | `-CXXMemberCallExpr
1913
  |   `-MemberExpr
1914
  |     `-ImplicitCastExpr
1915
  |       `-MaterializeTemporaryExpr
1916
  |         `-CXXOperatorCallExpr
1917
  |           |-ImplicitCastExpr
1918
  |           | `-DeclRefExpr 'operator<=>'
1919
  |           |-ImplicitCastExpr
1920
  |           | `-DeclRefExpr 'hs1'
1921
  |           `-ImplicitCastExpr
1922
  |             `-DeclRefExpr 'hs2'
1923
  `-IntegerLiteral
1924
)cpp");
1925
    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1926
                            BN[0].getNodeAs<Stmt>("binop")),
1927
              R"cpp(
1928
CXXRewrittenBinaryOperator
1929
|-DeclRefExpr 'hs1'
1930
`-DeclRefExpr 'hs2'
1931
)cpp");
1932
  }
1933
}
1934

1935
} // namespace clang
1936

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.