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