1 //===- unittest/Tooling/SourceCodeTest.cpp --------------------------------===//
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/Tooling/Transformer/SourceCode.h"
10 #include "TestVisitor.h"
11 #include "clang/Basic/Diagnostic.h"
12 #include "llvm/Testing/Support/Annotations.h"
13 #include "llvm/Testing/Support/Error.h"
14 #include "llvm/Testing/Support/SupportHelpers.h"
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 using namespace clang;
19 
20 using llvm::Failed;
21 using llvm::Succeeded;
22 using llvm::ValueIs;
23 using tooling::getExtendedText;
24 using tooling::getRangeForEdit;
25 using tooling::getText;
26 using tooling::validateEditRange;
27 
28 namespace {
29 
30 struct IntLitVisitor : TestVisitor<IntLitVisitor> {
31   bool VisitIntegerLiteral(IntegerLiteral *Expr) {
32     OnIntLit(Expr, Context);
33     return true;
34   }
35 
36   std::function<void(IntegerLiteral *, ASTContext *Context)> OnIntLit;
37 };
38 
39 struct CallsVisitor : TestVisitor<CallsVisitor> {
40   bool VisitCallExpr(CallExpr *Expr) {
41     OnCall(Expr, Context);
42     return true;
43   }
44 
45   std::function<void(CallExpr *, ASTContext *Context)> OnCall;
46 };
47 
48 // Equality matcher for `clang::CharSourceRange`, which lacks `operator==`.
49 MATCHER_P(EqualsRange, R, "") {
50   return arg.isTokenRange() == R.isTokenRange() &&
51          arg.getBegin() == R.getBegin() && arg.getEnd() == R.getEnd();
52 }
53 
54 static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM,
55                                                    llvm::Annotations::Range R) {
56   return EqualsRange(CharSourceRange::getCharRange(
57       SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.Begin),
58       SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.End)));
59 }
60 
61 TEST(SourceCodeTest, getText) {
62   CallsVisitor Visitor;
63 
64   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
65     EXPECT_EQ("foo(x, y)", getText(*CE, *Context));
66   };
67   Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
68 
69   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
70     EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context));
71   };
72   Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
73                   "void foo(int x, int y) { APPLY(foo, x, y); }");
74 }
75 
76 TEST(SourceCodeTest, getTextWithMacro) {
77   CallsVisitor Visitor;
78 
79   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
80     EXPECT_EQ("F OO", getText(*CE, *Context));
81     Expr *P0 = CE->getArg(0);
82     Expr *P1 = CE->getArg(1);
83     EXPECT_EQ("", getText(*P0, *Context));
84     EXPECT_EQ("", getText(*P1, *Context));
85   };
86   Visitor.runOver("#define F foo(\n"
87                   "#define OO x, y)\n"
88                   "void foo(int x, int y) { F OO ; }");
89 
90   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
91     EXPECT_EQ("", getText(*CE, *Context));
92     Expr *P0 = CE->getArg(0);
93     Expr *P1 = CE->getArg(1);
94     EXPECT_EQ("x", getText(*P0, *Context));
95     EXPECT_EQ("y", getText(*P1, *Context));
96   };
97   Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
98                   "void foo(int x, int y) { FOO(x,y) }");
99 }
100 
101 TEST(SourceCodeTest, getExtendedText) {
102   CallsVisitor Visitor;
103 
104   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
105     EXPECT_EQ("foo(x, y);",
106               getExtendedText(*CE, tok::TokenKind::semi, *Context));
107 
108     Expr *P0 = CE->getArg(0);
109     Expr *P1 = CE->getArg(1);
110     EXPECT_EQ("x", getExtendedText(*P0, tok::TokenKind::semi, *Context));
111     EXPECT_EQ("x,", getExtendedText(*P0, tok::TokenKind::comma, *Context));
112     EXPECT_EQ("y", getExtendedText(*P1, tok::TokenKind::semi, *Context));
113   };
114   Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
115   Visitor.runOver("void foo(int x, int y) { if (true) foo(x, y); }");
116   Visitor.runOver("int foo(int x, int y) { if (true) return 3 + foo(x, y); }");
117   Visitor.runOver("void foo(int x, int y) { for (foo(x, y);;) ++x; }");
118   Visitor.runOver(
119       "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }");
120 
121   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
122     EXPECT_EQ("foo()", getExtendedText(*CE, tok::TokenKind::semi, *Context));
123   };
124   Visitor.runOver("bool foo() { if (foo()) return true; return false; }");
125   Visitor.runOver("void foo() { int x; for (;; foo()) ++x; }");
126   Visitor.runOver("int foo() { return foo() + 3; }");
127 }
128 
129 TEST(SourceCodeTest, EditRangeWithMacroExpansionsShouldSucceed) {
130   // The call expression, whose range we are extracting, includes two macro
131   // expansions.
132   llvm::Annotations Code(R"cpp(
133 #define M(a) a * 13
134 int foo(int x, int y);
135 int a = $r[[foo(M(1), M(2))]];
136 )cpp");
137 
138   CallsVisitor Visitor;
139 
140   Visitor.OnCall = [&Code](CallExpr *CE, ASTContext *Context) {
141     auto Range = CharSourceRange::getTokenRange(CE->getSourceRange());
142     EXPECT_THAT(getRangeForEdit(Range, *Context),
143                 ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
144   };
145   Visitor.runOver(Code.code());
146 }
147 
148 TEST(SourceCodeTest, EditWholeMacroExpansionShouldSucceed) {
149   llvm::Annotations Code(R"cpp(
150 #define FOO 10
151 int a = $r[[FOO]];
152 )cpp");
153 
154   IntLitVisitor Visitor;
155   Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
156     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
157     EXPECT_THAT(getRangeForEdit(Range, *Context),
158                 ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
159   };
160   Visitor.runOver(Code.code());
161 }
162 
163 TEST(SourceCodeTest, EditPartialMacroExpansionShouldFail) {
164   std::string Code = R"cpp(
165 #define BAR 10+
166 int c = BAR 3.0;
167 )cpp";
168 
169   IntLitVisitor Visitor;
170   Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
171     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
172     EXPECT_FALSE(getRangeForEdit(Range, *Context).hasValue());
173   };
174   Visitor.runOver(Code);
175 }
176 
177 TEST(SourceCodeTest, EditWholeMacroArgShouldSucceed) {
178   llvm::Annotations Code(R"cpp(
179 #define FOO(a) a + 7.0;
180 int a = FOO($r[[10]]);
181 )cpp");
182 
183   IntLitVisitor Visitor;
184   Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
185     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
186     EXPECT_THAT(getRangeForEdit(Range, *Context),
187                 ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
188   };
189   Visitor.runOver(Code.code());
190 }
191 
192 TEST(SourceCodeTest, EditPartialMacroArgShouldSucceed) {
193   llvm::Annotations Code(R"cpp(
194 #define FOO(a) a + 7.0;
195 int a = FOO($r[[10]] + 10.0);
196 )cpp");
197 
198   IntLitVisitor Visitor;
199   Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
200     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
201     EXPECT_THAT(getRangeForEdit(Range, *Context),
202                 ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
203   };
204   Visitor.runOver(Code.code());
205 }
206 
207 TEST(SourceCodeTest, EditRangeWithMacroExpansionsIsValid) {
208   // The call expression, whose range we are extracting, includes two macro
209   // expansions.
210   llvm::StringRef Code = R"cpp(
211 #define M(a) a * 13
212 int foo(int x, int y);
213 int a = foo(M(1), M(2));
214 )cpp";
215 
216   CallsVisitor Visitor;
217 
218   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
219     auto Range = CharSourceRange::getTokenRange(CE->getSourceRange());
220     EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()),
221                       Succeeded());
222   };
223   Visitor.runOver(Code);
224 }
225 
226 TEST(SourceCodeTest, SpellingRangeOfMacroArgIsValid) {
227   llvm::StringRef Code = R"cpp(
228 #define FOO(a) a + 7.0;
229 int a = FOO(10);
230 )cpp";
231 
232   IntLitVisitor Visitor;
233   Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
234     SourceLocation ArgLoc =
235         Context->getSourceManager().getSpellingLoc(Expr->getBeginLoc());
236     // The integer literal is a single token.
237     auto ArgRange = CharSourceRange::getTokenRange(ArgLoc);
238     EXPECT_THAT_ERROR(validateEditRange(ArgRange, Context->getSourceManager()),
239                       Succeeded());
240   };
241   Visitor.runOver(Code);
242 }
243 
244 TEST(SourceCodeTest, InvalidEditRangeIsInvalid) {
245   llvm::StringRef Code = "int c = 10;";
246 
247   // We use the visitor just to get a valid context.
248   IntLitVisitor Visitor;
249   Visitor.OnIntLit = [](IntegerLiteral *, ASTContext *Context) {
250     CharSourceRange Invalid;
251     EXPECT_THAT_ERROR(validateEditRange(Invalid, Context->getSourceManager()),
252                       Failed());
253   };
254   Visitor.runOver(Code);
255 }
256 
257 TEST(SourceCodeTest, InvertedEditRangeIsInvalid) {
258   llvm::StringRef Code = R"cpp(
259 int foo(int x);
260 int a = foo(2);
261 )cpp";
262 
263   CallsVisitor Visitor;
264   Visitor.OnCall = [](CallExpr *Expr, ASTContext *Context) {
265     auto InvertedRange = CharSourceRange::getTokenRange(
266         SourceRange(Expr->getEndLoc(), Expr->getBeginLoc()));
267     EXPECT_THAT_ERROR(
268         validateEditRange(InvertedRange, Context->getSourceManager()),
269         Failed());
270   };
271   Visitor.runOver(Code);
272 }
273 
274 TEST(SourceCodeTest, MacroArgIsInvalid) {
275   llvm::StringRef Code = R"cpp(
276 #define FOO(a) a + 7.0;
277 int a = FOO(10);
278 )cpp";
279 
280   IntLitVisitor Visitor;
281   Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
282     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
283     EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()),
284                       Failed());
285   };
286   Visitor.runOver(Code);
287 }
288 
289 TEST(SourceCodeTest, EditWholeMacroExpansionIsInvalid) {
290   llvm::StringRef Code = R"cpp(
291 #define FOO 10
292 int a = FOO;
293 )cpp";
294 
295   IntLitVisitor Visitor;
296   Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
297     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
298     EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()),
299                       Failed());
300 
301   };
302   Visitor.runOver(Code);
303 }
304 
305 TEST(SourceCodeTest, EditPartialMacroExpansionIsInvalid) {
306   llvm::StringRef Code = R"cpp(
307 #define BAR 10+
308 int c = BAR 3.0;
309 )cpp";
310 
311   IntLitVisitor Visitor;
312   Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
313     auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
314     EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()),
315                       Failed());
316   };
317   Visitor.runOver(Code);
318 }
319 } // end anonymous namespace
320