1 //===-- ExtractVariableTests.cpp --------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "TweakTesting.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
17 TWEAK_TEST(ExtractVariable
);
19 TEST_F(ExtractVariableTest
, Test
) {
20 const char *AvailableCases
= R
"cpp(
27 return [[[[t.b[[a]]r]]([[t.z]])]];
30 int a = 5 + [[4 * [[[[xyz]]()]]]];
31 // multivariable initialization
33 int x = [[1]] + 1, y = a + [[1]], a = [[1]] + 2, z = a + 1;
48 for(a = [[1]] + 1; a > [[[[3]] + [[4]]]]; a++)
59 EXPECT_AVAILABLE(AvailableCases
);
62 const char *AvailableC
= R
"cpp(
66 EXPECT_AVAILABLE(AvailableC
);
69 const char *NoCrashCasesC
= R
"cpp(
70 // error-ok: broken code, but shouldn't crash
73 EXPECT_UNAVAILABLE(NoCrashCasesC
);
76 const char *NoCrashDesignator
= R
"cpp(
85 void foo(struct B *b) {
86 struct A a = {.x=b[[->]]y};
89 EXPECT_AVAILABLE(NoCrashDesignator
);
91 ExtraArgs
= {"-xobjective-c"};
92 const char *AvailableObjC
= R
"cpp(
93 __attribute__((objc_root_class))
101 EXPECT_AVAILABLE(AvailableObjC
);
104 const char *NoCrashCases
= R
"cpp(
105 // error-ok: broken code, but shouldn't crash
106 template<typename T, typename ...Args>
107 struct Test<T, Args...> {
108 Test(const T &v) :val[[(^]]) {}
112 EXPECT_UNAVAILABLE(NoCrashCases
);
114 const char *UnavailableCases
= R
"cpp(
115 int xyz(int a = [[1]]) {
117 int bar(int a = [[1]]) {
125 return [[t]].bar([[t]].z);
129 // function default argument
130 void f(int b = [[1]]) {
134 auto i = new int, j = new int;
135 [[[[delete i]], delete j]];
139 int x = 1, y = a + 1, a = 1, z = [[a + 1]];
144 for(int a = 1, b = 2, c = 3; a > [[b + c]]; [[a++]])
147 auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;};
151 // Variable DeclRefExpr
154 // statement expression
172 // lambdas: default args, cannot extract into function-local scope
173 [](int x = [[10]]){};
174 [](auto h = [[ [i = [](){}](){} ]]) {};
176 // lambdas: default args
177 // Extracting from capture initializers is usually fine,
178 // but not if the capture itself is nested inside a default argument
179 [](auto h = [i = [[ [](){} ]]](){}) {};
180 [](auto h = [i = [[ 42 ]]](){}) {};
184 if ([[ [&](){ return a + 1; } ]]() == 4)
187 for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
189 for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
192 // lambdas: scope with structured binding
198 if (const auto [x, y] = c; x > y)
199 auto f = [[ [&]() { return x + y; } ]];
201 // lambdas: referencing outside variables that block extraction
202 // in trailing return type or in a decltype used
205 if ([[ []() -> decltype(a) { return 1; } ]] () == 4)
208 if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4)
211 if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4)
215 EXPECT_UNAVAILABLE(UnavailableCases
);
217 ExtraArgs
= {"-std=c++20"};
218 const char *UnavailableCasesCXX20
= R
"cpp(
219 template <typename T>
220 concept Constraint = requires (T t) { true; };
222 // lambdas: referencing outside variables that block extraction
223 // in requires clause or defaulted explicit template parameters
225 if ([[ [](auto b) requires (Constraint<decltype(a)> && Constraint<decltype(b)>) { return true; } ]] (a))
229 if ([[ []<typename T = decltype(a)>(T b) { return true; } ]] (a))
233 EXPECT_UNAVAILABLE(UnavailableCasesCXX20
);
236 // vector of pairs of input and output strings
237 std::vector
<std::pair
<std::string
, std::string
>> InputOutputs
= {
238 // extraction from variable declaration/assignment
239 {R
"cpp(void varDecl() {
240 int a = 5 * (4 + (3 [[- 1)]]);
242 R
"cpp(void varDecl() {
243 auto placeholder = (3 - 1); int a = 5 * (4 + placeholder);
245 // FIXME: extraction from switch case
246 /*{R"cpp(void f(int a) {
257 R"cpp(void f(int a) {
258 auto placeholder = 1 + 2; if(1)
269 {R
"cpp(#define PLUS(x) x++
271 int y = PLUS([[1+a]]);
273 /*FIXME: It should be extracted like this.
274 R"cpp(#define PLUS(x) x++
276 auto placeholder = 1+a; int y = PLUS(placeholder);
278 R
"cpp(#define PLUS(x) x++
280 auto placeholder = PLUS(1+a); int y = placeholder;
282 // ensure InsertionPoint isn't inside a macro
283 {R
"cpp(#define LOOP(x) while (1) {a = x;}
288 R
"cpp(#define LOOP(x) while (1) {a = x;}
290 auto placeholder = 3; if(1)
291 LOOP(5 + placeholder)
293 {R
"cpp(#define LOOP(x) do {x;} while(1);
298 R
"cpp(#define LOOP(x) do {x;} while(1);
300 auto placeholder = 3; if(1)
301 LOOP(5 + placeholder)
304 {R
"cpp(void f(int a) {
305 [ [gsl::suppress("type
")] ] for (;;) a = [[1]] + 1;
307 R
"cpp(void f(int a) {
308 auto placeholder = 1; [ [gsl::suppress("type
")] ] for (;;) a = placeholder + 1;
313 return [[T().f()]].f();
318 auto placeholder = T().f(); return placeholder.f();
321 // Function DeclRefExpr
326 auto placeholder = f(); return placeholder;
328 // FIXME: Wrong result for \[\[clang::uninitialized\]\] int b = [[1]];
329 // since the attr is inside the DeclStmt and the bounds of
330 // DeclStmt don't cover the attribute.
332 // Binary subexpressions
334 int x = 1 + [[2 + 3 + 4]] + 5;
337 auto placeholder = 2 + 3 + 4; int x = 1 + placeholder + 5;
340 int x = [[1 + 2 + 3]] + 4 + 5;
343 auto placeholder = 1 + 2 + 3; int x = placeholder + 4 + 5;
346 int x = 1 + 2 + [[3 + 4 + 5]];
349 auto placeholder = 3 + 4 + 5; int x = 1 + 2 + placeholder;
351 // Non-associative operations have no special support
353 int x = 1 - [[2 - 3 - 4]] - 5;
356 auto placeholder = 1 - 2 - 3 - 4; int x = placeholder - 5;
358 // A mix of associative operators isn't associative.
360 int x = 0 + 1 * [[2 + 3]] * 4 + 5;
363 auto placeholder = 1 * 2 + 3 * 4; int x = 0 + placeholder + 5;
365 // Overloaded operators are supported, we assume associativity
366 // as if they were built-in.
373 S x = S(1) + [[S(2) + S(3) + S(4)]] + S(5);
381 auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
383 // lambda expressions
384 {R
"cpp(template <typename T> void f(T) {}
386 f([[ [](){ return 42; }]]);
389 R
"cpp(template <typename T> void f(T) {}
391 auto placeholder = [](){ return 42; }; f( placeholder);
394 {R
"cpp(template <typename T> void f(T) {}
396 f([x = [[40 + 2]] ](){ return 42; });
399 R
"cpp(template <typename T> void f(T) {}
401 auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; });
404 {R
"cpp(auto foo(int VarA) {
406 return [[ [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }]];
410 R
"cpp(auto foo(int VarA) {
412 auto placeholder = [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }; return placeholder;
416 {R
"cpp(template <typename T> void f(T) {}
418 f([[ [&var](){ auto internal_val = 42; return var + internal_val; }]]);
421 R
"cpp(template <typename T> void f(T) {}
423 auto placeholder = [&var](){ auto internal_val = 42; return var + internal_val; }; f( placeholder);
426 {R
"cpp(template <typename T> void f(T) { }
430 f([[ [&var, &local_var, this]() {
431 auto internal_val = 42;
432 return var + local_var + internal_val + member;
439 R
"cpp(template <typename T> void f(T) { }
443 auto placeholder = [&var, &local_var, this]() {
444 auto internal_val = 42;
445 return var + local_var + internal_val + member;
452 {R
"cpp(void f() { auto x = +[[ [](){ return 42; }]]; })cpp",
453 R
"cpp(void f() { auto placeholder = [](){ return 42; }; auto x = + placeholder; })cpp"},
455 template <typename T>
456 auto sink(T f) { return f(); }
458 return sink([[ []() { return 42; }]]);
462 template <typename T>
463 auto sink(T f) { return f(); }
465 auto placeholder = []() { return 42; }; return sink( placeholder);
471 if ([[ [&](){ return a + 1; } ]]() == 4)
478 auto placeholder = [&](){ return a + 1; }; if ( placeholder () == 4)
485 if ([[ [&](){ return a + 1; }() ]] == 4)
492 auto placeholder = [&](){ return a + 1; }(); if ( placeholder == 4)
497 template <typename T>
498 auto call(T t) { return t(); }
501 return [[ call([](){ int a = 1; return a + 1; }) ]] + 5;
504 template <typename T>
505 auto call(T t) { return t(); }
508 auto placeholder = call([](){ int a = 1; return a + 1; }); return placeholder + 5;
513 return [f = [[ [this](int g) { return g + x; } ]] ]() { return 42; }();
521 auto placeholder = [this](int g) { return g + x; }; return [f = placeholder ]() { return 42; }();
528 return [[ []() { return 42; }() ]];
532 auto placeholder = []() { return 42; }(); return placeholder ;
535 template <typename ...Ts>
536 void foo(Ts ...args) {
537 auto x = +[[ [&args...]() {} ]];
541 template <typename ...Ts>
542 void foo(Ts ...args) {
543 auto placeholder = [&args...]() {}; auto x = + placeholder ;
554 const auto [x, y] = c;
555 auto f = [[ [&]() { return x + y; } ]]();
566 const auto [x, y] = c;
567 auto placeholder = [&]() { return x + y; }; auto f = placeholder ();
578 if (const auto [x, y] = c; x > y) {
579 auto f = [[ [&]() { return x + y; } ]]();
591 if (const auto [x, y] = c; x > y) {
592 auto placeholder = [&]() { return x + y; }; auto f = placeholder ();
596 // Don't try to analyze across macro boundaries
597 // FIXME: it'd be nice to do this someday (in a safe way)
598 {R
"cpp(#define ECHO(X) X
600 int x = 1 + [[ECHO(2 + 3) + 4]] + 5;
602 R
"cpp(#define ECHO(X) X
604 auto placeholder = 1 + ECHO(2 + 3) + 4; int x = placeholder + 5;
606 {R
"cpp(#define ECHO(X) X
608 int x = 1 + [[ECHO(2) + ECHO(3) + 4]] + 5;
610 R
"cpp(#define ECHO(X) X
612 auto placeholder = 1 + ECHO(2) + ECHO(3) + 4; int x = placeholder + 5;
615 for (const auto &IO
: InputOutputs
) {
616 EXPECT_EQ(IO
.second
, apply(IO
.first
)) << IO
.first
;
622 {R
"cpp(struct Handlers {
623 void (*handlerFunc)(int);
625 void runFunction(void (*func)(int)) {}
626 void f(struct Handlers *handler) {
627 runFunction([[handler->handlerFunc]]);
629 R
"cpp(struct Handlers {
630 void (*handlerFunc)(int);
632 void runFunction(void (*func)(int)) {}
633 void f(struct Handlers *handler) {
634 void (*placeholder)(int) = handler->handlerFunc; runFunction(placeholder);
636 {R
"cpp(int (*foo(char))(int);
640 R
"cpp(int (*foo(char))(int);
642 int (*placeholder)(int) = foo('c'); (void)placeholder;
644 // Arithmetic on typedef types preserves typedef types
645 {R
"cpp(typedef long NSInteger;
648 NSInteger b = [[a * 7]] + 3;
650 R
"cpp(typedef long NSInteger;
653 NSInteger placeholder = a * 7; NSInteger b = placeholder + 3;
656 for (const auto &IO
: InputOutputs
) {
657 EXPECT_EQ(IO
.second
, apply(IO
.first
)) << IO
.first
;
660 ExtraArgs
= {"-xobjective-c"};
661 EXPECT_UNAVAILABLE(R
"cpp(
662 __attribute__((objc_root_class))
664 - (void)setMethod1:(int)a;
670 [[self.method1]] = 1;
671 [[self.method1]] += 1;
677 // Support ObjC property references (explicit property getter).
678 {R
"cpp(__attribute__((objc_root_class))
684 int x = [[self.prop1]] + 1;
687 R
"cpp(__attribute__((objc_root_class))
693 int placeholder = self.prop1; int x = placeholder + 1;
696 // Support ObjC property references (implicit property getter).
697 {R
"cpp(__attribute__((objc_root_class))
703 int x = [[self.method1]] + 1;
706 R
"cpp(__attribute__((objc_root_class))
712 int placeholder = self.method1; int x = placeholder + 1;
716 for (const auto &IO
: InputOutputs
) {
717 EXPECT_EQ(IO
.second
, apply(IO
.first
)) << IO
.first
;
722 } // namespace clangd