blob: d39ca4b39a7f302bec823da89d11e5f892457cf2 [file] [log] [blame]
Manuel Klimek20c1c892014-10-09 15:02:06 +00001//===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.cpp ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "TestVisitor.h"
Manuel Klimek20c1c892014-10-09 15:02:06 +000011
12using namespace clang;
13
14namespace {
15
16class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
17public:
18 bool VisitParenExpr(ParenExpr *Parens) {
19 Match("", Parens->getExprLoc());
20 return true;
21 }
22};
23
24TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
25 ParenExprVisitor Visitor;
26 Visitor.ExpectMatch("", 1, 9);
27 EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
28}
29
30class TemplateArgumentLocTraverser
31 : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
32public:
33 bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
34 std::string ArgStr;
35 llvm::raw_string_ostream Stream(ArgStr);
36 const TemplateArgument &Arg = ArgLoc.getArgument();
37
38 Arg.print(Context->getPrintingPolicy(), Stream);
39 Match(Stream.str(), ArgLoc.getLocation());
40 return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
41 TraverseTemplateArgumentLoc(ArgLoc);
42 }
43};
44
45TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
46 TemplateArgumentLocTraverser Visitor;
47 Visitor.ExpectMatch("X", 2, 40);
48 EXPECT_TRUE(Visitor.runOver(
49 "template<typename T> class X;\n"
50 "template<template <typename> class T = X> class Y;\n"
51 "template<template <typename> class T> class Y {};\n"));
52}
53
54class CXXBoolLiteralExprVisitor
55 : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
56public:
57 bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
58 if (BE->getValue())
59 Match("true", BE->getLocation());
60 else
61 Match("false", BE->getLocation());
62 return true;
63 }
64};
65
66TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
67 CXXBoolLiteralExprVisitor Visitor;
68 Visitor.ExpectMatch("true", 2, 19);
69 EXPECT_TRUE(Visitor.runOver(
70 "template<bool B> class X;\n"
71 "template<bool B = true> class Y;\n"
72 "template<bool B> class Y {};\n"));
73}
74
75// A visitor that visits implicit declarations and matches constructors.
76class ImplicitCtorVisitor
77 : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
78public:
79 bool shouldVisitImplicitCode() const { return true; }
80
81 bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
82 if (Ctor->isImplicit()) { // Was not written in source code
83 if (const CXXRecordDecl* Class = Ctor->getParent()) {
84 Match(Class->getName(), Ctor->getLocation());
85 }
86 }
87 return true;
88 }
89};
90
91TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
92 ImplicitCtorVisitor Visitor;
93 Visitor.ExpectMatch("Simple", 2, 8);
94 // Note: Clang lazily instantiates implicit declarations, so we need
95 // to use them in order to force them to appear in the AST.
96 EXPECT_TRUE(Visitor.runOver(
97 "struct WithCtor { WithCtor(); }; \n"
98 "struct Simple { Simple(); WithCtor w; }; \n"
99 "int main() { Simple s; Simple t(s); }\n"));
100}
101
102/// \brief A visitor that optionally includes implicit code and matches
103/// CXXConstructExpr.
104///
105/// The name recorded for the match is the name of the class whose constructor
106/// is invoked by the CXXConstructExpr, not the name of the class whose
107/// constructor the CXXConstructExpr is contained in.
108class ConstructExprVisitor
109 : public ExpectedLocationVisitor<ConstructExprVisitor> {
110public:
111 ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
112
113 bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
114
115 void setShouldVisitImplicitCode(bool NewValue) {
116 ShouldVisitImplicitCode = NewValue;
117 }
118
119 bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
120 if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
121 if (const CXXRecordDecl* Class = Ctor->getParent()) {
122 Match(Class->getName(), Expr->getLocation());
123 }
124 }
125 return true;
126 }
127
128 private:
129 bool ShouldVisitImplicitCode;
130};
131
132TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
133 ConstructExprVisitor Visitor;
134 Visitor.setShouldVisitImplicitCode(true);
135 Visitor.ExpectMatch("WithCtor", 2, 8);
136 // Simple has a constructor that implicitly initializes 'w'. Test
137 // that a visitor that visits implicit code visits that initialization.
138 // Note: Clang lazily instantiates implicit declarations, so we need
139 // to use them in order to force them to appear in the AST.
140 EXPECT_TRUE(Visitor.runOver(
141 "struct WithCtor { WithCtor(); }; \n"
142 "struct Simple { WithCtor w; }; \n"
143 "int main() { Simple s; }\n"));
144}
145
146// The same as CanVisitImplicitMemberInitializations, but checking that the
147// visits are omitted when the visitor does not include implicit code.
148TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
149 ConstructExprVisitor Visitor;
150 Visitor.setShouldVisitImplicitCode(false);
151 Visitor.DisallowMatch("WithCtor", 2, 8);
152 // Simple has a constructor that implicitly initializes 'w'. Test
153 // that a visitor that skips implicit code skips that initialization.
154 // Note: Clang lazily instantiates implicit declarations, so we need
155 // to use them in order to force them to appear in the AST.
156 EXPECT_TRUE(Visitor.runOver(
157 "struct WithCtor { WithCtor(); }; \n"
158 "struct Simple { WithCtor w; }; \n"
159 "int main() { Simple s; }\n"));
160}
161
162class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
163public:
164 bool VisitDeclRefExpr(DeclRefExpr *Reference) {
165 Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
166 return true;
167 }
168};
169
170TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
171 DeclRefExprVisitor Visitor;
172 Visitor.ExpectMatch("x", 2, 3);
173 EXPECT_TRUE(Visitor.runOver(
174 "void x(); template <void (*T)()> class X {};\nX<x> y;"));
175}
176
177TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
178 DeclRefExprVisitor Visitor;
179 Visitor.ExpectMatch("x", 2, 25);
180 Visitor.ExpectMatch("x", 2, 30);
181 EXPECT_TRUE(Visitor.runOver(
182 "int x[5];\n"
183 "void f() { for (int i : x) { x[0] = 1; } }",
184 DeclRefExprVisitor::Lang_CXX11));
185}
186
187TEST(RecursiveASTVisitor, VisitsCallExpr) {
188 DeclRefExprVisitor Visitor;
189 Visitor.ExpectMatch("x", 1, 22);
190 EXPECT_TRUE(Visitor.runOver(
191 "void x(); void y() { x(); }"));
192}
193
Martin Bohme78bac522016-08-01 12:15:46 +0000194TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
195 DeclRefExprVisitor Visitor;
196 Visitor.ExpectMatch("i", 1, 20);
197 EXPECT_TRUE(Visitor.runOver(
198 "void f() { int i; [i]{}; };",
199 DeclRefExprVisitor::Lang_CXX11));
200}
201
Manuel Klimek20c1c892014-10-09 15:02:06 +0000202/* FIXME: According to Richard Smith this is a bug in the AST.
203TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
204 DeclRefExprVisitor Visitor;
205 Visitor.ExpectMatch("x", 3, 43);
206 EXPECT_TRUE(Visitor.runOver(
207 "template <typename T> void x();\n"
208 "template <void (*T)()> class X {};\n"
209 "template <typename T> class Y : public X< x<T> > {};\n"
210 "Y<int> y;"));
211}
212*/
213
214TEST(RecursiveASTVisitor, VisitsExtension) {
215 DeclRefExprVisitor Visitor;
216 Visitor.ExpectMatch("s", 1, 24);
217 EXPECT_TRUE(Visitor.runOver(
218 "int s = __extension__ (s);\n"));
219}
220
221TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
222 DeclRefExprVisitor Visitor;
223 Visitor.ExpectMatch("x", 3, 24);
224 EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
225 "void g() { \n"
226 " f([&](int x){ return x; }); \n"
227 "}",
228 DeclRefExprVisitor::Lang_OBJCXX11));
229}
230
231} // end anonymous namespace