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