1//===--- Format.cpp - Format C++ code -------------------------------------===//
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/// \file
10/// This file implements functions declared in Format.h. This will be
11/// split into separate files as we go.
12///
13//===----------------------------------------------------------------------===//
14
15#include "clang/Format/Format.h"
16#include "DefinitionBlockSeparator.h"
17#include "IntegerLiteralSeparatorFixer.h"
18#include "NamespaceEndCommentsFixer.h"
19#include "ObjCPropertyAttributeOrderFixer.h"
20#include "QualifierAlignmentFixer.h"
21#include "SortJavaScriptImports.h"
22#include "UnwrappedLineFormatter.h"
23#include "UsingDeclarationsSorter.h"
24#include "clang/Tooling/Inclusions/HeaderIncludes.h"
25#include "llvm/ADT/Sequence.h"
26#include <limits>
27
28#define DEBUG_TYPE "format-formatter"
29
30using clang::format::FormatStyle;
31
32LLVM_YAML_IS_SEQUENCE_VECTOR(FormatStyle::RawStringFormat)
33
34namespace llvm {
35namespace yaml {
36template <>
37struct ScalarEnumerationTraits<FormatStyle::BreakBeforeNoexceptSpecifierStyle> {
38 static void
39 enumeration(IO &IO, FormatStyle::BreakBeforeNoexceptSpecifierStyle &Value) {
40 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BBNSS_Never);
41 IO.enumCase(Val&: Value, Str: "OnlyWithParen", ConstVal: FormatStyle::BBNSS_OnlyWithParen);
42 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::BBNSS_Always);
43 }
44};
45
46template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
47 static void enumInput(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
48 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::AlignConsecutiveStyle({}));
49 IO.enumCase(Val&: Value, Str: "Consecutive",
50 ConstVal: FormatStyle::AlignConsecutiveStyle(
51 {/*Enabled=*/true, /*AcrossEmptyLines=*/false,
52 /*AcrossComments=*/false, /*AlignCompound=*/false,
53 /*AlignFunctionDeclarations=*/true,
54 /*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
55 IO.enumCase(Val&: Value, Str: "AcrossEmptyLines",
56 ConstVal: FormatStyle::AlignConsecutiveStyle(
57 {/*Enabled=*/true, /*AcrossEmptyLines=*/true,
58 /*AcrossComments=*/false, /*AlignCompound=*/false,
59 /*AlignFunctionDeclarations=*/true,
60 /*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
61 IO.enumCase(Val&: Value, Str: "AcrossComments",
62 ConstVal: FormatStyle::AlignConsecutiveStyle(
63 {/*Enabled=*/true, /*AcrossEmptyLines=*/false,
64 /*AcrossComments=*/true, /*AlignCompound=*/false,
65 /*AlignFunctionDeclarations=*/true,
66 /*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
67 IO.enumCase(Val&: Value, Str: "AcrossEmptyLinesAndComments",
68 ConstVal: FormatStyle::AlignConsecutiveStyle(
69 {/*Enabled=*/true, /*AcrossEmptyLines=*/true,
70 /*AcrossComments=*/true, /*AlignCompound=*/false,
71 /*AlignFunctionDeclarations=*/true,
72 /*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
73
74 // For backward compatibility.
75 IO.enumCase(Val&: Value, Str: "true",
76 ConstVal: FormatStyle::AlignConsecutiveStyle(
77 {/*Enabled=*/true, /*AcrossEmptyLines=*/false,
78 /*AcrossComments=*/false, /*AlignCompound=*/false,
79 /*AlignFunctionDeclarations=*/true,
80 /*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
81 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::AlignConsecutiveStyle({}));
82 }
83
84 static void mapping(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
85 IO.mapOptional(Key: "Enabled", Val&: Value.Enabled);
86 IO.mapOptional(Key: "AcrossEmptyLines", Val&: Value.AcrossEmptyLines);
87 IO.mapOptional(Key: "AcrossComments", Val&: Value.AcrossComments);
88 IO.mapOptional(Key: "AlignCompound", Val&: Value.AlignCompound);
89 IO.mapOptional(Key: "AlignFunctionDeclarations",
90 Val&: Value.AlignFunctionDeclarations);
91 IO.mapOptional(Key: "AlignFunctionPointers", Val&: Value.AlignFunctionPointers);
92 IO.mapOptional(Key: "PadOperators", Val&: Value.PadOperators);
93 }
94};
95
96template <>
97struct MappingTraits<FormatStyle::ShortCaseStatementsAlignmentStyle> {
98 static void mapping(IO &IO,
99 FormatStyle::ShortCaseStatementsAlignmentStyle &Value) {
100 IO.mapOptional(Key: "Enabled", Val&: Value.Enabled);
101 IO.mapOptional(Key: "AcrossEmptyLines", Val&: Value.AcrossEmptyLines);
102 IO.mapOptional(Key: "AcrossComments", Val&: Value.AcrossComments);
103 IO.mapOptional(Key: "AlignCaseArrows", Val&: Value.AlignCaseArrows);
104 IO.mapOptional(Key: "AlignCaseColons", Val&: Value.AlignCaseColons);
105 }
106};
107
108template <>
109struct ScalarEnumerationTraits<FormatStyle::AttributeBreakingStyle> {
110 static void enumeration(IO &IO, FormatStyle::AttributeBreakingStyle &Value) {
111 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::ABS_Always);
112 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::ABS_Leave);
113 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::ABS_Never);
114 }
115};
116
117template <>
118struct ScalarEnumerationTraits<FormatStyle::ArrayInitializerAlignmentStyle> {
119 static void enumeration(IO &IO,
120 FormatStyle::ArrayInitializerAlignmentStyle &Value) {
121 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::AIAS_None);
122 IO.enumCase(Val&: Value, Str: "Left", ConstVal: FormatStyle::AIAS_Left);
123 IO.enumCase(Val&: Value, Str: "Right", ConstVal: FormatStyle::AIAS_Right);
124 }
125};
126
127template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
128 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
129 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::BOS_All);
130 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BOS_All);
131 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::BOS_None);
132 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BOS_None);
133 IO.enumCase(Val&: Value, Str: "NonAssignment", ConstVal: FormatStyle::BOS_NonAssignment);
134 }
135};
136
137template <>
138struct ScalarEnumerationTraits<FormatStyle::BinPackParametersStyle> {
139 static void enumeration(IO &IO, FormatStyle::BinPackParametersStyle &Value) {
140 IO.enumCase(Val&: Value, Str: "BinPack", ConstVal: FormatStyle::BPPS_BinPack);
141 IO.enumCase(Val&: Value, Str: "OnePerLine", ConstVal: FormatStyle::BPPS_OnePerLine);
142 IO.enumCase(Val&: Value, Str: "AlwaysOnePerLine", ConstVal: FormatStyle::BPPS_AlwaysOnePerLine);
143
144 // For backward compatibility.
145 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BPPS_BinPack);
146 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BPPS_OnePerLine);
147 }
148};
149
150template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
151 static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
152 IO.enumCase(Val&: Value, Str: "Auto", ConstVal: FormatStyle::BPS_Auto);
153 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::BPS_Always);
154 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BPS_Never);
155 }
156};
157
158template <>
159struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> {
160 static void enumeration(IO &IO,
161 FormatStyle::BitFieldColonSpacingStyle &Value) {
162 IO.enumCase(Val&: Value, Str: "Both", ConstVal: FormatStyle::BFCS_Both);
163 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::BFCS_None);
164 IO.enumCase(Val&: Value, Str: "Before", ConstVal: FormatStyle::BFCS_Before);
165 IO.enumCase(Val&: Value, Str: "After", ConstVal: FormatStyle::BFCS_After);
166 }
167};
168
169template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
170 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
171 IO.enumCase(Val&: Value, Str: "Attach", ConstVal: FormatStyle::BS_Attach);
172 IO.enumCase(Val&: Value, Str: "Linux", ConstVal: FormatStyle::BS_Linux);
173 IO.enumCase(Val&: Value, Str: "Mozilla", ConstVal: FormatStyle::BS_Mozilla);
174 IO.enumCase(Val&: Value, Str: "Stroustrup", ConstVal: FormatStyle::BS_Stroustrup);
175 IO.enumCase(Val&: Value, Str: "Allman", ConstVal: FormatStyle::BS_Allman);
176 IO.enumCase(Val&: Value, Str: "Whitesmiths", ConstVal: FormatStyle::BS_Whitesmiths);
177 IO.enumCase(Val&: Value, Str: "GNU", ConstVal: FormatStyle::BS_GNU);
178 IO.enumCase(Val&: Value, Str: "WebKit", ConstVal: FormatStyle::BS_WebKit);
179 IO.enumCase(Val&: Value, Str: "Custom", ConstVal: FormatStyle::BS_Custom);
180 }
181};
182
183template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
184 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
185 IO.mapOptional(Key: "AfterCaseLabel", Val&: Wrapping.AfterCaseLabel);
186 IO.mapOptional(Key: "AfterClass", Val&: Wrapping.AfterClass);
187 IO.mapOptional(Key: "AfterControlStatement", Val&: Wrapping.AfterControlStatement);
188 IO.mapOptional(Key: "AfterEnum", Val&: Wrapping.AfterEnum);
189 IO.mapOptional(Key: "AfterExternBlock", Val&: Wrapping.AfterExternBlock);
190 IO.mapOptional(Key: "AfterFunction", Val&: Wrapping.AfterFunction);
191 IO.mapOptional(Key: "AfterNamespace", Val&: Wrapping.AfterNamespace);
192 IO.mapOptional(Key: "AfterObjCDeclaration", Val&: Wrapping.AfterObjCDeclaration);
193 IO.mapOptional(Key: "AfterStruct", Val&: Wrapping.AfterStruct);
194 IO.mapOptional(Key: "AfterUnion", Val&: Wrapping.AfterUnion);
195 IO.mapOptional(Key: "BeforeCatch", Val&: Wrapping.BeforeCatch);
196 IO.mapOptional(Key: "BeforeElse", Val&: Wrapping.BeforeElse);
197 IO.mapOptional(Key: "BeforeLambdaBody", Val&: Wrapping.BeforeLambdaBody);
198 IO.mapOptional(Key: "BeforeWhile", Val&: Wrapping.BeforeWhile);
199 IO.mapOptional(Key: "IndentBraces", Val&: Wrapping.IndentBraces);
200 IO.mapOptional(Key: "SplitEmptyFunction", Val&: Wrapping.SplitEmptyFunction);
201 IO.mapOptional(Key: "SplitEmptyRecord", Val&: Wrapping.SplitEmptyRecord);
202 IO.mapOptional(Key: "SplitEmptyNamespace", Val&: Wrapping.SplitEmptyNamespace);
203 }
204};
205
206template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
207 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
208 IO.enumCase(Val&: Value, Str: "Align", ConstVal: FormatStyle::BAS_Align);
209 IO.enumCase(Val&: Value, Str: "DontAlign", ConstVal: FormatStyle::BAS_DontAlign);
210 IO.enumCase(Val&: Value, Str: "AlwaysBreak", ConstVal: FormatStyle::BAS_AlwaysBreak);
211 IO.enumCase(Val&: Value, Str: "BlockIndent", ConstVal: FormatStyle::BAS_BlockIndent);
212
213 // For backward compatibility.
214 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BAS_Align);
215 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BAS_DontAlign);
216 }
217};
218
219template <>
220struct ScalarEnumerationTraits<
221 FormatStyle::BraceWrappingAfterControlStatementStyle> {
222 static void
223 enumeration(IO &IO,
224 FormatStyle::BraceWrappingAfterControlStatementStyle &Value) {
225 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BWACS_Never);
226 IO.enumCase(Val&: Value, Str: "MultiLine", ConstVal: FormatStyle::BWACS_MultiLine);
227 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::BWACS_Always);
228
229 // For backward compatibility.
230 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BWACS_Never);
231 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BWACS_Always);
232 }
233};
234
235template <>
236struct ScalarEnumerationTraits<
237 FormatStyle::BreakBeforeConceptDeclarationsStyle> {
238 static void
239 enumeration(IO &IO, FormatStyle::BreakBeforeConceptDeclarationsStyle &Value) {
240 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BBCDS_Never);
241 IO.enumCase(Val&: Value, Str: "Allowed", ConstVal: FormatStyle::BBCDS_Allowed);
242 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::BBCDS_Always);
243
244 // For backward compatibility.
245 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BBCDS_Always);
246 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BBCDS_Allowed);
247 }
248};
249
250template <>
251struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
252 static void enumeration(IO &IO,
253 FormatStyle::BreakBeforeInlineASMColonStyle &Value) {
254 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BBIAS_Never);
255 IO.enumCase(Val&: Value, Str: "OnlyMultiline", ConstVal: FormatStyle::BBIAS_OnlyMultiline);
256 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::BBIAS_Always);
257 }
258};
259
260template <>
261struct ScalarEnumerationTraits<FormatStyle::BreakBinaryOperationsStyle> {
262 static void enumeration(IO &IO,
263 FormatStyle::BreakBinaryOperationsStyle &Value) {
264 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::BBO_Never);
265 IO.enumCase(Val&: Value, Str: "OnePerLine", ConstVal: FormatStyle::BBO_OnePerLine);
266 IO.enumCase(Val&: Value, Str: "RespectPrecedence", ConstVal: FormatStyle::BBO_RespectPrecedence);
267 }
268};
269
270template <>
271struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
272 static void
273 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
274 IO.enumCase(Val&: Value, Str: "BeforeColon", ConstVal: FormatStyle::BCIS_BeforeColon);
275 IO.enumCase(Val&: Value, Str: "BeforeComma", ConstVal: FormatStyle::BCIS_BeforeComma);
276 IO.enumCase(Val&: Value, Str: "AfterColon", ConstVal: FormatStyle::BCIS_AfterColon);
277 }
278};
279
280template <>
281struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> {
282 static void enumeration(IO &IO,
283 FormatStyle::BreakInheritanceListStyle &Value) {
284 IO.enumCase(Val&: Value, Str: "BeforeColon", ConstVal: FormatStyle::BILS_BeforeColon);
285 IO.enumCase(Val&: Value, Str: "BeforeComma", ConstVal: FormatStyle::BILS_BeforeComma);
286 IO.enumCase(Val&: Value, Str: "AfterColon", ConstVal: FormatStyle::BILS_AfterColon);
287 IO.enumCase(Val&: Value, Str: "AfterComma", ConstVal: FormatStyle::BILS_AfterComma);
288 }
289};
290
291template <>
292struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
293 static void enumeration(IO &IO,
294 FormatStyle::BreakTemplateDeclarationsStyle &Value) {
295 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::BTDS_Leave);
296 IO.enumCase(Val&: Value, Str: "No", ConstVal: FormatStyle::BTDS_No);
297 IO.enumCase(Val&: Value, Str: "MultiLine", ConstVal: FormatStyle::BTDS_MultiLine);
298 IO.enumCase(Val&: Value, Str: "Yes", ConstVal: FormatStyle::BTDS_Yes);
299
300 // For backward compatibility.
301 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::BTDS_MultiLine);
302 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::BTDS_Yes);
303 }
304};
305
306template <> struct ScalarEnumerationTraits<FormatStyle::DAGArgStyle> {
307 static void enumeration(IO &IO, FormatStyle::DAGArgStyle &Value) {
308 IO.enumCase(Val&: Value, Str: "DontBreak", ConstVal: FormatStyle::DAS_DontBreak);
309 IO.enumCase(Val&: Value, Str: "BreakElements", ConstVal: FormatStyle::DAS_BreakElements);
310 IO.enumCase(Val&: Value, Str: "BreakAll", ConstVal: FormatStyle::DAS_BreakAll);
311 }
312};
313
314template <>
315struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
316 static void
317 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
318 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::DRTBS_None);
319 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::DRTBS_All);
320 IO.enumCase(Val&: Value, Str: "TopLevel", ConstVal: FormatStyle::DRTBS_TopLevel);
321
322 // For backward compatibility.
323 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::DRTBS_None);
324 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::DRTBS_All);
325 }
326};
327
328template <>
329struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
330 static void enumeration(IO &IO,
331 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
332 IO.enumCase(Val&: Value, Str: "DontAlign", ConstVal: FormatStyle::ENAS_DontAlign);
333 IO.enumCase(Val&: Value, Str: "Left", ConstVal: FormatStyle::ENAS_Left);
334 IO.enumCase(Val&: Value, Str: "LeftWithLastLine", ConstVal: FormatStyle::ENAS_LeftWithLastLine);
335 IO.enumCase(Val&: Value, Str: "Right", ConstVal: FormatStyle::ENAS_Right);
336
337 // For backward compatibility.
338 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::ENAS_Left);
339 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::ENAS_Right);
340 }
341};
342
343template <>
344struct ScalarEnumerationTraits<FormatStyle::EmptyLineAfterAccessModifierStyle> {
345 static void
346 enumeration(IO &IO, FormatStyle::EmptyLineAfterAccessModifierStyle &Value) {
347 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::ELAAMS_Never);
348 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::ELAAMS_Leave);
349 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::ELAAMS_Always);
350 }
351};
352
353template <>
354struct ScalarEnumerationTraits<
355 FormatStyle::EmptyLineBeforeAccessModifierStyle> {
356 static void
357 enumeration(IO &IO, FormatStyle::EmptyLineBeforeAccessModifierStyle &Value) {
358 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::ELBAMS_Never);
359 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::ELBAMS_Leave);
360 IO.enumCase(Val&: Value, Str: "LogicalBlock", ConstVal: FormatStyle::ELBAMS_LogicalBlock);
361 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::ELBAMS_Always);
362 }
363};
364
365template <>
366struct ScalarEnumerationTraits<FormatStyle::EnumTrailingCommaStyle> {
367 static void enumeration(IO &IO, FormatStyle::EnumTrailingCommaStyle &Value) {
368 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::ETC_Leave);
369 IO.enumCase(Val&: Value, Str: "Insert", ConstVal: FormatStyle::ETC_Insert);
370 IO.enumCase(Val&: Value, Str: "Remove", ConstVal: FormatStyle::ETC_Remove);
371 }
372};
373
374template <>
375struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
376 static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
377 IO.enumCase(Val&: Value, Str: "AfterExternBlock", ConstVal: FormatStyle::IEBS_AfterExternBlock);
378 IO.enumCase(Val&: Value, Str: "Indent", ConstVal: FormatStyle::IEBS_Indent);
379 IO.enumCase(Val&: Value, Str: "NoIndent", ConstVal: FormatStyle::IEBS_NoIndent);
380 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::IEBS_Indent);
381 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::IEBS_NoIndent);
382 }
383};
384
385template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
386 static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
387 IO.mapOptional(Key: "Binary", Val&: Base.Binary);
388 IO.mapOptional(Key: "BinaryMinDigits", Val&: Base.BinaryMinDigits);
389 IO.mapOptional(Key: "Decimal", Val&: Base.Decimal);
390 IO.mapOptional(Key: "DecimalMinDigits", Val&: Base.DecimalMinDigits);
391 IO.mapOptional(Key: "Hex", Val&: Base.Hex);
392 IO.mapOptional(Key: "HexMinDigits", Val&: Base.HexMinDigits);
393 }
394};
395
396template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
397 static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
398 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::JSQS_Leave);
399 IO.enumCase(Val&: Value, Str: "Single", ConstVal: FormatStyle::JSQS_Single);
400 IO.enumCase(Val&: Value, Str: "Double", ConstVal: FormatStyle::JSQS_Double);
401 }
402};
403
404template <> struct MappingTraits<FormatStyle::KeepEmptyLinesStyle> {
405 static void mapping(IO &IO, FormatStyle::KeepEmptyLinesStyle &Value) {
406 IO.mapOptional(Key: "AtEndOfFile", Val&: Value.AtEndOfFile);
407 IO.mapOptional(Key: "AtStartOfBlock", Val&: Value.AtStartOfBlock);
408 IO.mapOptional(Key: "AtStartOfFile", Val&: Value.AtStartOfFile);
409 }
410};
411
412template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
413 static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
414 IO.enumCase(Val&: Value, Str: "C", ConstVal: FormatStyle::LK_C);
415 IO.enumCase(Val&: Value, Str: "Cpp", ConstVal: FormatStyle::LK_Cpp);
416 IO.enumCase(Val&: Value, Str: "Java", ConstVal: FormatStyle::LK_Java);
417 IO.enumCase(Val&: Value, Str: "JavaScript", ConstVal: FormatStyle::LK_JavaScript);
418 IO.enumCase(Val&: Value, Str: "ObjC", ConstVal: FormatStyle::LK_ObjC);
419 IO.enumCase(Val&: Value, Str: "Proto", ConstVal: FormatStyle::LK_Proto);
420 IO.enumCase(Val&: Value, Str: "TableGen", ConstVal: FormatStyle::LK_TableGen);
421 IO.enumCase(Val&: Value, Str: "TextProto", ConstVal: FormatStyle::LK_TextProto);
422 IO.enumCase(Val&: Value, Str: "CSharp", ConstVal: FormatStyle::LK_CSharp);
423 IO.enumCase(Val&: Value, Str: "Json", ConstVal: FormatStyle::LK_Json);
424 IO.enumCase(Val&: Value, Str: "Verilog", ConstVal: FormatStyle::LK_Verilog);
425 }
426};
427
428template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
429 static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
430 IO.enumCase(Val&: Value, Str: "c++03", ConstVal: FormatStyle::LS_Cpp03);
431 IO.enumCase(Val&: Value, Str: "C++03", ConstVal: FormatStyle::LS_Cpp03); // Legacy alias
432 IO.enumCase(Val&: Value, Str: "Cpp03", ConstVal: FormatStyle::LS_Cpp03); // Legacy alias
433
434 IO.enumCase(Val&: Value, Str: "c++11", ConstVal: FormatStyle::LS_Cpp11);
435 IO.enumCase(Val&: Value, Str: "C++11", ConstVal: FormatStyle::LS_Cpp11); // Legacy alias
436
437 IO.enumCase(Val&: Value, Str: "c++14", ConstVal: FormatStyle::LS_Cpp14);
438 IO.enumCase(Val&: Value, Str: "c++17", ConstVal: FormatStyle::LS_Cpp17);
439 IO.enumCase(Val&: Value, Str: "c++20", ConstVal: FormatStyle::LS_Cpp20);
440
441 IO.enumCase(Val&: Value, Str: "Latest", ConstVal: FormatStyle::LS_Latest);
442 IO.enumCase(Val&: Value, Str: "Cpp11", ConstVal: FormatStyle::LS_Latest); // Legacy alias
443 IO.enumCase(Val&: Value, Str: "Auto", ConstVal: FormatStyle::LS_Auto);
444 }
445};
446
447template <>
448struct ScalarEnumerationTraits<FormatStyle::LambdaBodyIndentationKind> {
449 static void enumeration(IO &IO,
450 FormatStyle::LambdaBodyIndentationKind &Value) {
451 IO.enumCase(Val&: Value, Str: "Signature", ConstVal: FormatStyle::LBI_Signature);
452 IO.enumCase(Val&: Value, Str: "OuterScope", ConstVal: FormatStyle::LBI_OuterScope);
453 }
454};
455
456template <> struct ScalarEnumerationTraits<FormatStyle::LineEndingStyle> {
457 static void enumeration(IO &IO, FormatStyle::LineEndingStyle &Value) {
458 IO.enumCase(Val&: Value, Str: "LF", ConstVal: FormatStyle::LE_LF);
459 IO.enumCase(Val&: Value, Str: "CRLF", ConstVal: FormatStyle::LE_CRLF);
460 IO.enumCase(Val&: Value, Str: "DeriveLF", ConstVal: FormatStyle::LE_DeriveLF);
461 IO.enumCase(Val&: Value, Str: "DeriveCRLF", ConstVal: FormatStyle::LE_DeriveCRLF);
462 }
463};
464
465template <>
466struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
467 static void enumeration(IO &IO,
468 FormatStyle::NamespaceIndentationKind &Value) {
469 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::NI_None);
470 IO.enumCase(Val&: Value, Str: "Inner", ConstVal: FormatStyle::NI_Inner);
471 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::NI_All);
472 }
473};
474
475template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
476 static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
477 IO.enumCase(Val&: Value, Str: "DontAlign", ConstVal: FormatStyle::OAS_DontAlign);
478 IO.enumCase(Val&: Value, Str: "Align", ConstVal: FormatStyle::OAS_Align);
479 IO.enumCase(Val&: Value, Str: "AlignAfterOperator",
480 ConstVal: FormatStyle::OAS_AlignAfterOperator);
481
482 // For backward compatibility.
483 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::OAS_Align);
484 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::OAS_DontAlign);
485 }
486};
487
488template <>
489struct ScalarEnumerationTraits<FormatStyle::PackConstructorInitializersStyle> {
490 static void
491 enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) {
492 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::PCIS_Never);
493 IO.enumCase(Val&: Value, Str: "BinPack", ConstVal: FormatStyle::PCIS_BinPack);
494 IO.enumCase(Val&: Value, Str: "CurrentLine", ConstVal: FormatStyle::PCIS_CurrentLine);
495 IO.enumCase(Val&: Value, Str: "NextLine", ConstVal: FormatStyle::PCIS_NextLine);
496 IO.enumCase(Val&: Value, Str: "NextLineOnly", ConstVal: FormatStyle::PCIS_NextLineOnly);
497 }
498};
499
500template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
501 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
502 IO.enumCase(Val&: Value, Str: "Middle", ConstVal: FormatStyle::PAS_Middle);
503 IO.enumCase(Val&: Value, Str: "Left", ConstVal: FormatStyle::PAS_Left);
504 IO.enumCase(Val&: Value, Str: "Right", ConstVal: FormatStyle::PAS_Right);
505
506 // For backward compatibility.
507 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::PAS_Left);
508 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::PAS_Right);
509 }
510};
511
512template <>
513struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
514 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
515 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::PPDIS_None);
516 IO.enumCase(Val&: Value, Str: "AfterHash", ConstVal: FormatStyle::PPDIS_AfterHash);
517 IO.enumCase(Val&: Value, Str: "BeforeHash", ConstVal: FormatStyle::PPDIS_BeforeHash);
518 }
519};
520
521template <>
522struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> {
523 static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) {
524 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::QAS_Leave);
525 IO.enumCase(Val&: Value, Str: "Left", ConstVal: FormatStyle::QAS_Left);
526 IO.enumCase(Val&: Value, Str: "Right", ConstVal: FormatStyle::QAS_Right);
527 IO.enumCase(Val&: Value, Str: "Custom", ConstVal: FormatStyle::QAS_Custom);
528 }
529};
530
531template <> struct MappingTraits<FormatStyle::RawStringFormat> {
532 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
533 IO.mapOptional(Key: "Language", Val&: Format.Language);
534 IO.mapOptional(Key: "Delimiters", Val&: Format.Delimiters);
535 IO.mapOptional(Key: "EnclosingFunctions", Val&: Format.EnclosingFunctions);
536 IO.mapOptional(Key: "CanonicalDelimiter", Val&: Format.CanonicalDelimiter);
537 IO.mapOptional(Key: "BasedOnStyle", Val&: Format.BasedOnStyle);
538 }
539};
540
541template <> struct ScalarEnumerationTraits<FormatStyle::ReflowCommentsStyle> {
542 static void enumeration(IO &IO, FormatStyle::ReflowCommentsStyle &Value) {
543 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::RCS_Never);
544 IO.enumCase(Val&: Value, Str: "IndentOnly", ConstVal: FormatStyle::RCS_IndentOnly);
545 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::RCS_Always);
546 // For backward compatibility:
547 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::RCS_Never);
548 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::RCS_Always);
549 }
550};
551
552template <>
553struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> {
554 static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) {
555 IO.enumCase(Val&: Value, Str: "Pointer", ConstVal: FormatStyle::RAS_Pointer);
556 IO.enumCase(Val&: Value, Str: "Middle", ConstVal: FormatStyle::RAS_Middle);
557 IO.enumCase(Val&: Value, Str: "Left", ConstVal: FormatStyle::RAS_Left);
558 IO.enumCase(Val&: Value, Str: "Right", ConstVal: FormatStyle::RAS_Right);
559 }
560};
561
562template <>
563struct ScalarEnumerationTraits<FormatStyle::RemoveParenthesesStyle> {
564 static void enumeration(IO &IO, FormatStyle::RemoveParenthesesStyle &Value) {
565 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::RPS_Leave);
566 IO.enumCase(Val&: Value, Str: "MultipleParentheses",
567 ConstVal: FormatStyle::RPS_MultipleParentheses);
568 IO.enumCase(Val&: Value, Str: "ReturnStatement", ConstVal: FormatStyle::RPS_ReturnStatement);
569 }
570};
571
572template <>
573struct ScalarEnumerationTraits<FormatStyle::RequiresClausePositionStyle> {
574 static void enumeration(IO &IO,
575 FormatStyle::RequiresClausePositionStyle &Value) {
576 IO.enumCase(Val&: Value, Str: "OwnLine", ConstVal: FormatStyle::RCPS_OwnLine);
577 IO.enumCase(Val&: Value, Str: "OwnLineWithBrace", ConstVal: FormatStyle::RCPS_OwnLineWithBrace);
578 IO.enumCase(Val&: Value, Str: "WithPreceding", ConstVal: FormatStyle::RCPS_WithPreceding);
579 IO.enumCase(Val&: Value, Str: "WithFollowing", ConstVal: FormatStyle::RCPS_WithFollowing);
580 IO.enumCase(Val&: Value, Str: "SingleLine", ConstVal: FormatStyle::RCPS_SingleLine);
581 }
582};
583
584template <>
585struct ScalarEnumerationTraits<FormatStyle::RequiresExpressionIndentationKind> {
586 static void
587 enumeration(IO &IO, FormatStyle::RequiresExpressionIndentationKind &Value) {
588 IO.enumCase(Val&: Value, Str: "Keyword", ConstVal: FormatStyle::REI_Keyword);
589 IO.enumCase(Val&: Value, Str: "OuterScope", ConstVal: FormatStyle::REI_OuterScope);
590 }
591};
592
593template <>
594struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
595 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
596 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::RTBS_None);
597 IO.enumCase(Val&: Value, Str: "Automatic", ConstVal: FormatStyle::RTBS_Automatic);
598 IO.enumCase(Val&: Value, Str: "ExceptShortType", ConstVal: FormatStyle::RTBS_ExceptShortType);
599 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::RTBS_All);
600 IO.enumCase(Val&: Value, Str: "TopLevel", ConstVal: FormatStyle::RTBS_TopLevel);
601 IO.enumCase(Val&: Value, Str: "TopLevelDefinitions",
602 ConstVal: FormatStyle::RTBS_TopLevelDefinitions);
603 IO.enumCase(Val&: Value, Str: "AllDefinitions", ConstVal: FormatStyle::RTBS_AllDefinitions);
604 }
605};
606
607template <>
608struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> {
609 static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) {
610 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::SDS_Leave);
611 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::SDS_Always);
612 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SDS_Never);
613 }
614};
615
616template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> {
617 static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) {
618 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SBS_Never);
619 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SBS_Never);
620 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::SBS_Always);
621 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SBS_Always);
622 IO.enumCase(Val&: Value, Str: "Empty", ConstVal: FormatStyle::SBS_Empty);
623 }
624};
625
626template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
627 static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
628 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::SFS_None);
629 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SFS_None);
630 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::SFS_All);
631 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SFS_All);
632 IO.enumCase(Val&: Value, Str: "Inline", ConstVal: FormatStyle::SFS_Inline);
633 IO.enumCase(Val&: Value, Str: "InlineOnly", ConstVal: FormatStyle::SFS_InlineOnly);
634 IO.enumCase(Val&: Value, Str: "Empty", ConstVal: FormatStyle::SFS_Empty);
635 }
636};
637
638template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> {
639 static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) {
640 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SIS_Never);
641 IO.enumCase(Val&: Value, Str: "WithoutElse", ConstVal: FormatStyle::SIS_WithoutElse);
642 IO.enumCase(Val&: Value, Str: "OnlyFirstIf", ConstVal: FormatStyle::SIS_OnlyFirstIf);
643 IO.enumCase(Val&: Value, Str: "AllIfsAndElse", ConstVal: FormatStyle::SIS_AllIfsAndElse);
644
645 // For backward compatibility.
646 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::SIS_OnlyFirstIf);
647 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SIS_Never);
648 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SIS_WithoutElse);
649 }
650};
651
652template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
653 static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) {
654 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::SLS_None);
655 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SLS_None);
656 IO.enumCase(Val&: Value, Str: "Empty", ConstVal: FormatStyle::SLS_Empty);
657 IO.enumCase(Val&: Value, Str: "Inline", ConstVal: FormatStyle::SLS_Inline);
658 IO.enumCase(Val&: Value, Str: "All", ConstVal: FormatStyle::SLS_All);
659 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SLS_All);
660 }
661};
662
663template <> struct MappingTraits<FormatStyle::SortIncludesOptions> {
664 static void enumInput(IO &IO, FormatStyle::SortIncludesOptions &Value) {
665 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SortIncludesOptions({}));
666 IO.enumCase(Val&: Value, Str: "CaseInsensitive",
667 ConstVal: FormatStyle::SortIncludesOptions({/*Enabled=*/true,
668 /*IgnoreCase=*/true}));
669 IO.enumCase(Val&: Value, Str: "CaseSensitive",
670 ConstVal: FormatStyle::SortIncludesOptions({/*Enabled=*/true,
671 /*IgnoreCase=*/false}));
672
673 // For backward compatibility.
674 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SortIncludesOptions({}));
675 IO.enumCase(Val&: Value, Str: "true",
676 ConstVal: FormatStyle::SortIncludesOptions({/*Enabled=*/true,
677 /*IgnoreCase=*/false}));
678 }
679
680 static void mapping(IO &IO, FormatStyle::SortIncludesOptions &Value) {
681 IO.mapOptional(Key: "Enabled", Val&: Value.Enabled);
682 IO.mapOptional(Key: "IgnoreCase", Val&: Value.IgnoreCase);
683 }
684};
685
686template <>
687struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> {
688 static void enumeration(IO &IO,
689 FormatStyle::SortJavaStaticImportOptions &Value) {
690 IO.enumCase(Val&: Value, Str: "Before", ConstVal: FormatStyle::SJSIO_Before);
691 IO.enumCase(Val&: Value, Str: "After", ConstVal: FormatStyle::SJSIO_After);
692 }
693};
694
695template <>
696struct ScalarEnumerationTraits<FormatStyle::SortUsingDeclarationsOptions> {
697 static void enumeration(IO &IO,
698 FormatStyle::SortUsingDeclarationsOptions &Value) {
699 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SUD_Never);
700 IO.enumCase(Val&: Value, Str: "Lexicographic", ConstVal: FormatStyle::SUD_Lexicographic);
701 IO.enumCase(Val&: Value, Str: "LexicographicNumeric",
702 ConstVal: FormatStyle::SUD_LexicographicNumeric);
703
704 // For backward compatibility.
705 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SUD_Never);
706 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SUD_LexicographicNumeric);
707 }
708};
709
710template <>
711struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
712 static void
713 enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) {
714 IO.enumCase(Val&: Value, Str: "Default", ConstVal: FormatStyle::SAPQ_Default);
715 IO.enumCase(Val&: Value, Str: "Before", ConstVal: FormatStyle::SAPQ_Before);
716 IO.enumCase(Val&: Value, Str: "After", ConstVal: FormatStyle::SAPQ_After);
717 IO.enumCase(Val&: Value, Str: "Both", ConstVal: FormatStyle::SAPQ_Both);
718 }
719};
720
721template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> {
722 static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) {
723 IO.mapOptional(Key: "AfterControlStatements", Val&: Spacing.AfterControlStatements);
724 IO.mapOptional(Key: "AfterForeachMacros", Val&: Spacing.AfterForeachMacros);
725 IO.mapOptional(Key: "AfterFunctionDefinitionName",
726 Val&: Spacing.AfterFunctionDefinitionName);
727 IO.mapOptional(Key: "AfterFunctionDeclarationName",
728 Val&: Spacing.AfterFunctionDeclarationName);
729 IO.mapOptional(Key: "AfterIfMacros", Val&: Spacing.AfterIfMacros);
730 IO.mapOptional(Key: "AfterNot", Val&: Spacing.AfterNot);
731 IO.mapOptional(Key: "AfterOverloadedOperator", Val&: Spacing.AfterOverloadedOperator);
732 IO.mapOptional(Key: "AfterPlacementOperator", Val&: Spacing.AfterPlacementOperator);
733 IO.mapOptional(Key: "AfterRequiresInClause", Val&: Spacing.AfterRequiresInClause);
734 IO.mapOptional(Key: "AfterRequiresInExpression",
735 Val&: Spacing.AfterRequiresInExpression);
736 IO.mapOptional(Key: "BeforeNonEmptyParentheses",
737 Val&: Spacing.BeforeNonEmptyParentheses);
738 }
739};
740
741template <>
742struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensStyle> {
743 static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) {
744 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SBPO_Never);
745 IO.enumCase(Val&: Value, Str: "ControlStatements",
746 ConstVal: FormatStyle::SBPO_ControlStatements);
747 IO.enumCase(Val&: Value, Str: "ControlStatementsExceptControlMacros",
748 ConstVal: FormatStyle::SBPO_ControlStatementsExceptControlMacros);
749 IO.enumCase(Val&: Value, Str: "NonEmptyParentheses",
750 ConstVal: FormatStyle::SBPO_NonEmptyParentheses);
751 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::SBPO_Always);
752 IO.enumCase(Val&: Value, Str: "Custom", ConstVal: FormatStyle::SBPO_Custom);
753
754 // For backward compatibility.
755 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SBPO_Never);
756 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SBPO_ControlStatements);
757 IO.enumCase(Val&: Value, Str: "ControlStatementsExceptForEachMacros",
758 ConstVal: FormatStyle::SBPO_ControlStatementsExceptControlMacros);
759 }
760};
761
762template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> {
763 static void enumeration(IO &IO, FormatStyle::SpacesInAnglesStyle &Value) {
764 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SIAS_Never);
765 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::SIAS_Always);
766 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::SIAS_Leave);
767
768 // For backward compatibility.
769 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::SIAS_Never);
770 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::SIAS_Always);
771 }
772};
773
774template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
775 static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) {
776 // Transform the maximum to signed, to parse "-1" correctly
777 int signedMaximum = static_cast<int>(Space.Maximum);
778 IO.mapOptional(Key: "Minimum", Val&: Space.Minimum);
779 IO.mapOptional(Key: "Maximum", Val&: signedMaximum);
780 Space.Maximum = static_cast<unsigned>(signedMaximum);
781
782 if (Space.Maximum < std::numeric_limits<unsigned>::max())
783 Space.Minimum = std::min(a: Space.Minimum, b: Space.Maximum);
784 }
785};
786
787template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
788 static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
789 IO.mapOptional(Key: "ExceptDoubleParentheses", Val&: Spaces.ExceptDoubleParentheses);
790 IO.mapOptional(Key: "InCStyleCasts", Val&: Spaces.InCStyleCasts);
791 IO.mapOptional(Key: "InConditionalStatements", Val&: Spaces.InConditionalStatements);
792 IO.mapOptional(Key: "InEmptyParentheses", Val&: Spaces.InEmptyParentheses);
793 IO.mapOptional(Key: "Other", Val&: Spaces.Other);
794 }
795};
796
797template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInParensStyle> {
798 static void enumeration(IO &IO, FormatStyle::SpacesInParensStyle &Value) {
799 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::SIPO_Never);
800 IO.enumCase(Val&: Value, Str: "Custom", ConstVal: FormatStyle::SIPO_Custom);
801 }
802};
803
804template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> {
805 static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) {
806 IO.enumCase(Val&: Value, Str: "None", ConstVal: FormatStyle::TCS_None);
807 IO.enumCase(Val&: Value, Str: "Wrapped", ConstVal: FormatStyle::TCS_Wrapped);
808 }
809};
810
811template <>
812struct ScalarEnumerationTraits<FormatStyle::TrailingCommentsAlignmentKinds> {
813 static void enumeration(IO &IO,
814 FormatStyle::TrailingCommentsAlignmentKinds &Value) {
815 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::TCAS_Leave);
816 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::TCAS_Always);
817 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::TCAS_Never);
818 }
819};
820
821template <> struct MappingTraits<FormatStyle::TrailingCommentsAlignmentStyle> {
822 static void enumInput(IO &IO,
823 FormatStyle::TrailingCommentsAlignmentStyle &Value) {
824 IO.enumCase(Val&: Value, Str: "Leave",
825 ConstVal: FormatStyle::TrailingCommentsAlignmentStyle(
826 {.Kind: FormatStyle::TCAS_Leave, .OverEmptyLines: 0}));
827
828 IO.enumCase(Val&: Value, Str: "Always",
829 ConstVal: FormatStyle::TrailingCommentsAlignmentStyle(
830 {.Kind: FormatStyle::TCAS_Always, .OverEmptyLines: 0}));
831
832 IO.enumCase(Val&: Value, Str: "Never",
833 ConstVal: FormatStyle::TrailingCommentsAlignmentStyle(
834 {.Kind: FormatStyle::TCAS_Never, .OverEmptyLines: 0}));
835
836 // For backwards compatibility
837 IO.enumCase(Val&: Value, Str: "true",
838 ConstVal: FormatStyle::TrailingCommentsAlignmentStyle(
839 {.Kind: FormatStyle::TCAS_Always, .OverEmptyLines: 0}));
840 IO.enumCase(Val&: Value, Str: "false",
841 ConstVal: FormatStyle::TrailingCommentsAlignmentStyle(
842 {.Kind: FormatStyle::TCAS_Never, .OverEmptyLines: 0}));
843 }
844
845 static void mapping(IO &IO,
846 FormatStyle::TrailingCommentsAlignmentStyle &Value) {
847 IO.mapOptional(Key: "Kind", Val&: Value.Kind);
848 IO.mapOptional(Key: "OverEmptyLines", Val&: Value.OverEmptyLines);
849 }
850};
851
852template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
853 static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
854 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::UT_Never);
855 IO.enumCase(Val&: Value, Str: "false", ConstVal: FormatStyle::UT_Never);
856 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::UT_Always);
857 IO.enumCase(Val&: Value, Str: "true", ConstVal: FormatStyle::UT_Always);
858 IO.enumCase(Val&: Value, Str: "ForIndentation", ConstVal: FormatStyle::UT_ForIndentation);
859 IO.enumCase(Val&: Value, Str: "ForContinuationAndIndentation",
860 ConstVal: FormatStyle::UT_ForContinuationAndIndentation);
861 IO.enumCase(Val&: Value, Str: "AlignWithSpaces", ConstVal: FormatStyle::UT_AlignWithSpaces);
862 }
863};
864
865template <>
866struct ScalarEnumerationTraits<
867 FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle> {
868 static void
869 enumeration(IO &IO,
870 FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle &Value) {
871 IO.enumCase(Val&: Value, Str: "Never", ConstVal: FormatStyle::WNBWELS_Never);
872 IO.enumCase(Val&: Value, Str: "Always", ConstVal: FormatStyle::WNBWELS_Always);
873 IO.enumCase(Val&: Value, Str: "Leave", ConstVal: FormatStyle::WNBWELS_Leave);
874 }
875};
876
877template <> struct MappingTraits<FormatStyle> {
878 static void mapping(IO &IO, FormatStyle &Style) {
879 // When reading, read the language first, we need it for getPredefinedStyle.
880 IO.mapOptional(Key: "Language", Val&: Style.Language);
881
882 StringRef BasedOnStyle;
883 if (IO.outputting()) {
884 StringRef Styles[] = {"LLVM", "Google", "Chromium", "Mozilla",
885 "WebKit", "GNU", "Microsoft", "clang-format"};
886 for (StringRef StyleName : Styles) {
887 FormatStyle PredefinedStyle;
888 if (getPredefinedStyle(Name: StyleName, Language: Style.Language, Style: &PredefinedStyle) &&
889 Style == PredefinedStyle) {
890 BasedOnStyle = StyleName;
891 break;
892 }
893 }
894 } else {
895 IO.mapOptional(Key: "BasedOnStyle", Val&: BasedOnStyle);
896 if (!BasedOnStyle.empty()) {
897 FormatStyle::LanguageKind OldLanguage = Style.Language;
898 FormatStyle::LanguageKind Language =
899 ((FormatStyle *)IO.getContext())->Language;
900 if (!getPredefinedStyle(Name: BasedOnStyle, Language, Style: &Style)) {
901 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
902 return;
903 }
904 Style.Language = OldLanguage;
905 }
906 }
907
908 // Initialize some variables used in the parsing. The using logic is at the
909 // end.
910
911 // For backward compatibility:
912 // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was
913 // false unless BasedOnStyle was Google or Chromium whereas that of
914 // AllowAllConstructorInitializersOnNextLine was always true, so the
915 // equivalent default value of PackConstructorInitializers is PCIS_NextLine
916 // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options
917 // had a non-default value while PackConstructorInitializers has a default
918 // value, set the latter to an equivalent non-default value if needed.
919 const bool IsGoogleOrChromium = BasedOnStyle.equals_insensitive(RHS: "google") ||
920 BasedOnStyle.equals_insensitive(RHS: "chromium");
921 bool OnCurrentLine = IsGoogleOrChromium;
922 bool OnNextLine = true;
923
924 bool BreakBeforeInheritanceComma = false;
925 bool BreakConstructorInitializersBeforeComma = false;
926
927 bool DeriveLineEnding = true;
928 bool UseCRLF = false;
929
930 bool SpaceInEmptyParentheses = false;
931 bool SpacesInConditionalStatement = false;
932 bool SpacesInCStyleCastParentheses = false;
933 bool SpacesInParentheses = false;
934
935 // For backward compatibility.
936 if (!IO.outputting()) {
937 IO.mapOptional(Key: "AlignEscapedNewlinesLeft", Val&: Style.AlignEscapedNewlines);
938 IO.mapOptional(Key: "AllowAllConstructorInitializersOnNextLine", Val&: OnNextLine);
939 IO.mapOptional(Key: "AlwaysBreakAfterReturnType", Val&: Style.BreakAfterReturnType);
940 IO.mapOptional(Key: "AlwaysBreakTemplateDeclarations",
941 Val&: Style.BreakTemplateDeclarations);
942 IO.mapOptional(Key: "BreakBeforeInheritanceComma",
943 Val&: BreakBeforeInheritanceComma);
944 IO.mapOptional(Key: "BreakConstructorInitializersBeforeComma",
945 Val&: BreakConstructorInitializersBeforeComma);
946 IO.mapOptional(Key: "ConstructorInitializerAllOnOneLineOrOnePerLine",
947 Val&: OnCurrentLine);
948 IO.mapOptional(Key: "DeriveLineEnding", Val&: DeriveLineEnding);
949 IO.mapOptional(Key: "DerivePointerBinding", Val&: Style.DerivePointerAlignment);
950 IO.mapOptional(Key: "KeepEmptyLinesAtEOF", Val&: Style.KeepEmptyLines.AtEndOfFile);
951 IO.mapOptional(Key: "KeepEmptyLinesAtTheStartOfBlocks",
952 Val&: Style.KeepEmptyLines.AtStartOfBlock);
953 IO.mapOptional(Key: "IndentFunctionDeclarationAfterType",
954 Val&: Style.IndentWrappedFunctionNames);
955 IO.mapOptional(Key: "IndentRequires", Val&: Style.IndentRequiresClause);
956 IO.mapOptional(Key: "PointerBindsToType", Val&: Style.PointerAlignment);
957 IO.mapOptional(Key: "SpaceAfterControlStatementKeyword",
958 Val&: Style.SpaceBeforeParens);
959 IO.mapOptional(Key: "SpaceInEmptyParentheses", Val&: SpaceInEmptyParentheses);
960 IO.mapOptional(Key: "SpacesInConditionalStatement",
961 Val&: SpacesInConditionalStatement);
962 IO.mapOptional(Key: "SpacesInCStyleCastParentheses",
963 Val&: SpacesInCStyleCastParentheses);
964 IO.mapOptional(Key: "SpacesInParentheses", Val&: SpacesInParentheses);
965 IO.mapOptional(Key: "UseCRLF", Val&: UseCRLF);
966 }
967
968 IO.mapOptional(Key: "AccessModifierOffset", Val&: Style.AccessModifierOffset);
969 IO.mapOptional(Key: "AlignAfterOpenBracket", Val&: Style.AlignAfterOpenBracket);
970 IO.mapOptional(Key: "AlignArrayOfStructures", Val&: Style.AlignArrayOfStructures);
971 IO.mapOptional(Key: "AlignConsecutiveAssignments",
972 Val&: Style.AlignConsecutiveAssignments);
973 IO.mapOptional(Key: "AlignConsecutiveBitFields",
974 Val&: Style.AlignConsecutiveBitFields);
975 IO.mapOptional(Key: "AlignConsecutiveDeclarations",
976 Val&: Style.AlignConsecutiveDeclarations);
977 IO.mapOptional(Key: "AlignConsecutiveMacros", Val&: Style.AlignConsecutiveMacros);
978 IO.mapOptional(Key: "AlignConsecutiveShortCaseStatements",
979 Val&: Style.AlignConsecutiveShortCaseStatements);
980 IO.mapOptional(Key: "AlignConsecutiveTableGenBreakingDAGArgColons",
981 Val&: Style.AlignConsecutiveTableGenBreakingDAGArgColons);
982 IO.mapOptional(Key: "AlignConsecutiveTableGenCondOperatorColons",
983 Val&: Style.AlignConsecutiveTableGenCondOperatorColons);
984 IO.mapOptional(Key: "AlignConsecutiveTableGenDefinitionColons",
985 Val&: Style.AlignConsecutiveTableGenDefinitionColons);
986 IO.mapOptional(Key: "AlignEscapedNewlines", Val&: Style.AlignEscapedNewlines);
987 IO.mapOptional(Key: "AlignOperands", Val&: Style.AlignOperands);
988 IO.mapOptional(Key: "AlignTrailingComments", Val&: Style.AlignTrailingComments);
989 IO.mapOptional(Key: "AllowAllArgumentsOnNextLine",
990 Val&: Style.AllowAllArgumentsOnNextLine);
991 IO.mapOptional(Key: "AllowAllParametersOfDeclarationOnNextLine",
992 Val&: Style.AllowAllParametersOfDeclarationOnNextLine);
993 IO.mapOptional(Key: "AllowBreakBeforeNoexceptSpecifier",
994 Val&: Style.AllowBreakBeforeNoexceptSpecifier);
995 IO.mapOptional(Key: "AllowShortBlocksOnASingleLine",
996 Val&: Style.AllowShortBlocksOnASingleLine);
997 IO.mapOptional(Key: "AllowShortCaseExpressionOnASingleLine",
998 Val&: Style.AllowShortCaseExpressionOnASingleLine);
999 IO.mapOptional(Key: "AllowShortCaseLabelsOnASingleLine",
1000 Val&: Style.AllowShortCaseLabelsOnASingleLine);
1001 IO.mapOptional(Key: "AllowShortCompoundRequirementOnASingleLine",
1002 Val&: Style.AllowShortCompoundRequirementOnASingleLine);
1003 IO.mapOptional(Key: "AllowShortEnumsOnASingleLine",
1004 Val&: Style.AllowShortEnumsOnASingleLine);
1005 IO.mapOptional(Key: "AllowShortFunctionsOnASingleLine",
1006 Val&: Style.AllowShortFunctionsOnASingleLine);
1007 IO.mapOptional(Key: "AllowShortIfStatementsOnASingleLine",
1008 Val&: Style.AllowShortIfStatementsOnASingleLine);
1009 IO.mapOptional(Key: "AllowShortLambdasOnASingleLine",
1010 Val&: Style.AllowShortLambdasOnASingleLine);
1011 IO.mapOptional(Key: "AllowShortLoopsOnASingleLine",
1012 Val&: Style.AllowShortLoopsOnASingleLine);
1013 IO.mapOptional(Key: "AllowShortNamespacesOnASingleLine",
1014 Val&: Style.AllowShortNamespacesOnASingleLine);
1015 IO.mapOptional(Key: "AlwaysBreakAfterDefinitionReturnType",
1016 Val&: Style.AlwaysBreakAfterDefinitionReturnType);
1017 IO.mapOptional(Key: "AlwaysBreakBeforeMultilineStrings",
1018 Val&: Style.AlwaysBreakBeforeMultilineStrings);
1019 IO.mapOptional(Key: "AttributeMacros", Val&: Style.AttributeMacros);
1020 IO.mapOptional(Key: "BinPackArguments", Val&: Style.BinPackArguments);
1021 IO.mapOptional(Key: "BinPackLongBracedList", Val&: Style.BinPackLongBracedList);
1022 IO.mapOptional(Key: "BinPackParameters", Val&: Style.BinPackParameters);
1023 IO.mapOptional(Key: "BitFieldColonSpacing", Val&: Style.BitFieldColonSpacing);
1024 IO.mapOptional(Key: "BracedInitializerIndentWidth",
1025 Val&: Style.BracedInitializerIndentWidth);
1026 IO.mapOptional(Key: "BraceWrapping", Val&: Style.BraceWrapping);
1027 IO.mapOptional(Key: "BreakAdjacentStringLiterals",
1028 Val&: Style.BreakAdjacentStringLiterals);
1029 IO.mapOptional(Key: "BreakAfterAttributes", Val&: Style.BreakAfterAttributes);
1030 IO.mapOptional(Key: "BreakAfterJavaFieldAnnotations",
1031 Val&: Style.BreakAfterJavaFieldAnnotations);
1032 IO.mapOptional(Key: "BreakAfterReturnType", Val&: Style.BreakAfterReturnType);
1033 IO.mapOptional(Key: "BreakArrays", Val&: Style.BreakArrays);
1034 IO.mapOptional(Key: "BreakBeforeBinaryOperators",
1035 Val&: Style.BreakBeforeBinaryOperators);
1036 IO.mapOptional(Key: "BreakBeforeConceptDeclarations",
1037 Val&: Style.BreakBeforeConceptDeclarations);
1038 IO.mapOptional(Key: "BreakBeforeBraces", Val&: Style.BreakBeforeBraces);
1039 IO.mapOptional(Key: "BreakBeforeInlineASMColon",
1040 Val&: Style.BreakBeforeInlineASMColon);
1041 IO.mapOptional(Key: "BreakBeforeTemplateCloser",
1042 Val&: Style.BreakBeforeTemplateCloser);
1043 IO.mapOptional(Key: "BreakBeforeTernaryOperators",
1044 Val&: Style.BreakBeforeTernaryOperators);
1045 IO.mapOptional(Key: "BreakBinaryOperations", Val&: Style.BreakBinaryOperations);
1046 IO.mapOptional(Key: "BreakConstructorInitializers",
1047 Val&: Style.BreakConstructorInitializers);
1048 IO.mapOptional(Key: "BreakFunctionDefinitionParameters",
1049 Val&: Style.BreakFunctionDefinitionParameters);
1050 IO.mapOptional(Key: "BreakInheritanceList", Val&: Style.BreakInheritanceList);
1051 IO.mapOptional(Key: "BreakStringLiterals", Val&: Style.BreakStringLiterals);
1052 IO.mapOptional(Key: "BreakTemplateDeclarations",
1053 Val&: Style.BreakTemplateDeclarations);
1054 IO.mapOptional(Key: "ColumnLimit", Val&: Style.ColumnLimit);
1055 IO.mapOptional(Key: "CommentPragmas", Val&: Style.CommentPragmas);
1056 IO.mapOptional(Key: "CompactNamespaces", Val&: Style.CompactNamespaces);
1057 IO.mapOptional(Key: "ConstructorInitializerIndentWidth",
1058 Val&: Style.ConstructorInitializerIndentWidth);
1059 IO.mapOptional(Key: "ContinuationIndentWidth", Val&: Style.ContinuationIndentWidth);
1060 IO.mapOptional(Key: "Cpp11BracedListStyle", Val&: Style.Cpp11BracedListStyle);
1061 IO.mapOptional(Key: "DerivePointerAlignment", Val&: Style.DerivePointerAlignment);
1062 IO.mapOptional(Key: "DisableFormat", Val&: Style.DisableFormat);
1063 IO.mapOptional(Key: "EmptyLineAfterAccessModifier",
1064 Val&: Style.EmptyLineAfterAccessModifier);
1065 IO.mapOptional(Key: "EmptyLineBeforeAccessModifier",
1066 Val&: Style.EmptyLineBeforeAccessModifier);
1067 IO.mapOptional(Key: "EnumTrailingComma", Val&: Style.EnumTrailingComma);
1068 IO.mapOptional(Key: "ExperimentalAutoDetectBinPacking",
1069 Val&: Style.ExperimentalAutoDetectBinPacking);
1070 IO.mapOptional(Key: "FixNamespaceComments", Val&: Style.FixNamespaceComments);
1071 IO.mapOptional(Key: "ForEachMacros", Val&: Style.ForEachMacros);
1072 IO.mapOptional(Key: "IfMacros", Val&: Style.IfMacros);
1073 IO.mapOptional(Key: "IncludeBlocks", Val&: Style.IncludeStyle.IncludeBlocks);
1074 IO.mapOptional(Key: "IncludeCategories", Val&: Style.IncludeStyle.IncludeCategories);
1075 IO.mapOptional(Key: "IncludeIsMainRegex", Val&: Style.IncludeStyle.IncludeIsMainRegex);
1076 IO.mapOptional(Key: "IncludeIsMainSourceRegex",
1077 Val&: Style.IncludeStyle.IncludeIsMainSourceRegex);
1078 IO.mapOptional(Key: "IndentAccessModifiers", Val&: Style.IndentAccessModifiers);
1079 IO.mapOptional(Key: "IndentCaseBlocks", Val&: Style.IndentCaseBlocks);
1080 IO.mapOptional(Key: "IndentCaseLabels", Val&: Style.IndentCaseLabels);
1081 IO.mapOptional(Key: "IndentExportBlock", Val&: Style.IndentExportBlock);
1082 IO.mapOptional(Key: "IndentExternBlock", Val&: Style.IndentExternBlock);
1083 IO.mapOptional(Key: "IndentGotoLabels", Val&: Style.IndentGotoLabels);
1084 IO.mapOptional(Key: "IndentPPDirectives", Val&: Style.IndentPPDirectives);
1085 IO.mapOptional(Key: "IndentRequiresClause", Val&: Style.IndentRequiresClause);
1086 IO.mapOptional(Key: "IndentWidth", Val&: Style.IndentWidth);
1087 IO.mapOptional(Key: "IndentWrappedFunctionNames",
1088 Val&: Style.IndentWrappedFunctionNames);
1089 IO.mapOptional(Key: "InsertBraces", Val&: Style.InsertBraces);
1090 IO.mapOptional(Key: "InsertNewlineAtEOF", Val&: Style.InsertNewlineAtEOF);
1091 IO.mapOptional(Key: "InsertTrailingCommas", Val&: Style.InsertTrailingCommas);
1092 IO.mapOptional(Key: "IntegerLiteralSeparator", Val&: Style.IntegerLiteralSeparator);
1093 IO.mapOptional(Key: "JavaImportGroups", Val&: Style.JavaImportGroups);
1094 IO.mapOptional(Key: "JavaScriptQuotes", Val&: Style.JavaScriptQuotes);
1095 IO.mapOptional(Key: "JavaScriptWrapImports", Val&: Style.JavaScriptWrapImports);
1096 IO.mapOptional(Key: "KeepEmptyLines", Val&: Style.KeepEmptyLines);
1097 IO.mapOptional(Key: "KeepFormFeed", Val&: Style.KeepFormFeed);
1098 IO.mapOptional(Key: "LambdaBodyIndentation", Val&: Style.LambdaBodyIndentation);
1099 IO.mapOptional(Key: "LineEnding", Val&: Style.LineEnding);
1100 IO.mapOptional(Key: "MacroBlockBegin", Val&: Style.MacroBlockBegin);
1101 IO.mapOptional(Key: "MacroBlockEnd", Val&: Style.MacroBlockEnd);
1102 IO.mapOptional(Key: "Macros", Val&: Style.Macros);
1103 IO.mapOptional(Key: "MacrosSkippedByRemoveParentheses",
1104 Val&: Style.MacrosSkippedByRemoveParentheses);
1105 IO.mapOptional(Key: "MainIncludeChar", Val&: Style.IncludeStyle.MainIncludeChar);
1106 IO.mapOptional(Key: "MaxEmptyLinesToKeep", Val&: Style.MaxEmptyLinesToKeep);
1107 IO.mapOptional(Key: "NamespaceIndentation", Val&: Style.NamespaceIndentation);
1108 IO.mapOptional(Key: "NamespaceMacros", Val&: Style.NamespaceMacros);
1109 IO.mapOptional(Key: "ObjCBinPackProtocolList", Val&: Style.ObjCBinPackProtocolList);
1110 IO.mapOptional(Key: "ObjCBlockIndentWidth", Val&: Style.ObjCBlockIndentWidth);
1111 IO.mapOptional(Key: "ObjCBreakBeforeNestedBlockParam",
1112 Val&: Style.ObjCBreakBeforeNestedBlockParam);
1113 IO.mapOptional(Key: "ObjCPropertyAttributeOrder",
1114 Val&: Style.ObjCPropertyAttributeOrder);
1115 IO.mapOptional(Key: "ObjCSpaceAfterProperty", Val&: Style.ObjCSpaceAfterProperty);
1116 IO.mapOptional(Key: "ObjCSpaceBeforeProtocolList",
1117 Val&: Style.ObjCSpaceBeforeProtocolList);
1118 IO.mapOptional(Key: "OneLineFormatOffRegex", Val&: Style.OneLineFormatOffRegex);
1119 IO.mapOptional(Key: "PackConstructorInitializers",
1120 Val&: Style.PackConstructorInitializers);
1121 IO.mapOptional(Key: "PenaltyBreakAssignment", Val&: Style.PenaltyBreakAssignment);
1122 IO.mapOptional(Key: "PenaltyBreakBeforeFirstCallParameter",
1123 Val&: Style.PenaltyBreakBeforeFirstCallParameter);
1124 IO.mapOptional(Key: "PenaltyBreakBeforeMemberAccess",
1125 Val&: Style.PenaltyBreakBeforeMemberAccess);
1126 IO.mapOptional(Key: "PenaltyBreakComment", Val&: Style.PenaltyBreakComment);
1127 IO.mapOptional(Key: "PenaltyBreakFirstLessLess",
1128 Val&: Style.PenaltyBreakFirstLessLess);
1129 IO.mapOptional(Key: "PenaltyBreakOpenParenthesis",
1130 Val&: Style.PenaltyBreakOpenParenthesis);
1131 IO.mapOptional(Key: "PenaltyBreakScopeResolution",
1132 Val&: Style.PenaltyBreakScopeResolution);
1133 IO.mapOptional(Key: "PenaltyBreakString", Val&: Style.PenaltyBreakString);
1134 IO.mapOptional(Key: "PenaltyBreakTemplateDeclaration",
1135 Val&: Style.PenaltyBreakTemplateDeclaration);
1136 IO.mapOptional(Key: "PenaltyExcessCharacter", Val&: Style.PenaltyExcessCharacter);
1137 IO.mapOptional(Key: "PenaltyIndentedWhitespace",
1138 Val&: Style.PenaltyIndentedWhitespace);
1139 IO.mapOptional(Key: "PenaltyReturnTypeOnItsOwnLine",
1140 Val&: Style.PenaltyReturnTypeOnItsOwnLine);
1141 IO.mapOptional(Key: "PointerAlignment", Val&: Style.PointerAlignment);
1142 IO.mapOptional(Key: "PPIndentWidth", Val&: Style.PPIndentWidth);
1143 IO.mapOptional(Key: "QualifierAlignment", Val&: Style.QualifierAlignment);
1144 // Default Order for Left/Right based Qualifier alignment.
1145 if (Style.QualifierAlignment == FormatStyle::QAS_Right)
1146 Style.QualifierOrder = {"type", "const", "volatile"};
1147 else if (Style.QualifierAlignment == FormatStyle::QAS_Left)
1148 Style.QualifierOrder = {"const", "volatile", "type"};
1149 else if (Style.QualifierAlignment == FormatStyle::QAS_Custom)
1150 IO.mapOptional(Key: "QualifierOrder", Val&: Style.QualifierOrder);
1151 IO.mapOptional(Key: "RawStringFormats", Val&: Style.RawStringFormats);
1152 IO.mapOptional(Key: "ReferenceAlignment", Val&: Style.ReferenceAlignment);
1153 IO.mapOptional(Key: "ReflowComments", Val&: Style.ReflowComments);
1154 IO.mapOptional(Key: "RemoveBracesLLVM", Val&: Style.RemoveBracesLLVM);
1155 IO.mapOptional(Key: "RemoveEmptyLinesInUnwrappedLines",
1156 Val&: Style.RemoveEmptyLinesInUnwrappedLines);
1157 IO.mapOptional(Key: "RemoveParentheses", Val&: Style.RemoveParentheses);
1158 IO.mapOptional(Key: "RemoveSemicolon", Val&: Style.RemoveSemicolon);
1159 IO.mapOptional(Key: "RequiresClausePosition", Val&: Style.RequiresClausePosition);
1160 IO.mapOptional(Key: "RequiresExpressionIndentation",
1161 Val&: Style.RequiresExpressionIndentation);
1162 IO.mapOptional(Key: "SeparateDefinitionBlocks", Val&: Style.SeparateDefinitionBlocks);
1163 IO.mapOptional(Key: "ShortNamespaceLines", Val&: Style.ShortNamespaceLines);
1164 IO.mapOptional(Key: "SkipMacroDefinitionBody", Val&: Style.SkipMacroDefinitionBody);
1165 IO.mapOptional(Key: "SortIncludes", Val&: Style.SortIncludes);
1166 IO.mapOptional(Key: "SortJavaStaticImport", Val&: Style.SortJavaStaticImport);
1167 IO.mapOptional(Key: "SortUsingDeclarations", Val&: Style.SortUsingDeclarations);
1168 IO.mapOptional(Key: "SpaceAfterCStyleCast", Val&: Style.SpaceAfterCStyleCast);
1169 IO.mapOptional(Key: "SpaceAfterLogicalNot", Val&: Style.SpaceAfterLogicalNot);
1170 IO.mapOptional(Key: "SpaceAfterOperatorKeyword",
1171 Val&: Style.SpaceAfterOperatorKeyword);
1172 IO.mapOptional(Key: "SpaceAfterTemplateKeyword",
1173 Val&: Style.SpaceAfterTemplateKeyword);
1174 IO.mapOptional(Key: "SpaceAroundPointerQualifiers",
1175 Val&: Style.SpaceAroundPointerQualifiers);
1176 IO.mapOptional(Key: "SpaceBeforeAssignmentOperators",
1177 Val&: Style.SpaceBeforeAssignmentOperators);
1178 IO.mapOptional(Key: "SpaceBeforeCaseColon", Val&: Style.SpaceBeforeCaseColon);
1179 IO.mapOptional(Key: "SpaceBeforeCpp11BracedList",
1180 Val&: Style.SpaceBeforeCpp11BracedList);
1181 IO.mapOptional(Key: "SpaceBeforeCtorInitializerColon",
1182 Val&: Style.SpaceBeforeCtorInitializerColon);
1183 IO.mapOptional(Key: "SpaceBeforeInheritanceColon",
1184 Val&: Style.SpaceBeforeInheritanceColon);
1185 IO.mapOptional(Key: "SpaceBeforeJsonColon", Val&: Style.SpaceBeforeJsonColon);
1186 IO.mapOptional(Key: "SpaceBeforeParens", Val&: Style.SpaceBeforeParens);
1187 IO.mapOptional(Key: "SpaceBeforeParensOptions", Val&: Style.SpaceBeforeParensOptions);
1188 IO.mapOptional(Key: "SpaceBeforeRangeBasedForLoopColon",
1189 Val&: Style.SpaceBeforeRangeBasedForLoopColon);
1190 IO.mapOptional(Key: "SpaceBeforeSquareBrackets",
1191 Val&: Style.SpaceBeforeSquareBrackets);
1192 IO.mapOptional(Key: "SpaceInEmptyBlock", Val&: Style.SpaceInEmptyBlock);
1193 IO.mapOptional(Key: "SpacesBeforeTrailingComments",
1194 Val&: Style.SpacesBeforeTrailingComments);
1195 IO.mapOptional(Key: "SpacesInAngles", Val&: Style.SpacesInAngles);
1196 IO.mapOptional(Key: "SpacesInContainerLiterals",
1197 Val&: Style.SpacesInContainerLiterals);
1198 IO.mapOptional(Key: "SpacesInLineCommentPrefix",
1199 Val&: Style.SpacesInLineCommentPrefix);
1200 IO.mapOptional(Key: "SpacesInParens", Val&: Style.SpacesInParens);
1201 IO.mapOptional(Key: "SpacesInParensOptions", Val&: Style.SpacesInParensOptions);
1202 IO.mapOptional(Key: "SpacesInSquareBrackets", Val&: Style.SpacesInSquareBrackets);
1203 IO.mapOptional(Key: "Standard", Val&: Style.Standard);
1204 IO.mapOptional(Key: "StatementAttributeLikeMacros",
1205 Val&: Style.StatementAttributeLikeMacros);
1206 IO.mapOptional(Key: "StatementMacros", Val&: Style.StatementMacros);
1207 IO.mapOptional(Key: "TableGenBreakingDAGArgOperators",
1208 Val&: Style.TableGenBreakingDAGArgOperators);
1209 IO.mapOptional(Key: "TableGenBreakInsideDAGArg",
1210 Val&: Style.TableGenBreakInsideDAGArg);
1211 IO.mapOptional(Key: "TabWidth", Val&: Style.TabWidth);
1212 IO.mapOptional(Key: "TemplateNames", Val&: Style.TemplateNames);
1213 IO.mapOptional(Key: "TypeNames", Val&: Style.TypeNames);
1214 IO.mapOptional(Key: "TypenameMacros", Val&: Style.TypenameMacros);
1215 IO.mapOptional(Key: "UseTab", Val&: Style.UseTab);
1216 IO.mapOptional(Key: "VariableTemplates", Val&: Style.VariableTemplates);
1217 IO.mapOptional(Key: "VerilogBreakBetweenInstancePorts",
1218 Val&: Style.VerilogBreakBetweenInstancePorts);
1219 IO.mapOptional(Key: "WhitespaceSensitiveMacros",
1220 Val&: Style.WhitespaceSensitiveMacros);
1221 IO.mapOptional(Key: "WrapNamespaceBodyWithEmptyLines",
1222 Val&: Style.WrapNamespaceBodyWithEmptyLines);
1223
1224 // If AlwaysBreakAfterDefinitionReturnType was specified but
1225 // BreakAfterReturnType was not, initialize the latter from the former for
1226 // backwards compatibility.
1227 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
1228 Style.BreakAfterReturnType == FormatStyle::RTBS_None) {
1229 if (Style.AlwaysBreakAfterDefinitionReturnType ==
1230 FormatStyle::DRTBS_All) {
1231 Style.BreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
1232 } else if (Style.AlwaysBreakAfterDefinitionReturnType ==
1233 FormatStyle::DRTBS_TopLevel) {
1234 Style.BreakAfterReturnType = FormatStyle::RTBS_TopLevelDefinitions;
1235 }
1236 }
1237
1238 // If BreakBeforeInheritanceComma was specified but BreakInheritance was
1239 // not, initialize the latter from the former for backwards compatibility.
1240 if (BreakBeforeInheritanceComma &&
1241 Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) {
1242 Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
1243 }
1244
1245 // If BreakConstructorInitializersBeforeComma was specified but
1246 // BreakConstructorInitializers was not, initialize the latter from the
1247 // former for backwards compatibility.
1248 if (BreakConstructorInitializersBeforeComma &&
1249 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) {
1250 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
1251 }
1252
1253 if (!IsGoogleOrChromium) {
1254 if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack &&
1255 OnCurrentLine) {
1256 Style.PackConstructorInitializers = OnNextLine
1257 ? FormatStyle::PCIS_NextLine
1258 : FormatStyle::PCIS_CurrentLine;
1259 }
1260 } else if (Style.PackConstructorInitializers ==
1261 FormatStyle::PCIS_NextLine) {
1262 if (!OnCurrentLine)
1263 Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
1264 else if (!OnNextLine)
1265 Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine;
1266 }
1267
1268 if (Style.LineEnding == FormatStyle::LE_DeriveLF) {
1269 if (!DeriveLineEnding)
1270 Style.LineEnding = UseCRLF ? FormatStyle::LE_CRLF : FormatStyle::LE_LF;
1271 else if (UseCRLF)
1272 Style.LineEnding = FormatStyle::LE_DeriveCRLF;
1273 }
1274
1275 if (Style.SpacesInParens != FormatStyle::SIPO_Custom &&
1276 (SpacesInParentheses || SpaceInEmptyParentheses ||
1277 SpacesInConditionalStatement || SpacesInCStyleCastParentheses)) {
1278 if (SpacesInParentheses) {
1279 // For backward compatibility.
1280 Style.SpacesInParensOptions.ExceptDoubleParentheses = false;
1281 Style.SpacesInParensOptions.InConditionalStatements = true;
1282 Style.SpacesInParensOptions.InCStyleCasts =
1283 SpacesInCStyleCastParentheses;
1284 Style.SpacesInParensOptions.InEmptyParentheses =
1285 SpaceInEmptyParentheses;
1286 Style.SpacesInParensOptions.Other = true;
1287 } else {
1288 Style.SpacesInParensOptions = {};
1289 Style.SpacesInParensOptions.InConditionalStatements =
1290 SpacesInConditionalStatement;
1291 Style.SpacesInParensOptions.InCStyleCasts =
1292 SpacesInCStyleCastParentheses;
1293 Style.SpacesInParensOptions.InEmptyParentheses =
1294 SpaceInEmptyParentheses;
1295 }
1296 Style.SpacesInParens = FormatStyle::SIPO_Custom;
1297 }
1298 }
1299};
1300
1301// Allows to read vector<FormatStyle> while keeping default values.
1302// IO.getContext() should contain a pointer to the FormatStyle structure, that
1303// will be used to get default values for missing keys.
1304// If the first element has no Language specified, it will be treated as the
1305// default one for the following elements.
1306template <> struct DocumentListTraits<std::vector<FormatStyle>> {
1307 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
1308 return Seq.size();
1309 }
1310 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
1311 size_t Index) {
1312 if (Index >= Seq.size()) {
1313 assert(Index == Seq.size());
1314 FormatStyle Template;
1315 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
1316 Template = Seq[0];
1317 } else {
1318 Template = *((const FormatStyle *)IO.getContext());
1319 Template.Language = FormatStyle::LK_None;
1320 }
1321 Seq.resize(new_size: Index + 1, x: Template);
1322 }
1323 return Seq[Index];
1324 }
1325};
1326} // namespace yaml
1327} // namespace llvm
1328
1329namespace clang {
1330namespace format {
1331
1332const std::error_category &getParseCategory() {
1333 static const ParseErrorCategory C{};
1334 return C;
1335}
1336std::error_code make_error_code(ParseError e) {
1337 return std::error_code(static_cast<int>(e), getParseCategory());
1338}
1339
1340inline llvm::Error make_string_error(const Twine &Message) {
1341 return llvm::make_error<llvm::StringError>(Args: Message,
1342 Args: llvm::inconvertibleErrorCode());
1343}
1344
1345const char *ParseErrorCategory::name() const noexcept {
1346 return "clang-format.parse_error";
1347}
1348
1349std::string ParseErrorCategory::message(int EV) const {
1350 switch (static_cast<ParseError>(EV)) {
1351 case ParseError::Success:
1352 return "Success";
1353 case ParseError::Error:
1354 return "Invalid argument";
1355 case ParseError::Unsuitable:
1356 return "Unsuitable";
1357 case ParseError::BinPackTrailingCommaConflict:
1358 return "trailing comma insertion cannot be used with bin packing";
1359 case ParseError::InvalidQualifierSpecified:
1360 return "Invalid qualifier specified in QualifierOrder";
1361 case ParseError::DuplicateQualifierSpecified:
1362 return "Duplicate qualifier specified in QualifierOrder";
1363 case ParseError::MissingQualifierType:
1364 return "Missing type in QualifierOrder";
1365 case ParseError::MissingQualifierOrder:
1366 return "Missing QualifierOrder";
1367 }
1368 llvm_unreachable("unexpected parse error");
1369}
1370
1371static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
1372 if (Expanded.BreakBeforeBraces == FormatStyle::BS_Custom)
1373 return;
1374 Expanded.BraceWrapping = {/*AfterCaseLabel=*/false,
1375 /*AfterClass=*/false,
1376 /*AfterControlStatement=*/FormatStyle::BWACS_Never,
1377 /*AfterEnum=*/false,
1378 /*AfterFunction=*/false,
1379 /*AfterNamespace=*/false,
1380 /*AfterObjCDeclaration=*/false,
1381 /*AfterStruct=*/false,
1382 /*AfterUnion=*/false,
1383 /*AfterExternBlock=*/false,
1384 /*BeforeCatch=*/false,
1385 /*BeforeElse=*/false,
1386 /*BeforeLambdaBody=*/false,
1387 /*BeforeWhile=*/false,
1388 /*IndentBraces=*/false,
1389 /*SplitEmptyFunction=*/true,
1390 /*SplitEmptyRecord=*/true,
1391 /*SplitEmptyNamespace=*/true};
1392 switch (Expanded.BreakBeforeBraces) {
1393 case FormatStyle::BS_Linux:
1394 Expanded.BraceWrapping.AfterClass = true;
1395 Expanded.BraceWrapping.AfterFunction = true;
1396 Expanded.BraceWrapping.AfterNamespace = true;
1397 break;
1398 case FormatStyle::BS_Mozilla:
1399 Expanded.BraceWrapping.AfterClass = true;
1400 Expanded.BraceWrapping.AfterEnum = true;
1401 Expanded.BraceWrapping.AfterFunction = true;
1402 Expanded.BraceWrapping.AfterStruct = true;
1403 Expanded.BraceWrapping.AfterUnion = true;
1404 Expanded.BraceWrapping.AfterExternBlock = true;
1405 Expanded.BraceWrapping.SplitEmptyFunction = true;
1406 Expanded.BraceWrapping.SplitEmptyRecord = false;
1407 break;
1408 case FormatStyle::BS_Stroustrup:
1409 Expanded.BraceWrapping.AfterFunction = true;
1410 Expanded.BraceWrapping.BeforeCatch = true;
1411 Expanded.BraceWrapping.BeforeElse = true;
1412 break;
1413 case FormatStyle::BS_Allman:
1414 Expanded.BraceWrapping.AfterCaseLabel = true;
1415 Expanded.BraceWrapping.AfterClass = true;
1416 Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
1417 Expanded.BraceWrapping.AfterEnum = true;
1418 Expanded.BraceWrapping.AfterFunction = true;
1419 Expanded.BraceWrapping.AfterNamespace = true;
1420 Expanded.BraceWrapping.AfterObjCDeclaration = true;
1421 Expanded.BraceWrapping.AfterStruct = true;
1422 Expanded.BraceWrapping.AfterUnion = true;
1423 Expanded.BraceWrapping.AfterExternBlock = true;
1424 Expanded.BraceWrapping.BeforeCatch = true;
1425 Expanded.BraceWrapping.BeforeElse = true;
1426 Expanded.BraceWrapping.BeforeLambdaBody = true;
1427 break;
1428 case FormatStyle::BS_Whitesmiths:
1429 Expanded.BraceWrapping.AfterCaseLabel = true;
1430 Expanded.BraceWrapping.AfterClass = true;
1431 Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
1432 Expanded.BraceWrapping.AfterEnum = true;
1433 Expanded.BraceWrapping.AfterFunction = true;
1434 Expanded.BraceWrapping.AfterNamespace = true;
1435 Expanded.BraceWrapping.AfterObjCDeclaration = true;
1436 Expanded.BraceWrapping.AfterStruct = true;
1437 Expanded.BraceWrapping.AfterExternBlock = true;
1438 Expanded.BraceWrapping.BeforeCatch = true;
1439 Expanded.BraceWrapping.BeforeElse = true;
1440 Expanded.BraceWrapping.BeforeLambdaBody = true;
1441 break;
1442 case FormatStyle::BS_GNU:
1443 Expanded.BraceWrapping = {
1444 /*AfterCaseLabel=*/true,
1445 /*AfterClass=*/true,
1446 /*AfterControlStatement=*/FormatStyle::BWACS_Always,
1447 /*AfterEnum=*/true,
1448 /*AfterFunction=*/true,
1449 /*AfterNamespace=*/true,
1450 /*AfterObjCDeclaration=*/true,
1451 /*AfterStruct=*/true,
1452 /*AfterUnion=*/true,
1453 /*AfterExternBlock=*/true,
1454 /*BeforeCatch=*/true,
1455 /*BeforeElse=*/true,
1456 /*BeforeLambdaBody=*/true,
1457 /*BeforeWhile=*/true,
1458 /*IndentBraces=*/true,
1459 /*SplitEmptyFunction=*/true,
1460 /*SplitEmptyRecord=*/true,
1461 /*SplitEmptyNamespace=*/true};
1462 break;
1463 case FormatStyle::BS_WebKit:
1464 Expanded.BraceWrapping.AfterFunction = true;
1465 break;
1466 default:
1467 break;
1468 }
1469}
1470
1471static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) {
1472 if (Expanded.SpaceBeforeParens == FormatStyle::SBPO_Custom)
1473 return;
1474 // Reset all flags
1475 Expanded.SpaceBeforeParensOptions = {};
1476 Expanded.SpaceBeforeParensOptions.AfterPlacementOperator = true;
1477
1478 switch (Expanded.SpaceBeforeParens) {
1479 case FormatStyle::SBPO_ControlStatements:
1480 Expanded.SpaceBeforeParensOptions.AfterControlStatements = true;
1481 Expanded.SpaceBeforeParensOptions.AfterForeachMacros = true;
1482 Expanded.SpaceBeforeParensOptions.AfterIfMacros = true;
1483 break;
1484 case FormatStyle::SBPO_ControlStatementsExceptControlMacros:
1485 Expanded.SpaceBeforeParensOptions.AfterControlStatements = true;
1486 break;
1487 case FormatStyle::SBPO_NonEmptyParentheses:
1488 Expanded.SpaceBeforeParensOptions.BeforeNonEmptyParentheses = true;
1489 break;
1490 default:
1491 break;
1492 }
1493}
1494
1495static void expandPresetsSpacesInParens(FormatStyle &Expanded) {
1496 if (Expanded.SpacesInParens == FormatStyle::SIPO_Custom)
1497 return;
1498 assert(Expanded.SpacesInParens == FormatStyle::SIPO_Never);
1499 // Reset all flags
1500 Expanded.SpacesInParensOptions = {};
1501}
1502
1503FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
1504 FormatStyle LLVMStyle;
1505 LLVMStyle.AccessModifierOffset = -2;
1506 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
1507 LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None;
1508 LLVMStyle.AlignConsecutiveAssignments = {};
1509 LLVMStyle.AlignConsecutiveAssignments.PadOperators = true;
1510 LLVMStyle.AlignConsecutiveBitFields = {};
1511 LLVMStyle.AlignConsecutiveDeclarations = {};
1512 LLVMStyle.AlignConsecutiveDeclarations.AlignFunctionDeclarations = true;
1513 LLVMStyle.AlignConsecutiveMacros = {};
1514 LLVMStyle.AlignConsecutiveShortCaseStatements = {};
1515 LLVMStyle.AlignConsecutiveTableGenBreakingDAGArgColons = {};
1516 LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {};
1517 LLVMStyle.AlignConsecutiveTableGenDefinitionColons = {};
1518 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
1519 LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
1520 LLVMStyle.AlignTrailingComments = {};
1521 LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always;
1522 LLVMStyle.AlignTrailingComments.OverEmptyLines = 0;
1523 LLVMStyle.AllowAllArgumentsOnNextLine = true;
1524 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
1525 LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never;
1526 LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
1527 LLVMStyle.AllowShortCaseExpressionOnASingleLine = true;
1528 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
1529 LLVMStyle.AllowShortCompoundRequirementOnASingleLine = true;
1530 LLVMStyle.AllowShortEnumsOnASingleLine = true;
1531 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
1532 LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1533 LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
1534 LLVMStyle.AllowShortLoopsOnASingleLine = false;
1535 LLVMStyle.AllowShortNamespacesOnASingleLine = false;
1536 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
1537 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
1538 LLVMStyle.AttributeMacros.push_back(x: "__capability");
1539 LLVMStyle.BinPackArguments = true;
1540 LLVMStyle.BinPackLongBracedList = true;
1541 LLVMStyle.BinPackParameters = FormatStyle::BPPS_BinPack;
1542 LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
1543 LLVMStyle.BracedInitializerIndentWidth = -1;
1544 LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
1545 /*AfterClass=*/false,
1546 /*AfterControlStatement=*/FormatStyle::BWACS_Never,
1547 /*AfterEnum=*/false,
1548 /*AfterFunction=*/false,
1549 /*AfterNamespace=*/false,
1550 /*AfterObjCDeclaration=*/false,
1551 /*AfterStruct=*/false,
1552 /*AfterUnion=*/false,
1553 /*AfterExternBlock=*/false,
1554 /*BeforeCatch=*/false,
1555 /*BeforeElse=*/false,
1556 /*BeforeLambdaBody=*/false,
1557 /*BeforeWhile=*/false,
1558 /*IndentBraces=*/false,
1559 /*SplitEmptyFunction=*/true,
1560 /*SplitEmptyRecord=*/true,
1561 /*SplitEmptyNamespace=*/true};
1562 LLVMStyle.BreakAdjacentStringLiterals = true;
1563 LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Leave;
1564 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
1565 LLVMStyle.BreakAfterReturnType = FormatStyle::RTBS_None;
1566 LLVMStyle.BreakArrays = true;
1567 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
1568 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
1569 LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
1570 LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
1571 LLVMStyle.BreakBeforeTemplateCloser = false;
1572 LLVMStyle.BreakBeforeTernaryOperators = true;
1573 LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
1574 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
1575 LLVMStyle.BreakFunctionDefinitionParameters = false;
1576 LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
1577 LLVMStyle.BreakStringLiterals = true;
1578 LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
1579 LLVMStyle.ColumnLimit = 80;
1580 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
1581 LLVMStyle.CompactNamespaces = false;
1582 LLVMStyle.ConstructorInitializerIndentWidth = 4;
1583 LLVMStyle.ContinuationIndentWidth = 4;
1584 LLVMStyle.Cpp11BracedListStyle = true;
1585 LLVMStyle.DerivePointerAlignment = false;
1586 LLVMStyle.DisableFormat = false;
1587 LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
1588 LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
1589 LLVMStyle.EnumTrailingComma = FormatStyle::ETC_Leave;
1590 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
1591 LLVMStyle.FixNamespaceComments = true;
1592 LLVMStyle.ForEachMacros.push_back(x: "foreach");
1593 LLVMStyle.ForEachMacros.push_back(x: "Q_FOREACH");
1594 LLVMStyle.ForEachMacros.push_back(x: "BOOST_FOREACH");
1595 LLVMStyle.IfMacros.push_back(x: "KJ_IF_MAYBE");
1596 LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve;
1597 LLVMStyle.IncludeStyle.IncludeCategories = {
1598 {.Regex: "^\"(llvm|llvm-c|clang|clang-c)/", .Priority: 2, .SortPriority: 0, .RegexIsCaseSensitive: false},
1599 {.Regex: "^(<|\"(gtest|gmock|isl|json)/)", .Priority: 3, .SortPriority: 0, .RegexIsCaseSensitive: false},
1600 {.Regex: ".*", .Priority: 1, .SortPriority: 0, .RegexIsCaseSensitive: false}};
1601 LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$";
1602 LLVMStyle.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote;
1603 LLVMStyle.IndentAccessModifiers = false;
1604 LLVMStyle.IndentCaseBlocks = false;
1605 LLVMStyle.IndentCaseLabels = false;
1606 LLVMStyle.IndentExportBlock = true;
1607 LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
1608 LLVMStyle.IndentGotoLabels = true;
1609 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
1610 LLVMStyle.IndentRequiresClause = true;
1611 LLVMStyle.IndentWidth = 2;
1612 LLVMStyle.IndentWrappedFunctionNames = false;
1613 LLVMStyle.InheritsParentConfig = false;
1614 LLVMStyle.InsertBraces = false;
1615 LLVMStyle.InsertNewlineAtEOF = false;
1616 LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
1617 LLVMStyle.IntegerLiteralSeparator = {
1618 /*Binary=*/0, /*BinaryMinDigits=*/0,
1619 /*Decimal=*/0, /*DecimalMinDigits=*/0,
1620 /*Hex=*/0, /*HexMinDigits=*/0};
1621 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
1622 LLVMStyle.JavaScriptWrapImports = true;
1623 LLVMStyle.KeepEmptyLines = {
1624 /*AtEndOfFile=*/false,
1625 /*AtStartOfBlock=*/true,
1626 /*AtStartOfFile=*/true,
1627 };
1628 LLVMStyle.KeepFormFeed = false;
1629 LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature;
1630 LLVMStyle.Language = Language;
1631 LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
1632 LLVMStyle.MaxEmptyLinesToKeep = 1;
1633 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
1634 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
1635 LLVMStyle.ObjCBlockIndentWidth = 2;
1636 LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
1637 LLVMStyle.ObjCSpaceAfterProperty = false;
1638 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
1639 LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
1640 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
1641 LLVMStyle.PPIndentWidth = -1;
1642 LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
1643 LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
1644 LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
1645 LLVMStyle.RemoveBracesLLVM = false;
1646 LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false;
1647 LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave;
1648 LLVMStyle.RemoveSemicolon = false;
1649 LLVMStyle.RequiresClausePosition = FormatStyle::RCPS_OwnLine;
1650 LLVMStyle.RequiresExpressionIndentation = FormatStyle::REI_OuterScope;
1651 LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave;
1652 LLVMStyle.ShortNamespaceLines = 1;
1653 LLVMStyle.SkipMacroDefinitionBody = false;
1654 LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false};
1655 LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
1656 LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric;
1657 LLVMStyle.SpaceAfterCStyleCast = false;
1658 LLVMStyle.SpaceAfterLogicalNot = false;
1659 LLVMStyle.SpaceAfterOperatorKeyword = false;
1660 LLVMStyle.SpaceAfterTemplateKeyword = true;
1661 LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default;
1662 LLVMStyle.SpaceBeforeAssignmentOperators = true;
1663 LLVMStyle.SpaceBeforeCaseColon = false;
1664 LLVMStyle.SpaceBeforeCpp11BracedList = false;
1665 LLVMStyle.SpaceBeforeCtorInitializerColon = true;
1666 LLVMStyle.SpaceBeforeInheritanceColon = true;
1667 LLVMStyle.SpaceBeforeJsonColon = false;
1668 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
1669 LLVMStyle.SpaceBeforeParensOptions = {};
1670 LLVMStyle.SpaceBeforeParensOptions.AfterControlStatements = true;
1671 LLVMStyle.SpaceBeforeParensOptions.AfterForeachMacros = true;
1672 LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true;
1673 LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
1674 LLVMStyle.SpaceBeforeSquareBrackets = false;
1675 LLVMStyle.SpaceInEmptyBlock = false;
1676 LLVMStyle.SpacesBeforeTrailingComments = 1;
1677 LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
1678 LLVMStyle.SpacesInContainerLiterals = true;
1679 LLVMStyle.SpacesInLineCommentPrefix = {
1680 /*Minimum=*/1, /*Maximum=*/std::numeric_limits<unsigned>::max()};
1681 LLVMStyle.SpacesInParens = FormatStyle::SIPO_Never;
1682 LLVMStyle.SpacesInSquareBrackets = false;
1683 LLVMStyle.Standard = FormatStyle::LS_Latest;
1684 LLVMStyle.StatementAttributeLikeMacros.push_back(x: "Q_EMIT");
1685 LLVMStyle.StatementMacros.push_back(x: "Q_UNUSED");
1686 LLVMStyle.StatementMacros.push_back(x: "QT_REQUIRE_VERSION");
1687 LLVMStyle.TableGenBreakingDAGArgOperators = {};
1688 LLVMStyle.TableGenBreakInsideDAGArg = FormatStyle::DAS_DontBreak;
1689 LLVMStyle.TabWidth = 8;
1690 LLVMStyle.UseTab = FormatStyle::UT_Never;
1691 LLVMStyle.VerilogBreakBetweenInstancePorts = true;
1692 LLVMStyle.WhitespaceSensitiveMacros.push_back(x: "BOOST_PP_STRINGIZE");
1693 LLVMStyle.WhitespaceSensitiveMacros.push_back(x: "CF_SWIFT_NAME");
1694 LLVMStyle.WhitespaceSensitiveMacros.push_back(x: "NS_SWIFT_NAME");
1695 LLVMStyle.WhitespaceSensitiveMacros.push_back(x: "PP_STRINGIZE");
1696 LLVMStyle.WhitespaceSensitiveMacros.push_back(x: "STRINGIZE");
1697 LLVMStyle.WrapNamespaceBodyWithEmptyLines = FormatStyle::WNBWELS_Leave;
1698
1699 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
1700 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
1701 LLVMStyle.PenaltyBreakBeforeMemberAccess = 150;
1702 LLVMStyle.PenaltyBreakComment = 300;
1703 LLVMStyle.PenaltyBreakFirstLessLess = 120;
1704 LLVMStyle.PenaltyBreakOpenParenthesis = 0;
1705 LLVMStyle.PenaltyBreakScopeResolution = 500;
1706 LLVMStyle.PenaltyBreakString = 1000;
1707 LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
1708 LLVMStyle.PenaltyExcessCharacter = 1'000'000;
1709 LLVMStyle.PenaltyIndentedWhitespace = 0;
1710 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
1711
1712 // Defaults that differ when not C++.
1713 switch (Language) {
1714 case FormatStyle::LK_TableGen:
1715 LLVMStyle.SpacesInContainerLiterals = false;
1716 break;
1717 case FormatStyle::LK_Json:
1718 LLVMStyle.ColumnLimit = 0;
1719 break;
1720 case FormatStyle::LK_Verilog:
1721 LLVMStyle.IndentCaseLabels = true;
1722 LLVMStyle.SpacesInContainerLiterals = false;
1723 break;
1724 default:
1725 break;
1726 }
1727
1728 return LLVMStyle;
1729}
1730
1731FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
1732 if (Language == FormatStyle::LK_TextProto) {
1733 FormatStyle GoogleStyle = getGoogleStyle(Language: FormatStyle::LK_Proto);
1734 GoogleStyle.Language = FormatStyle::LK_TextProto;
1735
1736 return GoogleStyle;
1737 }
1738
1739 FormatStyle GoogleStyle = getLLVMStyle(Language);
1740
1741 GoogleStyle.AccessModifierOffset = -1;
1742 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
1743 GoogleStyle.AllowShortIfStatementsOnASingleLine =
1744 FormatStyle::SIS_WithoutElse;
1745 GoogleStyle.AllowShortLoopsOnASingleLine = true;
1746 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
1747 // Abseil aliases to clang's `_Nonnull`, `_Nullable` and `_Null_unspecified`.
1748 GoogleStyle.AttributeMacros.push_back(x: "absl_nonnull");
1749 GoogleStyle.AttributeMacros.push_back(x: "absl_nullable");
1750 GoogleStyle.AttributeMacros.push_back(x: "absl_nullability_unknown");
1751 GoogleStyle.BreakTemplateDeclarations = FormatStyle::BTDS_Yes;
1752 GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup;
1753 GoogleStyle.IncludeStyle.IncludeCategories = {{.Regex: "^<ext/.*\\.h>", .Priority: 2, .SortPriority: 0, .RegexIsCaseSensitive: false},
1754 {.Regex: "^<.*\\.h>", .Priority: 1, .SortPriority: 0, .RegexIsCaseSensitive: false},
1755 {.Regex: "^<.*", .Priority: 2, .SortPriority: 0, .RegexIsCaseSensitive: false},
1756 {.Regex: ".*", .Priority: 3, .SortPriority: 0, .RegexIsCaseSensitive: false}};
1757 GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
1758 GoogleStyle.IndentCaseLabels = true;
1759 GoogleStyle.KeepEmptyLines.AtStartOfBlock = false;
1760 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
1761 GoogleStyle.ObjCSpaceAfterProperty = false;
1762 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
1763 GoogleStyle.PackConstructorInitializers = FormatStyle::PCIS_NextLine;
1764 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
1765 GoogleStyle.RawStringFormats = {
1766 {
1767 .Language: FormatStyle::LK_Cpp,
1768 /*Delimiters=*/
1769 {
1770 "cc",
1771 "CC",
1772 "cpp",
1773 "Cpp",
1774 "CPP",
1775 "c++",
1776 "C++",
1777 },
1778 /*EnclosingFunctionNames=*/
1779 .EnclosingFunctions: {},
1780 /*CanonicalDelimiter=*/"",
1781 /*BasedOnStyle=*/"google",
1782 },
1783 {
1784 .Language: FormatStyle::LK_TextProto,
1785 /*Delimiters=*/
1786 {
1787 "pb",
1788 "PB",
1789 "proto",
1790 "PROTO",
1791 },
1792 /*EnclosingFunctionNames=*/
1793 .EnclosingFunctions: {
1794 "EqualsProto",
1795 "EquivToProto",
1796 "PARSE_PARTIAL_TEXT_PROTO",
1797 "PARSE_TEST_PROTO",
1798 "PARSE_TEXT_PROTO",
1799 "ParseTextOrDie",
1800 "ParseTextProtoOrDie",
1801 "ParseTestProto",
1802 "ParsePartialTestProto",
1803 },
1804 /*CanonicalDelimiter=*/"pb",
1805 /*BasedOnStyle=*/"google",
1806 },
1807 };
1808
1809 GoogleStyle.SpacesBeforeTrailingComments = 2;
1810 GoogleStyle.Standard = FormatStyle::LS_Auto;
1811
1812 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
1813 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
1814
1815 if (Language == FormatStyle::LK_Java) {
1816 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
1817 GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
1818 GoogleStyle.AlignTrailingComments = {};
1819 GoogleStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Never;
1820 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1821 GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1822 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1823 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
1824 GoogleStyle.ColumnLimit = 100;
1825 GoogleStyle.SpaceAfterCStyleCast = true;
1826 GoogleStyle.SpacesBeforeTrailingComments = 1;
1827 } else if (Language == FormatStyle::LK_JavaScript) {
1828 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
1829 GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
1830 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1831 // TODO: still under discussion whether to switch to SLS_All.
1832 GoogleStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty;
1833 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1834 GoogleStyle.BreakBeforeTernaryOperators = false;
1835 // taze:, triple slash directives (`/// <...`), tslint:, and @see, which is
1836 // commonly followed by overlong URLs.
1837 GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|tslint:|@see)";
1838 // TODO: enable once decided, in particular re disabling bin packing.
1839 // https://google.github.io/styleguide/jsguide.html#features-arrays-trailing-comma
1840 // GoogleStyle.InsertTrailingCommas = FormatStyle::TCS_Wrapped;
1841 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
1842 GoogleStyle.JavaScriptWrapImports = false;
1843 GoogleStyle.MaxEmptyLinesToKeep = 3;
1844 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
1845 GoogleStyle.SpacesInContainerLiterals = false;
1846 } else if (Language == FormatStyle::LK_Proto) {
1847 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1848 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1849 // This affects protocol buffer options specifications and text protos.
1850 // Text protos are currently mostly formatted inside C++ raw string literals
1851 // and often the current breaking behavior of string literals is not
1852 // beneficial there. Investigate turning this on once proper string reflow
1853 // has been implemented.
1854 GoogleStyle.BreakStringLiterals = false;
1855 GoogleStyle.Cpp11BracedListStyle = false;
1856 GoogleStyle.SpacesInContainerLiterals = false;
1857 } else if (Language == FormatStyle::LK_ObjC) {
1858 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1859 GoogleStyle.ColumnLimit = 100;
1860 GoogleStyle.DerivePointerAlignment = true;
1861 // "Regroup" doesn't work well for ObjC yet (main header heuristic,
1862 // relationship between ObjC standard library headers and other heades,
1863 // #imports, etc.)
1864 GoogleStyle.IncludeStyle.IncludeBlocks =
1865 tooling::IncludeStyle::IBS_Preserve;
1866 } else if (Language == FormatStyle::LK_CSharp) {
1867 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1868 GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1869 GoogleStyle.BreakStringLiterals = false;
1870 GoogleStyle.ColumnLimit = 100;
1871 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
1872 }
1873
1874 return GoogleStyle;
1875}
1876
1877FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
1878 FormatStyle ChromiumStyle = getGoogleStyle(Language);
1879
1880 // Disable include reordering across blocks in Chromium code.
1881 // - clang-format tries to detect that foo.h is the "main" header for
1882 // foo.cc and foo_unittest.cc via IncludeIsMainRegex. However, Chromium
1883 // uses many other suffices (_win.cc, _mac.mm, _posix.cc, _browsertest.cc,
1884 // _private.cc, _impl.cc etc) in different permutations
1885 // (_win_browsertest.cc) so disable this until IncludeIsMainRegex has a
1886 // better default for Chromium code.
1887 // - The default for .cc and .mm files is different (r357695) for Google style
1888 // for the same reason. The plan is to unify this again once the main
1889 // header detection works for Google's ObjC code, but this hasn't happened
1890 // yet. Since Chromium has some ObjC code, switching Chromium is blocked
1891 // on that.
1892 // - Finally, "If include reordering is harmful, put things in different
1893 // blocks to prevent it" has been a recommendation for a long time that
1894 // people are used to. We'll need a dev education push to change this to
1895 // "If include reordering is harmful, put things in a different block and
1896 // _prepend that with a comment_ to prevent it" before changing behavior.
1897 ChromiumStyle.IncludeStyle.IncludeBlocks =
1898 tooling::IncludeStyle::IBS_Preserve;
1899
1900 if (Language == FormatStyle::LK_Java) {
1901 ChromiumStyle.AllowShortIfStatementsOnASingleLine =
1902 FormatStyle::SIS_WithoutElse;
1903 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
1904 ChromiumStyle.ContinuationIndentWidth = 8;
1905 ChromiumStyle.IndentWidth = 4;
1906 // See styleguide for import groups:
1907 // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/java/java.md#Import-Order
1908 ChromiumStyle.JavaImportGroups = {
1909 "android",
1910 "androidx",
1911 "com",
1912 "dalvik",
1913 "junit",
1914 "org",
1915 "com.google.android.apps.chrome",
1916 "org.chromium",
1917 "java",
1918 "javax",
1919 };
1920 } else if (Language == FormatStyle::LK_JavaScript) {
1921 ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1922 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
1923 } else {
1924 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
1925 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1926 ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1927 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
1928 ChromiumStyle.BinPackParameters = FormatStyle::BPPS_OnePerLine;
1929 ChromiumStyle.DerivePointerAlignment = false;
1930 if (Language == FormatStyle::LK_ObjC)
1931 ChromiumStyle.ColumnLimit = 80;
1932 }
1933 return ChromiumStyle;
1934}
1935
1936FormatStyle getMozillaStyle() {
1937 FormatStyle MozillaStyle = getLLVMStyle();
1938 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
1939 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1940 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
1941 FormatStyle::DRTBS_TopLevel;
1942 MozillaStyle.BinPackArguments = false;
1943 MozillaStyle.BinPackParameters = FormatStyle::BPPS_OnePerLine;
1944 MozillaStyle.BreakAfterReturnType = FormatStyle::RTBS_TopLevel;
1945 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
1946 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
1947 MozillaStyle.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
1948 MozillaStyle.BreakTemplateDeclarations = FormatStyle::BTDS_Yes;
1949 MozillaStyle.ConstructorInitializerIndentWidth = 2;
1950 MozillaStyle.ContinuationIndentWidth = 2;
1951 MozillaStyle.Cpp11BracedListStyle = false;
1952 MozillaStyle.FixNamespaceComments = false;
1953 MozillaStyle.IndentCaseLabels = true;
1954 MozillaStyle.ObjCSpaceAfterProperty = true;
1955 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
1956 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
1957 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
1958 MozillaStyle.SpaceAfterTemplateKeyword = false;
1959 return MozillaStyle;
1960}
1961
1962FormatStyle getWebKitStyle() {
1963 FormatStyle Style = getLLVMStyle();
1964 Style.AccessModifierOffset = -4;
1965 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
1966 Style.AlignOperands = FormatStyle::OAS_DontAlign;
1967 Style.AlignTrailingComments = {};
1968 Style.AlignTrailingComments.Kind = FormatStyle::TCAS_Never;
1969 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
1970 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
1971 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
1972 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
1973 Style.ColumnLimit = 0;
1974 Style.Cpp11BracedListStyle = false;
1975 Style.FixNamespaceComments = false;
1976 Style.IndentWidth = 4;
1977 Style.NamespaceIndentation = FormatStyle::NI_Inner;
1978 Style.ObjCBlockIndentWidth = 4;
1979 Style.ObjCSpaceAfterProperty = true;
1980 Style.PointerAlignment = FormatStyle::PAS_Left;
1981 Style.SpaceBeforeCpp11BracedList = true;
1982 Style.SpaceInEmptyBlock = true;
1983 return Style;
1984}
1985
1986FormatStyle getGNUStyle() {
1987 FormatStyle Style = getLLVMStyle();
1988 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
1989 Style.BreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
1990 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
1991 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
1992 Style.BreakBeforeTernaryOperators = true;
1993 Style.ColumnLimit = 79;
1994 Style.Cpp11BracedListStyle = false;
1995 Style.FixNamespaceComments = false;
1996 Style.KeepFormFeed = true;
1997 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
1998 return Style;
1999}
2000
2001FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) {
2002 FormatStyle Style = getLLVMStyle(Language);
2003 Style.ColumnLimit = 120;
2004 Style.TabWidth = 4;
2005 Style.IndentWidth = 4;
2006 Style.UseTab = FormatStyle::UT_Never;
2007 Style.BreakBeforeBraces = FormatStyle::BS_Custom;
2008 Style.BraceWrapping.AfterClass = true;
2009 Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
2010 Style.BraceWrapping.AfterEnum = true;
2011 Style.BraceWrapping.AfterFunction = true;
2012 Style.BraceWrapping.AfterNamespace = true;
2013 Style.BraceWrapping.AfterObjCDeclaration = true;
2014 Style.BraceWrapping.AfterStruct = true;
2015 Style.BraceWrapping.AfterExternBlock = true;
2016 Style.BraceWrapping.BeforeCatch = true;
2017 Style.BraceWrapping.BeforeElse = true;
2018 Style.BraceWrapping.BeforeWhile = false;
2019 Style.PenaltyReturnTypeOnItsOwnLine = 1000;
2020 Style.AllowShortEnumsOnASingleLine = false;
2021 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
2022 Style.AllowShortCaseLabelsOnASingleLine = false;
2023 Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
2024 Style.AllowShortLoopsOnASingleLine = false;
2025 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
2026 Style.BreakAfterReturnType = FormatStyle::RTBS_None;
2027 return Style;
2028}
2029
2030FormatStyle getClangFormatStyle() {
2031 FormatStyle Style = getLLVMStyle();
2032 Style.InsertBraces = true;
2033 Style.InsertNewlineAtEOF = true;
2034 Style.IntegerLiteralSeparator.Decimal = 3;
2035 Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
2036 Style.LineEnding = FormatStyle::LE_LF;
2037 Style.RemoveBracesLLVM = true;
2038 Style.RemoveEmptyLinesInUnwrappedLines = true;
2039 Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement;
2040 Style.RemoveSemicolon = true;
2041 return Style;
2042}
2043
2044FormatStyle getNoStyle() {
2045 FormatStyle NoStyle = getLLVMStyle();
2046 NoStyle.DisableFormat = true;
2047 NoStyle.SortIncludes = {};
2048 NoStyle.SortUsingDeclarations = FormatStyle::SUD_Never;
2049 return NoStyle;
2050}
2051
2052bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
2053 FormatStyle *Style) {
2054 if (Name.equals_insensitive(RHS: "llvm"))
2055 *Style = getLLVMStyle(Language);
2056 else if (Name.equals_insensitive(RHS: "chromium"))
2057 *Style = getChromiumStyle(Language);
2058 else if (Name.equals_insensitive(RHS: "mozilla"))
2059 *Style = getMozillaStyle();
2060 else if (Name.equals_insensitive(RHS: "google"))
2061 *Style = getGoogleStyle(Language);
2062 else if (Name.equals_insensitive(RHS: "webkit"))
2063 *Style = getWebKitStyle();
2064 else if (Name.equals_insensitive(RHS: "gnu"))
2065 *Style = getGNUStyle();
2066 else if (Name.equals_insensitive(RHS: "microsoft"))
2067 *Style = getMicrosoftStyle(Language);
2068 else if (Name.equals_insensitive(RHS: "clang-format"))
2069 *Style = getClangFormatStyle();
2070 else if (Name.equals_insensitive(RHS: "none"))
2071 *Style = getNoStyle();
2072 else if (Name.equals_insensitive(RHS: "inheritparentconfig"))
2073 Style->InheritsParentConfig = true;
2074 else
2075 return false;
2076
2077 Style->Language = Language;
2078 return true;
2079}
2080
2081ParseError validateQualifierOrder(FormatStyle *Style) {
2082 // If its empty then it means don't do anything.
2083 if (Style->QualifierOrder.empty())
2084 return ParseError::MissingQualifierOrder;
2085
2086 // Ensure the list contains only currently valid qualifiers.
2087 for (const auto &Qualifier : Style->QualifierOrder) {
2088 if (Qualifier == "type")
2089 continue;
2090 auto token =
2091 LeftRightQualifierAlignmentFixer::getTokenFromQualifier(Qualifier);
2092 if (token == tok::identifier)
2093 return ParseError::InvalidQualifierSpecified;
2094 }
2095
2096 // Ensure the list is unique (no duplicates).
2097 std::set<std::string> UniqueQualifiers(Style->QualifierOrder.begin(),
2098 Style->QualifierOrder.end());
2099 if (Style->QualifierOrder.size() != UniqueQualifiers.size()) {
2100 LLVM_DEBUG(llvm::dbgs()
2101 << "Duplicate Qualifiers " << Style->QualifierOrder.size()
2102 << " vs " << UniqueQualifiers.size() << "\n");
2103 return ParseError::DuplicateQualifierSpecified;
2104 }
2105
2106 // Ensure the list has 'type' in it.
2107 if (!llvm::is_contained(Range&: Style->QualifierOrder, Element: "type"))
2108 return ParseError::MissingQualifierType;
2109
2110 return ParseError::Success;
2111}
2112
2113std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
2114 FormatStyle *Style, bool AllowUnknownOptions,
2115 llvm::SourceMgr::DiagHandlerTy DiagHandler,
2116 void *DiagHandlerCtxt, bool IsDotHFile) {
2117 assert(Style);
2118 FormatStyle::LanguageKind Language = Style->Language;
2119 assert(Language != FormatStyle::LK_None);
2120 if (Config.getBuffer().trim().empty())
2121 return make_error_code(e: ParseError::Success);
2122 Style->StyleSet.Clear();
2123 std::vector<FormatStyle> Styles;
2124 llvm::yaml::Input Input(Config, /*Ctxt=*/nullptr, DiagHandler,
2125 DiagHandlerCtxt);
2126 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
2127 // values for the fields, keys for which are missing from the configuration.
2128 // Mapping also uses the context to get the language to find the correct
2129 // base style.
2130 Input.setContext(Style);
2131 Input.setAllowUnknownKeys(AllowUnknownOptions);
2132 Input >> Styles;
2133 if (Input.error())
2134 return Input.error();
2135 if (Styles.empty())
2136 return make_error_code(e: ParseError::Success);
2137
2138 const auto StyleCount = Styles.size();
2139
2140 // Start from the second style as (only) the first one may be the default.
2141 for (unsigned I = 1; I < StyleCount; ++I) {
2142 const auto Lang = Styles[I].Language;
2143 if (Lang == FormatStyle::LK_None)
2144 return make_error_code(e: ParseError::Error);
2145 // Ensure that each language is configured at most once.
2146 for (unsigned J = 0; J < I; ++J) {
2147 if (Lang == Styles[J].Language) {
2148 LLVM_DEBUG(llvm::dbgs()
2149 << "Duplicate languages in the config file on positions "
2150 << J << " and " << I << '\n');
2151 return make_error_code(e: ParseError::Error);
2152 }
2153 }
2154 }
2155
2156 int LanguagePos = -1; // Position of the style for Language.
2157 int CppPos = -1; // Position of the style for C++.
2158 int CPos = -1; // Position of the style for C.
2159
2160 // Search Styles for Language and store the positions of C++ and C styles in
2161 // case Language is not found.
2162 for (unsigned I = 0; I < StyleCount; ++I) {
2163 const auto Lang = Styles[I].Language;
2164 if (Lang == Language) {
2165 LanguagePos = I;
2166 break;
2167 }
2168 if (Lang == FormatStyle::LK_Cpp)
2169 CppPos = I;
2170 else if (Lang == FormatStyle::LK_C)
2171 CPos = I;
2172 }
2173
2174 // If Language is not found, use the default style if there is one. Otherwise,
2175 // use the C style for C++ .h files and for backward compatibility, the C++
2176 // style for .c files.
2177 if (LanguagePos < 0) {
2178 if (Styles[0].Language == FormatStyle::LK_None) // Default style.
2179 LanguagePos = 0;
2180 else if (IsDotHFile && Language == FormatStyle::LK_Cpp)
2181 LanguagePos = CPos;
2182 else if (!IsDotHFile && Language == FormatStyle::LK_C)
2183 LanguagePos = CppPos;
2184 if (LanguagePos < 0)
2185 return make_error_code(e: ParseError::Unsuitable);
2186 }
2187
2188 for (const auto &S : llvm::reverse(C: llvm::drop_begin(RangeOrContainer&: Styles)))
2189 Style->StyleSet.Add(Style: S);
2190
2191 *Style = Styles[LanguagePos];
2192
2193 if (LanguagePos == 0) {
2194 if (Style->Language == FormatStyle::LK_None) // Default style.
2195 Style->Language = Language;
2196 Style->StyleSet.Add(Style: *Style);
2197 }
2198
2199 if (Style->InsertTrailingCommas != FormatStyle::TCS_None &&
2200 Style->BinPackArguments) {
2201 // See comment on FormatStyle::TSC_Wrapped.
2202 return make_error_code(e: ParseError::BinPackTrailingCommaConflict);
2203 }
2204 if (Style->QualifierAlignment != FormatStyle::QAS_Leave)
2205 return make_error_code(e: validateQualifierOrder(Style));
2206 return make_error_code(e: ParseError::Success);
2207}
2208
2209std::string configurationAsText(const FormatStyle &Style) {
2210 std::string Text;
2211 llvm::raw_string_ostream Stream(Text);
2212 llvm::yaml::Output Output(Stream);
2213 // We use the same mapping method for input and output, so we need a non-const
2214 // reference here.
2215 FormatStyle NonConstStyle = Style;
2216 expandPresetsBraceWrapping(Expanded&: NonConstStyle);
2217 expandPresetsSpaceBeforeParens(Expanded&: NonConstStyle);
2218 expandPresetsSpacesInParens(Expanded&: NonConstStyle);
2219 Output << NonConstStyle;
2220
2221 return Stream.str();
2222}
2223
2224std::optional<FormatStyle>
2225FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
2226 if (!Styles)
2227 return std::nullopt;
2228 auto It = Styles->find(x: Language);
2229 if (It == Styles->end())
2230 return std::nullopt;
2231 FormatStyle Style = It->second;
2232 Style.StyleSet = *this;
2233 return Style;
2234}
2235
2236void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
2237 assert(Style.Language != LK_None &&
2238 "Cannot add a style for LK_None to a StyleSet");
2239 assert(
2240 !Style.StyleSet.Styles &&
2241 "Cannot add a style associated with an existing StyleSet to a StyleSet");
2242 if (!Styles)
2243 Styles = std::make_shared<MapType>();
2244 (*Styles)[Style.Language] = std::move(Style);
2245}
2246
2247void FormatStyle::FormatStyleSet::Clear() { Styles.reset(); }
2248
2249std::optional<FormatStyle>
2250FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
2251 return StyleSet.Get(Language);
2252}
2253
2254namespace {
2255
2256void replaceToken(const FormatToken &Token, FormatToken *Next,
2257 const SourceManager &SourceMgr, tooling::Replacements &Result,
2258 StringRef Text = "") {
2259 const auto &Tok = Token.Tok;
2260 SourceLocation Start;
2261 if (Next && Next->NewlinesBefore == 0 && Next->isNot(Kind: tok::eof)) {
2262 Start = Tok.getLocation();
2263 Next->WhitespaceRange = Token.WhitespaceRange;
2264 } else {
2265 Start = Token.WhitespaceRange.getBegin();
2266 }
2267 const auto &Range = CharSourceRange::getCharRange(B: Start, E: Tok.getEndLoc());
2268 cantFail(Err: Result.add(R: tooling::Replacement(SourceMgr, Range, Text)));
2269}
2270
2271class ParensRemover : public TokenAnalyzer {
2272public:
2273 ParensRemover(const Environment &Env, const FormatStyle &Style)
2274 : TokenAnalyzer(Env, Style) {}
2275
2276 std::pair<tooling::Replacements, unsigned>
2277 analyze(TokenAnnotator &Annotator,
2278 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2279 FormatTokenLexer &Tokens) override {
2280 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2281 tooling::Replacements Result;
2282 removeParens(Lines&: AnnotatedLines, Result);
2283 return {Result, 0};
2284 }
2285
2286private:
2287 void removeParens(SmallVectorImpl<AnnotatedLine *> &Lines,
2288 tooling::Replacements &Result) {
2289 const auto &SourceMgr = Env.getSourceManager();
2290 for (auto *Line : Lines) {
2291 if (!Line->Children.empty())
2292 removeParens(Lines&: Line->Children, Result);
2293 if (!Line->Affected)
2294 continue;
2295 for (const auto *Token = Line->First; Token && !Token->Finalized;
2296 Token = Token->Next) {
2297 if (Token->Optional && Token->isOneOf(K1: tok::l_paren, K2: tok::r_paren))
2298 replaceToken(Token: *Token, Next: Token->Next, SourceMgr, Result, Text: " ");
2299 }
2300 }
2301 }
2302};
2303
2304class BracesInserter : public TokenAnalyzer {
2305public:
2306 BracesInserter(const Environment &Env, const FormatStyle &Style)
2307 : TokenAnalyzer(Env, Style) {}
2308
2309 std::pair<tooling::Replacements, unsigned>
2310 analyze(TokenAnnotator &Annotator,
2311 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2312 FormatTokenLexer &Tokens) override {
2313 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2314 tooling::Replacements Result;
2315 insertBraces(Lines&: AnnotatedLines, Result);
2316 return {Result, 0};
2317 }
2318
2319private:
2320 void insertBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
2321 tooling::Replacements &Result) {
2322 const auto &SourceMgr = Env.getSourceManager();
2323 int OpeningBraceSurplus = 0;
2324 for (AnnotatedLine *Line : Lines) {
2325 if (!Line->Children.empty())
2326 insertBraces(Lines&: Line->Children, Result);
2327 if (!Line->Affected && OpeningBraceSurplus == 0)
2328 continue;
2329 for (FormatToken *Token = Line->First; Token && !Token->Finalized;
2330 Token = Token->Next) {
2331 int BraceCount = Token->BraceCount;
2332 if (BraceCount == 0)
2333 continue;
2334 std::string Brace;
2335 if (BraceCount < 0) {
2336 assert(BraceCount == -1);
2337 if (!Line->Affected)
2338 break;
2339 Brace = Token->is(Kind: tok::comment) ? "\n{" : "{";
2340 ++OpeningBraceSurplus;
2341 } else {
2342 if (OpeningBraceSurplus == 0)
2343 break;
2344 if (OpeningBraceSurplus < BraceCount)
2345 BraceCount = OpeningBraceSurplus;
2346 Brace = '\n' + std::string(BraceCount, '}');
2347 OpeningBraceSurplus -= BraceCount;
2348 }
2349 Token->BraceCount = 0;
2350 const auto Start = Token->Tok.getEndLoc();
2351 cantFail(Err: Result.add(R: tooling::Replacement(SourceMgr, Start, 0, Brace)));
2352 }
2353 }
2354 assert(OpeningBraceSurplus == 0);
2355 }
2356};
2357
2358class BracesRemover : public TokenAnalyzer {
2359public:
2360 BracesRemover(const Environment &Env, const FormatStyle &Style)
2361 : TokenAnalyzer(Env, Style) {}
2362
2363 std::pair<tooling::Replacements, unsigned>
2364 analyze(TokenAnnotator &Annotator,
2365 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2366 FormatTokenLexer &Tokens) override {
2367 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2368 tooling::Replacements Result;
2369 removeBraces(Lines&: AnnotatedLines, Result);
2370 return {Result, 0};
2371 }
2372
2373private:
2374 void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
2375 tooling::Replacements &Result) {
2376 const auto &SourceMgr = Env.getSourceManager();
2377 const auto *End = Lines.end();
2378 for (const auto *I = Lines.begin(); I != End; ++I) {
2379 const auto &Line = *I;
2380 if (!Line->Children.empty())
2381 removeBraces(Lines&: Line->Children, Result);
2382 if (!Line->Affected)
2383 continue;
2384 const auto *NextLine = I + 1 == End ? nullptr : I[1];
2385 for (const auto *Token = Line->First; Token && !Token->Finalized;
2386 Token = Token->Next) {
2387 if (!Token->Optional || !Token->isOneOf(K1: tok::l_brace, K2: tok::r_brace))
2388 continue;
2389 auto *Next = Token->Next;
2390 assert(Next || Token == Line->Last);
2391 if (!Next && NextLine)
2392 Next = NextLine->First;
2393 replaceToken(Token: *Token, Next, SourceMgr, Result);
2394 }
2395 }
2396 }
2397};
2398
2399class SemiRemover : public TokenAnalyzer {
2400public:
2401 SemiRemover(const Environment &Env, const FormatStyle &Style)
2402 : TokenAnalyzer(Env, Style) {}
2403
2404 std::pair<tooling::Replacements, unsigned>
2405 analyze(TokenAnnotator &Annotator,
2406 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2407 FormatTokenLexer &Tokens) override {
2408 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2409 tooling::Replacements Result;
2410 removeSemi(Annotator, Lines&: AnnotatedLines, Result);
2411 return {Result, 0};
2412 }
2413
2414private:
2415 void removeSemi(TokenAnnotator &Annotator,
2416 SmallVectorImpl<AnnotatedLine *> &Lines,
2417 tooling::Replacements &Result) {
2418 auto PrecededByFunctionRBrace = [](const FormatToken &Tok) {
2419 const auto *Prev = Tok.Previous;
2420 if (!Prev || Prev->isNot(Kind: tok::r_brace))
2421 return false;
2422 const auto *LBrace = Prev->MatchingParen;
2423 return LBrace && LBrace->is(TT: TT_FunctionLBrace);
2424 };
2425 const auto &SourceMgr = Env.getSourceManager();
2426 const auto *End = Lines.end();
2427 for (const auto *I = Lines.begin(); I != End; ++I) {
2428 const auto &Line = *I;
2429 if (!Line->Children.empty())
2430 removeSemi(Annotator, Lines&: Line->Children, Result);
2431 if (!Line->Affected)
2432 continue;
2433 Annotator.calculateFormattingInformation(Line&: *Line);
2434 const auto *NextLine = I + 1 == End ? nullptr : I[1];
2435 for (const auto *Token = Line->First; Token && !Token->Finalized;
2436 Token = Token->Next) {
2437 if (Token->isNot(Kind: tok::semi) ||
2438 (!Token->Optional && !PrecededByFunctionRBrace(*Token))) {
2439 continue;
2440 }
2441 auto *Next = Token->Next;
2442 assert(Next || Token == Line->Last);
2443 if (!Next && NextLine)
2444 Next = NextLine->First;
2445 replaceToken(Token: *Token, Next, SourceMgr, Result);
2446 }
2447 }
2448 }
2449};
2450
2451class EnumTrailingCommaEditor : public TokenAnalyzer {
2452public:
2453 EnumTrailingCommaEditor(const Environment &Env, const FormatStyle &Style)
2454 : TokenAnalyzer(Env, Style) {}
2455
2456 std::pair<tooling::Replacements, unsigned>
2457 analyze(TokenAnnotator &Annotator,
2458 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2459 FormatTokenLexer &Tokens) override {
2460 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2461 tooling::Replacements Result;
2462 editEnumTrailingComma(Lines&: AnnotatedLines, Result);
2463 return {Result, 0};
2464 }
2465
2466private:
2467 void editEnumTrailingComma(SmallVectorImpl<AnnotatedLine *> &Lines,
2468 tooling::Replacements &Result) {
2469 bool InEnumBraces = false;
2470 const FormatToken *BeforeRBrace = nullptr;
2471 const auto &SourceMgr = Env.getSourceManager();
2472 for (auto *Line : Lines) {
2473 if (!Line->Children.empty())
2474 editEnumTrailingComma(Lines&: Line->Children, Result);
2475 for (const auto *Token = Line->First; Token && !Token->Finalized;
2476 Token = Token->Next) {
2477 if (Token->isNot(Kind: TT_EnumRBrace)) {
2478 if (Token->is(TT: TT_EnumLBrace))
2479 InEnumBraces = true;
2480 else if (InEnumBraces && Token->isNot(Kind: tok::comment))
2481 BeforeRBrace = Line->Affected ? Token : nullptr;
2482 continue;
2483 }
2484 InEnumBraces = false;
2485 if (!BeforeRBrace) // Empty braces or Line not affected.
2486 continue;
2487 if (BeforeRBrace->is(Kind: tok::comma)) {
2488 if (Style.EnumTrailingComma == FormatStyle::ETC_Remove)
2489 replaceToken(Token: *BeforeRBrace, Next: BeforeRBrace->Next, SourceMgr, Result);
2490 } else if (Style.EnumTrailingComma == FormatStyle::ETC_Insert) {
2491 cantFail(Err: Result.add(R: tooling::Replacement(
2492 SourceMgr, BeforeRBrace->Tok.getEndLoc(), 0, ",")));
2493 }
2494 BeforeRBrace = nullptr;
2495 }
2496 }
2497 }
2498};
2499
2500class JavaScriptRequoter : public TokenAnalyzer {
2501public:
2502 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
2503 : TokenAnalyzer(Env, Style) {}
2504
2505 std::pair<tooling::Replacements, unsigned>
2506 analyze(TokenAnnotator &Annotator,
2507 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2508 FormatTokenLexer &Tokens) override {
2509 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2510 tooling::Replacements Result;
2511 requoteJSStringLiteral(Lines&: AnnotatedLines, Result);
2512 return {Result, 0};
2513 }
2514
2515private:
2516 // Replaces double/single-quoted string literal as appropriate, re-escaping
2517 // the contents in the process.
2518 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
2519 tooling::Replacements &Result) {
2520 for (AnnotatedLine *Line : Lines) {
2521 requoteJSStringLiteral(Lines&: Line->Children, Result);
2522 if (!Line->Affected)
2523 continue;
2524 for (FormatToken *FormatTok = Line->First; FormatTok;
2525 FormatTok = FormatTok->Next) {
2526 StringRef Input = FormatTok->TokenText;
2527 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
2528 // NB: testing for not starting with a double quote to avoid
2529 // breaking `template strings`.
2530 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
2531 !Input.starts_with(Prefix: "\"")) ||
2532 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
2533 !Input.starts_with(Prefix: "\'"))) {
2534 continue;
2535 }
2536
2537 // Change start and end quote.
2538 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
2539 SourceLocation Start = FormatTok->Tok.getLocation();
2540 auto Replace = [&](SourceLocation Start, unsigned Length,
2541 StringRef ReplacementText) {
2542 auto Err = Result.add(R: tooling::Replacement(
2543 Env.getSourceManager(), Start, Length, ReplacementText));
2544 // FIXME: handle error. For now, print error message and skip the
2545 // replacement for release version.
2546 if (Err) {
2547 llvm::errs() << toString(E: std::move(Err)) << "\n";
2548 assert(false);
2549 }
2550 };
2551 Replace(Start, 1, IsSingle ? "'" : "\"");
2552 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(Offset: -1), 1,
2553 IsSingle ? "'" : "\"");
2554
2555 // Escape internal quotes.
2556 bool Escaped = false;
2557 for (size_t i = 1; i < Input.size() - 1; i++) {
2558 switch (Input[i]) {
2559 case '\\':
2560 if (!Escaped && i + 1 < Input.size() &&
2561 ((IsSingle && Input[i + 1] == '"') ||
2562 (!IsSingle && Input[i + 1] == '\''))) {
2563 // Remove this \, it's escaping a " or ' that no longer needs
2564 // escaping
2565 Replace(Start.getLocWithOffset(Offset: i), 1, "");
2566 continue;
2567 }
2568 Escaped = !Escaped;
2569 break;
2570 case '\"':
2571 case '\'':
2572 if (!Escaped && IsSingle == (Input[i] == '\'')) {
2573 // Escape the quote.
2574 Replace(Start.getLocWithOffset(Offset: i), 0, "\\");
2575 }
2576 Escaped = false;
2577 break;
2578 default:
2579 Escaped = false;
2580 break;
2581 }
2582 }
2583 }
2584 }
2585 }
2586};
2587
2588class Formatter : public TokenAnalyzer {
2589public:
2590 Formatter(const Environment &Env, const FormatStyle &Style,
2591 FormattingAttemptStatus *Status)
2592 : TokenAnalyzer(Env, Style), Status(Status) {}
2593
2594 std::pair<tooling::Replacements, unsigned>
2595 analyze(TokenAnnotator &Annotator,
2596 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2597 FormatTokenLexer &Tokens) override {
2598 tooling::Replacements Result;
2599 deriveLocalStyle(AnnotatedLines);
2600 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2601 for (AnnotatedLine *Line : AnnotatedLines)
2602 Annotator.calculateFormattingInformation(Line&: *Line);
2603 Annotator.setCommentLineLevels(AnnotatedLines);
2604
2605 WhitespaceManager Whitespaces(
2606 Env.getSourceManager(), Style,
2607 Style.LineEnding > FormatStyle::LE_CRLF
2608 ? WhitespaceManager::inputUsesCRLF(
2609 Text: Env.getSourceManager().getBufferData(FID: Env.getFileID()),
2610 DefaultToCRLF: Style.LineEnding == FormatStyle::LE_DeriveCRLF)
2611 : Style.LineEnding == FormatStyle::LE_CRLF);
2612 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
2613 Env.getSourceManager(), Whitespaces, Encoding,
2614 BinPackInconclusiveFunctions);
2615 unsigned Penalty =
2616 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
2617 Tokens.getKeywords(), Env.getSourceManager(),
2618 Status)
2619 .format(Lines: AnnotatedLines, /*DryRun=*/false,
2620 /*AdditionalIndent=*/0,
2621 /*FixBadIndentation=*/false,
2622 /*FirstStartColumn=*/Env.getFirstStartColumn(),
2623 /*NextStartColumn=*/Env.getNextStartColumn(),
2624 /*LastStartColumn=*/Env.getLastStartColumn());
2625 for (const auto &R : Whitespaces.generateReplacements())
2626 if (Result.add(R))
2627 return std::make_pair(x&: Result, y: 0);
2628 return std::make_pair(x&: Result, y&: Penalty);
2629 }
2630
2631private:
2632 bool
2633 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
2634 for (const AnnotatedLine *Line : Lines) {
2635 if (hasCpp03IncompatibleFormat(Lines: Line->Children))
2636 return true;
2637 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
2638 if (!Tok->hasWhitespaceBefore()) {
2639 if (Tok->is(Kind: tok::coloncolon) && Tok->Previous->is(TT: TT_TemplateOpener))
2640 return true;
2641 if (Tok->is(TT: TT_TemplateCloser) &&
2642 Tok->Previous->is(TT: TT_TemplateCloser)) {
2643 return true;
2644 }
2645 }
2646 }
2647 }
2648 return false;
2649 }
2650
2651 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
2652 int AlignmentDiff = 0;
2653 for (const AnnotatedLine *Line : Lines) {
2654 AlignmentDiff += countVariableAlignments(Lines: Line->Children);
2655 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
2656 if (Tok->isNot(Kind: TT_PointerOrReference))
2657 continue;
2658 // Don't treat space in `void foo() &&` as evidence.
2659 if (const auto *Prev = Tok->getPreviousNonComment()) {
2660 if (Prev->is(Kind: tok::r_paren) && Prev->MatchingParen) {
2661 if (const auto *Func =
2662 Prev->MatchingParen->getPreviousNonComment()) {
2663 if (Func->isOneOf(K1: TT_FunctionDeclarationName, K2: TT_StartOfName,
2664 Ks: TT_OverloadedOperator)) {
2665 continue;
2666 }
2667 }
2668 }
2669 }
2670 bool SpaceBefore = Tok->hasWhitespaceBefore();
2671 bool SpaceAfter = Tok->Next->hasWhitespaceBefore();
2672 if (SpaceBefore && !SpaceAfter)
2673 ++AlignmentDiff;
2674 if (!SpaceBefore && SpaceAfter)
2675 --AlignmentDiff;
2676 }
2677 }
2678 return AlignmentDiff;
2679 }
2680
2681 void
2682 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
2683 bool HasBinPackedFunction = false;
2684 bool HasOnePerLineFunction = false;
2685 for (AnnotatedLine *Line : AnnotatedLines) {
2686 if (!Line->First->Next)
2687 continue;
2688 FormatToken *Tok = Line->First->Next;
2689 while (Tok->Next) {
2690 if (Tok->is(PPK: PPK_BinPacked))
2691 HasBinPackedFunction = true;
2692 if (Tok->is(PPK: PPK_OnePerLine))
2693 HasOnePerLineFunction = true;
2694
2695 Tok = Tok->Next;
2696 }
2697 }
2698 if (Style.DerivePointerAlignment) {
2699 const auto NetRightCount = countVariableAlignments(Lines: AnnotatedLines);
2700 if (NetRightCount > 0)
2701 Style.PointerAlignment = FormatStyle::PAS_Right;
2702 else if (NetRightCount < 0)
2703 Style.PointerAlignment = FormatStyle::PAS_Left;
2704 Style.ReferenceAlignment = FormatStyle::RAS_Pointer;
2705 }
2706 if (Style.Standard == FormatStyle::LS_Auto) {
2707 Style.Standard = hasCpp03IncompatibleFormat(Lines: AnnotatedLines)
2708 ? FormatStyle::LS_Latest
2709 : FormatStyle::LS_Cpp03;
2710 }
2711 BinPackInconclusiveFunctions =
2712 HasBinPackedFunction || !HasOnePerLineFunction;
2713 }
2714
2715 bool BinPackInconclusiveFunctions;
2716 FormattingAttemptStatus *Status;
2717};
2718
2719/// TrailingCommaInserter inserts trailing commas into container literals.
2720/// E.g.:
2721/// const x = [
2722/// 1,
2723/// ];
2724/// TrailingCommaInserter runs after formatting. To avoid causing a required
2725/// reformatting (and thus reflow), it never inserts a comma that'd exceed the
2726/// ColumnLimit.
2727///
2728/// Because trailing commas disable binpacking of arrays, TrailingCommaInserter
2729/// is conceptually incompatible with bin packing.
2730class TrailingCommaInserter : public TokenAnalyzer {
2731public:
2732 TrailingCommaInserter(const Environment &Env, const FormatStyle &Style)
2733 : TokenAnalyzer(Env, Style) {}
2734
2735 std::pair<tooling::Replacements, unsigned>
2736 analyze(TokenAnnotator &Annotator,
2737 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2738 FormatTokenLexer &Tokens) override {
2739 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2740 tooling::Replacements Result;
2741 insertTrailingCommas(Lines&: AnnotatedLines, Result);
2742 return {Result, 0};
2743 }
2744
2745private:
2746 /// Inserts trailing commas in [] and {} initializers if they wrap over
2747 /// multiple lines.
2748 void insertTrailingCommas(SmallVectorImpl<AnnotatedLine *> &Lines,
2749 tooling::Replacements &Result) {
2750 for (AnnotatedLine *Line : Lines) {
2751 insertTrailingCommas(Lines&: Line->Children, Result);
2752 if (!Line->Affected)
2753 continue;
2754 for (FormatToken *FormatTok = Line->First; FormatTok;
2755 FormatTok = FormatTok->Next) {
2756 if (FormatTok->NewlinesBefore == 0)
2757 continue;
2758 FormatToken *Matching = FormatTok->MatchingParen;
2759 if (!Matching || !FormatTok->getPreviousNonComment())
2760 continue;
2761 if (!(FormatTok->is(Kind: tok::r_square) &&
2762 Matching->is(TT: TT_ArrayInitializerLSquare)) &&
2763 !(FormatTok->is(Kind: tok::r_brace) && Matching->is(TT: TT_DictLiteral))) {
2764 continue;
2765 }
2766 FormatToken *Prev = FormatTok->getPreviousNonComment();
2767 if (Prev->is(Kind: tok::comma) || Prev->is(Kind: tok::semi))
2768 continue;
2769 // getEndLoc is not reliably set during re-lexing, use text length
2770 // instead.
2771 SourceLocation Start =
2772 Prev->Tok.getLocation().getLocWithOffset(Offset: Prev->TokenText.size());
2773 // If inserting a comma would push the code over the column limit, skip
2774 // this location - it'd introduce an unstable formatting due to the
2775 // required reflow.
2776 unsigned ColumnNumber =
2777 Env.getSourceManager().getSpellingColumnNumber(Loc: Start);
2778 if (ColumnNumber > Style.ColumnLimit)
2779 continue;
2780 // Comma insertions cannot conflict with each other, and this pass has a
2781 // clean set of Replacements, so the operation below cannot fail.
2782 cantFail(Err: Result.add(
2783 R: tooling::Replacement(Env.getSourceManager(), Start, 0, ",")));
2784 }
2785 }
2786 }
2787};
2788
2789// This class clean up the erroneous/redundant code around the given ranges in
2790// file.
2791class Cleaner : public TokenAnalyzer {
2792public:
2793 Cleaner(const Environment &Env, const FormatStyle &Style)
2794 : TokenAnalyzer(Env, Style),
2795 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
2796
2797 // FIXME: eliminate unused parameters.
2798 std::pair<tooling::Replacements, unsigned>
2799 analyze(TokenAnnotator &Annotator,
2800 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2801 FormatTokenLexer &Tokens) override {
2802 // FIXME: in the current implementation the granularity of affected range
2803 // is an annotated line. However, this is not sufficient. Furthermore,
2804 // redundant code introduced by replacements does not necessarily
2805 // intercept with ranges of replacements that result in the redundancy.
2806 // To determine if some redundant code is actually introduced by
2807 // replacements(e.g. deletions), we need to come up with a more
2808 // sophisticated way of computing affected ranges.
2809 AffectedRangeMgr.computeAffectedLines(Lines&: AnnotatedLines);
2810
2811 checkEmptyNamespace(AnnotatedLines);
2812
2813 for (auto *Line : AnnotatedLines)
2814 cleanupLine(Line);
2815
2816 return {generateFixes(), 0};
2817 }
2818
2819private:
2820 void cleanupLine(AnnotatedLine *Line) {
2821 for (auto *Child : Line->Children)
2822 cleanupLine(Line: Child);
2823
2824 if (Line->Affected) {
2825 cleanupRight(Start: Line->First, LK: tok::comma, RK: tok::comma);
2826 cleanupRight(Start: Line->First, LK: TT_CtorInitializerColon, RK: tok::comma);
2827 cleanupRight(Start: Line->First, LK: tok::l_paren, RK: tok::comma);
2828 cleanupLeft(Start: Line->First, LK: tok::comma, RK: tok::r_paren);
2829 cleanupLeft(Start: Line->First, LK: TT_CtorInitializerComma, RK: tok::l_brace);
2830 cleanupLeft(Start: Line->First, LK: TT_CtorInitializerColon, RK: tok::l_brace);
2831 cleanupLeft(Start: Line->First, LK: TT_CtorInitializerColon, RK: tok::equal);
2832 }
2833 }
2834
2835 bool containsOnlyComments(const AnnotatedLine &Line) {
2836 for (FormatToken *Tok = Line.First; Tok; Tok = Tok->Next)
2837 if (Tok->isNot(Kind: tok::comment))
2838 return false;
2839 return true;
2840 }
2841
2842 // Iterate through all lines and remove any empty (nested) namespaces.
2843 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
2844 std::set<unsigned> DeletedLines;
2845 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
2846 auto &Line = *AnnotatedLines[i];
2847 if (Line.startsWithNamespace())
2848 checkEmptyNamespace(AnnotatedLines, CurrentLine: i, NewLine&: i, DeletedLines);
2849 }
2850
2851 for (auto Line : DeletedLines) {
2852 FormatToken *Tok = AnnotatedLines[Line]->First;
2853 while (Tok) {
2854 deleteToken(Tok);
2855 Tok = Tok->Next;
2856 }
2857 }
2858 }
2859
2860 // The function checks if the namespace, which starts from \p CurrentLine, and
2861 // its nested namespaces are empty and delete them if they are empty. It also
2862 // sets \p NewLine to the last line checked.
2863 // Returns true if the current namespace is empty.
2864 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2865 unsigned CurrentLine, unsigned &NewLine,
2866 std::set<unsigned> &DeletedLines) {
2867 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
2868 if (Style.BraceWrapping.AfterNamespace) {
2869 // If the left brace is in a new line, we should consume it first so that
2870 // it does not make the namespace non-empty.
2871 // FIXME: error handling if there is no left brace.
2872 if (!AnnotatedLines[++CurrentLine]->startsWith(Tokens: tok::l_brace)) {
2873 NewLine = CurrentLine;
2874 return false;
2875 }
2876 } else if (!AnnotatedLines[CurrentLine]->endsWith(Tokens: tok::l_brace)) {
2877 return false;
2878 }
2879 while (++CurrentLine < End) {
2880 if (AnnotatedLines[CurrentLine]->startsWith(Tokens: tok::r_brace))
2881 break;
2882
2883 if (AnnotatedLines[CurrentLine]->startsWithNamespace()) {
2884 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
2885 DeletedLines)) {
2886 return false;
2887 }
2888 CurrentLine = NewLine;
2889 continue;
2890 }
2891
2892 if (containsOnlyComments(Line: *AnnotatedLines[CurrentLine]))
2893 continue;
2894
2895 // If there is anything other than comments or nested namespaces in the
2896 // current namespace, the namespace cannot be empty.
2897 NewLine = CurrentLine;
2898 return false;
2899 }
2900
2901 NewLine = CurrentLine;
2902 if (CurrentLine >= End)
2903 return false;
2904
2905 // Check if the empty namespace is actually affected by changed ranges.
2906 if (!AffectedRangeMgr.affectsCharSourceRange(Range: CharSourceRange::getCharRange(
2907 B: AnnotatedLines[InitLine]->First->Tok.getLocation(),
2908 E: AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc()))) {
2909 return false;
2910 }
2911
2912 for (unsigned i = InitLine; i <= CurrentLine; ++i)
2913 DeletedLines.insert(x: i);
2914
2915 return true;
2916 }
2917
2918 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
2919 // of the token in the pair if the left token has \p LK token kind and the
2920 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
2921 // is deleted on match; otherwise, the right token is deleted.
2922 template <typename LeftKind, typename RightKind>
2923 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
2924 bool DeleteLeft) {
2925 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
2926 for (auto *Res = Tok.Next; Res; Res = Res->Next) {
2927 if (Res->isNot(Kind: tok::comment) &&
2928 DeletedTokens.find(x: Res) == DeletedTokens.end()) {
2929 return Res;
2930 }
2931 }
2932 return nullptr;
2933 };
2934 for (auto *Left = Start; Left;) {
2935 auto *Right = NextNotDeleted(*Left);
2936 if (!Right)
2937 break;
2938 if (Left->is(LK) && Right->is(RK)) {
2939 deleteToken(Tok: DeleteLeft ? Left : Right);
2940 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
2941 deleteToken(Tok);
2942 // If the right token is deleted, we should keep the left token
2943 // unchanged and pair it with the new right token.
2944 if (!DeleteLeft)
2945 continue;
2946 }
2947 Left = Right;
2948 }
2949 }
2950
2951 template <typename LeftKind, typename RightKind>
2952 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
2953 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
2954 }
2955
2956 template <typename LeftKind, typename RightKind>
2957 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
2958 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
2959 }
2960
2961 // Delete the given token.
2962 inline void deleteToken(FormatToken *Tok) {
2963 if (Tok)
2964 DeletedTokens.insert(x: Tok);
2965 }
2966
2967 tooling::Replacements generateFixes() {
2968 tooling::Replacements Fixes;
2969 SmallVector<FormatToken *> Tokens;
2970 std::copy(first: DeletedTokens.begin(), last: DeletedTokens.end(),
2971 result: std::back_inserter(x&: Tokens));
2972
2973 // Merge multiple continuous token deletions into one big deletion so that
2974 // the number of replacements can be reduced. This makes computing affected
2975 // ranges more efficient when we run reformat on the changed code.
2976 unsigned Idx = 0;
2977 while (Idx < Tokens.size()) {
2978 unsigned St = Idx, End = Idx;
2979 while ((End + 1) < Tokens.size() && Tokens[End]->Next == Tokens[End + 1])
2980 ++End;
2981 auto SR = CharSourceRange::getCharRange(B: Tokens[St]->Tok.getLocation(),
2982 E: Tokens[End]->Tok.getEndLoc());
2983 auto Err =
2984 Fixes.add(R: tooling::Replacement(Env.getSourceManager(), SR, ""));
2985 // FIXME: better error handling. for now just print error message and skip
2986 // for the release version.
2987 if (Err) {
2988 llvm::errs() << toString(E: std::move(Err)) << "\n";
2989 assert(false && "Fixes must not conflict!");
2990 }
2991 Idx = End + 1;
2992 }
2993
2994 return Fixes;
2995 }
2996
2997 // Class for less-than inequality comparason for the set `RedundantTokens`.
2998 // We store tokens in the order they appear in the translation unit so that
2999 // we do not need to sort them in `generateFixes()`.
3000 struct FormatTokenLess {
3001 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
3002
3003 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
3004 return SM.isBeforeInTranslationUnit(LHS: LHS->Tok.getLocation(),
3005 RHS: RHS->Tok.getLocation());
3006 }
3007 const SourceManager &SM;
3008 };
3009
3010 // Tokens to be deleted.
3011 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
3012};
3013
3014class ObjCHeaderStyleGuesser : public TokenAnalyzer {
3015public:
3016 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
3017 : TokenAnalyzer(Env, Style), IsObjC(false) {}
3018
3019 std::pair<tooling::Replacements, unsigned>
3020 analyze(TokenAnnotator &Annotator,
3021 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
3022 FormatTokenLexer &Tokens) override {
3023 assert(Style.Language == FormatStyle::LK_Cpp);
3024 IsObjC = guessIsObjC(SourceManager: Env.getSourceManager(), AnnotatedLines,
3025 Keywords: Tokens.getKeywords());
3026 tooling::Replacements Result;
3027 return {Result, 0};
3028 }
3029
3030 bool isObjC() { return IsObjC; }
3031
3032private:
3033 static bool
3034 guessIsObjC(const SourceManager &SourceManager,
3035 const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
3036 const AdditionalKeywords &Keywords) {
3037 // Keep this array sorted, since we are binary searching over it.
3038 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
3039 "CGFloat",
3040 "CGPoint",
3041 "CGPointMake",
3042 "CGPointZero",
3043 "CGRect",
3044 "CGRectEdge",
3045 "CGRectInfinite",
3046 "CGRectMake",
3047 "CGRectNull",
3048 "CGRectZero",
3049 "CGSize",
3050 "CGSizeMake",
3051 "CGVector",
3052 "CGVectorMake",
3053 "FOUNDATION_EXPORT", // This is an alias for FOUNDATION_EXTERN.
3054 "FOUNDATION_EXTERN",
3055 "NSAffineTransform",
3056 "NSArray",
3057 "NSAttributedString",
3058 "NSBlockOperation",
3059 "NSBundle",
3060 "NSCache",
3061 "NSCalendar",
3062 "NSCharacterSet",
3063 "NSCountedSet",
3064 "NSData",
3065 "NSDataDetector",
3066 "NSDecimal",
3067 "NSDecimalNumber",
3068 "NSDictionary",
3069 "NSEdgeInsets",
3070 "NSError",
3071 "NSErrorDomain",
3072 "NSHashTable",
3073 "NSIndexPath",
3074 "NSIndexSet",
3075 "NSInteger",
3076 "NSInvocationOperation",
3077 "NSLocale",
3078 "NSMapTable",
3079 "NSMutableArray",
3080 "NSMutableAttributedString",
3081 "NSMutableCharacterSet",
3082 "NSMutableData",
3083 "NSMutableDictionary",
3084 "NSMutableIndexSet",
3085 "NSMutableOrderedSet",
3086 "NSMutableSet",
3087 "NSMutableString",
3088 "NSNumber",
3089 "NSNumberFormatter",
3090 "NSObject",
3091 "NSOperation",
3092 "NSOperationQueue",
3093 "NSOperationQueuePriority",
3094 "NSOrderedSet",
3095 "NSPoint",
3096 "NSPointerArray",
3097 "NSQualityOfService",
3098 "NSRange",
3099 "NSRect",
3100 "NSRegularExpression",
3101 "NSSet",
3102 "NSSize",
3103 "NSString",
3104 "NSTimeZone",
3105 "NSUInteger",
3106 "NSURL",
3107 "NSURLComponents",
3108 "NSURLQueryItem",
3109 "NSUUID",
3110 "NSValue",
3111 "NS_ASSUME_NONNULL_BEGIN",
3112 "UIImage",
3113 "UIView",
3114 };
3115
3116 for (auto *Line : AnnotatedLines) {
3117 if (Line->First && (Line->First->TokenText.starts_with(Prefix: "#") ||
3118 Line->First->TokenText == "__pragma" ||
3119 Line->First->TokenText == "_Pragma")) {
3120 continue;
3121 }
3122 for (const FormatToken *FormatTok = Line->First; FormatTok;
3123 FormatTok = FormatTok->Next) {
3124 if ((FormatTok->Previous && FormatTok->Previous->is(Kind: tok::at) &&
3125 (FormatTok->isNot(Kind: tok::objc_not_keyword) ||
3126 FormatTok->isOneOf(K1: tok::numeric_constant, K2: tok::l_square,
3127 Ks: tok::l_brace))) ||
3128 (FormatTok->Tok.isAnyIdentifier() &&
3129 llvm::binary_search(Range: FoundationIdentifiers,
3130 Value: FormatTok->TokenText)) ||
3131 FormatTok->is(TT: TT_ObjCStringLiteral) ||
3132 FormatTok->isOneOf(K1: Keywords.kw_NS_CLOSED_ENUM, K2: Keywords.kw_NS_ENUM,
3133 Ks: Keywords.kw_NS_ERROR_ENUM,
3134 Ks: Keywords.kw_NS_OPTIONS, Ks: TT_ObjCBlockLBrace,
3135 Ks: TT_ObjCBlockLParen, Ks: TT_ObjCDecl, Ks: TT_ObjCForIn,
3136 Ks: TT_ObjCMethodExpr, Ks: TT_ObjCMethodSpecifier,
3137 Ks: TT_ObjCProperty)) {
3138 LLVM_DEBUG(llvm::dbgs()
3139 << "Detected ObjC at location "
3140 << FormatTok->Tok.getLocation().printToString(
3141 SourceManager)
3142 << " token: " << FormatTok->TokenText << " token type: "
3143 << getTokenTypeName(FormatTok->getType()) << "\n");
3144 return true;
3145 }
3146 }
3147 if (guessIsObjC(SourceManager, AnnotatedLines: Line->Children, Keywords))
3148 return true;
3149 }
3150 return false;
3151 }
3152
3153 bool IsObjC;
3154};
3155
3156struct IncludeDirective {
3157 StringRef Filename;
3158 StringRef Text;
3159 unsigned Offset;
3160 int Category;
3161 int Priority;
3162};
3163
3164struct JavaImportDirective {
3165 StringRef Identifier;
3166 StringRef Text;
3167 unsigned Offset;
3168 SmallVector<StringRef> AssociatedCommentLines;
3169 bool IsStatic;
3170};
3171
3172} // end anonymous namespace
3173
3174// Determines whether 'Ranges' intersects with ('Start', 'End').
3175static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
3176 unsigned End) {
3177 for (const auto &Range : Ranges) {
3178 if (Range.getOffset() < End &&
3179 Range.getOffset() + Range.getLength() > Start) {
3180 return true;
3181 }
3182 }
3183 return false;
3184}
3185
3186// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
3187// before sorting/deduplicating. Index is the index of the include under the
3188// cursor in the original set of includes. If this include has duplicates, it is
3189// the index of the first of the duplicates as the others are going to be
3190// removed. OffsetToEOL describes the cursor's position relative to the end of
3191// its current line.
3192// If `Cursor` is not on any #include, `Index` will be
3193// std::numeric_limits<unsigned>::max().
3194static std::pair<unsigned, unsigned>
3195FindCursorIndex(const ArrayRef<IncludeDirective> &Includes,
3196 const ArrayRef<unsigned> &Indices, unsigned Cursor) {
3197 unsigned CursorIndex = std::numeric_limits<unsigned>::max();
3198 unsigned OffsetToEOL = 0;
3199 for (int i = 0, e = Includes.size(); i != e; ++i) {
3200 unsigned Start = Includes[Indices[i]].Offset;
3201 unsigned End = Start + Includes[Indices[i]].Text.size();
3202 if (!(Cursor >= Start && Cursor < End))
3203 continue;
3204 CursorIndex = Indices[i];
3205 OffsetToEOL = End - Cursor;
3206 // Put the cursor on the only remaining #include among the duplicate
3207 // #includes.
3208 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
3209 CursorIndex = i;
3210 break;
3211 }
3212 return std::make_pair(x&: CursorIndex, y&: OffsetToEOL);
3213}
3214
3215// Replace all "\r\n" with "\n".
3216std::string replaceCRLF(const std::string &Code) {
3217 std::string NewCode;
3218 size_t Pos = 0, LastPos = 0;
3219
3220 do {
3221 Pos = Code.find(s: "\r\n", pos: LastPos);
3222 if (Pos == LastPos) {
3223 ++LastPos;
3224 continue;
3225 }
3226 if (Pos == std::string::npos) {
3227 NewCode += Code.substr(pos: LastPos);
3228 break;
3229 }
3230 NewCode += Code.substr(pos: LastPos, n: Pos - LastPos) + "\n";
3231 LastPos = Pos + 2;
3232 } while (Pos != std::string::npos);
3233
3234 return NewCode;
3235}
3236
3237// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
3238// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
3239// source order.
3240// #include directives with the same text will be deduplicated, and only the
3241// first #include in the duplicate #includes remains. If the `Cursor` is
3242// provided and put on a deleted #include, it will be moved to the remaining
3243// #include in the duplicate #includes.
3244static void sortCppIncludes(const FormatStyle &Style,
3245 const ArrayRef<IncludeDirective> &Includes,
3246 ArrayRef<tooling::Range> Ranges, StringRef FileName,
3247 StringRef Code, tooling::Replacements &Replaces,
3248 unsigned *Cursor) {
3249 tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName);
3250 const unsigned IncludesBeginOffset = Includes.front().Offset;
3251 const unsigned IncludesEndOffset =
3252 Includes.back().Offset + Includes.back().Text.size();
3253 const unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
3254 if (!affectsRange(Ranges, Start: IncludesBeginOffset, End: IncludesEndOffset))
3255 return;
3256 SmallVector<unsigned, 16> Indices =
3257 llvm::to_vector<16>(Range: llvm::seq<unsigned>(Begin: 0, End: Includes.size()));
3258
3259 if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) {
3260 stable_sort(Range&: Indices, C: [&](unsigned LHSI, unsigned RHSI) {
3261 const auto LHSFilenameLower = Includes[LHSI].Filename.lower();
3262 const auto RHSFilenameLower = Includes[RHSI].Filename.lower();
3263 return std::tie(args: Includes[LHSI].Priority, args: LHSFilenameLower,
3264 args: Includes[LHSI].Filename) <
3265 std::tie(args: Includes[RHSI].Priority, args: RHSFilenameLower,
3266 args: Includes[RHSI].Filename);
3267 });
3268 } else {
3269 stable_sort(Range&: Indices, C: [&](unsigned LHSI, unsigned RHSI) {
3270 return std::tie(args: Includes[LHSI].Priority, args: Includes[LHSI].Filename) <
3271 std::tie(args: Includes[RHSI].Priority, args: Includes[RHSI].Filename);
3272 });
3273 }
3274
3275 // The index of the include on which the cursor will be put after
3276 // sorting/deduplicating.
3277 unsigned CursorIndex;
3278 // The offset from cursor to the end of line.
3279 unsigned CursorToEOLOffset;
3280 if (Cursor) {
3281 std::tie(args&: CursorIndex, args&: CursorToEOLOffset) =
3282 FindCursorIndex(Includes, Indices, Cursor: *Cursor);
3283 }
3284
3285 // Deduplicate #includes.
3286 Indices.erase(CS: llvm::unique(R&: Indices,
3287 P: [&](unsigned LHSI, unsigned RHSI) {
3288 return Includes[LHSI].Text.trim() ==
3289 Includes[RHSI].Text.trim();
3290 }),
3291 CE: Indices.end());
3292
3293 int CurrentCategory = Includes.front().Category;
3294
3295 // If the #includes are out of order, we generate a single replacement fixing
3296 // the entire block. Otherwise, no replacement is generated.
3297 // In case Style.IncldueStyle.IncludeBlocks != IBS_Preserve, this check is not
3298 // enough as additional newlines might be added or removed across #include
3299 // blocks. This we handle below by generating the updated #include blocks and
3300 // comparing it to the original.
3301 if (Indices.size() == Includes.size() && is_sorted(Range&: Indices) &&
3302 Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Preserve) {
3303 return;
3304 }
3305
3306 const auto OldCursor = Cursor ? *Cursor : 0;
3307 std::string result;
3308 for (unsigned Index : Indices) {
3309 if (!result.empty()) {
3310 result += "\n";
3311 if (Style.IncludeStyle.IncludeBlocks ==
3312 tooling::IncludeStyle::IBS_Regroup &&
3313 CurrentCategory != Includes[Index].Category) {
3314 result += "\n";
3315 }
3316 }
3317 result += Includes[Index].Text;
3318 if (Cursor && CursorIndex == Index)
3319 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
3320 CurrentCategory = Includes[Index].Category;
3321 }
3322
3323 if (Cursor && *Cursor >= IncludesEndOffset)
3324 *Cursor += result.size() - IncludesBlockSize;
3325
3326 // If the #includes are out of order, we generate a single replacement fixing
3327 // the entire range of blocks. Otherwise, no replacement is generated.
3328 if (replaceCRLF(Code: result) == replaceCRLF(Code: std::string(Code.substr(
3329 Start: IncludesBeginOffset, N: IncludesBlockSize)))) {
3330 if (Cursor)
3331 *Cursor = OldCursor;
3332 return;
3333 }
3334
3335 auto Err = Replaces.add(R: tooling::Replacement(
3336 FileName, Includes.front().Offset, IncludesBlockSize, result));
3337 // FIXME: better error handling. For now, just skip the replacement for the
3338 // release version.
3339 if (Err) {
3340 llvm::errs() << toString(E: std::move(Err)) << "\n";
3341 assert(false);
3342 }
3343}
3344
3345tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
3346 ArrayRef<tooling::Range> Ranges,
3347 StringRef FileName,
3348 tooling::Replacements &Replaces,
3349 unsigned *Cursor) {
3350 unsigned Prev = llvm::StringSwitch<size_t>(Code)
3351 .StartsWith(S: "\xEF\xBB\xBF", Value: 3) // UTF-8 BOM
3352 .Default(Value: 0);
3353 unsigned SearchFrom = 0;
3354 SmallVector<StringRef, 4> Matches;
3355 SmallVector<IncludeDirective, 16> IncludesInBlock;
3356
3357 // In compiled files, consider the first #include to be the main #include of
3358 // the file if it is not a system #include. This ensures that the header
3359 // doesn't have hidden dependencies
3360 // (http://llvm.org/docs/CodingStandards.html#include-style).
3361 //
3362 // FIXME: Do some validation, e.g. edit distance of the base name, to fix
3363 // cases where the first #include is unlikely to be the main header.
3364 tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName);
3365 bool FirstIncludeBlock = true;
3366 bool MainIncludeFound = false;
3367 bool FormattingOff = false;
3368
3369 // '[' must be the first and '-' the last character inside [...].
3370 llvm::Regex RawStringRegex(
3371 "R\"([][A-Za-z0-9_{}#<>%:;.?*+/^&\\$|~!=,'-]*)\\(");
3372 SmallVector<StringRef, 2> RawStringMatches;
3373 std::string RawStringTermination = ")\"";
3374
3375 for (const auto Size = Code.size(); SearchFrom < Size;) {
3376 size_t Pos = SearchFrom;
3377 if (Code[SearchFrom] != '\n') {
3378 do { // Search for the first newline while skipping line splices.
3379 ++Pos;
3380 Pos = Code.find(C: '\n', From: Pos);
3381 } while (Pos != StringRef::npos && Code[Pos - 1] == '\\');
3382 }
3383
3384 StringRef Line =
3385 Code.substr(Start: Prev, N: (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
3386
3387 StringRef Trimmed = Line.trim();
3388
3389 // #includes inside raw string literals need to be ignored.
3390 // or we will sort the contents of the string.
3391 // Skip past until we think we are at the rawstring literal close.
3392 if (RawStringRegex.match(String: Trimmed, Matches: &RawStringMatches)) {
3393 std::string CharSequence = RawStringMatches[1].str();
3394 RawStringTermination = ")" + CharSequence + "\"";
3395 FormattingOff = true;
3396 }
3397
3398 if (Trimmed.contains(Other: RawStringTermination))
3399 FormattingOff = false;
3400
3401 bool IsBlockComment = false;
3402
3403 if (isClangFormatOff(Comment: Trimmed)) {
3404 FormattingOff = true;
3405 } else if (isClangFormatOn(Comment: Trimmed)) {
3406 FormattingOff = false;
3407 } else if (Trimmed.starts_with(Prefix: "/*")) {
3408 IsBlockComment = true;
3409 Pos = Code.find(Str: "*/", From: SearchFrom + 2);
3410 }
3411
3412 const bool EmptyLineSkipped =
3413 Trimmed.empty() &&
3414 (Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Merge ||
3415 Style.IncludeStyle.IncludeBlocks ==
3416 tooling::IncludeStyle::IBS_Regroup);
3417
3418 bool MergeWithNextLine = Trimmed.ends_with(Suffix: "\\");
3419 if (!FormattingOff && !MergeWithNextLine) {
3420 if (!IsBlockComment &&
3421 tooling::HeaderIncludes::IncludeRegex.match(String: Trimmed, Matches: &Matches)) {
3422 StringRef IncludeName = Matches[2];
3423 if (Trimmed.contains(Other: "/*") && !Trimmed.contains(Other: "*/")) {
3424 // #include with a start of a block comment, but without the end.
3425 // Need to keep all the lines until the end of the comment together.
3426 // FIXME: This is somehow simplified check that probably does not work
3427 // correctly if there are multiple comments on a line.
3428 Pos = Code.find(Str: "*/", From: SearchFrom);
3429 Line = Code.substr(
3430 Start: Prev, N: (Pos != StringRef::npos ? Pos + 2 : Code.size()) - Prev);
3431 }
3432 int Category = Categories.getIncludePriority(
3433 IncludeName,
3434 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
3435 int Priority = Categories.getSortIncludePriority(
3436 IncludeName, CheckMainHeader: !MainIncludeFound && FirstIncludeBlock);
3437 if (Category == 0)
3438 MainIncludeFound = true;
3439 IncludesInBlock.push_back(
3440 Elt: {.Filename: IncludeName, .Text: Line, .Offset: Prev, .Category: Category, .Priority: Priority});
3441 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
3442 sortCppIncludes(Style, Includes: IncludesInBlock, Ranges, FileName, Code,
3443 Replaces, Cursor);
3444 IncludesInBlock.clear();
3445 if (Trimmed.starts_with(Prefix: "#pragma hdrstop")) // Precompiled headers.
3446 FirstIncludeBlock = true;
3447 else
3448 FirstIncludeBlock = false;
3449 }
3450 }
3451 if (Pos == StringRef::npos || Pos + 1 == Code.size())
3452 break;
3453
3454 if (!MergeWithNextLine)
3455 Prev = Pos + 1;
3456 SearchFrom = Pos + 1;
3457 }
3458 if (!IncludesInBlock.empty()) {
3459 sortCppIncludes(Style, Includes: IncludesInBlock, Ranges, FileName, Code, Replaces,
3460 Cursor);
3461 }
3462 return Replaces;
3463}
3464
3465// Returns group number to use as a first order sort on imports. Gives
3466// std::numeric_limits<unsigned>::max() if the import does not match any given
3467// groups.
3468static unsigned findJavaImportGroup(const FormatStyle &Style,
3469 StringRef ImportIdentifier) {
3470 unsigned LongestMatchIndex = std::numeric_limits<unsigned>::max();
3471 unsigned LongestMatchLength = 0;
3472 for (unsigned I = 0; I < Style.JavaImportGroups.size(); I++) {
3473 const std::string &GroupPrefix = Style.JavaImportGroups[I];
3474 if (ImportIdentifier.starts_with(Prefix: GroupPrefix) &&
3475 GroupPrefix.length() > LongestMatchLength) {
3476 LongestMatchIndex = I;
3477 LongestMatchLength = GroupPrefix.length();
3478 }
3479 }
3480 return LongestMatchIndex;
3481}
3482
3483// Sorts and deduplicates a block of includes given by 'Imports' based on
3484// JavaImportGroups, then adding the necessary replacement to 'Replaces'.
3485// Import declarations with the same text will be deduplicated. Between each
3486// import group, a newline is inserted, and within each import group, a
3487// lexicographic sort based on ASCII value is performed.
3488static void sortJavaImports(const FormatStyle &Style,
3489 const ArrayRef<JavaImportDirective> &Imports,
3490 ArrayRef<tooling::Range> Ranges, StringRef FileName,
3491 StringRef Code, tooling::Replacements &Replaces) {
3492 unsigned ImportsBeginOffset = Imports.front().Offset;
3493 unsigned ImportsEndOffset =
3494 Imports.back().Offset + Imports.back().Text.size();
3495 unsigned ImportsBlockSize = ImportsEndOffset - ImportsBeginOffset;
3496 if (!affectsRange(Ranges, Start: ImportsBeginOffset, End: ImportsEndOffset))
3497 return;
3498
3499 SmallVector<unsigned, 16> Indices =
3500 llvm::to_vector<16>(Range: llvm::seq<unsigned>(Begin: 0, End: Imports.size()));
3501 SmallVector<unsigned, 16> JavaImportGroups;
3502 JavaImportGroups.reserve(N: Imports.size());
3503 for (const JavaImportDirective &Import : Imports)
3504 JavaImportGroups.push_back(Elt: findJavaImportGroup(Style, ImportIdentifier: Import.Identifier));
3505
3506 bool StaticImportAfterNormalImport =
3507 Style.SortJavaStaticImport == FormatStyle::SJSIO_After;
3508 sort(C&: Indices, Comp: [&](unsigned LHSI, unsigned RHSI) {
3509 // Negating IsStatic to push static imports above non-static imports.
3510 return std::make_tuple(args: !Imports[LHSI].IsStatic ^
3511 StaticImportAfterNormalImport,
3512 args&: JavaImportGroups[LHSI], args: Imports[LHSI].Identifier) <
3513 std::make_tuple(args: !Imports[RHSI].IsStatic ^
3514 StaticImportAfterNormalImport,
3515 args&: JavaImportGroups[RHSI], args: Imports[RHSI].Identifier);
3516 });
3517
3518 // Deduplicate imports.
3519 Indices.erase(CS: llvm::unique(R&: Indices,
3520 P: [&](unsigned LHSI, unsigned RHSI) {
3521 return Imports[LHSI].Text == Imports[RHSI].Text;
3522 }),
3523 CE: Indices.end());
3524
3525 bool CurrentIsStatic = Imports[Indices.front()].IsStatic;
3526 unsigned CurrentImportGroup = JavaImportGroups[Indices.front()];
3527
3528 std::string result;
3529 for (unsigned Index : Indices) {
3530 if (!result.empty()) {
3531 result += "\n";
3532 if (CurrentIsStatic != Imports[Index].IsStatic ||
3533 CurrentImportGroup != JavaImportGroups[Index]) {
3534 result += "\n";
3535 }
3536 }
3537 for (StringRef CommentLine : Imports[Index].AssociatedCommentLines) {
3538 result += CommentLine;
3539 result += "\n";
3540 }
3541 result += Imports[Index].Text;
3542 CurrentIsStatic = Imports[Index].IsStatic;
3543 CurrentImportGroup = JavaImportGroups[Index];
3544 }
3545
3546 // If the imports are out of order, we generate a single replacement fixing
3547 // the entire block. Otherwise, no replacement is generated.
3548 if (replaceCRLF(Code: result) == replaceCRLF(Code: std::string(Code.substr(
3549 Start: Imports.front().Offset, N: ImportsBlockSize)))) {
3550 return;
3551 }
3552
3553 auto Err = Replaces.add(R: tooling::Replacement(FileName, Imports.front().Offset,
3554 ImportsBlockSize, result));
3555 // FIXME: better error handling. For now, just skip the replacement for the
3556 // release version.
3557 if (Err) {
3558 llvm::errs() << toString(E: std::move(Err)) << "\n";
3559 assert(false);
3560 }
3561}
3562
3563namespace {
3564
3565const char JavaImportRegexPattern[] =
3566 "^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
3567
3568} // anonymous namespace
3569
3570tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
3571 ArrayRef<tooling::Range> Ranges,
3572 StringRef FileName,
3573 tooling::Replacements &Replaces) {
3574 unsigned Prev = 0;
3575 unsigned SearchFrom = 0;
3576 llvm::Regex ImportRegex(JavaImportRegexPattern);
3577 SmallVector<StringRef, 4> Matches;
3578 SmallVector<JavaImportDirective, 16> ImportsInBlock;
3579 SmallVector<StringRef> AssociatedCommentLines;
3580
3581 bool FormattingOff = false;
3582
3583 for (;;) {
3584 auto Pos = Code.find(C: '\n', From: SearchFrom);
3585 StringRef Line =
3586 Code.substr(Start: Prev, N: (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
3587
3588 StringRef Trimmed = Line.trim();
3589 if (isClangFormatOff(Comment: Trimmed))
3590 FormattingOff = true;
3591 else if (isClangFormatOn(Comment: Trimmed))
3592 FormattingOff = false;
3593
3594 if (ImportRegex.match(String: Line, Matches: &Matches)) {
3595 if (FormattingOff) {
3596 // If at least one import line has formatting turned off, turn off
3597 // formatting entirely.
3598 return Replaces;
3599 }
3600 StringRef Static = Matches[1];
3601 StringRef Identifier = Matches[2];
3602 bool IsStatic = false;
3603 if (Static.contains(Other: "static"))
3604 IsStatic = true;
3605 ImportsInBlock.push_back(
3606 Elt: {.Identifier: Identifier, .Text: Line, .Offset: Prev, .AssociatedCommentLines: AssociatedCommentLines, .IsStatic: IsStatic});
3607 AssociatedCommentLines.clear();
3608 } else if (!Trimmed.empty() && !ImportsInBlock.empty()) {
3609 // Associating comments within the imports with the nearest import below
3610 AssociatedCommentLines.push_back(Elt: Line);
3611 }
3612 Prev = Pos + 1;
3613 if (Pos == StringRef::npos || Pos + 1 == Code.size())
3614 break;
3615 SearchFrom = Pos + 1;
3616 }
3617 if (!ImportsInBlock.empty())
3618 sortJavaImports(Style, Imports: ImportsInBlock, Ranges, FileName, Code, Replaces);
3619 return Replaces;
3620}
3621
3622bool isMpegTS(StringRef Code) {
3623 // MPEG transport streams use the ".ts" file extension. clang-format should
3624 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
3625 // 189 bytes - detect that and return.
3626 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
3627}
3628
3629bool isLikelyXml(StringRef Code) { return Code.ltrim().starts_with(Prefix: "<"); }
3630
3631tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
3632 ArrayRef<tooling::Range> Ranges,
3633 StringRef FileName, unsigned *Cursor) {
3634 tooling::Replacements Replaces;
3635 if (!Style.SortIncludes.Enabled || Style.DisableFormat)
3636 return Replaces;
3637 if (isLikelyXml(Code))
3638 return Replaces;
3639 if (Style.isJavaScript()) {
3640 if (isMpegTS(Code))
3641 return Replaces;
3642 return sortJavaScriptImports(Style, Code, Ranges, FileName);
3643 }
3644 if (Style.isJava())
3645 return sortJavaImports(Style, Code, Ranges, FileName, Replaces);
3646 if (Style.isCpp())
3647 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
3648 return Replaces;
3649}
3650
3651template <typename T>
3652static Expected<tooling::Replacements>
3653processReplacements(T ProcessFunc, StringRef Code,
3654 const tooling::Replacements &Replaces,
3655 const FormatStyle &Style) {
3656 if (Replaces.empty())
3657 return tooling::Replacements();
3658
3659 auto NewCode = applyAllReplacements(Code, Replaces);
3660 if (!NewCode)
3661 return NewCode.takeError();
3662 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
3663 StringRef FileName = Replaces.begin()->getFilePath();
3664
3665 tooling::Replacements FormatReplaces =
3666 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
3667
3668 return Replaces.merge(Replaces: FormatReplaces);
3669}
3670
3671Expected<tooling::Replacements>
3672formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
3673 const FormatStyle &Style) {
3674 // We need to use lambda function here since there are two versions of
3675 // `sortIncludes`.
3676 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
3677 std::vector<tooling::Range> Ranges,
3678 StringRef FileName) -> tooling::Replacements {
3679 return sortIncludes(Style, Code, Ranges, FileName);
3680 };
3681 auto SortedReplaces =
3682 processReplacements(ProcessFunc: SortIncludes, Code, Replaces, Style);
3683 if (!SortedReplaces)
3684 return SortedReplaces.takeError();
3685
3686 // We need to use lambda function here since there are two versions of
3687 // `reformat`.
3688 auto Reformat = [](const FormatStyle &Style, StringRef Code,
3689 std::vector<tooling::Range> Ranges,
3690 StringRef FileName) -> tooling::Replacements {
3691 return reformat(Style, Code, Ranges, FileName);
3692 };
3693 return processReplacements(ProcessFunc: Reformat, Code, Replaces: *SortedReplaces, Style);
3694}
3695
3696namespace {
3697
3698inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
3699 return Replace.getOffset() == std::numeric_limits<unsigned>::max() &&
3700 Replace.getLength() == 0 &&
3701 tooling::HeaderIncludes::IncludeRegex.match(
3702 String: Replace.getReplacementText());
3703}
3704
3705inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
3706 return Replace.getOffset() == std::numeric_limits<unsigned>::max() &&
3707 Replace.getLength() == 1;
3708}
3709
3710// FIXME: insert empty lines between newly created blocks.
3711tooling::Replacements
3712fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
3713 const FormatStyle &Style) {
3714 if (!Style.isCpp())
3715 return Replaces;
3716
3717 tooling::Replacements HeaderInsertions;
3718 std::set<StringRef> HeadersToDelete;
3719 tooling::Replacements Result;
3720 for (const auto &R : Replaces) {
3721 if (isHeaderInsertion(Replace: R)) {
3722 // Replacements from \p Replaces must be conflict-free already, so we can
3723 // simply consume the error.
3724 consumeError(Err: HeaderInsertions.add(R));
3725 } else if (isHeaderDeletion(Replace: R)) {
3726 HeadersToDelete.insert(x: R.getReplacementText());
3727 } else if (R.getOffset() == std::numeric_limits<unsigned>::max()) {
3728 llvm::errs() << "Insertions other than header #include insertion are "
3729 "not supported! "
3730 << R.getReplacementText() << "\n";
3731 } else {
3732 consumeError(Err: Result.add(R));
3733 }
3734 }
3735 if (HeaderInsertions.empty() && HeadersToDelete.empty())
3736 return Replaces;
3737
3738 StringRef FileName = Replaces.begin()->getFilePath();
3739 tooling::HeaderIncludes Includes(FileName, Code, Style.IncludeStyle);
3740
3741 for (const auto &Header : HeadersToDelete) {
3742 tooling::Replacements Replaces =
3743 Includes.remove(Header: Header.trim(Chars: "\"<>"), IsAngled: Header.starts_with(Prefix: "<"));
3744 for (const auto &R : Replaces) {
3745 auto Err = Result.add(R);
3746 if (Err) {
3747 // Ignore the deletion on conflict.
3748 llvm::errs() << "Failed to add header deletion replacement for "
3749 << Header << ": " << toString(E: std::move(Err)) << "\n";
3750 }
3751 }
3752 }
3753
3754 SmallVector<StringRef, 4> Matches;
3755 for (const auto &R : HeaderInsertions) {
3756 auto IncludeDirective = R.getReplacementText();
3757 bool Matched =
3758 tooling::HeaderIncludes::IncludeRegex.match(String: IncludeDirective, Matches: &Matches);
3759 assert(Matched && "Header insertion replacement must have replacement text "
3760 "'#include ...'");
3761 (void)Matched;
3762 auto IncludeName = Matches[2];
3763 auto Replace =
3764 Includes.insert(Header: IncludeName.trim(Chars: "\"<>"), IsAngled: IncludeName.starts_with(Prefix: "<"),
3765 Directive: tooling::IncludeDirective::Include);
3766 if (Replace) {
3767 auto Err = Result.add(R: *Replace);
3768 if (Err) {
3769 consumeError(Err: std::move(Err));
3770 unsigned NewOffset =
3771 Result.getShiftedCodePosition(Position: Replace->getOffset());
3772 auto Shifted = tooling::Replacement(FileName, NewOffset, 0,
3773 Replace->getReplacementText());
3774 Result = Result.merge(Replaces: tooling::Replacements(Shifted));
3775 }
3776 }
3777 }
3778 return Result;
3779}
3780
3781} // anonymous namespace
3782
3783Expected<tooling::Replacements>
3784cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
3785 const FormatStyle &Style) {
3786 // We need to use lambda function here since there are two versions of
3787 // `cleanup`.
3788 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
3789 ArrayRef<tooling::Range> Ranges,
3790 StringRef FileName) -> tooling::Replacements {
3791 return cleanup(Style, Code, Ranges, FileName);
3792 };
3793 // Make header insertion replacements insert new headers into correct blocks.
3794 tooling::Replacements NewReplaces =
3795 fixCppIncludeInsertions(Code, Replaces, Style);
3796 return cantFail(ValOrErr: processReplacements(ProcessFunc: Cleanup, Code, Replaces: NewReplaces, Style));
3797}
3798
3799namespace internal {
3800std::pair<tooling::Replacements, unsigned>
3801reformat(const FormatStyle &Style, StringRef Code,
3802 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
3803 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
3804 FormattingAttemptStatus *Status) {
3805 FormatStyle Expanded = Style;
3806 expandPresetsBraceWrapping(Expanded);
3807 expandPresetsSpaceBeforeParens(Expanded);
3808 expandPresetsSpacesInParens(Expanded);
3809 Expanded.InsertBraces = false;
3810 Expanded.RemoveBracesLLVM = false;
3811 Expanded.RemoveParentheses = FormatStyle::RPS_Leave;
3812 Expanded.RemoveSemicolon = false;
3813 switch (Expanded.RequiresClausePosition) {
3814 case FormatStyle::RCPS_SingleLine:
3815 case FormatStyle::RCPS_WithPreceding:
3816 Expanded.IndentRequiresClause = false;
3817 break;
3818 default:
3819 break;
3820 }
3821
3822 if (Expanded.DisableFormat)
3823 return {tooling::Replacements(), 0};
3824 if (isLikelyXml(Code))
3825 return {tooling::Replacements(), 0};
3826 if (Expanded.isJavaScript() && isMpegTS(Code))
3827 return {tooling::Replacements(), 0};
3828
3829 // JSON only needs the formatting passing.
3830 if (Style.isJson()) {
3831 std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
3832 auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn,
3833 NextStartColumn, LastStartColumn);
3834 if (!Env)
3835 return {};
3836 // Perform the actual formatting pass.
3837 tooling::Replacements Replaces =
3838 Formatter(*Env, Style, Status).process().first;
3839 // add a replacement to remove the "x = " from the result.
3840 if (Code.starts_with(Prefix: "x = ")) {
3841 Replaces = Replaces.merge(
3842 Replaces: tooling::Replacements(tooling::Replacement(FileName, 0, 4, "")));
3843 }
3844 // apply the reformatting changes and the removal of "x = ".
3845 if (applyAllReplacements(Code, Replaces))
3846 return {Replaces, 0};
3847 return {tooling::Replacements(), 0};
3848 }
3849
3850 auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn,
3851 NextStartColumn, LastStartColumn);
3852 if (!Env)
3853 return {};
3854
3855 typedef std::function<std::pair<tooling::Replacements, unsigned>(
3856 const Environment &)>
3857 AnalyzerPass;
3858
3859 SmallVector<AnalyzerPass, 16> Passes;
3860
3861 Passes.emplace_back(Args: [&](const Environment &Env) {
3862 return IntegerLiteralSeparatorFixer().process(Env, Style: Expanded);
3863 });
3864
3865 if (Style.isCpp()) {
3866 if (Style.QualifierAlignment != FormatStyle::QAS_Leave)
3867 addQualifierAlignmentFixerPasses(Style: Expanded, Passes);
3868
3869 if (Style.RemoveParentheses != FormatStyle::RPS_Leave) {
3870 FormatStyle S = Expanded;
3871 S.RemoveParentheses = Style.RemoveParentheses;
3872 Passes.emplace_back(Args: [&, S = std::move(S)](const Environment &Env) {
3873 return ParensRemover(Env, S).process(/*SkipAnnotation=*/true);
3874 });
3875 }
3876
3877 if (Style.InsertBraces) {
3878 FormatStyle S = Expanded;
3879 S.InsertBraces = true;
3880 Passes.emplace_back(Args: [&, S = std::move(S)](const Environment &Env) {
3881 return BracesInserter(Env, S).process(/*SkipAnnotation=*/true);
3882 });
3883 }
3884
3885 if (Style.RemoveBracesLLVM) {
3886 FormatStyle S = Expanded;
3887 S.RemoveBracesLLVM = true;
3888 Passes.emplace_back(Args: [&, S = std::move(S)](const Environment &Env) {
3889 return BracesRemover(Env, S).process(/*SkipAnnotation=*/true);
3890 });
3891 }
3892
3893 if (Style.RemoveSemicolon) {
3894 FormatStyle S = Expanded;
3895 S.RemoveSemicolon = true;
3896 Passes.emplace_back(Args: [&, S = std::move(S)](const Environment &Env) {
3897 return SemiRemover(Env, S).process();
3898 });
3899 }
3900
3901 if (Style.EnumTrailingComma != FormatStyle::ETC_Leave) {
3902 Passes.emplace_back(Args: [&](const Environment &Env) {
3903 return EnumTrailingCommaEditor(Env, Expanded)
3904 .process(/*SkipAnnotation=*/true);
3905 });
3906 }
3907
3908 if (Style.FixNamespaceComments) {
3909 Passes.emplace_back(Args: [&](const Environment &Env) {
3910 return NamespaceEndCommentsFixer(Env, Expanded).process();
3911 });
3912 }
3913
3914 if (Style.SortUsingDeclarations != FormatStyle::SUD_Never) {
3915 Passes.emplace_back(Args: [&](const Environment &Env) {
3916 return UsingDeclarationsSorter(Env, Expanded).process();
3917 });
3918 }
3919 }
3920
3921 if (Style.SeparateDefinitionBlocks != FormatStyle::SDS_Leave) {
3922 Passes.emplace_back(Args: [&](const Environment &Env) {
3923 return DefinitionBlockSeparator(Env, Expanded).process();
3924 });
3925 }
3926
3927 if (Style.Language == FormatStyle::LK_ObjC &&
3928 !Style.ObjCPropertyAttributeOrder.empty()) {
3929 Passes.emplace_back(Args: [&](const Environment &Env) {
3930 return ObjCPropertyAttributeOrderFixer(Env, Expanded).process();
3931 });
3932 }
3933
3934 if (Style.isJavaScript() &&
3935 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
3936 Passes.emplace_back(Args: [&](const Environment &Env) {
3937 return JavaScriptRequoter(Env, Expanded).process(/*SkipAnnotation=*/true);
3938 });
3939 }
3940
3941 Passes.emplace_back(Args: [&](const Environment &Env) {
3942 return Formatter(Env, Expanded, Status).process();
3943 });
3944
3945 if (Style.isJavaScript() &&
3946 Style.InsertTrailingCommas == FormatStyle::TCS_Wrapped) {
3947 Passes.emplace_back(Args: [&](const Environment &Env) {
3948 return TrailingCommaInserter(Env, Expanded).process();
3949 });
3950 }
3951
3952 std::optional<std::string> CurrentCode;
3953 tooling::Replacements Fixes;
3954 unsigned Penalty = 0;
3955 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
3956 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
3957 auto NewCode = applyAllReplacements(
3958 Code: CurrentCode ? StringRef(*CurrentCode) : Code, Replaces: PassFixes.first);
3959 if (NewCode) {
3960 Fixes = Fixes.merge(Replaces: PassFixes.first);
3961 Penalty += PassFixes.second;
3962 if (I + 1 < E) {
3963 CurrentCode = std::move(*NewCode);
3964 Env = Environment::make(
3965 Code: *CurrentCode, FileName,
3966 Ranges: tooling::calculateRangesAfterReplacements(Replaces: Fixes, Ranges),
3967 FirstStartColumn, NextStartColumn, LastStartColumn);
3968 if (!Env)
3969 return {};
3970 }
3971 }
3972 }
3973
3974 if (Style.QualifierAlignment != FormatStyle::QAS_Leave) {
3975 // Don't make replacements that replace nothing. QualifierAlignment can
3976 // produce them if one of its early passes changes e.g. `const volatile` to
3977 // `volatile const` and then a later pass changes it back again.
3978 tooling::Replacements NonNoOpFixes;
3979 for (const tooling::Replacement &Fix : Fixes) {
3980 StringRef OriginalCode = Code.substr(Start: Fix.getOffset(), N: Fix.getLength());
3981 if (OriginalCode != Fix.getReplacementText()) {
3982 auto Err = NonNoOpFixes.add(R: Fix);
3983 if (Err) {
3984 llvm::errs() << "Error adding replacements : "
3985 << toString(E: std::move(Err)) << "\n";
3986 }
3987 }
3988 }
3989 Fixes = std::move(NonNoOpFixes);
3990 }
3991
3992 return {Fixes, Penalty};
3993}
3994} // namespace internal
3995
3996tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
3997 ArrayRef<tooling::Range> Ranges,
3998 StringRef FileName,
3999 FormattingAttemptStatus *Status) {
4000 return internal::reformat(Style, Code, Ranges,
4001 /*FirstStartColumn=*/0,
4002 /*NextStartColumn=*/0,
4003 /*LastStartColumn=*/0, FileName, Status)
4004 .first;
4005}
4006
4007tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
4008 ArrayRef<tooling::Range> Ranges,
4009 StringRef FileName) {
4010 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
4011 if (Style.Language != FormatStyle::LK_Cpp)
4012 return tooling::Replacements();
4013 auto Env = Environment::make(Code, FileName, Ranges);
4014 if (!Env)
4015 return {};
4016 return Cleaner(*Env, Style).process().first;
4017}
4018
4019tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
4020 ArrayRef<tooling::Range> Ranges,
4021 StringRef FileName, bool *IncompleteFormat) {
4022 FormattingAttemptStatus Status;
4023 auto Result = reformat(Style, Code, Ranges, FileName, Status: &Status);
4024 if (!Status.FormatComplete)
4025 *IncompleteFormat = true;
4026 return Result;
4027}
4028
4029tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
4030 StringRef Code,
4031 ArrayRef<tooling::Range> Ranges,
4032 StringRef FileName) {
4033 auto Env = Environment::make(Code, FileName, Ranges);
4034 if (!Env)
4035 return {};
4036 return NamespaceEndCommentsFixer(*Env, Style).process().first;
4037}
4038
4039tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
4040 StringRef Code,
4041 ArrayRef<tooling::Range> Ranges,
4042 StringRef FileName) {
4043 auto Env = Environment::make(Code, FileName, Ranges);
4044 if (!Env)
4045 return {};
4046 return UsingDeclarationsSorter(*Env, Style).process().first;
4047}
4048
4049LangOptions getFormattingLangOpts(const FormatStyle &Style) {
4050 LangOptions LangOpts;
4051
4052 auto LexingStd = Style.Standard;
4053 if (LexingStd == FormatStyle::LS_Auto || LexingStd == FormatStyle::LS_Latest)
4054 LexingStd = FormatStyle::LS_Cpp20;
4055
4056 const bool SinceCpp11 = LexingStd >= FormatStyle::LS_Cpp11;
4057 const bool SinceCpp20 = LexingStd >= FormatStyle::LS_Cpp20;
4058
4059 switch (Style.Language) {
4060 case FormatStyle::LK_C:
4061 LangOpts.C11 = 1;
4062 LangOpts.C23 = 1;
4063 break;
4064 case FormatStyle::LK_Cpp:
4065 case FormatStyle::LK_ObjC:
4066 LangOpts.CXXOperatorNames = 1;
4067 LangOpts.CPlusPlus11 = SinceCpp11;
4068 LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp14;
4069 LangOpts.CPlusPlus17 = LexingStd >= FormatStyle::LS_Cpp17;
4070 LangOpts.CPlusPlus20 = SinceCpp20;
4071 [[fallthrough]];
4072 default:
4073 LangOpts.CPlusPlus = 1;
4074 }
4075
4076 LangOpts.Char8 = SinceCpp20;
4077 // Turning on digraphs in standards before C++0x is error-prone, because e.g.
4078 // the sequence "<::" will be unconditionally treated as "[:".
4079 // Cf. Lexer::LexTokenInternal.
4080 LangOpts.Digraphs = SinceCpp11;
4081
4082 LangOpts.LineComment = 1;
4083 LangOpts.Bool = 1;
4084 LangOpts.ObjC = 1;
4085 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
4086 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
4087 LangOpts.C99 = 1; // To get kw_restrict for non-underscore-prefixed restrict.
4088
4089 return LangOpts;
4090}
4091
4092const char *StyleOptionHelpDescription =
4093 "Set coding style. <string> can be:\n"
4094 "1. A preset: LLVM, GNU, Google, Chromium, Microsoft,\n"
4095 " Mozilla, WebKit.\n"
4096 "2. 'file' to load style configuration from a\n"
4097 " .clang-format file in one of the parent directories\n"
4098 " of the source file (for stdin, see --assume-filename).\n"
4099 " If no .clang-format file is found, falls back to\n"
4100 " --fallback-style.\n"
4101 " --style=file is the default.\n"
4102 "3. 'file:<format_file_path>' to explicitly specify\n"
4103 " the configuration file.\n"
4104 "4. \"{key: value, ...}\" to set specific parameters, e.g.:\n"
4105 " --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
4106
4107static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
4108 if (FileName.ends_with(Suffix: ".c"))
4109 return FormatStyle::LK_C;
4110 if (FileName.ends_with(Suffix: ".java"))
4111 return FormatStyle::LK_Java;
4112 if (FileName.ends_with_insensitive(Suffix: ".js") ||
4113 FileName.ends_with_insensitive(Suffix: ".mjs") ||
4114 FileName.ends_with_insensitive(Suffix: ".cjs") ||
4115 FileName.ends_with_insensitive(Suffix: ".ts")) {
4116 return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript.
4117 }
4118 if (FileName.ends_with(Suffix: ".m") || FileName.ends_with(Suffix: ".mm"))
4119 return FormatStyle::LK_ObjC;
4120 if (FileName.ends_with_insensitive(Suffix: ".proto") ||
4121 FileName.ends_with_insensitive(Suffix: ".protodevel")) {
4122 return FormatStyle::LK_Proto;
4123 }
4124 // txtpb is the canonical extension, and textproto is the legacy canonical
4125 // extension
4126 // https://protobuf.dev/reference/protobuf/textformat-spec/#text-format-files
4127 if (FileName.ends_with_insensitive(Suffix: ".txtpb") ||
4128 FileName.ends_with_insensitive(Suffix: ".textpb") ||
4129 FileName.ends_with_insensitive(Suffix: ".pb.txt") ||
4130 FileName.ends_with_insensitive(Suffix: ".textproto") ||
4131 FileName.ends_with_insensitive(Suffix: ".asciipb")) {
4132 return FormatStyle::LK_TextProto;
4133 }
4134 if (FileName.ends_with_insensitive(Suffix: ".td"))
4135 return FormatStyle::LK_TableGen;
4136 if (FileName.ends_with_insensitive(Suffix: ".cs"))
4137 return FormatStyle::LK_CSharp;
4138 if (FileName.ends_with_insensitive(Suffix: ".json") ||
4139 FileName.ends_with_insensitive(Suffix: ".ipynb")) {
4140 return FormatStyle::LK_Json;
4141 }
4142 if (FileName.ends_with_insensitive(Suffix: ".sv") ||
4143 FileName.ends_with_insensitive(Suffix: ".svh") ||
4144 FileName.ends_with_insensitive(Suffix: ".v") ||
4145 FileName.ends_with_insensitive(Suffix: ".vh")) {
4146 return FormatStyle::LK_Verilog;
4147 }
4148 return FormatStyle::LK_Cpp;
4149}
4150
4151static FormatStyle::LanguageKind getLanguageByComment(const Environment &Env) {
4152 const auto ID = Env.getFileID();
4153 const auto &SourceMgr = Env.getSourceManager();
4154
4155 LangOptions LangOpts;
4156 LangOpts.CPlusPlus = 1;
4157 LangOpts.LineComment = 1;
4158
4159 Lexer Lex(ID, SourceMgr.getBufferOrFake(FID: ID), SourceMgr, LangOpts);
4160 Lex.SetCommentRetentionState(true);
4161
4162 for (Token Tok; !Lex.LexFromRawLexer(Result&: Tok) && Tok.is(K: tok::comment);) {
4163 auto Text = StringRef(SourceMgr.getCharacterData(SL: Tok.getLocation()),
4164 Tok.getLength());
4165 if (!Text.consume_front(Prefix: "// clang-format Language:"))
4166 continue;
4167
4168 Text = Text.trim();
4169 if (Text == "C")
4170 return FormatStyle::LK_C;
4171 if (Text == "Cpp")
4172 return FormatStyle::LK_Cpp;
4173 if (Text == "ObjC")
4174 return FormatStyle::LK_ObjC;
4175 }
4176
4177 return FormatStyle::LK_None;
4178}
4179
4180FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
4181 const auto GuessedLanguage = getLanguageByFileName(FileName);
4182 if (GuessedLanguage == FormatStyle::LK_Cpp) {
4183 auto Extension = llvm::sys::path::extension(path: FileName);
4184 // If there's no file extension (or it's .h), we need to check the contents
4185 // of the code to see if it contains Objective-C.
4186 if (!Code.empty() && (Extension.empty() || Extension == ".h")) {
4187 auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
4188 Environment Env(Code, NonEmptyFileName, /*Ranges=*/{});
4189 if (const auto Language = getLanguageByComment(Env);
4190 Language != FormatStyle::LK_None) {
4191 return Language;
4192 }
4193 ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle());
4194 Guesser.process();
4195 if (Guesser.isObjC())
4196 return FormatStyle::LK_ObjC;
4197 }
4198 }
4199 return GuessedLanguage;
4200}
4201
4202// Update StyleOptionHelpDescription above when changing this.
4203const char *DefaultFormatStyle = "file";
4204
4205const char *DefaultFallbackStyle = "LLVM";
4206
4207llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
4208loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
4209 FormatStyle *Style, bool AllowUnknownOptions,
4210 llvm::SourceMgr::DiagHandlerTy DiagHandler,
4211 bool IsDotHFile) {
4212 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
4213 FS->getBufferForFile(Name: ConfigFile.str());
4214 if (auto EC = Text.getError())
4215 return EC;
4216 if (auto EC = parseConfiguration(Config: *Text.get(), Style, AllowUnknownOptions,
4217 DiagHandler, /*DiagHandlerCtx=*/DiagHandlerCtxt: nullptr,
4218 IsDotHFile)) {
4219 return EC;
4220 }
4221 return Text;
4222}
4223
4224Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
4225 StringRef FallbackStyleName, StringRef Code,
4226 llvm::vfs::FileSystem *FS,
4227 bool AllowUnknownOptions,
4228 llvm::SourceMgr::DiagHandlerTy DiagHandler) {
4229 FormatStyle Style = getLLVMStyle(Language: guessLanguage(FileName, Code));
4230 FormatStyle FallbackStyle = getNoStyle();
4231 if (!getPredefinedStyle(Name: FallbackStyleName, Language: Style.Language, Style: &FallbackStyle))
4232 return make_string_error(Message: "Invalid fallback style: " + FallbackStyleName);
4233
4234 SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1> ChildFormatTextToApply;
4235
4236 if (StyleName.starts_with(Prefix: "{")) {
4237 // Parse YAML/JSON style from the command line.
4238 StringRef Source = "<command-line>";
4239 if (std::error_code ec =
4240 parseConfiguration(Config: llvm::MemoryBufferRef(StyleName, Source), Style: &Style,
4241 AllowUnknownOptions, DiagHandler)) {
4242 return make_string_error(Message: "Error parsing -style: " + ec.message());
4243 }
4244
4245 if (!Style.InheritsParentConfig)
4246 return Style;
4247
4248 ChildFormatTextToApply.emplace_back(
4249 Args: llvm::MemoryBuffer::getMemBuffer(InputData: StyleName, BufferName: Source, RequiresNullTerminator: false));
4250 }
4251
4252 if (!FS)
4253 FS = llvm::vfs::getRealFileSystem().get();
4254 assert(FS);
4255
4256 const bool IsDotHFile = FileName.ends_with(Suffix: ".h");
4257
4258 // User provided clang-format file using -style=file:path/to/format/file.
4259 if (!Style.InheritsParentConfig &&
4260 StyleName.starts_with_insensitive(Prefix: "file:")) {
4261 auto ConfigFile = StyleName.substr(Start: 5);
4262 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
4263 loadAndParseConfigFile(ConfigFile, FS, Style: &Style, AllowUnknownOptions,
4264 DiagHandler, IsDotHFile);
4265 if (auto EC = Text.getError()) {
4266 return make_string_error(Message: "Error reading " + ConfigFile + ": " +
4267 EC.message());
4268 }
4269
4270 LLVM_DEBUG(llvm::dbgs()
4271 << "Using configuration file " << ConfigFile << "\n");
4272
4273 if (!Style.InheritsParentConfig)
4274 return Style;
4275
4276 // Search for parent configs starting from the parent directory of
4277 // ConfigFile.
4278 FileName = ConfigFile;
4279 ChildFormatTextToApply.emplace_back(Args: std::move(*Text));
4280 }
4281
4282 // If the style inherits the parent configuration it is a command line
4283 // configuration, which wants to inherit, so we have to skip the check of the
4284 // StyleName.
4285 if (!Style.InheritsParentConfig && !StyleName.equals_insensitive(RHS: "file")) {
4286 if (!getPredefinedStyle(Name: StyleName, Language: Style.Language, Style: &Style))
4287 return make_string_error(Message: "Invalid value for -style");
4288 if (!Style.InheritsParentConfig)
4289 return Style;
4290 }
4291
4292 SmallString<128> Path(FileName);
4293 if (std::error_code EC = FS->makeAbsolute(Path))
4294 return make_string_error(Message: EC.message());
4295
4296 // Reset possible inheritance
4297 Style.InheritsParentConfig = false;
4298
4299 auto dropDiagnosticHandler = [](const llvm::SMDiagnostic &, void *) {};
4300
4301 auto applyChildFormatTexts = [&](FormatStyle *Style) {
4302 for (const auto &MemBuf : llvm::reverse(C&: ChildFormatTextToApply)) {
4303 auto EC =
4304 parseConfiguration(Config: *MemBuf, Style, AllowUnknownOptions,
4305 DiagHandler: DiagHandler ? DiagHandler : dropDiagnosticHandler);
4306 // It was already correctly parsed.
4307 assert(!EC);
4308 static_cast<void>(EC);
4309 }
4310 };
4311
4312 // Look for .clang-format/_clang-format file in the file's parent directories.
4313 SmallVector<std::string, 2> FilesToLookFor;
4314 FilesToLookFor.push_back(Elt: ".clang-format");
4315 FilesToLookFor.push_back(Elt: "_clang-format");
4316
4317 SmallString<128> UnsuitableConfigFiles;
4318 for (StringRef Directory = Path; !Directory.empty();
4319 Directory = llvm::sys::path::parent_path(path: Directory)) {
4320 auto Status = FS->status(Path: Directory);
4321 if (!Status ||
4322 Status->getType() != llvm::sys::fs::file_type::directory_file) {
4323 continue;
4324 }
4325
4326 for (const auto &F : FilesToLookFor) {
4327 SmallString<128> ConfigFile(Directory);
4328
4329 llvm::sys::path::append(path&: ConfigFile, a: F);
4330 LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
4331
4332 Status = FS->status(Path: ConfigFile);
4333 if (!Status ||
4334 Status->getType() != llvm::sys::fs::file_type::regular_file) {
4335 continue;
4336 }
4337
4338 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
4339 loadAndParseConfigFile(ConfigFile, FS, Style: &Style, AllowUnknownOptions,
4340 DiagHandler, IsDotHFile);
4341 if (auto EC = Text.getError()) {
4342 if (EC != ParseError::Unsuitable) {
4343 return make_string_error(Message: "Error reading " + ConfigFile + ": " +
4344 EC.message());
4345 }
4346 if (!UnsuitableConfigFiles.empty())
4347 UnsuitableConfigFiles.append(RHS: ", ");
4348 UnsuitableConfigFiles.append(RHS: ConfigFile);
4349 continue;
4350 }
4351
4352 LLVM_DEBUG(llvm::dbgs()
4353 << "Using configuration file " << ConfigFile << "\n");
4354
4355 if (!Style.InheritsParentConfig) {
4356 if (!ChildFormatTextToApply.empty()) {
4357 LLVM_DEBUG(llvm::dbgs() << "Applying child configurations\n");
4358 applyChildFormatTexts(&Style);
4359 }
4360 return Style;
4361 }
4362
4363 LLVM_DEBUG(llvm::dbgs() << "Inherits parent configuration\n");
4364
4365 // Reset inheritance of style
4366 Style.InheritsParentConfig = false;
4367
4368 ChildFormatTextToApply.emplace_back(Args: std::move(*Text));
4369
4370 // Breaking out of the inner loop, since we don't want to parse
4371 // .clang-format AND _clang-format, if both exist. Then we continue the
4372 // outer loop (parent directories) in search for the parent
4373 // configuration.
4374 break;
4375 }
4376 }
4377
4378 if (!UnsuitableConfigFiles.empty()) {
4379 return make_string_error(Message: "Configuration file(s) do(es) not support " +
4380 getLanguageName(Language: Style.Language) + ": " +
4381 UnsuitableConfigFiles);
4382 }
4383
4384 if (!ChildFormatTextToApply.empty()) {
4385 LLVM_DEBUG(llvm::dbgs()
4386 << "Applying child configurations on fallback style\n");
4387 applyChildFormatTexts(&FallbackStyle);
4388 }
4389
4390 return FallbackStyle;
4391}
4392
4393static bool isClangFormatOnOff(StringRef Comment, bool On) {
4394 if (Comment == (On ? "/* clang-format on */" : "/* clang-format off */"))
4395 return true;
4396
4397 static const char ClangFormatOn[] = "// clang-format on";
4398 static const char ClangFormatOff[] = "// clang-format off";
4399 const unsigned Size = (On ? sizeof ClangFormatOn : sizeof ClangFormatOff) - 1;
4400
4401 return Comment.starts_with(Prefix: On ? ClangFormatOn : ClangFormatOff) &&
4402 (Comment.size() == Size || Comment[Size] == ':');
4403}
4404
4405bool isClangFormatOn(StringRef Comment) {
4406 return isClangFormatOnOff(Comment, /*On=*/true);
4407}
4408
4409bool isClangFormatOff(StringRef Comment) {
4410 return isClangFormatOnOff(Comment, /*On=*/false);
4411}
4412
4413} // namespace format
4414} // namespace clang
4415

source code of clang/lib/Format/Format.cpp