blob: 7b62fc1571abb742ccc6f655162b29707d60674c [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
Manuel Klimek20c1c892014-10-09 15:02:06 +0000194/* FIXME: According to Richard Smith this is a bug in the AST.
195TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
196 DeclRefExprVisitor Visitor;
197 Visitor.ExpectMatch("x", 3, 43);
198 EXPECT_TRUE(Visitor.runOver(
199 "template <typename T> void x();\n"
200 "template <void (*T)()> class X {};\n"
201 "template <typename T> class Y : public X< x<T> > {};\n"
202 "Y<int> y;"));
203}
204*/
205
206TEST(RecursiveASTVisitor, VisitsExtension) {
207 DeclRefExprVisitor Visitor;
208 Visitor.ExpectMatch("s", 1, 24);
209 EXPECT_TRUE(Visitor.runOver(
210 "int s = __extension__ (s);\n"));
211}
212
213TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
214 DeclRefExprVisitor Visitor;
215 Visitor.ExpectMatch("x", 3, 24);
216 EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
217 "void g() { \n"
218 " f([&](int x){ return x; }); \n"
219 "}",
220 DeclRefExprVisitor::Lang_OBJCXX11));
221}
222
223} // end anonymous namespace