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