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