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