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