1 //===-- FormatTests.cpp - Automatic code formatting tests -----------------===//
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 "Format.h"
10 #include "Annotations.h"
11 #include "SourceCode.h"
12 #include "TestFS.h"
13 #include "clang/Format/Format.h"
14 #include "clang/Tooling/Core/Replacement.h"
15 #include "llvm/Support/Error.h"
16 #include "gmock/gmock.h"
17 #include "gtest/gtest.h"
18
19 namespace clang {
20 namespace clangd {
21 namespace {
22
afterTyped(llvm::StringRef CodeWithCursor,llvm::StringRef Typed)23 std::string afterTyped(llvm::StringRef CodeWithCursor,
24 llvm::StringRef Typed) {
25 Annotations Code(CodeWithCursor);
26 unsigned Cursor = llvm::cantFail(positionToOffset(Code.code(), Code.point()));
27 auto Changes =
28 formatIncremental(Code.code(), Cursor, Typed,
29 format::getGoogleStyle(format::FormatStyle::LK_Cpp));
30 tooling::Replacements Merged;
31 for (const auto& R : Changes)
32 if (llvm::Error E = Merged.add(R))
33 ADD_FAILURE() << llvm::toString(std::move(E));
34 auto NewCode = tooling::applyAllReplacements(Code.code(), Merged);
35 EXPECT_TRUE(bool(NewCode))
36 << "Bad replacements: " << llvm::toString(NewCode.takeError());
37 NewCode->insert(transformCursorPosition(Cursor, Changes), "^");
38 return *NewCode;
39 }
40
41 // We can't pass raw strings directly to EXPECT_EQ because of gcc bugs.
expectAfterNewline(const char * Before,const char * After)42 void expectAfterNewline(const char *Before, const char *After) {
43 EXPECT_EQ(After, afterTyped(Before, "\n")) << Before;
44 }
expectAfter(const char * Typed,const char * Before,const char * After)45 void expectAfter(const char *Typed, const char *Before, const char *After) {
46 EXPECT_EQ(After, afterTyped(Before, Typed)) << Before;
47 }
48
TEST(FormatIncremental,SplitComment)49 TEST(FormatIncremental, SplitComment) {
50 expectAfterNewline(R"cpp(
51 // this comment was
52 ^split
53 )cpp",
54 R"cpp(
55 // this comment was
56 // ^split
57 )cpp");
58
59 expectAfterNewline(R"cpp(
60 // trailing whitespace is not a split
61 ^
62 )cpp",
63 R"cpp(
64 // trailing whitespace is not a split
65 ^
66 )cpp");
67
68 expectAfterNewline(R"cpp(
69 // splitting a
70 ^
71 // multiline comment
72 )cpp",
73 R"cpp(
74 // splitting a
75 // ^
76 // multiline comment
77 )cpp");
78
79 expectAfterNewline(R"cpp(
80 // extra
81 ^ whitespace
82 )cpp",
83 R"cpp(
84 // extra
85 // ^whitespace
86 )cpp");
87
88 expectAfterNewline(R"cpp(
89 /// triple
90 ^slash
91 )cpp",
92 R"cpp(
93 /// triple
94 /// ^slash
95 )cpp");
96
97 expectAfterNewline(R"cpp(
98 /// editor continuation
99 //^
100 )cpp",
101 R"cpp(
102 /// editor continuation
103 /// ^
104 )cpp");
105
106 expectAfterNewline(R"cpp(
107 // break before
108 ^ // slashes
109 )cpp",
110 R"cpp(
111 // break before
112 ^// slashes
113 )cpp");
114
115
116 expectAfterNewline(R"cpp(
117 int x; // aligned
118 ^comment
119 )cpp",
120 R"cpp(
121 int x; // aligned
122 // ^comment
123 )cpp");
124
125 // Fixed bug: the second line of the aligned comment shouldn't be "attached"
126 // to the cursor and outdented.
127 expectAfterNewline(R"cpp(
128 void foo() {
129 if (x)
130 return; // All spelled tokens are accounted for.
131 // that takes two lines
132 ^
133 }
134 )cpp",
135 R"cpp(
136 void foo() {
137 if (x)
138 return; // All spelled tokens are accounted for.
139 // that takes two lines
140 ^
141 }
142 )cpp");
143 }
144
TEST(FormatIncremental,Indentation)145 TEST(FormatIncremental, Indentation) {
146 expectAfterNewline(R"cpp(
147 void foo() {
148 if (bar)
149 ^
150 )cpp",
151 R"cpp(
152 void foo() {
153 if (bar)
154 ^
155 )cpp");
156
157 expectAfterNewline(R"cpp(
158 void foo() {
159 bar(baz(
160 ^
161 )cpp",
162 R"cpp(
163 void foo() {
164 bar(baz(
165 ^
166 )cpp");
167
168 expectAfterNewline(R"cpp(
169 void foo() {
170 ^}
171 )cpp",
172 R"cpp(
173 void foo() {
174 ^
175 }
176 )cpp");
177
178 expectAfterNewline(R"cpp(
179 class X {
180 protected:
181 ^
182 )cpp",
183 R"cpp(
184 class X {
185 protected:
186 ^
187 )cpp");
188
189 // Mismatched brackets (1)
190 expectAfterNewline(R"cpp(
191 void foo() {
192 foo{bar(
193 ^}
194 }
195 )cpp",
196 R"cpp(
197 void foo() {
198 foo {
199 bar(
200 ^}
201 }
202 )cpp");
203 // Mismatched brackets (2)
204 expectAfterNewline(R"cpp(
205 void foo() {
206 foo{bar(
207 ^text}
208 }
209 )cpp",
210 R"cpp(
211 void foo() {
212 foo {
213 bar(
214 ^text}
215 }
216 )cpp");
217 // Matched brackets
218 expectAfterNewline(R"cpp(
219 void foo() {
220 foo{bar(
221 ^)
222 }
223 )cpp",
224 R"cpp(
225 void foo() {
226 foo {
227 bar(
228 ^)
229 }
230 )cpp");
231 }
232
TEST(FormatIncremental,FormatPreviousLine)233 TEST(FormatIncremental, FormatPreviousLine) {
234 expectAfterNewline(R"cpp(
235 void foo() {
236 untouched( );
237 int x=2;
238 ^
239 )cpp",
240 R"cpp(
241 void foo() {
242 untouched( );
243 int x = 2;
244 ^
245 )cpp");
246
247 expectAfterNewline(R"cpp(
248 int x=untouched( );
249 auto L = []{return;return;};
250 ^
251 )cpp",
252 R"cpp(
253 int x=untouched( );
254 auto L = [] {
255 return;
256 return;
257 };
258 ^
259 )cpp");
260 }
261
TEST(FormatIncremental,Annoyances)262 TEST(FormatIncremental, Annoyances) {
263 // Don't remove newlines the user typed!
264 expectAfterNewline(R"cpp(
265 int x(){
266
267
268 ^
269 }
270 )cpp",
271 R"cpp(
272 int x(){
273
274
275 ^
276 }
277 )cpp");
278 // FIXME: we should not remove newlines here, either.
279 expectAfterNewline(R"cpp(
280 class x{
281 public:
282
283 ^
284 }
285 )cpp",
286 R"cpp(
287 class x{
288 public:
289 ^
290 }
291 )cpp");
292 }
293
TEST(FormatIncremental,FormatBrace)294 TEST(FormatIncremental, FormatBrace) {
295 expectAfter("}", R"cpp(
296 vector<int> x= {
297 1,
298 2,
299 3}^
300 )cpp",
301 R"cpp(
302 vector<int> x = {1, 2, 3}^
303 )cpp");
304 }
305
306 } // namespace
307 } // namespace clangd
308 } // namespace clang
309