llvm-project
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
18using namespace clang::tooling;19using namespace clang::ast_matchers;20
21namespace clang {22
23class NodeTreePrinter : public TextTreeStructure {24llvm::raw_ostream &OS;25
26public:27NodeTreePrinter(llvm::raw_ostream &OS)28: TextTreeStructure(OS, /* showColors */ false), OS(OS) {}29
30void Visit(const Decl *D) {31OS << D->getDeclKindName() << "Decl";32if (auto *ND = dyn_cast<NamedDecl>(D)) {33OS << " '" << ND->getDeclName() << "'";34}35}36
37void Visit(const Stmt *S) {38if (!S) {39OS << "<<<NULL>>>";40return;41}42OS << S->getStmtClassName();43if (auto *E = dyn_cast<DeclRefExpr>(S)) {44OS << " '" << E->getDecl()->getDeclName() << "'";45}46}47
48void Visit(QualType QT) {49OS << "QualType " << QT.split().Quals.getAsString();50}51
52void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }53
54void Visit(const comments::Comment *C, const comments::FullComment *FC) {55OS << C->getCommentKindName();56}57
58void Visit(const CXXCtorInitializer *Init) {59OS << "CXXCtorInitializer";60if (const auto *F = Init->getAnyMember()) {61OS << " '" << F->getNameAsString() << "'";62} else if (auto const *TSI = Init->getTypeSourceInfo()) {63OS << " '" << TSI->getType() << "'";64}65}66
67void Visit(const Attr *A) {68switch (A->getKind()) {69#define ATTR(X) \70case attr::X: \71OS << #X; \72break;73#include "clang/Basic/AttrList.inc"74}75OS << "Attr";76}77
78void Visit(const OMPClause *C) { OS << "OMPClause"; }79void Visit(const TemplateArgument &A, SourceRange R = {},80const Decl *From = nullptr, const char *Label = nullptr) {81OS << "TemplateArgument";82switch (A.getKind()) {83case TemplateArgument::Type: {84OS << " type " << A.getAsType();85break;86}87default:88break;89}90}91
92template <typename... T> void Visit(T...) {}93};94
95class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {96
97NodeTreePrinter MyNodeRecorder;98
99public:100TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}101NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }102};103
104template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {105std::string Buffer;106llvm::raw_string_ostream OS(Buffer);107
108TestASTDumper Dumper(OS);109
110OS << "\n";111
112Dumper.Visit(std::forward<NodeType &&>(N)...);113
114return Buffer;115}
116
117template <typename... NodeType>118std::string dumpASTString(TraversalKind TK, NodeType &&... N) {119std::string Buffer;120llvm::raw_string_ostream OS(Buffer);121
122TestASTDumper Dumper(OS);123Dumper.SetTraversalKind(TK);124
125OS << "\n";126
127Dumper.Visit(std::forward<NodeType &&>(N)...);128
129return Buffer;130}
131
132const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,133const std::string &Name) {134auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),135AST->getASTContext());136EXPECT_EQ(Result.size(), 1u);137return Result[0].getNodeAs<FunctionDecl>("fn");138}
139
140template <typename T> struct Verifier {141static void withDynNode(T Node, const std::string &DumpString) {142EXPECT_EQ(dumpASTString(DynTypedNode::create(Node)), DumpString);143}144};145
146template <typename T> struct Verifier<T *> {147static void withDynNode(T *Node, const std::string &DumpString) {148EXPECT_EQ(dumpASTString(DynTypedNode::create(*Node)), DumpString);149}150};151
152template <typename T>153void verifyWithDynNode(T Node, const std::string &DumpString) {154EXPECT_EQ(dumpASTString(Node), DumpString);155
156Verifier<T>::withDynNode(Node, DumpString);157}
158
159TEST(Traverse, Dump) {160
161auto AST = buildASTFromCode(R"cpp(162struct A {
163int m_number;
164
165/// CTor
166A() : m_number(42) {}
167
168[[nodiscard]] const int func() {
169return 42;
170}
171
172};
173
174template<typename T>
175struct templ
176{
177};
178
179template<>
180struct templ<int>
181{
182};
183
184void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
185
186)cpp");187
188const FunctionDecl *Func = getFunctionNode(AST.get(), "func");189
190verifyWithDynNode(Func,191R"cpp(192CXXMethodDecl 'func'
193|-CompoundStmt
194| `-ReturnStmt
195| `-IntegerLiteral
196`-WarnUnusedResultAttr
197)cpp");198
199Stmt *Body = Func->getBody();200
201verifyWithDynNode(Body,202R"cpp(203CompoundStmt
204`-ReturnStmt
205`-IntegerLiteral
206)cpp");207
208QualType QT = Func->getType();209
210verifyWithDynNode(QT,211R"cpp(212FunctionProtoType
213`-QualType const
214`-BuiltinType
215)cpp");216
217const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");218
219verifyWithDynNode(CTorFunc->getType(),220R"cpp(221FunctionProtoType
222`-BuiltinType
223)cpp");224
225Attr *A = *Func->attr_begin();226
227{228std::string expectedString = R"cpp(229WarnUnusedResultAttr
230)cpp";231
232EXPECT_EQ(dumpASTString(A), expectedString);233}234
235auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);236const CXXCtorInitializer *Init = *CTor->init_begin();237
238verifyWithDynNode(Init,239R"cpp(240CXXCtorInitializer 'm_number'
241`-IntegerLiteral
242)cpp");243
244const comments::FullComment *Comment =245AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);246{247std::string expectedString = R"cpp(248FullComment
249`-ParagraphComment
250`-TextComment
251)cpp";252EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);253}254
255auto Result = ast_matchers::match(256classTemplateSpecializationDecl(hasName("templ")).bind("fn"),257AST->getASTContext());258EXPECT_EQ(Result.size(), 1u);259auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");260
261TemplateArgument TA = Templ->getTemplateArgs()[0];262
263verifyWithDynNode(TA,264R"cpp(265TemplateArgument type int
266`-BuiltinType
267)cpp");268
269Func = getFunctionNode(AST.get(), "parmvardecl_attr");270
271const auto *Parm = Func->getParamDecl(0);272const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();273ASSERT_TRUE(TL.getType()->isPointerType());274
275const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>();276const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr());277EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())),27819u);279}
280
281TEST(Traverse, IgnoreUnlessSpelledInSourceVars) {282
283auto AST = buildASTFromCodeWithArgs(R"cpp(284
285struct String
286{
287String(const char*, int = -1) {}
288
289int overloaded() const;
290int& overloaded();
291};
292
293void stringConstruct()
294{
295String s = "foo";
296s = "bar";
297}
298
299void overloadCall()
300{
301String s = "foo";
302(s).overloaded();
303}
304
305struct C1 {};
306struct C2 { operator C1(); };
307
308void conversionOperator()
309{
310C2* c2;
311C1 c1 = (*c2);
312}
313
314template <unsigned alignment>
315void template_test() {
316static_assert(alignment, "");
317}
318void actual_template_test() {
319template_test<4>();
320}
321
322struct OneParamCtor {
323explicit OneParamCtor(int);
324};
325struct TwoParamCtor {
326explicit TwoParamCtor(int, int);
327};
328
329void varDeclCtors() {
330{
331auto var1 = OneParamCtor(5);
332auto var2 = TwoParamCtor(6, 7);
333}
334{
335OneParamCtor var3(5);
336TwoParamCtor var4(6, 7);
337}
338int i = 0;
339{
340auto var5 = OneParamCtor(i);
341auto var6 = TwoParamCtor(i, 7);
342}
343{
344OneParamCtor var7(i);
345TwoParamCtor var8(i, 7);
346}
347}
348
349)cpp", {"-std=c++14"});350
351{352auto FN =353ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"),354AST->getASTContext());355EXPECT_EQ(FN.size(), 1u);356
357EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),358R"cpp(359FunctionDecl '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
387EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,388FN[0].getNodeAs<Decl>("fn")),389R"cpp(390FunctionDecl '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{403auto FN =404ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),405AST->getASTContext());406EXPECT_EQ(FN.size(), 1u);407
408EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),409R"cpp(410FunctionDecl '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
430EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,431FN[0].getNodeAs<Decl>("fn")),432R"cpp(433FunctionDecl 'overloadCall'
434`-CompoundStmt
435|-DeclStmt
436| `-VarDecl 's'
437| `-StringLiteral
438`-CXXMemberCallExpr
439`-MemberExpr
440`-DeclRefExpr 's'
441)cpp");442}443
444{445auto FN = ast_matchers::match(446functionDecl(hasName("conversionOperator"),447hasDescendant(varDecl(hasName("c1")).bind("var"))),448AST->getASTContext());449EXPECT_EQ(FN.size(), 1u);450
451EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("var")),452R"cpp(453VarDecl '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
466EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,467FN[0].getNodeAs<Decl>("var")),468R"cpp(469VarDecl 'c1'
470`-UnaryOperator
471`-DeclRefExpr 'c2'
472)cpp");473}474
475{476auto FN = ast_matchers::match(477functionDecl(hasName("template_test"),478hasDescendant(staticAssertDecl().bind("staticAssert"))),479AST->getASTContext());480EXPECT_EQ(FN.size(), 2u);481
482EXPECT_EQ(dumpASTString(TK_AsIs, FN[1].getNodeAs<Decl>("staticAssert")),483R"cpp(484StaticAssertDecl
485|-ImplicitCastExpr
486| `-SubstNonTypeTemplateParmExpr
487| |-NonTypeTemplateParmDecl 'alignment'
488| `-IntegerLiteral
489`-StringLiteral
490)cpp");491
492EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,493FN[1].getNodeAs<Decl>("staticAssert")),494R"cpp(495StaticAssertDecl
496|-IntegerLiteral
497`-StringLiteral
498)cpp");499}500
501auto varChecker = [&AST](StringRef varName, StringRef SemanticDump,502StringRef SyntacticDump) {503auto FN = ast_matchers::match(504functionDecl(505hasName("varDeclCtors"),506forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))),507AST->getASTContext());508EXPECT_EQ(FN.size(), 1u);509
510EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")),511SemanticDump);512
513EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,514FN[0].getNodeAs<Decl>("varDeclCtor")),515SyntacticDump);516};517
518varChecker("var1",519R"cpp(520VarDecl 'var1'
521`-ExprWithCleanups
522`-CXXConstructExpr
523`-MaterializeTemporaryExpr
524`-CXXFunctionalCastExpr
525`-CXXConstructExpr
526`-IntegerLiteral
527)cpp",528R"cpp(529VarDecl 'var1'
530`-CXXConstructExpr
531`-IntegerLiteral
532)cpp");533
534varChecker("var2",535R"cpp(536VarDecl 'var2'
537`-ExprWithCleanups
538`-CXXConstructExpr
539`-MaterializeTemporaryExpr
540`-CXXTemporaryObjectExpr
541|-IntegerLiteral
542`-IntegerLiteral
543)cpp",544R"cpp(545VarDecl 'var2'
546`-CXXTemporaryObjectExpr
547|-IntegerLiteral
548`-IntegerLiteral
549)cpp");550
551varChecker("var3",552R"cpp(553VarDecl 'var3'
554`-CXXConstructExpr
555`-IntegerLiteral
556)cpp",557R"cpp(558VarDecl 'var3'
559`-CXXConstructExpr
560`-IntegerLiteral
561)cpp");562
563varChecker("var4",564R"cpp(565VarDecl 'var4'
566`-CXXConstructExpr
567|-IntegerLiteral
568`-IntegerLiteral
569)cpp",570R"cpp(571VarDecl 'var4'
572`-CXXConstructExpr
573|-IntegerLiteral
574`-IntegerLiteral
575)cpp");576
577varChecker("var5",578R"cpp(579VarDecl 'var5'
580`-ExprWithCleanups
581`-CXXConstructExpr
582`-MaterializeTemporaryExpr
583`-CXXFunctionalCastExpr
584`-CXXConstructExpr
585`-ImplicitCastExpr
586`-DeclRefExpr 'i'
587)cpp",588R"cpp(589VarDecl 'var5'
590`-CXXConstructExpr
591`-DeclRefExpr 'i'
592)cpp");593
594varChecker("var6",595R"cpp(596VarDecl 'var6'
597`-ExprWithCleanups
598`-CXXConstructExpr
599`-MaterializeTemporaryExpr
600`-CXXTemporaryObjectExpr
601|-ImplicitCastExpr
602| `-DeclRefExpr 'i'
603`-IntegerLiteral
604)cpp",605R"cpp(606VarDecl 'var6'
607`-CXXTemporaryObjectExpr
608|-DeclRefExpr 'i'
609`-IntegerLiteral
610)cpp");611
612varChecker("var7",613R"cpp(614VarDecl 'var7'
615`-CXXConstructExpr
616`-ImplicitCastExpr
617`-DeclRefExpr 'i'
618)cpp",619R"cpp(620VarDecl 'var7'
621`-CXXConstructExpr
622`-DeclRefExpr 'i'
623)cpp");624
625varChecker("var8",626R"cpp(627VarDecl 'var8'
628`-CXXConstructExpr
629|-ImplicitCastExpr
630| `-DeclRefExpr 'i'
631`-IntegerLiteral
632)cpp",633R"cpp(634VarDecl 'var8'
635`-CXXConstructExpr
636|-DeclRefExpr 'i'
637`-IntegerLiteral
638)cpp");639}
640
641TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) {642auto AST = buildASTFromCode(R"cpp(643
644struct MyStruct {
645MyStruct();
646MyStruct(int i) {
647MyStruct();
648}
649~MyStruct();
650};
651
652)cpp");653
654auto BN = ast_matchers::match(655cxxConstructorDecl(hasName("MyStruct"),656hasParameter(0, parmVarDecl(hasType(isInteger()))))657.bind("ctor"),658AST->getASTContext());659EXPECT_EQ(BN.size(), 1u);660
661EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,662BN[0].getNodeAs<Decl>("ctor")),663R"cpp(664CXXConstructorDecl 'MyStruct'
665|-ParmVarDecl 'i'
666`-CompoundStmt
667`-CXXTemporaryObjectExpr
668)cpp");669
670EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("ctor")),671R"cpp(672CXXConstructorDecl 'MyStruct'
673|-ParmVarDecl 'i'
674`-CompoundStmt
675`-ExprWithCleanups
676`-CXXBindTemporaryExpr
677`-CXXTemporaryObjectExpr
678)cpp");679}
680
681TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) {682
683auto AST = buildASTFromCode(R"cpp(684struct Retval {
685Retval() {}
686~Retval() {}
687};
688
689Retval someFun();
690
691void foo()
692{
693someFun();
694}
695)cpp");696
697auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),698AST->getASTContext());699EXPECT_EQ(BN.size(), 1u);700
701EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,702BN[0].getNodeAs<Decl>("fn")),703R"cpp(704FunctionDecl 'foo'
705`-CompoundStmt
706`-CallExpr
707`-DeclRefExpr 'someFun'
708)cpp");709
710EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),711R"cpp(712FunctionDecl 'foo'
713`-CompoundStmt
714`-ExprWithCleanups
715`-CXXBindTemporaryExpr
716`-CallExpr
717`-ImplicitCastExpr
718`-DeclRefExpr 'someFun'
719)cpp");720}
721
722TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) {723
724auto AST = buildASTFromCodeWithArgs(R"cpp(725
726struct A
727{
728};
729
730struct B
731{
732B(int);
733B(A const& a);
734B();
735};
736
737struct C
738{
739operator B();
740};
741
742B func1() {
743return 42;
744}
745
746B func2() {
747return B{42};
748}
749
750B func3() {
751return B(42);
752}
753
754B func4() {
755return B();
756}
757
758B func5() {
759return B{};
760}
761
762B func6() {
763return C();
764}
765
766B func7() {
767return A();
768}
769
770B func8() {
771return C{};
772}
773
774B func9() {
775return A{};
776}
777
778B func10() {
779A a;
780return a;
781}
782
783B func11() {
784B b;
785return b;
786}
787
788B func12() {
789C c;
790return c;
791}
792
793)cpp", {"-std=c++14"});794
795auto getFunctionNode = [&AST](const std::string &name) {796auto BN = ast_matchers::match(functionDecl(hasName(name)).bind("fn"),797AST->getASTContext());798EXPECT_EQ(BN.size(), 1u);799return BN[0].getNodeAs<Decl>("fn");800};801
802{803auto FN = getFunctionNode("func1");804llvm::StringRef Expected = R"cpp(805FunctionDecl 'func1'
806`-CompoundStmt
807`-ReturnStmt
808`-ExprWithCleanups
809`-CXXConstructExpr
810`-MaterializeTemporaryExpr
811`-ImplicitCastExpr
812`-CXXConstructExpr
813`-IntegerLiteral
814)cpp";815
816EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected);817
818Expected = R"cpp(819FunctionDecl 'func1'
820`-CompoundStmt
821`-ReturnStmt
822`-IntegerLiteral
823)cpp";824EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected);825}826
827llvm::StringRef Expected = R"cpp(828FunctionDecl 'func2'
829`-CompoundStmt
830`-ReturnStmt
831`-CXXTemporaryObjectExpr
832`-IntegerLiteral
833)cpp";834EXPECT_EQ(835dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func2")),836Expected);837
838Expected = R"cpp(839FunctionDecl 'func3'
840`-CompoundStmt
841`-ReturnStmt
842`-CXXConstructExpr
843`-IntegerLiteral
844)cpp";845EXPECT_EQ(846dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func3")),847Expected);848
849Expected = R"cpp(850FunctionDecl 'func4'
851`-CompoundStmt
852`-ReturnStmt
853`-CXXTemporaryObjectExpr
854)cpp";855EXPECT_EQ(856dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func4")),857Expected);858
859Expected = R"cpp(860FunctionDecl 'func5'
861`-CompoundStmt
862`-ReturnStmt
863`-CXXTemporaryObjectExpr
864)cpp";865EXPECT_EQ(866dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func5")),867Expected);868
869Expected = R"cpp(870FunctionDecl 'func6'
871`-CompoundStmt
872`-ReturnStmt
873`-CXXTemporaryObjectExpr
874)cpp";875EXPECT_EQ(876dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func6")),877Expected);878
879Expected = R"cpp(880FunctionDecl 'func7'
881`-CompoundStmt
882`-ReturnStmt
883`-CXXTemporaryObjectExpr
884)cpp";885EXPECT_EQ(886dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func7")),887Expected);888
889Expected = R"cpp(890FunctionDecl 'func8'
891`-CompoundStmt
892`-ReturnStmt
893`-CXXFunctionalCastExpr
894`-InitListExpr
895)cpp";896EXPECT_EQ(897dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func8")),898Expected);899
900Expected = R"cpp(901FunctionDecl 'func9'
902`-CompoundStmt
903`-ReturnStmt
904`-CXXFunctionalCastExpr
905`-InitListExpr
906)cpp";907EXPECT_EQ(908dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func9")),909Expected);910
911Expected = R"cpp(912FunctionDecl 'func10'
913`-CompoundStmt
914|-DeclStmt
915| `-VarDecl 'a'
916| `-CXXConstructExpr
917`-ReturnStmt
918`-DeclRefExpr 'a'
919)cpp";920EXPECT_EQ(921dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func10")),922Expected);923
924Expected = R"cpp(925FunctionDecl 'func11'
926`-CompoundStmt
927|-DeclStmt
928| `-VarDecl 'b'
929| `-CXXConstructExpr
930`-ReturnStmt
931`-DeclRefExpr 'b'
932)cpp";933EXPECT_EQ(934dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func11")),935Expected);936
937Expected = R"cpp(938FunctionDecl 'func12'
939`-CompoundStmt
940|-DeclStmt
941| `-VarDecl 'c'
942| `-CXXConstructExpr
943`-ReturnStmt
944`-DeclRefExpr 'c'
945)cpp";946EXPECT_EQ(947dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func12")),948Expected);949}
950
951TEST(Traverse, LambdaUnlessSpelledInSource) {952
953auto AST =954buildASTFromCodeWithArgs(R"cpp(955
956void captures() {
957int a = 0;
958int b = 0;
959int d = 0;
960int f = 0;
961
962[a, &b, c = d, &e = f](int g, int h = 42) {};
963}
964
965void templated() {
966int a = 0;
967[a]<typename T>(T t) {};
968}
969
970struct SomeStruct {
971int a = 0;
972void capture_this() {
973[this]() {};
974}
975void capture_this_copy() {
976[self = *this]() {};
977}
978};
979)cpp",980{"-Wno-unused-value", "-Wno-c++2a-extensions"});981
982auto getLambdaNode = [&AST](const std::string &name) {983auto BN = ast_matchers::match(984lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),985AST->getASTContext());986EXPECT_EQ(BN.size(), 1u);987return BN[0].getNodeAs<LambdaExpr>("lambda");988};989
990{991auto L = getLambdaNode("captures");992
993llvm::StringRef Expected = R"cpp(994LambdaExpr
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";1006EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1007
1008Expected = R"cpp(1009LambdaExpr
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";1029EXPECT_EQ(dumpASTString(TK_AsIs, L), Expected);1030}1031
1032{1033auto L = getLambdaNode("templated");1034
1035llvm::StringRef Expected = R"cpp(1036LambdaExpr
1037|-DeclRefExpr 'a'
1038|-TemplateTypeParmDecl 'T'
1039|-ParmVarDecl 't'
1040`-CompoundStmt
1041)cpp";1042EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1043}1044
1045{1046auto L = getLambdaNode("capture_this");1047
1048llvm::StringRef Expected = R"cpp(1049LambdaExpr
1050|-CXXThisExpr
1051`-CompoundStmt
1052)cpp";1053EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1054}1055
1056{1057auto L = getLambdaNode("capture_this_copy");1058
1059llvm::StringRef Expected = R"cpp(1060LambdaExpr
1061|-VarDecl 'self'
1062| `-UnaryOperator
1063| `-CXXThisExpr
1064`-CompoundStmt
1065)cpp";1066EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1067}1068}
1069
1070TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {1071{1072auto AST = buildASTFromCode(R"cpp(1073int i = 0;
1074)cpp");1075const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();1076
1077EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),1078R"cpp(1079TranslationUnitDecl
1080`-VarDecl 'i'
1081`-IntegerLiteral
1082)cpp");1083}1084
1085auto AST2 = buildASTFromCodeWithArgs(R"cpp(1086struct Simple {
1087};
1088struct Other {
1089};
1090
1091struct Record : Simple, Other {
1092Record() : Simple(), m_i(42) {}
1093private:
1094int m_i;
1095int m_i2 = 42;
1096Simple m_s;
1097};
1098
1099struct NonTrivial {
1100NonTrivial() {}
1101NonTrivial(NonTrivial&) {}
1102NonTrivial& operator=(NonTrivial&) { return *this; }
1103
1104~NonTrivial() {}
1105};
1106
1107struct ContainsArray {
1108NonTrivial arr[2];
1109int irr[2];
1110ContainsArray& operator=(ContainsArray &) = default;
1111};
1112
1113void copyIt()
1114{
1115ContainsArray ca;
1116ContainsArray ca2;
1117ca2 = ca;
1118}
1119
1120void forLoop()
1121{
1122int arr[2];
1123for (auto i : arr)
1124{
1125
1126}
1127for (auto& a = arr; auto i : a)
1128{
1129
1130}
1131}
1132
1133struct DefaultedAndDeleted {
1134NonTrivial nt;
1135DefaultedAndDeleted() = default;
1136~DefaultedAndDeleted() = default;
1137DefaultedAndDeleted(DefaultedAndDeleted &) = default;
1138DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
1139DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
1140DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
1141};
1142
1143void copyIt2()
1144{
1145DefaultedAndDeleted ca;
1146DefaultedAndDeleted ca2;
1147ca2 = ca;
1148}
1149
1150void hasDefaultArg(int i, int j = 0)
1151{
1152}
1153void callDefaultArg()
1154{
1155hasDefaultArg(42);
1156}
1157
1158void decomposition()
1159{
1160int arr[3];
1161auto &[f, s, t] = arr;
1162
1163f = 42;
1164}
1165
1166typedef __typeof(sizeof(int)) size_t;
1167
1168struct Pair
1169{
1170int x, y;
1171};
1172
1173// Note: these utilities are required to force binding to tuple like structure
1174namespace std
1175{
1176template <typename E>
1177struct tuple_size
1178{
1179};
1180
1181template <>
1182struct tuple_size<Pair>
1183{
1184static constexpr size_t value = 2;
1185};
1186
1187template <size_t I, class T>
1188struct tuple_element
1189{
1190using type = int;
1191};
1192
1193};
1194
1195template <size_t I>
1196int &&get(Pair &&p);
1197
1198void decompTuple()
1199{
1200Pair p{1, 2};
1201auto [a, b] = p;
1202
1203a = 3;
1204}
1205
1206)cpp",1207{"-std=c++20"});1208
1209{1210auto BN = ast_matchers::match(1211cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),1212AST2->getASTContext());1213EXPECT_EQ(BN.size(), 1u);1214
1215EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1216R"cpp(1217CXXRecordDecl '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
1239EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1240BN[0].getNodeAs<Decl>("rec")),1241R"cpp(1242CXXRecordDecl '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{1257auto BN = ast_matchers::match(1258cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))1259.bind("rec"),1260AST2->getASTContext());1261EXPECT_EQ(BN.size(), 1u);1262
1263EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1264R"cpp(1265CXXRecordDecl '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
1322EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1323BN[0].getNodeAs<Decl>("rec")),1324R"cpp(1325CXXRecordDecl 'ContainsArray'
1326|-FieldDecl 'arr'
1327|-FieldDecl 'irr'
1328`-CXXMethodDecl 'operator='
1329`-ParmVarDecl ''
1330)cpp");1331}1332{1333auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),1334AST2->getASTContext());1335EXPECT_EQ(BN.size(), 1u);1336
1337EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),1338R"cpp(1339FunctionDecl '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
1405EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1406BN[0].getNodeAs<Decl>("func")),1407R"cpp(1408FunctionDecl '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{1427auto BN = ast_matchers::match(1428cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))1429.bind("rec"),1430AST2->getASTContext());1431EXPECT_EQ(BN.size(), 1u);1432
1433EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1434R"cpp(1435CXXRecordDecl '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
1464EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1465BN[0].getNodeAs<Decl>("rec")),1466R"cpp(1467CXXRecordDecl '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{1482auto BN = ast_matchers::match(1483callExpr(callee(functionDecl(hasName("hasDefaultArg"))))1484.bind("funcCall"),1485AST2->getASTContext());1486EXPECT_EQ(BN.size(), 1u);1487
1488EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),1489R"cpp(1490CallExpr
1491|-ImplicitCastExpr
1492| `-DeclRefExpr 'hasDefaultArg'
1493|-IntegerLiteral
1494`-CXXDefaultArgExpr
1495`-IntegerLiteral
1496)cpp");1497EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1498BN[0].getNodeAs<CallExpr>("funcCall")),1499R"cpp(1500CallExpr
1501|-DeclRefExpr 'hasDefaultArg'
1502`-IntegerLiteral
1503)cpp");1504}1505
1506{1507auto FN = ast_matchers::match(1508functionDecl(hasName("decomposition"),1509hasDescendant(decompositionDecl().bind("decomp"))),1510AST2->getASTContext());1511EXPECT_EQ(FN.size(), 1u);1512
1513EXPECT_EQ(1514dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),1515R"cpp(1516DecompositionDecl ''
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
1535EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1536FN[0].getNodeAs<DecompositionDecl>("decomp")),1537R"cpp(1538DecompositionDecl ''
1539|-DeclRefExpr 'arr'
1540|-BindingDecl 'f'
1541|-BindingDecl 's'
1542`-BindingDecl 't'
1543)cpp");1544}1545
1546{1547auto FN = ast_matchers::match(1548functionDecl(hasName("decompTuple"),1549hasDescendant(decompositionDecl().bind("decomp"))),1550AST2->getASTContext());1551EXPECT_EQ(FN.size(), 1u);1552
1553EXPECT_EQ(1554dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),1555R"cpp(1556DecompositionDecl ''
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
1578EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1579FN[0].getNodeAs<DecompositionDecl>("decomp")),1580R"cpp(1581DecompositionDecl ''
1582|-DeclRefExpr 'p'
1583|-BindingDecl 'a'
1584`-BindingDecl 'b'
1585)cpp");1586}1587}
1588
1589TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {1590
1591auto AST = buildASTFromCode(R"cpp(1592template<typename T>
1593struct TemplStruct {
1594TemplStruct() {}
1595~TemplStruct() {}
1596
1597private:
1598T m_t;
1599};
1600
1601template<typename T>
1602T timesTwo(T input)
1603{
1604return input * 2;
1605}
1606
1607void instantiate()
1608{
1609TemplStruct<int> ti;
1610TemplStruct<double> td;
1611(void)timesTwo<int>(2);
1612(void)timesTwo<double>(2);
1613}
1614
1615template class TemplStruct<float>;
1616
1617extern template class TemplStruct<long>;
1618
1619template<> class TemplStruct<bool> {
1620TemplStruct() {}
1621~TemplStruct() {}
1622
1623void foo() {}
1624private:
1625bool m_t;
1626};
1627
1628// Explicit instantiation of template functions do not appear in the AST
1629template float timesTwo(float);
1630
1631template<> bool timesTwo<bool>(bool) {
1632return true;
1633}
1634)cpp");1635{1636auto BN = ast_matchers::match(1637classTemplateDecl(hasName("TemplStruct")).bind("rec"),1638AST->getASTContext());1639EXPECT_EQ(BN.size(), 1u);1640
1641EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1642BN[0].getNodeAs<Decl>("rec")),1643R"cpp(1644ClassTemplateDecl '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
1655EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1656R"cpp(1657ClassTemplateDecl '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{1724auto BN = ast_matchers::match(1725classTemplateSpecializationDecl(1726hasTemplateArgument(17270, templateArgument(refersToType(asString("_Bool")))))1728.bind("templSpec"),1729AST->getASTContext());1730EXPECT_EQ(BN.size(), 1u);1731
1732EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")),1733R"cpp(1734ClassTemplateSpecializationDecl '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
1748EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1749BN[0].getNodeAs<Decl>("templSpec")),1750R"cpp(1751ClassTemplateSpecializationDecl '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{1765auto BN = ast_matchers::match(1766functionTemplateDecl(hasName("timesTwo")).bind("fn"),1767AST->getASTContext());1768EXPECT_EQ(BN.size(), 1u);1769
1770EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1771BN[0].getNodeAs<Decl>("fn")),1772R"cpp(1773FunctionTemplateDecl 'timesTwo'
1774|-TemplateTypeParmDecl 'T'
1775`-FunctionDecl 'timesTwo'
1776|-ParmVarDecl 'input'
1777`-CompoundStmt
1778`-ReturnStmt
1779`-BinaryOperator
1780|-DeclRefExpr 'input'
1781`-IntegerLiteral
1782)cpp");1783
1784EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),1785R"cpp(1786FunctionTemplateDecl '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{1841auto BN = ast_matchers::match(1842classTemplateSpecializationDecl(1843hasName("TemplStruct"),1844hasTemplateArgument(18450, templateArgument(refersToType(asString("float")))),1846hasParent(translationUnitDecl()))1847.bind("rec"),1848AST->getASTContext());1849EXPECT_EQ(BN.size(), 1u);1850
1851EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1852BN[0].getNodeAs<Decl>("rec")),1853R"cpp(1854ClassTemplateSpecializationDecl 'TemplStruct'
1855`-TemplateArgument type float
1856`-BuiltinType
1857)cpp");1858
1859EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1860R"cpp(1861ClassTemplateSpecializationDecl '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
1875TEST(Traverse, CXXRewrittenBinaryOperator) {1876
1877auto AST = buildASTFromCodeWithArgs(R"cpp(1878namespace std {
1879struct strong_ordering {
1880int n;
1881constexpr operator int() const { return n; }
1882static const strong_ordering equal, greater, less;
1883};
1884constexpr strong_ordering strong_ordering::equal = {0};
1885constexpr strong_ordering strong_ordering::greater = {1};
1886constexpr strong_ordering strong_ordering::less = {-1};
1887}
1888
1889struct HasSpaceshipMem {
1890int a;
1891constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1892};
1893
1894void binop()
1895{
1896HasSpaceshipMem hs1, hs2;
1897if (hs1 < hs2)
1898return;
1899}
1900)cpp",1901{"-std=c++20"});1902{1903auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),1904AST->getASTContext());1905EXPECT_EQ(BN.size(), 1u);1906
1907EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")),1908R"cpp(1909CXXRewrittenBinaryOperator
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");1925EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1926BN[0].getNodeAs<Stmt>("binop")),1927R"cpp(1928CXXRewrittenBinaryOperator
1929|-DeclRefExpr 'hs1'
1930`-DeclRefExpr 'hs2'
1931)cpp");1932}1933}
1934
1935} // namespace clang1936