xref: /llvm-project/clang-tools-extra/clangd/unittests/tweaks/PopulateSwitchTests.cpp (revision 4d006520b8c0cc3a52913b4665bf741c737e5592)
1 //===-- PopulateSwitchTest.cpp ----------------------------------*- C++ -*-===//
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 "TweakTesting.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
12 
13 namespace clang {
14 namespace clangd {
15 namespace {
16 
17 TWEAK_TEST(PopulateSwitch);
18 
TEST_F(PopulateSwitchTest,Test)19 TEST_F(PopulateSwitchTest, Test) {
20   struct Case {
21     CodeContext Context;
22     llvm::StringRef TestSource;
23     llvm::StringRef ExpectedSource;
24     llvm::StringRef FileName = "TestTU.cpp";
25   };
26 
27   Case Cases[]{
28       {
29           // No enumerators
30           Function,
31           R""(enum Enum {}; ^switch ((Enum)0) {})"",
32           "unavailable",
33       },
34       {
35           // All enumerators already in switch (unscoped)
36           Function,
37           R""(enum Enum {A,B}; ^switch (A) {case A:break;case B:break;})"",
38           "unavailable",
39       },
40       {
41           // All enumerators already in switch (scoped)
42           Function,
43           R""(
44             enum class Enum {A,B};
45             ^switch (Enum::A) {case Enum::A:break;case Enum::B:break;}
46           )"",
47           "unavailable",
48       },
49       {
50           // Default case in switch
51           Function,
52           R""(
53             enum class Enum {A,B};
54             ^switch (Enum::A) {default:break;}
55           )"",
56           "unavailable",
57       },
58       {
59           // GNU range in switch
60           Function,
61           R""(
62             enum class Enum {A,B};
63             ^switch (Enum::A) {case Enum::A ... Enum::B:break;}
64           )"",
65           "unavailable",
66       },
67       {
68           // Value dependent case expression
69           File,
70           R""(
71             enum class Enum {A,B};
72             template<Enum Value>
73             void function() {
74                 ^switch (Enum::A) {case Value:break;}
75             }
76           )"",
77           "unavailable",
78       },
79       {
80           // Body not CompoundStmt
81           Function,
82           R""(enum Enum {A}; ^switch (A);)"",
83           "unavailable",
84       },
85       {
86           // Selection on switch token
87           Function,
88           R""(enum Enum {A}; ^switch (A) {})"",
89           R""(enum Enum {A}; switch (A) {case A:break;})"",
90       },
91       {
92           // Selection on switch condition
93           Function,
94           R""(enum Enum {A}; switch (^A) {})"",
95           R""(enum Enum {A}; switch (A) {case A:break;})"",
96       },
97       {
98           // Selection of whole switch condition
99           Function,
100           R""(enum Enum {A}; switch ([[A]]) {})"",
101           R""(enum Enum {A}; switch (A) {case A:break;})"",
102       },
103       {
104           // Selection in switch body
105           Function,
106           R""(enum Enum {A}; switch (A) {^})"",
107           R""(enum Enum {A}; switch (A) {case A:break;})"",
108       },
109       {
110           // Scoped enumeration
111           Function,
112           R""(enum class Enum {A}; ^switch (Enum::A) {})"",
113           R""(enum class Enum {A}; switch (Enum::A) {case Enum::A:break;})"",
114       },
115       {
116           // Scoped enumeration with multiple enumerators
117           Function,
118           R""(
119             enum class Enum {A,B};
120             ^switch (Enum::A) {}
121           )"",
122           R""(
123             enum class Enum {A,B};
124             switch (Enum::A) {case Enum::A:case Enum::B:break;}
125           )"",
126       },
127       {
128           // Only filling in missing enumerators (unscoped)
129           Function,
130           R""(
131             enum Enum {A,B,C};
132             ^switch (A) {case B:break;}
133           )"",
134           R""(
135             enum Enum {A,B,C};
136             switch (A) {case B:break;case A:case C:break;}
137           )"",
138       },
139       {
140           // Only filling in missing enumerators,
141           // even when using integer literals
142           Function,
143           R""(
144             enum Enum {A,B=1,C};
145             ^switch (A) {case 1:break;}
146           )"",
147           R""(
148             enum Enum {A,B=1,C};
149             switch (A) {case 1:break;case A:case C:break;}
150           )"",
151       },
152       {
153           // Only filling in missing enumerators (scoped)
154           Function,
155           R""(
156             enum class Enum {A,B,C};
157             ^switch (Enum::A)
158             {case Enum::B:break;}
159           )"",
160           R""(
161             enum class Enum {A,B,C};
162             switch (Enum::A)
163             {case Enum::B:break;case Enum::A:case Enum::C:break;}
164           )"",
165       },
166       {
167           // Scoped enumerations in namespace
168           File,
169           R""(
170             namespace ns { enum class Enum {A}; }
171             void function() { ^switch (ns::Enum::A) {} }
172           )"",
173           R""(
174             namespace ns { enum class Enum {A}; }
175             void function() { switch (ns::Enum::A) {case ns::Enum::A:break;} }
176           )"",
177       },
178       {
179           // Unscoped enumerations in namespace
180           File,
181           R""(
182             namespace ns { enum Enum {A}; }
183             void function() { ^switch (ns::A) {} }
184           )"",
185           R""(
186             namespace ns { enum Enum {A}; }
187             void function() { switch (ns::A) {case ns::A:break;} }
188           )"",
189       },
190       {
191           // Duplicated constant names
192           Function,
193           R""(enum Enum {A,B,b=B}; ^switch (A) {})"",
194           R""(enum Enum {A,B,b=B}; switch (A) {case A:case B:break;})"",
195       },
196       {
197           // Duplicated constant names all in switch
198           Function,
199           R""(enum Enum {A,B,b=B}; ^switch (A) {case A:case B:break;})"",
200           "unavailable",
201       },
202       {
203           // Enum is dependent type
204           File,
205           R""(template<typename T> void f() {enum Enum {A}; ^switch (A) {}})"",
206           "unavailable",
207       },
208       {// C: Only filling in missing enumerators
209        Function,
210        R""(
211             enum CEnum {A,B,C};
212             enum CEnum val = A;
213             ^switch (val) {case B:break;}
214           )"",
215        R""(
216             enum CEnum {A,B,C};
217             enum CEnum val = A;
218             switch (val) {case B:break;case A:case C:break;}
219           )"",
220        "TestTU.c"},
221       {// C: Only filling in missing enumerators w/ typedefs
222        Function,
223        R""(
224             typedef unsigned long UInteger;
225             enum ControlState : UInteger;
226             typedef enum ControlState ControlState;
227             enum ControlState : UInteger {A,B,C};
228             ControlState controlState = A;
229             switch (^controlState) {case A:break;}
230           )"",
231        R""(
232             typedef unsigned long UInteger;
233             enum ControlState : UInteger;
234             typedef enum ControlState ControlState;
235             enum ControlState : UInteger {A,B,C};
236             ControlState controlState = A;
237             switch (controlState) {case A:break;case B:case C:break;}
238           )"",
239        "TestTU.c"},
240   };
241 
242   for (const auto &Case : Cases) {
243     Context = Case.Context;
244     FileName = Case.FileName;
245     EXPECT_EQ(apply(Case.TestSource), Case.ExpectedSource);
246   }
247 }
248 
249 } // namespace
250 } // namespace clangd
251 } // namespace clang
252