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 "clang/Basic/SourceLocation.h" |
13 | #include "clang/Lex/Lexer.h" |
14 | #include "llvm/Testing/Annotations/Annotations.h" |
15 | #include "llvm/Testing/Support/Error.h" |
16 | #include "llvm/Testing/Support/SupportHelpers.h" |
17 | #include <gmock/gmock.h> |
18 | #include <gtest/gtest.h> |
19 | |
20 | using namespace clang; |
21 | |
22 | using llvm::Failed; |
23 | using llvm::Succeeded; |
24 | using llvm::ValueIs; |
25 | using tooling::getAssociatedRange; |
26 | using tooling::getExtendedRange; |
27 | using tooling::getExtendedText; |
28 | using tooling::getFileRangeForEdit; |
29 | using tooling::getText; |
30 | using tooling::maybeExtendRange; |
31 | using tooling::validateEditRange; |
32 | |
33 | namespace { |
34 | |
35 | struct IntLitVisitor : TestVisitor<IntLitVisitor> { |
36 | bool VisitIntegerLiteral(IntegerLiteral *Expr) { |
37 | OnIntLit(Expr, Context); |
38 | return true; |
39 | } |
40 | |
41 | std::function<void(IntegerLiteral *, ASTContext *Context)> OnIntLit; |
42 | }; |
43 | |
44 | struct CallsVisitor : TestVisitor<CallsVisitor> { |
45 | bool VisitCallExpr(CallExpr *Expr) { |
46 | OnCall(Expr, Context); |
47 | return true; |
48 | } |
49 | |
50 | std::function<void(CallExpr *, ASTContext *Context)> OnCall; |
51 | }; |
52 | |
53 | // Equality matcher for `clang::CharSourceRange`, which lacks `operator==`. |
54 | MATCHER_P(EqualsRange, R, "" ) { |
55 | return arg.isTokenRange() == R.isTokenRange() && |
56 | arg.getBegin() == R.getBegin() && arg.getEnd() == R.getEnd(); |
57 | } |
58 | |
59 | MATCHER_P2(EqualsAnnotatedRange, Context, R, "" ) { |
60 | if (arg.getBegin().isMacroID()) { |
61 | *result_listener << "which starts in a macro" ; |
62 | return false; |
63 | } |
64 | if (arg.getEnd().isMacroID()) { |
65 | *result_listener << "which ends in a macro" ; |
66 | return false; |
67 | } |
68 | |
69 | CharSourceRange Range = Lexer::getAsCharRange( |
70 | arg, Context->getSourceManager(), Context->getLangOpts()); |
71 | unsigned Begin = Context->getSourceManager().getFileOffset(Range.getBegin()); |
72 | unsigned End = Context->getSourceManager().getFileOffset(Range.getEnd()); |
73 | |
74 | *result_listener << "which is a " << (arg.isTokenRange() ? "Token" : "Char" ) |
75 | << " range [" << Begin << "," << End << ")" ; |
76 | return Begin == R.Begin && End == R.End; |
77 | } |
78 | |
79 | static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM, |
80 | llvm::Annotations::Range R) { |
81 | return EqualsRange(gmock_p0: CharSourceRange::getCharRange( |
82 | B: SM.getLocForStartOfFile(FID: SM.getMainFileID()).getLocWithOffset(Offset: R.Begin), |
83 | E: SM.getLocForStartOfFile(FID: SM.getMainFileID()).getLocWithOffset(Offset: R.End))); |
84 | } |
85 | |
86 | // Base class for visitors that expect a single match corresponding to a |
87 | // specific annotated range. |
88 | template <typename T> class AnnotatedCodeVisitor : public TestVisitor<T> { |
89 | protected: |
90 | int MatchCount = 0; |
91 | llvm::Annotations Code; |
92 | |
93 | public: |
94 | AnnotatedCodeVisitor() : Code("$r[[]]" ) {} |
95 | // Helper for tests of `getAssociatedRange`. |
96 | bool VisitDeclHelper(Decl *Decl) { |
97 | // Only consider explicit declarations. |
98 | if (Decl->isImplicit()) |
99 | return true; |
100 | |
101 | ++MatchCount; |
102 | EXPECT_THAT(getAssociatedRange(*Decl, *this->Context), |
103 | EqualsAnnotatedRange(this->Context, Code.range("r" ))) |
104 | << Code.code(); |
105 | return true; |
106 | } |
107 | |
108 | bool runOverAnnotated(llvm::StringRef AnnotatedCode, |
109 | std::vector<std::string> Args = {}) { |
110 | Code = llvm::Annotations(AnnotatedCode); |
111 | MatchCount = 0; |
112 | Args.push_back(x: "-std=c++11" ); |
113 | Args.push_back(x: "-fno-delayed-template-parsing" ); |
114 | bool result = tooling::runToolOnCodeWithArgs(this->CreateTestAction(), |
115 | Code.code(), Args); |
116 | EXPECT_EQ(MatchCount, 1) << AnnotatedCode; |
117 | return result; |
118 | } |
119 | }; |
120 | |
121 | TEST(SourceCodeTest, getText) { |
122 | CallsVisitor Visitor; |
123 | |
124 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
125 | EXPECT_EQ("foo(x, y)" , getText(*CE, *Context)); |
126 | }; |
127 | Visitor.runOver(Code: "void foo(int x, int y) { foo(x, y); }" ); |
128 | |
129 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
130 | EXPECT_EQ("APPLY(foo, x, y)" , getText(*CE, *Context)); |
131 | }; |
132 | Visitor.runOver(Code: "#define APPLY(f, x, y) f(x, y)\n" |
133 | "void foo(int x, int y) { APPLY(foo, x, y); }" ); |
134 | } |
135 | |
136 | TEST(SourceCodeTest, getTextWithMacro) { |
137 | CallsVisitor Visitor; |
138 | |
139 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
140 | EXPECT_EQ("F OO" , getText(*CE, *Context)); |
141 | Expr *P0 = CE->getArg(Arg: 0); |
142 | Expr *P1 = CE->getArg(Arg: 1); |
143 | EXPECT_EQ("" , getText(*P0, *Context)); |
144 | EXPECT_EQ("" , getText(*P1, *Context)); |
145 | }; |
146 | Visitor.runOver(Code: "#define F foo(\n" |
147 | "#define OO x, y)\n" |
148 | "void foo(int x, int y) { F OO ; }" ); |
149 | |
150 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
151 | EXPECT_EQ("" , getText(*CE, *Context)); |
152 | Expr *P0 = CE->getArg(Arg: 0); |
153 | Expr *P1 = CE->getArg(Arg: 1); |
154 | EXPECT_EQ("x" , getText(*P0, *Context)); |
155 | EXPECT_EQ("y" , getText(*P1, *Context)); |
156 | }; |
157 | Visitor.runOver(Code: "#define FOO(x, y) (void)x; (void)y; foo(x, y);\n" |
158 | "void foo(int x, int y) { FOO(x,y) }" ); |
159 | } |
160 | |
161 | TEST(SourceCodeTest, getExtendedText) { |
162 | CallsVisitor Visitor; |
163 | |
164 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
165 | EXPECT_EQ("foo(x, y);" , |
166 | getExtendedText(*CE, tok::TokenKind::semi, *Context)); |
167 | |
168 | Expr *P0 = CE->getArg(Arg: 0); |
169 | Expr *P1 = CE->getArg(Arg: 1); |
170 | EXPECT_EQ("x" , getExtendedText(*P0, tok::TokenKind::semi, *Context)); |
171 | EXPECT_EQ("x," , getExtendedText(*P0, tok::TokenKind::comma, *Context)); |
172 | EXPECT_EQ("y" , getExtendedText(*P1, tok::TokenKind::semi, *Context)); |
173 | }; |
174 | Visitor.runOver(Code: "void foo(int x, int y) { foo(x, y); }" ); |
175 | Visitor.runOver(Code: "void foo(int x, int y) { if (true) foo(x, y); }" ); |
176 | Visitor.runOver(Code: "int foo(int x, int y) { if (true) return 3 + foo(x, y); }" ); |
177 | Visitor.runOver(Code: "void foo(int x, int y) { for (foo(x, y);;) ++x; }" ); |
178 | Visitor.runOver( |
179 | Code: "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }" ); |
180 | |
181 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
182 | EXPECT_EQ("foo()" , getExtendedText(*CE, tok::TokenKind::semi, *Context)); |
183 | }; |
184 | Visitor.runOver(Code: "bool foo() { if (foo()) return true; return false; }" ); |
185 | Visitor.runOver(Code: "void foo() { int x; for (;; foo()) ++x; }" ); |
186 | Visitor.runOver(Code: "int foo() { return foo() + 3; }" ); |
187 | } |
188 | |
189 | TEST(SourceCodeTest, maybeExtendRange_TokenRange) { |
190 | struct ExtendTokenRangeVisitor |
191 | : AnnotatedCodeVisitor<ExtendTokenRangeVisitor> { |
192 | bool VisitCallExpr(CallExpr *CE) { |
193 | ++MatchCount; |
194 | EXPECT_THAT(getExtendedRange(*CE, tok::TokenKind::semi, *Context), |
195 | EqualsAnnotatedRange(Context, Code.range("r" ))); |
196 | return true; |
197 | } |
198 | }; |
199 | |
200 | ExtendTokenRangeVisitor Visitor; |
201 | // Extends to include semicolon. |
202 | Visitor.runOverAnnotated(AnnotatedCode: "void f(int x, int y) { $r[[f(x, y);]] }" ); |
203 | // Does not extend to include semicolon. |
204 | Visitor.runOverAnnotated( |
205 | AnnotatedCode: "int f(int x, int y) { if (0) return $r[[f(x, y)]] + 3; }" ); |
206 | } |
207 | |
208 | TEST(SourceCodeTest, maybeExtendRange_CharRange) { |
209 | struct ExtendCharRangeVisitor : AnnotatedCodeVisitor<ExtendCharRangeVisitor> { |
210 | bool VisitCallExpr(CallExpr *CE) { |
211 | ++MatchCount; |
212 | CharSourceRange Call = Lexer::getAsCharRange(CE->getSourceRange(), |
213 | Context->getSourceManager(), |
214 | Context->getLangOpts()); |
215 | EXPECT_THAT(maybeExtendRange(Call, tok::TokenKind::semi, *Context), |
216 | EqualsAnnotatedRange(Context, Code.range("r" ))); |
217 | return true; |
218 | } |
219 | }; |
220 | ExtendCharRangeVisitor Visitor; |
221 | // Extends to include semicolon. |
222 | Visitor.runOverAnnotated(AnnotatedCode: "void f(int x, int y) { $r[[f(x, y);]] }" ); |
223 | // Does not extend to include semicolon. |
224 | Visitor.runOverAnnotated( |
225 | AnnotatedCode: "int f(int x, int y) { if (0) return $r[[f(x, y)]] + 3; }" ); |
226 | } |
227 | |
228 | TEST(SourceCodeTest, getAssociatedRange) { |
229 | struct VarDeclsVisitor : AnnotatedCodeVisitor<VarDeclsVisitor> { |
230 | bool VisitVarDecl(VarDecl *Decl) { return VisitDeclHelper(Decl); } |
231 | }; |
232 | VarDeclsVisitor Visitor; |
233 | |
234 | // Includes semicolon. |
235 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int x = 4;]]" ); |
236 | |
237 | // Includes newline and semicolon. |
238 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int x = 4;\n]]" ); |
239 | |
240 | // Includes trailing comments. |
241 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int x = 4; // Comment\n]]" ); |
242 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int x = 4; /* Comment */\n]]" ); |
243 | |
244 | // Does *not* include trailing comments when another entity appears between |
245 | // the decl and the comment. |
246 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int x = 4;]] class C {}; // Comment\n" ); |
247 | |
248 | // Includes attributes. |
249 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
250 | $r[[__attribute__((deprecated("message"))) |
251 | int x;]])cpp" ); |
252 | |
253 | // Includes attributes and comments together. |
254 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
255 | $r[[__attribute__((deprecated("message"))) |
256 | // Comment. |
257 | int x;]])cpp" ); |
258 | |
259 | // Includes attributes through macro expansion. |
260 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
261 | #define MACRO_EXPANSION __attribute__((deprecated("message"))) |
262 | $r[[MACRO_EXPANSION |
263 | int x;]])cpp" ); |
264 | |
265 | // Includes attributes through macro expansion with comments. |
266 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
267 | #define MACRO_EXPANSION __attribute__((deprecated("message"))) |
268 | $r[[MACRO_EXPANSION |
269 | // Comment. |
270 | int x;]])cpp" ); |
271 | } |
272 | |
273 | TEST(SourceCodeTest, getAssociatedRangeClasses) { |
274 | struct RecordDeclsVisitor : AnnotatedCodeVisitor<RecordDeclsVisitor> { |
275 | bool VisitRecordDecl(RecordDecl *Decl) { return VisitDeclHelper(Decl); } |
276 | }; |
277 | RecordDeclsVisitor Visitor; |
278 | |
279 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[class A;]]" ); |
280 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[class A {};]]" ); |
281 | |
282 | // Includes leading template annotation. |
283 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[template <typename T> class A;]]" ); |
284 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[template <typename T> class A {};]]" ); |
285 | } |
286 | |
287 | TEST(SourceCodeTest, getAssociatedRangeClassTemplateSpecializations) { |
288 | struct CXXRecordDeclsVisitor : AnnotatedCodeVisitor<CXXRecordDeclsVisitor> { |
289 | bool VisitCXXRecordDecl(CXXRecordDecl *Decl) { |
290 | return Decl->getTemplateSpecializationKind() != |
291 | TSK_ExplicitSpecialization || |
292 | VisitDeclHelper(Decl); |
293 | } |
294 | }; |
295 | CXXRecordDeclsVisitor Visitor; |
296 | |
297 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
298 | template <typename T> class A{}; |
299 | $r[[template <> class A<int>;]])cpp" ); |
300 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
301 | template <typename T> class A{}; |
302 | $r[[template <> class A<int> {};]])cpp" ); |
303 | } |
304 | |
305 | TEST(SourceCodeTest, getAssociatedRangeFunctions) { |
306 | struct FunctionDeclsVisitor : AnnotatedCodeVisitor<FunctionDeclsVisitor> { |
307 | bool VisitFunctionDecl(FunctionDecl *Decl) { return VisitDeclHelper(Decl); } |
308 | }; |
309 | FunctionDeclsVisitor Visitor; |
310 | |
311 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int f();]]" ); |
312 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[int f() { return 0; }]]" ); |
313 | // Includes leading template annotation. |
314 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[template <typename T> int f();]]" ); |
315 | Visitor.runOverAnnotated(AnnotatedCode: "$r[[template <typename T> int f() { return 0; }]]" ); |
316 | } |
317 | |
318 | TEST(SourceCodeTest, getAssociatedRangeMemberTemplates) { |
319 | struct CXXMethodDeclsVisitor : AnnotatedCodeVisitor<CXXMethodDeclsVisitor> { |
320 | bool VisitCXXMethodDecl(CXXMethodDecl *Decl) { |
321 | // Only consider the definition of the template. |
322 | return !Decl->doesThisDeclarationHaveABody() || VisitDeclHelper(Decl); |
323 | } |
324 | }; |
325 | CXXMethodDeclsVisitor Visitor; |
326 | |
327 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
328 | template <typename C> |
329 | struct A { template <typename T> int member(T v); }; |
330 | |
331 | $r[[template <typename C> |
332 | template <typename T> |
333 | int A<C>::member(T v) { return 0; }]])cpp" ); |
334 | } |
335 | |
336 | TEST(SourceCodeTest, getAssociatedRangeWithComments) { |
337 | struct VarDeclsVisitor : AnnotatedCodeVisitor<VarDeclsVisitor> { |
338 | bool VisitVarDecl(VarDecl *Decl) { return VisitDeclHelper(Decl); } |
339 | }; |
340 | |
341 | VarDeclsVisitor Visitor; |
342 | auto Visit = [&](llvm::StringRef AnnotatedCode) { |
343 | Visitor.runOverAnnotated(AnnotatedCode, Args: {"-fparse-all-comments" }); |
344 | }; |
345 | |
346 | // Includes leading comments. |
347 | Visit("$r[[// Comment.\nint x = 4;]]" ); |
348 | Visit("$r[[// Comment.\nint x = 4;\n]]" ); |
349 | Visit("$r[[/* Comment.*/\nint x = 4;\n]]" ); |
350 | // ... even if separated by (extra) horizontal whitespace. |
351 | Visit("$r[[/* Comment.*/ \nint x = 4;\n]]" ); |
352 | |
353 | // Includes comments even in the presence of trailing whitespace. |
354 | Visit("$r[[// Comment.\nint x = 4;]] " ); |
355 | |
356 | // Includes comments when the declaration is followed by the beginning or end |
357 | // of a compound statement. |
358 | Visit(R"cpp( |
359 | void foo() { |
360 | $r[[/* C */ |
361 | int x = 4; |
362 | ]]};)cpp" ); |
363 | Visit(R"cpp( |
364 | void foo() { |
365 | $r[[/* C */ |
366 | int x = 4; |
367 | ]]{ class Foo {}; } |
368 | })cpp" ); |
369 | |
370 | // Includes comments inside macros (when decl is in the same macro). |
371 | Visit(R"cpp( |
372 | #define DECL /* Comment */ int x |
373 | $r[[DECL;]])cpp" ); |
374 | |
375 | Visit(R"cpp( |
376 | #define DECL int x |
377 | $r[[// Comment |
378 | DECL;]])cpp" ); |
379 | // Does not include comments when only the comment come from a macro. |
380 | Visit(R"cpp( |
381 | #define COMMENT /* Comment */ |
382 | COMMENT |
383 | $r[[int x;]])cpp" ); |
384 | |
385 | // Includes multi-line comments. |
386 | Visit(R"cpp( |
387 | $r[[/* multi |
388 | * line |
389 | * comment |
390 | */ |
391 | int x;]])cpp" ); |
392 | Visit(R"cpp( |
393 | $r[[// multi |
394 | // line |
395 | // comment |
396 | int x;]])cpp" ); |
397 | |
398 | // Does not include comments separated by multiple empty lines. |
399 | Visit("// Comment.\n\n\n$r[[int x = 4;\n]]" ); |
400 | Visit("/* Comment.*/\n\n\n$r[[int x = 4;\n]]" ); |
401 | |
402 | // Does not include comments before a *series* of declarations. |
403 | Visit(R"cpp( |
404 | // Comment. |
405 | $r[[int x = 4; |
406 | ]]class foo {};)cpp" ); |
407 | |
408 | // Does not include IfThisThenThat comments |
409 | Visit("// LINT.IfChange.\n$r[[int x = 4;]]" ); |
410 | Visit("// LINT.ThenChange.\n$r[[int x = 4;]]" ); |
411 | |
412 | // Includes attributes. |
413 | Visit(R"cpp( |
414 | $r[[__attribute__((deprecated("message"))) |
415 | int x;]])cpp" ); |
416 | |
417 | // Includes attributes and comments together. |
418 | Visit(R"cpp( |
419 | $r[[__attribute__((deprecated("message"))) |
420 | // Comment. |
421 | int x;]])cpp" ); |
422 | |
423 | // Includes attributes through macro expansion. |
424 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
425 | #define MACRO_EXPANSION __attribute__((deprecated("message"))) |
426 | $r[[MACRO_EXPANSION |
427 | int x;]])cpp" ); |
428 | |
429 | // Includes attributes through macro expansion with comments. |
430 | Visitor.runOverAnnotated(AnnotatedCode: R"cpp( |
431 | #define MACRO_EXPANSION __attribute__((deprecated("message"))) |
432 | $r[[MACRO_EXPANSION |
433 | // Comment. |
434 | int x;]])cpp" ); |
435 | } |
436 | |
437 | TEST(SourceCodeTest, getAssociatedRangeInvalidForPartialExpansions) { |
438 | struct FailingVarDeclsVisitor : TestVisitor<FailingVarDeclsVisitor> { |
439 | FailingVarDeclsVisitor() {} |
440 | bool VisitVarDecl(VarDecl *Decl) { |
441 | EXPECT_TRUE(getAssociatedRange(*Decl, *Context).isInvalid()); |
442 | return true; |
443 | } |
444 | }; |
445 | |
446 | FailingVarDeclsVisitor Visitor; |
447 | // Should fail because it only includes a part of the expansion. |
448 | std::string Code = R"cpp( |
449 | #define DECL class foo { }; int x |
450 | DECL;)cpp" ; |
451 | Visitor.runOver(Code); |
452 | } |
453 | |
454 | class GetFileRangeForEditTest : public testing::TestWithParam<bool> {}; |
455 | INSTANTIATE_TEST_SUITE_P(WithAndWithoutExpansions, GetFileRangeForEditTest, |
456 | testing::Bool()); |
457 | |
458 | TEST_P(GetFileRangeForEditTest, EditRangeWithMacroExpansionsShouldSucceed) { |
459 | // The call expression, whose range we are extracting, includes two macro |
460 | // expansions. |
461 | llvm::Annotations Code(R"cpp( |
462 | #define M(a) a * 13 |
463 | int foo(int x, int y); |
464 | int a = $r[[foo(M(1), M(2))]]; |
465 | )cpp" ); |
466 | |
467 | CallsVisitor Visitor; |
468 | Visitor.OnCall = [&Code](CallExpr *CE, ASTContext *Context) { |
469 | auto Range = CharSourceRange::getTokenRange(CE->getSourceRange()); |
470 | EXPECT_THAT(getFileRangeForEdit(Range, *Context, GetParam()), |
471 | ValueIs(AsRange(Context->getSourceManager(), Code.range("r" )))); |
472 | }; |
473 | Visitor.runOver(Code: Code.code()); |
474 | } |
475 | |
476 | TEST(SourceCodeTest, EditWholeMacroExpansionShouldSucceed) { |
477 | llvm::Annotations Code(R"cpp( |
478 | #define FOO 10 |
479 | int a = $r[[FOO]]; |
480 | )cpp" ); |
481 | |
482 | IntLitVisitor Visitor; |
483 | Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) { |
484 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
485 | EXPECT_THAT(getFileRangeForEdit(Range, *Context), |
486 | ValueIs(AsRange(Context->getSourceManager(), Code.range("r" )))); |
487 | }; |
488 | Visitor.runOver(Code: Code.code()); |
489 | } |
490 | |
491 | TEST(SourceCodeTest, EditInvolvingExpansionIgnoringExpansionShouldFail) { |
492 | // If we specify to ignore macro expansions, none of these call expressions |
493 | // should have an editable range. |
494 | llvm::Annotations Code(R"cpp( |
495 | #define M1(x) x(1) |
496 | #define M2(x, y) x ## y |
497 | #define M3(x) foobar(x) |
498 | int foobar(int); |
499 | int a = M1(foobar); |
500 | int b = M2(foo, bar(2)); |
501 | int c = M3(3); |
502 | )cpp" ); |
503 | |
504 | CallsVisitor Visitor; |
505 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
506 | auto Range = CharSourceRange::getTokenRange(CE->getSourceRange()); |
507 | EXPECT_FALSE( |
508 | getFileRangeForEdit(Range, *Context, /*IncludeMacroExpansion=*/false)); |
509 | }; |
510 | Visitor.runOver(Code: Code.code()); |
511 | } |
512 | |
513 | TEST_P(GetFileRangeForEditTest, EditPartialMacroExpansionShouldFail) { |
514 | std::string Code = R"cpp( |
515 | #define BAR 10+ |
516 | int c = BAR 3.0; |
517 | )cpp" ; |
518 | |
519 | IntLitVisitor Visitor; |
520 | Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) { |
521 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
522 | EXPECT_FALSE(getFileRangeForEdit(Range, *Context, GetParam())); |
523 | }; |
524 | Visitor.runOver(Code); |
525 | } |
526 | |
527 | TEST_P(GetFileRangeForEditTest, EditWholeMacroArgShouldSucceed) { |
528 | llvm::Annotations Code(R"cpp( |
529 | #define FOO(a) a + 7.0; |
530 | int a = FOO($r[[10]]); |
531 | )cpp" ); |
532 | |
533 | IntLitVisitor Visitor; |
534 | Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) { |
535 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
536 | EXPECT_THAT(getFileRangeForEdit(Range, *Context, GetParam()), |
537 | ValueIs(AsRange(Context->getSourceManager(), Code.range("r" )))); |
538 | }; |
539 | Visitor.runOver(Code: Code.code()); |
540 | } |
541 | |
542 | TEST_P(GetFileRangeForEditTest, EditPartialMacroArgShouldSucceed) { |
543 | llvm::Annotations Code(R"cpp( |
544 | #define FOO(a) a + 7.0; |
545 | int a = FOO($r[[10]] + 10.0); |
546 | )cpp" ); |
547 | |
548 | IntLitVisitor Visitor; |
549 | Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) { |
550 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
551 | EXPECT_THAT(getFileRangeForEdit(Range, *Context, GetParam()), |
552 | ValueIs(AsRange(Context->getSourceManager(), Code.range("r" )))); |
553 | }; |
554 | Visitor.runOver(Code: Code.code()); |
555 | } |
556 | |
557 | TEST(SourceCodeTest, EditRangeWithMacroExpansionsIsValid) { |
558 | // The call expression, whose range we are extracting, includes two macro |
559 | // expansions. |
560 | llvm::StringRef Code = R"cpp( |
561 | #define M(a) a * 13 |
562 | int foo(int x, int y); |
563 | int a = foo(M(1), M(2)); |
564 | )cpp" ; |
565 | |
566 | CallsVisitor Visitor; |
567 | Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { |
568 | auto Range = CharSourceRange::getTokenRange(CE->getSourceRange()); |
569 | EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()), |
570 | Succeeded()); |
571 | }; |
572 | Visitor.runOver(Code); |
573 | } |
574 | |
575 | TEST(SourceCodeTest, SpellingRangeOfMacroArgIsValid) { |
576 | llvm::StringRef Code = R"cpp( |
577 | #define FOO(a) a + 7.0; |
578 | int a = FOO(10); |
579 | )cpp" ; |
580 | |
581 | IntLitVisitor Visitor; |
582 | Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) { |
583 | SourceLocation ArgLoc = |
584 | Context->getSourceManager().getSpellingLoc(Loc: Expr->getBeginLoc()); |
585 | // The integer literal is a single token. |
586 | auto ArgRange = CharSourceRange::getTokenRange(R: ArgLoc); |
587 | EXPECT_THAT_ERROR(validateEditRange(ArgRange, Context->getSourceManager()), |
588 | Succeeded()); |
589 | }; |
590 | Visitor.runOver(Code); |
591 | } |
592 | |
593 | TEST(SourceCodeTest, InvalidEditRangeIsInvalid) { |
594 | llvm::StringRef Code = "int c = 10;" ; |
595 | |
596 | // We use the visitor just to get a valid context. |
597 | IntLitVisitor Visitor; |
598 | Visitor.OnIntLit = [](IntegerLiteral *, ASTContext *Context) { |
599 | CharSourceRange Invalid; |
600 | EXPECT_THAT_ERROR(validateEditRange(Invalid, Context->getSourceManager()), |
601 | Failed()); |
602 | }; |
603 | Visitor.runOver(Code); |
604 | } |
605 | |
606 | TEST(SourceCodeTest, InvertedEditRangeIsInvalid) { |
607 | llvm::StringRef Code = R"cpp( |
608 | int foo(int x); |
609 | int a = foo(2); |
610 | )cpp" ; |
611 | |
612 | CallsVisitor Visitor; |
613 | Visitor.OnCall = [](CallExpr *Expr, ASTContext *Context) { |
614 | auto InvertedRange = CharSourceRange::getTokenRange( |
615 | R: SourceRange(Expr->getEndLoc(), Expr->getBeginLoc())); |
616 | EXPECT_THAT_ERROR( |
617 | validateEditRange(InvertedRange, Context->getSourceManager()), |
618 | Failed()); |
619 | }; |
620 | Visitor.runOver(Code); |
621 | } |
622 | |
623 | TEST(SourceCodeTest, MacroArgIsInvalid) { |
624 | llvm::StringRef Code = R"cpp( |
625 | #define FOO(a) a + 7.0; |
626 | int a = FOO(10); |
627 | )cpp" ; |
628 | |
629 | IntLitVisitor Visitor; |
630 | Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) { |
631 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
632 | EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()), |
633 | Failed()); |
634 | }; |
635 | Visitor.runOver(Code); |
636 | } |
637 | |
638 | TEST(SourceCodeTest, EditWholeMacroExpansionIsInvalid) { |
639 | llvm::StringRef Code = R"cpp( |
640 | #define FOO 10 |
641 | int a = FOO; |
642 | )cpp" ; |
643 | |
644 | IntLitVisitor Visitor; |
645 | Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) { |
646 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
647 | EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()), |
648 | Failed()); |
649 | |
650 | }; |
651 | Visitor.runOver(Code); |
652 | } |
653 | |
654 | TEST(SourceCodeTest, EditPartialMacroExpansionIsInvalid) { |
655 | llvm::StringRef Code = R"cpp( |
656 | #define BAR 10+ |
657 | int c = BAR 3.0; |
658 | )cpp" ; |
659 | |
660 | IntLitVisitor Visitor; |
661 | Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) { |
662 | auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange()); |
663 | EXPECT_THAT_ERROR(validateEditRange(Range, Context->getSourceManager()), |
664 | Failed()); |
665 | }; |
666 | Visitor.runOver(Code); |
667 | } |
668 | |
669 | TEST(SourceCodeTest, GetCallReturnType_Dependent) { |
670 | llvm::Annotations Code{R"cpp( |
671 | template<class T, class F> |
672 | void templ(const T& t, F f) {} |
673 | |
674 | template<class T, class F> |
675 | void templ1(const T& t, F f) { |
676 | $test1[[f(t)]]; |
677 | } |
678 | |
679 | int f_overload(int) { return 1; } |
680 | int f_overload(double) { return 2; } |
681 | |
682 | void f1() { |
683 | int i = 0; |
684 | templ(i, [](const auto &p) { |
685 | $test2[[f_overload(p)]]; |
686 | }); |
687 | } |
688 | |
689 | struct A { |
690 | void f_overload(int); |
691 | void f_overload(double); |
692 | }; |
693 | |
694 | void f2() { |
695 | int i = 0; |
696 | templ(i, [](const auto &p) { |
697 | A a; |
698 | $test3[[a.f_overload(p)]]; |
699 | }); |
700 | } |
701 | )cpp" }; |
702 | |
703 | llvm::Annotations::Range R1 = Code.range(Name: "test1" ); |
704 | llvm::Annotations::Range R2 = Code.range(Name: "test2" ); |
705 | llvm::Annotations::Range R3 = Code.range(Name: "test3" ); |
706 | |
707 | CallsVisitor Visitor; |
708 | Visitor.OnCall = [&R1, &R2, &R3](CallExpr *Expr, ASTContext *Context) { |
709 | unsigned Begin = Context->getSourceManager().getFileOffset( |
710 | SpellingLoc: Expr->getSourceRange().getBegin()); |
711 | unsigned End = Context->getSourceManager().getFileOffset( |
712 | SpellingLoc: Expr->getSourceRange().getEnd()); |
713 | llvm::Annotations::Range R{.Begin: Begin, .End: End + 1}; |
714 | |
715 | QualType CalleeType = Expr->getCallee()->getType(); |
716 | if (R == R1) { |
717 | ASSERT_TRUE(CalleeType->isDependentType()); |
718 | EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy); |
719 | } else if (R == R2) { |
720 | ASSERT_FALSE(CalleeType->isDependentType()); |
721 | ASSERT_TRUE(CalleeType->isSpecificPlaceholderType(BuiltinType::Overload)); |
722 | ASSERT_TRUE(isa<UnresolvedLookupExpr>(Expr->getCallee())); |
723 | EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy); |
724 | } else if (R == R3) { |
725 | ASSERT_FALSE(CalleeType->isDependentType()); |
726 | ASSERT_TRUE( |
727 | CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)); |
728 | ASSERT_TRUE(isa<UnresolvedMemberExpr>(Expr->getCallee())); |
729 | EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy); |
730 | } |
731 | }; |
732 | Visitor.runOver(Code: Code.code(), L: CallsVisitor::Lang_CXX14); |
733 | } |
734 | |
735 | } // end anonymous namespace |
736 | |