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 | |
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 | .Context: Function, |
31 | .TestSource: R""(enum Enum {}; ^switch ((Enum)0) {})"" , |
32 | .ExpectedSource: "unavailable" , |
33 | }, |
34 | { |
35 | // All enumerators already in switch (unscoped) |
36 | .Context: Function, |
37 | .TestSource: R""(enum Enum {A,B}; ^switch (A) {case A:break;case B:break;})"" , |
38 | .ExpectedSource: "unavailable" , |
39 | }, |
40 | { |
41 | // All enumerators already in switch (scoped) |
42 | .Context: Function, |
43 | .TestSource: R""( |
44 | enum class Enum {A,B}; |
45 | ^switch (Enum::A) {case Enum::A:break;case Enum::B:break;} |
46 | )"" , |
47 | .ExpectedSource: "unavailable" , |
48 | }, |
49 | { |
50 | // Default case in switch |
51 | .Context: Function, |
52 | .TestSource: R""( |
53 | enum class Enum {A,B}; |
54 | ^switch (Enum::A) {default:break;} |
55 | )"" , |
56 | .ExpectedSource: "unavailable" , |
57 | }, |
58 | { |
59 | // GNU range in switch |
60 | .Context: Function, |
61 | .TestSource: R""( |
62 | enum class Enum {A,B}; |
63 | ^switch (Enum::A) {case Enum::A ... Enum::B:break;} |
64 | )"" , |
65 | .ExpectedSource: "unavailable" , |
66 | }, |
67 | { |
68 | // Value dependent case expression |
69 | .Context: File, |
70 | .TestSource: R""( |
71 | enum class Enum {A,B}; |
72 | template<Enum Value> |
73 | void function() { |
74 | ^switch (Enum::A) {case Value:break;} |
75 | } |
76 | )"" , |
77 | .ExpectedSource: "unavailable" , |
78 | }, |
79 | { |
80 | // Body not CompoundStmt |
81 | .Context: Function, |
82 | .TestSource: R""(enum Enum {A}; ^switch (A);)"" , |
83 | .ExpectedSource: "unavailable" , |
84 | }, |
85 | { |
86 | // Selection on switch token |
87 | .Context: Function, |
88 | .TestSource: R""(enum Enum {A}; ^switch (A) {})"" , |
89 | .ExpectedSource: R""(enum Enum {A}; switch (A) {case A:break;})"" , |
90 | }, |
91 | { |
92 | // Selection on switch condition |
93 | .Context: Function, |
94 | .TestSource: R""(enum Enum {A}; switch (^A) {})"" , |
95 | .ExpectedSource: R""(enum Enum {A}; switch (A) {case A:break;})"" , |
96 | }, |
97 | { |
98 | // Selection of whole switch condition |
99 | .Context: Function, |
100 | .TestSource: R""(enum Enum {A}; switch ([[A]]) {})"" , |
101 | .ExpectedSource: R""(enum Enum {A}; switch (A) {case A:break;})"" , |
102 | }, |
103 | { |
104 | // Selection in switch body |
105 | .Context: Function, |
106 | .TestSource: R""(enum Enum {A}; switch (A) {^})"" , |
107 | .ExpectedSource: R""(enum Enum {A}; switch (A) {case A:break;})"" , |
108 | }, |
109 | { |
110 | // Scoped enumeration |
111 | .Context: Function, |
112 | .TestSource: R""(enum class Enum {A}; ^switch (Enum::A) {})"" , |
113 | .ExpectedSource: R""(enum class Enum {A}; switch (Enum::A) {case Enum::A:break;})"" , |
114 | }, |
115 | { |
116 | // Scoped enumeration with multiple enumerators |
117 | .Context: Function, |
118 | .TestSource: R""( |
119 | enum class Enum {A,B}; |
120 | ^switch (Enum::A) {} |
121 | )"" , |
122 | .ExpectedSource: 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 | .Context: Function, |
130 | .TestSource: R""( |
131 | enum Enum {A,B,C}; |
132 | ^switch (A) {case B:break;} |
133 | )"" , |
134 | .ExpectedSource: 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 | .Context: Function, |
143 | .TestSource: R""( |
144 | enum Enum {A,B=1,C}; |
145 | ^switch (A) {case 1:break;} |
146 | )"" , |
147 | .ExpectedSource: 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 | .Context: Function, |
155 | .TestSource: R""( |
156 | enum class Enum {A,B,C}; |
157 | ^switch (Enum::A) |
158 | {case Enum::B:break;} |
159 | )"" , |
160 | .ExpectedSource: 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 | .Context: File, |
169 | .TestSource: R""( |
170 | namespace ns { enum class Enum {A}; } |
171 | void function() { ^switch (ns::Enum::A) {} } |
172 | )"" , |
173 | .ExpectedSource: 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 | .Context: File, |
181 | .TestSource: R""( |
182 | namespace ns { enum Enum {A}; } |
183 | void function() { ^switch (ns::A) {} } |
184 | )"" , |
185 | .ExpectedSource: 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 | .Context: Function, |
193 | .TestSource: R""(enum Enum {A,B,b=B}; ^switch (A) {})"" , |
194 | .ExpectedSource: R""(enum Enum {A,B,b=B}; switch (A) {case A:case B:break;})"" , |
195 | }, |
196 | { |
197 | // Duplicated constant names all in switch |
198 | .Context: Function, |
199 | .TestSource: R""(enum Enum {A,B,b=B}; ^switch (A) {case A:case B:break;})"" , |
200 | .ExpectedSource: "unavailable" , |
201 | }, |
202 | { |
203 | // Enum is dependent type |
204 | .Context: File, |
205 | .TestSource: R""(template<typename T> void f() {enum Enum {A}; ^switch (A) {}})"" , |
206 | .ExpectedSource: "unavailable" , |
207 | }, |
208 | {// C: Only filling in missing enumerators |
209 | .Context: Function, |
210 | .TestSource: R""( |
211 | enum CEnum {A,B,C}; |
212 | enum CEnum val = A; |
213 | ^switch (val) {case B:break;} |
214 | )"" , |
215 | .ExpectedSource: 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 | .FileName: "TestTU.c" }, |
221 | {// C: Only filling in missing enumerators w/ typedefs |
222 | .Context: Function, |
223 | .TestSource: 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 | .ExpectedSource: 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 | .FileName: "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 | |