clang-tools 19.0.0git
FormatTests.cpp
Go to the documentation of this file.
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
18namespace clang {
19namespace clangd {
20namespace {
21
22std::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.
39void 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}
44void 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
50TEST(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(
118int x; // aligned
119^comment
120)cpp",
121 R"cpp(
122int 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(
129void foo() {
130 if (x)
131 return; // All spelled tokens are accounted for.
132 // that takes two lines
133 ^
134}
135)cpp",
136 R"cpp(
137void 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
157TEST(FormatIncremental, Indentation) {
158 expectAfterNewline(R"cpp(
159void foo() {
160 if (bar)
161^
162)cpp",
163 R"cpp(
164void foo() {
165 if (bar)
166 ^
167)cpp");
168
169 expectAfterNewline(R"cpp(
170void foo() {
171 bar(baz(
172^
173)cpp",
174 R"cpp(
175void foo() {
176 bar(baz(
177 ^
178)cpp");
179
180 expectAfterNewline(R"cpp(
181void foo() {
182^}
183)cpp",
184 R"cpp(
185void foo() {
186 ^
187}
188)cpp");
189
190 expectAfterNewline(R"cpp(
191class X {
192protected:
193^
194)cpp",
195 R"cpp(
196class X {
197 protected:
198 ^
199)cpp");
200
201// Mismatched brackets (1)
202 expectAfterNewline(R"cpp(
203void foo() {
204 foo{bar(
205^}
206}
207)cpp",
208 R"cpp(
209void foo() {
210 foo {
211 bar(
212 ^}
213}
214)cpp");
215// Mismatched brackets (2)
216 expectAfterNewline(R"cpp(
217void foo() {
218 foo{bar(
219^text}
220}
221)cpp",
222 R"cpp(
223void foo() {
224 foo {
225 bar(
226 ^text}
227}
228)cpp");
229// Matched brackets
230 expectAfterNewline(R"cpp(
231void foo() {
232 foo{bar(
233^)
234}
235)cpp",
236 R"cpp(
237void foo() {
238 foo {
239 bar(
240 ^)
241}
242)cpp");
243}
244
245TEST(FormatIncremental, FormatPreviousLine) {
246 expectAfterNewline(R"cpp(
247void foo() {
248 untouched( );
249int x=2;
250^
251)cpp",
252 R"cpp(
253void foo() {
254 untouched( );
255 int x = 2;
256 ^
257)cpp");
258
259 expectAfterNewline(R"cpp(
260int x=untouched( );
261auto L = []{return;return;};
262^
263)cpp",
264 R"cpp(
265int x=untouched( );
266auto L = [] {
267 return;
268 return;
269};
270^
271)cpp");
272}
273
274TEST(FormatIncremental, Annoyances) {
275 // Don't remove newlines the user typed!
276 expectAfterNewline(R"cpp(
277int x(){
278
279
280^
281}
282)cpp",
283 R"cpp(
284int x(){
285
286
287 ^
288}
289)cpp");
290 // FIXME: we should not remove newlines here, either.
291 expectAfterNewline(R"cpp(
292class x{
293 public:
294
295^
296}
297)cpp",
298 R"cpp(
299class x{
300 public:
301 ^
302}
303)cpp");
304}
305
306TEST(FormatIncremental, FormatBrace) {
307 expectAfter("}", R"cpp(
308vector<int> x= {
309 1,
310 2,
311 3}^
312)cpp",
313 R"cpp(
314vector<int> x = {1, 2, 3}^
315)cpp");
316}
317
318} // namespace
319} // namespace clangd
320} // namespace clang
const Expr * E
std::string Code
tooling::Replacements Changes
Definition: Format.cpp:109
unsigned transformCursorPosition(unsigned Offset, const std::vector< tooling::Replacement > &Replacements)
Determine the new cursor position after applying Replacements.
Definition: Format.cpp:383
std::vector< tooling::Replacement > formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style)
Applies limited formatting around new InsertedText.
Definition: Format.cpp:277
TEST(BackgroundQueueTest, Priority)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:173
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//