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