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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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