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 "FormatInternal.h"
20 #include "FormatTokenLexer.h"
21 #include "NamespaceEndCommentsFixer.h"
22 #include "SortJavaScriptImports.h"
23 #include "TokenAnalyzer.h"
24 #include "TokenAnnotator.h"
25 #include "UnwrappedLineFormatter.h"
26 #include "UnwrappedLineParser.h"
27 #include "UsingDeclarationsSorter.h"
28 #include "WhitespaceManager.h"
29 #include "clang/Basic/Diagnostic.h"
30 #include "clang/Basic/DiagnosticOptions.h"
31 #include "clang/Basic/SourceManager.h"
32 #include "clang/Lex/Lexer.h"
33 #include "clang/Tooling/Inclusions/HeaderIncludes.h"
34 #include "llvm/ADT/STLExtras.h"
35 #include "llvm/ADT/StringRef.h"
36 #include "llvm/Support/Allocator.h"
37 #include "llvm/Support/Debug.h"
38 #include "llvm/Support/Path.h"
39 #include "llvm/Support/Regex.h"
40 #include "llvm/Support/VirtualFileSystem.h"
41 #include "llvm/Support/YAMLTraits.h"
42 #include <algorithm>
43 #include <memory>
44 #include <mutex>
45 #include <string>
46 #include <unordered_map>
47
48 #define DEBUG_TYPE "format-formatter"
49
50 using clang::format::FormatStyle;
51
52 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
53
54 namespace llvm {
55 namespace yaml {
56 template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
enumerationllvm::yaml::ScalarEnumerationTraits57 static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
58 IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
59 IO.enumCase(Value, "Java", FormatStyle::LK_Java);
60 IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
61 IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
62 IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
63 IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
64 IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
65 IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp);
66 }
67 };
68
69 template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
enumerationllvm::yaml::ScalarEnumerationTraits70 static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
71 IO.enumCase(Value, "c++03", FormatStyle::LS_Cpp03);
72 IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); // Legacy alias
73 IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); // Legacy alias
74
75 IO.enumCase(Value, "c++11", FormatStyle::LS_Cpp11);
76 IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); // Legacy alias
77
78 IO.enumCase(Value, "c++14", FormatStyle::LS_Cpp14);
79 IO.enumCase(Value, "c++17", FormatStyle::LS_Cpp17);
80 IO.enumCase(Value, "c++20", FormatStyle::LS_Cpp20);
81
82 IO.enumCase(Value, "Latest", FormatStyle::LS_Latest);
83 IO.enumCase(Value, "Cpp11", FormatStyle::LS_Latest); // Legacy alias
84 IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
85 }
86 };
87
88 template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits89 static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
90 IO.enumCase(Value, "Never", FormatStyle::UT_Never);
91 IO.enumCase(Value, "false", FormatStyle::UT_Never);
92 IO.enumCase(Value, "Always", FormatStyle::UT_Always);
93 IO.enumCase(Value, "true", FormatStyle::UT_Always);
94 IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
95 IO.enumCase(Value, "ForContinuationAndIndentation",
96 FormatStyle::UT_ForContinuationAndIndentation);
97 IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces);
98 }
99 };
100
101 template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits102 static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
103 IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
104 IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
105 IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
106 }
107 };
108
109 template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits110 static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) {
111 IO.enumCase(Value, "Never", FormatStyle::SBS_Never);
112 IO.enumCase(Value, "false", FormatStyle::SBS_Never);
113 IO.enumCase(Value, "Always", FormatStyle::SBS_Always);
114 IO.enumCase(Value, "true", FormatStyle::SBS_Always);
115 IO.enumCase(Value, "Empty", FormatStyle::SBS_Empty);
116 }
117 };
118
119 template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits120 static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
121 IO.enumCase(Value, "None", FormatStyle::SFS_None);
122 IO.enumCase(Value, "false", FormatStyle::SFS_None);
123 IO.enumCase(Value, "All", FormatStyle::SFS_All);
124 IO.enumCase(Value, "true", FormatStyle::SFS_All);
125 IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
126 IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
127 IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
128 }
129 };
130
131 template <> struct ScalarEnumerationTraits<FormatStyle::AlignConsecutiveStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits132 static void enumeration(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
133 IO.enumCase(Value, "None", FormatStyle::ACS_None);
134 IO.enumCase(Value, "Consecutive", FormatStyle::ACS_Consecutive);
135 IO.enumCase(Value, "AcrossEmptyLines", FormatStyle::ACS_AcrossEmptyLines);
136 IO.enumCase(Value, "AcrossComments", FormatStyle::ACS_AcrossComments);
137 IO.enumCase(Value, "AcrossEmptyLinesAndComments",
138 FormatStyle::ACS_AcrossEmptyLinesAndComments);
139
140 // For backward compability.
141 IO.enumCase(Value, "true", FormatStyle::ACS_Consecutive);
142 IO.enumCase(Value, "false", FormatStyle::ACS_None);
143 }
144 };
145
146 template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits147 static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) {
148 IO.enumCase(Value, "Never", FormatStyle::SIS_Never);
149 IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse);
150 IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf);
151 IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse);
152
153 // For backward compatibility.
154 IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf);
155 IO.enumCase(Value, "false", FormatStyle::SIS_Never);
156 IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse);
157 }
158 };
159
160 template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits161 static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) {
162 IO.enumCase(Value, "None", FormatStyle::SLS_None);
163 IO.enumCase(Value, "false", FormatStyle::SLS_None);
164 IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty);
165 IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline);
166 IO.enumCase(Value, "All", FormatStyle::SLS_All);
167 IO.enumCase(Value, "true", FormatStyle::SLS_All);
168 }
169 };
170
171 template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits172 static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
173 IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto);
174 IO.enumCase(Value, "Always", FormatStyle::BPS_Always);
175 IO.enumCase(Value, "Never", FormatStyle::BPS_Never);
176 }
177 };
178
179 template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits180 static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) {
181 IO.enumCase(Value, "None", FormatStyle::TCS_None);
182 IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped);
183 }
184 };
185
186 template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits187 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
188 IO.enumCase(Value, "All", FormatStyle::BOS_All);
189 IO.enumCase(Value, "true", FormatStyle::BOS_All);
190 IO.enumCase(Value, "None", FormatStyle::BOS_None);
191 IO.enumCase(Value, "false", FormatStyle::BOS_None);
192 IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
193 }
194 };
195
196 template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits197 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
198 IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
199 IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
200 IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
201 IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
202 IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
203 IO.enumCase(Value, "Whitesmiths", FormatStyle::BS_Whitesmiths);
204 IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
205 IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
206 IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
207 }
208 };
209
210 template <>
211 struct ScalarEnumerationTraits<
212 FormatStyle::BraceWrappingAfterControlStatementStyle> {
213 static void
enumerationllvm::yaml::ScalarEnumerationTraits214 enumeration(IO &IO,
215 FormatStyle::BraceWrappingAfterControlStatementStyle &Value) {
216 IO.enumCase(Value, "Never", FormatStyle::BWACS_Never);
217 IO.enumCase(Value, "MultiLine", FormatStyle::BWACS_MultiLine);
218 IO.enumCase(Value, "Always", FormatStyle::BWACS_Always);
219
220 // For backward compatibility.
221 IO.enumCase(Value, "false", FormatStyle::BWACS_Never);
222 IO.enumCase(Value, "true", FormatStyle::BWACS_Always);
223 }
224 };
225
226 template <>
227 struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
228 static void
enumerationllvm::yaml::ScalarEnumerationTraits229 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
230 IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
231 IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
232 IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
233 }
234 };
235
236 template <>
237 struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits238 static void enumeration(IO &IO,
239 FormatStyle::BreakInheritanceListStyle &Value) {
240 IO.enumCase(Value, "BeforeColon", FormatStyle::BILS_BeforeColon);
241 IO.enumCase(Value, "BeforeComma", FormatStyle::BILS_BeforeComma);
242 IO.enumCase(Value, "AfterColon", FormatStyle::BILS_AfterColon);
243 }
244 };
245
246 template <>
247 struct ScalarEnumerationTraits<FormatStyle::EmptyLineAfterAccessModifierStyle> {
248 static void
enumerationllvm::yaml::ScalarEnumerationTraits249 enumeration(IO &IO, FormatStyle::EmptyLineAfterAccessModifierStyle &Value) {
250 IO.enumCase(Value, "Never", FormatStyle::ELAAMS_Never);
251 IO.enumCase(Value, "Leave", FormatStyle::ELAAMS_Leave);
252 IO.enumCase(Value, "Always", FormatStyle::ELAAMS_Always);
253 }
254 };
255
256 template <>
257 struct ScalarEnumerationTraits<
258 FormatStyle::EmptyLineBeforeAccessModifierStyle> {
259 static void
enumerationllvm::yaml::ScalarEnumerationTraits260 enumeration(IO &IO, FormatStyle::EmptyLineBeforeAccessModifierStyle &Value) {
261 IO.enumCase(Value, "Never", FormatStyle::ELBAMS_Never);
262 IO.enumCase(Value, "Leave", FormatStyle::ELBAMS_Leave);
263 IO.enumCase(Value, "LogicalBlock", FormatStyle::ELBAMS_LogicalBlock);
264 IO.enumCase(Value, "Always", FormatStyle::ELBAMS_Always);
265 }
266 };
267
268 template <>
269 struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits270 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
271 IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
272 IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
273 IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash);
274 }
275 };
276
277 template <>
278 struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits279 static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
280 IO.enumCase(Value, "AfterExternBlock", FormatStyle::IEBS_AfterExternBlock);
281 IO.enumCase(Value, "Indent", FormatStyle::IEBS_Indent);
282 IO.enumCase(Value, "NoIndent", FormatStyle::IEBS_NoIndent);
283 IO.enumCase(Value, "true", FormatStyle::IEBS_Indent);
284 IO.enumCase(Value, "false", FormatStyle::IEBS_NoIndent);
285 }
286 };
287
288 template <>
289 struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits290 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
291 IO.enumCase(Value, "None", FormatStyle::RTBS_None);
292 IO.enumCase(Value, "All", FormatStyle::RTBS_All);
293 IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
294 IO.enumCase(Value, "TopLevelDefinitions",
295 FormatStyle::RTBS_TopLevelDefinitions);
296 IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
297 }
298 };
299
300 template <>
301 struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits302 static void enumeration(IO &IO,
303 FormatStyle::BreakTemplateDeclarationsStyle &Value) {
304 IO.enumCase(Value, "No", FormatStyle::BTDS_No);
305 IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
306 IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);
307
308 // For backward compatibility.
309 IO.enumCase(Value, "false", FormatStyle::BTDS_MultiLine);
310 IO.enumCase(Value, "true", FormatStyle::BTDS_Yes);
311 }
312 };
313
314 template <>
315 struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
316 static void
enumerationllvm::yaml::ScalarEnumerationTraits317 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
318 IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
319 IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
320 IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
321
322 // For backward compatibility.
323 IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
324 IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
325 }
326 };
327
328 template <>
329 struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
enumerationllvm::yaml::ScalarEnumerationTraits330 static void enumeration(IO &IO,
331 FormatStyle::NamespaceIndentationKind &Value) {
332 IO.enumCase(Value, "None", FormatStyle::NI_None);
333 IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
334 IO.enumCase(Value, "All", FormatStyle::NI_All);
335 }
336 };
337
338 template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits339 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
340 IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
341 IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
342 IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
343
344 // For backward compatibility.
345 IO.enumCase(Value, "true", FormatStyle::BAS_Align);
346 IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
347 }
348 };
349
350 template <>
351 struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits352 static void enumeration(IO &IO,
353 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
354 IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
355 IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
356 IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
357
358 // For backward compatibility.
359 IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
360 IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
361 }
362 };
363
364 template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits365 static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
366 IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
367 IO.enumCase(Value, "Align", FormatStyle::OAS_Align);
368 IO.enumCase(Value, "AlignAfterOperator",
369 FormatStyle::OAS_AlignAfterOperator);
370
371 // For backward compatibility.
372 IO.enumCase(Value, "true", FormatStyle::OAS_Align);
373 IO.enumCase(Value, "false", FormatStyle::OAS_DontAlign);
374 }
375 };
376
377 template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits378 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
379 IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
380 IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
381 IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
382
383 // For backward compatibility.
384 IO.enumCase(Value, "true", FormatStyle::PAS_Left);
385 IO.enumCase(Value, "false", FormatStyle::PAS_Right);
386 }
387 };
388
389 template <>
390 struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
391 static void
enumerationllvm::yaml::ScalarEnumerationTraits392 enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) {
393 IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default);
394 IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before);
395 IO.enumCase(Value, "After", FormatStyle::SAPQ_After);
396 IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both);
397 }
398 };
399
400 template <>
401 struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
enumerationllvm::yaml::ScalarEnumerationTraits402 static void enumeration(IO &IO,
403 FormatStyle::SpaceBeforeParensOptions &Value) {
404 IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
405 IO.enumCase(Value, "ControlStatements",
406 FormatStyle::SBPO_ControlStatements);
407 IO.enumCase(Value, "ControlStatementsExceptForEachMacros",
408 FormatStyle::SBPO_ControlStatementsExceptForEachMacros);
409 IO.enumCase(Value, "NonEmptyParentheses",
410 FormatStyle::SBPO_NonEmptyParentheses);
411 IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
412
413 // For backward compatibility.
414 IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
415 IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
416 }
417 };
418
419 template <>
420 struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits421 static void enumeration(IO &IO,
422 FormatStyle::BitFieldColonSpacingStyle &Value) {
423 IO.enumCase(Value, "Both", FormatStyle::BFCS_Both);
424 IO.enumCase(Value, "None", FormatStyle::BFCS_None);
425 IO.enumCase(Value, "Before", FormatStyle::BFCS_Before);
426 IO.enumCase(Value, "After", FormatStyle::BFCS_After);
427 }
428 };
429
430 template <> struct ScalarEnumerationTraits<FormatStyle::SortIncludesOptions> {
enumerationllvm::yaml::ScalarEnumerationTraits431 static void enumeration(IO &IO, FormatStyle::SortIncludesOptions &Value) {
432 IO.enumCase(Value, "Never", FormatStyle::SI_Never);
433 IO.enumCase(Value, "CaseInsensitive", FormatStyle::SI_CaseInsensitive);
434 IO.enumCase(Value, "CaseSensitive", FormatStyle::SI_CaseSensitive);
435
436 // For backward compatibility.
437 IO.enumCase(Value, "false", FormatStyle::SI_Never);
438 IO.enumCase(Value, "true", FormatStyle::SI_CaseSensitive);
439 }
440 };
441
442 template <>
443 struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> {
enumerationllvm::yaml::ScalarEnumerationTraits444 static void enumeration(IO &IO,
445 FormatStyle::SortJavaStaticImportOptions &Value) {
446 IO.enumCase(Value, "Before", FormatStyle::SJSIO_Before);
447 IO.enumCase(Value, "After", FormatStyle::SJSIO_After);
448 }
449 };
450
451 template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> {
enumerationllvm::yaml::ScalarEnumerationTraits452 static void enumeration(IO &IO, FormatStyle::SpacesInAnglesStyle &Value) {
453 IO.enumCase(Value, "Never", FormatStyle::SIAS_Never);
454 IO.enumCase(Value, "Always", FormatStyle::SIAS_Always);
455 IO.enumCase(Value, "Leave", FormatStyle::SIAS_Leave);
456
457 // For backward compatibility.
458 IO.enumCase(Value, "false", FormatStyle::SIAS_Never);
459 IO.enumCase(Value, "true", FormatStyle::SIAS_Always);
460 }
461 };
462
463 template <> struct MappingTraits<FormatStyle> {
mappingllvm::yaml::MappingTraits464 static void mapping(IO &IO, FormatStyle &Style) {
465 // When reading, read the language first, we need it for getPredefinedStyle.
466 IO.mapOptional("Language", Style.Language);
467
468 if (IO.outputting()) {
469 StringRef StylesArray[] = {"LLVM", "Google", "Chromium", "Mozilla",
470 "WebKit", "GNU", "Microsoft"};
471 ArrayRef<StringRef> Styles(StylesArray);
472 for (size_t i = 0, e = Styles.size(); i < e; ++i) {
473 StringRef StyleName(Styles[i]);
474 FormatStyle PredefinedStyle;
475 if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
476 Style == PredefinedStyle) {
477 IO.mapOptional("# BasedOnStyle", StyleName);
478 break;
479 }
480 }
481 } else {
482 StringRef BasedOnStyle;
483 IO.mapOptional("BasedOnStyle", BasedOnStyle);
484 if (!BasedOnStyle.empty()) {
485 FormatStyle::LanguageKind OldLanguage = Style.Language;
486 FormatStyle::LanguageKind Language =
487 ((FormatStyle *)IO.getContext())->Language;
488 if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
489 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
490 return;
491 }
492 Style.Language = OldLanguage;
493 }
494 }
495
496 // For backward compatibility.
497 if (!IO.outputting()) {
498 IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
499 IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
500 IO.mapOptional("IndentFunctionDeclarationAfterType",
501 Style.IndentWrappedFunctionNames);
502 IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
503 IO.mapOptional("SpaceAfterControlStatementKeyword",
504 Style.SpaceBeforeParens);
505 }
506
507 IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
508 IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
509 IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
510 IO.mapOptional("AlignConsecutiveAssignments",
511 Style.AlignConsecutiveAssignments);
512 IO.mapOptional("AlignConsecutiveBitFields",
513 Style.AlignConsecutiveBitFields);
514 IO.mapOptional("AlignConsecutiveDeclarations",
515 Style.AlignConsecutiveDeclarations);
516 IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
517 IO.mapOptional("AlignOperands", Style.AlignOperands);
518 IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
519 IO.mapOptional("AllowAllArgumentsOnNextLine",
520 Style.AllowAllArgumentsOnNextLine);
521 IO.mapOptional("AllowAllConstructorInitializersOnNextLine",
522 Style.AllowAllConstructorInitializersOnNextLine);
523 IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
524 Style.AllowAllParametersOfDeclarationOnNextLine);
525 IO.mapOptional("AllowShortEnumsOnASingleLine",
526 Style.AllowShortEnumsOnASingleLine);
527 IO.mapOptional("AllowShortBlocksOnASingleLine",
528 Style.AllowShortBlocksOnASingleLine);
529 IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
530 Style.AllowShortCaseLabelsOnASingleLine);
531 IO.mapOptional("AllowShortFunctionsOnASingleLine",
532 Style.AllowShortFunctionsOnASingleLine);
533 IO.mapOptional("AllowShortLambdasOnASingleLine",
534 Style.AllowShortLambdasOnASingleLine);
535 IO.mapOptional("AllowShortIfStatementsOnASingleLine",
536 Style.AllowShortIfStatementsOnASingleLine);
537 IO.mapOptional("AllowShortLoopsOnASingleLine",
538 Style.AllowShortLoopsOnASingleLine);
539 IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
540 Style.AlwaysBreakAfterDefinitionReturnType);
541 IO.mapOptional("AlwaysBreakAfterReturnType",
542 Style.AlwaysBreakAfterReturnType);
543
544 // If AlwaysBreakAfterDefinitionReturnType was specified but
545 // AlwaysBreakAfterReturnType was not, initialize the latter from the
546 // former for backwards compatibility.
547 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
548 Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
549 if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
550 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
551 else if (Style.AlwaysBreakAfterDefinitionReturnType ==
552 FormatStyle::DRTBS_TopLevel)
553 Style.AlwaysBreakAfterReturnType =
554 FormatStyle::RTBS_TopLevelDefinitions;
555 }
556
557 IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
558 Style.AlwaysBreakBeforeMultilineStrings);
559 IO.mapOptional("AlwaysBreakTemplateDeclarations",
560 Style.AlwaysBreakTemplateDeclarations);
561 IO.mapOptional("AttributeMacros", Style.AttributeMacros);
562 IO.mapOptional("BinPackArguments", Style.BinPackArguments);
563 IO.mapOptional("BinPackParameters", Style.BinPackParameters);
564 IO.mapOptional("BraceWrapping", Style.BraceWrapping);
565 IO.mapOptional("BreakBeforeBinaryOperators",
566 Style.BreakBeforeBinaryOperators);
567 IO.mapOptional("BreakBeforeConceptDeclarations",
568 Style.BreakBeforeConceptDeclarations);
569 IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
570
571 bool BreakBeforeInheritanceComma = false;
572 IO.mapOptional("BreakBeforeInheritanceComma", BreakBeforeInheritanceComma);
573 IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList);
574 // If BreakBeforeInheritanceComma was specified but
575 // BreakInheritance was not, initialize the latter from the
576 // former for backwards compatibility.
577 if (BreakBeforeInheritanceComma &&
578 Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon)
579 Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
580
581 IO.mapOptional("BreakBeforeTernaryOperators",
582 Style.BreakBeforeTernaryOperators);
583
584 bool BreakConstructorInitializersBeforeComma = false;
585 IO.mapOptional("BreakConstructorInitializersBeforeComma",
586 BreakConstructorInitializersBeforeComma);
587 IO.mapOptional("BreakConstructorInitializers",
588 Style.BreakConstructorInitializers);
589 // If BreakConstructorInitializersBeforeComma was specified but
590 // BreakConstructorInitializers was not, initialize the latter from the
591 // former for backwards compatibility.
592 if (BreakConstructorInitializersBeforeComma &&
593 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
594 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
595
596 IO.mapOptional("BreakAfterJavaFieldAnnotations",
597 Style.BreakAfterJavaFieldAnnotations);
598 IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
599 IO.mapOptional("ColumnLimit", Style.ColumnLimit);
600 IO.mapOptional("CommentPragmas", Style.CommentPragmas);
601 IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
602 IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
603 Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
604 IO.mapOptional("ConstructorInitializerIndentWidth",
605 Style.ConstructorInitializerIndentWidth);
606 IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
607 IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
608 IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding);
609 IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
610 IO.mapOptional("DisableFormat", Style.DisableFormat);
611 IO.mapOptional("EmptyLineAfterAccessModifier",
612 Style.EmptyLineAfterAccessModifier);
613 IO.mapOptional("EmptyLineBeforeAccessModifier",
614 Style.EmptyLineBeforeAccessModifier);
615 IO.mapOptional("ExperimentalAutoDetectBinPacking",
616 Style.ExperimentalAutoDetectBinPacking);
617 IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
618 IO.mapOptional("ForEachMacros", Style.ForEachMacros);
619 IO.mapOptional("StatementAttributeLikeMacros",
620 Style.StatementAttributeLikeMacros);
621 IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks);
622 IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories);
623 IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex);
624 IO.mapOptional("IncludeIsMainSourceRegex",
625 Style.IncludeStyle.IncludeIsMainSourceRegex);
626 IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers);
627 IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
628 IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks);
629 IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
630 IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
631 IO.mapOptional("IndentExternBlock", Style.IndentExternBlock);
632 IO.mapOptional("IndentRequires", Style.IndentRequires);
633 IO.mapOptional("IndentWidth", Style.IndentWidth);
634 IO.mapOptional("IndentWrappedFunctionNames",
635 Style.IndentWrappedFunctionNames);
636 IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas);
637 IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
638 IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
639 IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
640 IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
641 Style.KeepEmptyLinesAtTheStartOfBlocks);
642 IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
643 IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
644 IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
645 IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
646 IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
647 IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
648 IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
649 IO.mapOptional("ObjCBreakBeforeNestedBlockParam",
650 Style.ObjCBreakBeforeNestedBlockParam);
651 IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
652 IO.mapOptional("ObjCSpaceBeforeProtocolList",
653 Style.ObjCSpaceBeforeProtocolList);
654 IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
655 IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
656 Style.PenaltyBreakBeforeFirstCallParameter);
657 IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
658 IO.mapOptional("PenaltyBreakFirstLessLess",
659 Style.PenaltyBreakFirstLessLess);
660 IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
661 IO.mapOptional("PenaltyBreakTemplateDeclaration",
662 Style.PenaltyBreakTemplateDeclaration);
663 IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
664 IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
665 Style.PenaltyReturnTypeOnItsOwnLine);
666 IO.mapOptional("PenaltyIndentedWhitespace",
667 Style.PenaltyIndentedWhitespace);
668 IO.mapOptional("PointerAlignment", Style.PointerAlignment);
669 IO.mapOptional("RawStringFormats", Style.RawStringFormats);
670 IO.mapOptional("ReflowComments", Style.ReflowComments);
671 IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines);
672 IO.mapOptional("SortIncludes", Style.SortIncludes);
673 IO.mapOptional("SortJavaStaticImport", Style.SortJavaStaticImport);
674 IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
675 IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
676 IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot);
677 IO.mapOptional("SpaceAfterTemplateKeyword",
678 Style.SpaceAfterTemplateKeyword);
679 IO.mapOptional("SpaceBeforeAssignmentOperators",
680 Style.SpaceBeforeAssignmentOperators);
681 IO.mapOptional("SpaceBeforeCaseColon", Style.SpaceBeforeCaseColon);
682 IO.mapOptional("SpaceBeforeCpp11BracedList",
683 Style.SpaceBeforeCpp11BracedList);
684 IO.mapOptional("SpaceBeforeCtorInitializerColon",
685 Style.SpaceBeforeCtorInitializerColon);
686 IO.mapOptional("SpaceBeforeInheritanceColon",
687 Style.SpaceBeforeInheritanceColon);
688 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
689 IO.mapOptional("SpaceAroundPointerQualifiers",
690 Style.SpaceAroundPointerQualifiers);
691 IO.mapOptional("SpaceBeforeRangeBasedForLoopColon",
692 Style.SpaceBeforeRangeBasedForLoopColon);
693 IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
694 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
695 IO.mapOptional("SpacesBeforeTrailingComments",
696 Style.SpacesBeforeTrailingComments);
697 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
698 IO.mapOptional("SpacesInConditionalStatement",
699 Style.SpacesInConditionalStatement);
700 IO.mapOptional("SpacesInContainerLiterals",
701 Style.SpacesInContainerLiterals);
702 IO.mapOptional("SpacesInCStyleCastParentheses",
703 Style.SpacesInCStyleCastParentheses);
704 IO.mapOptional("SpacesInLineCommentPrefix",
705 Style.SpacesInLineCommentPrefix);
706 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
707 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
708 IO.mapOptional("SpaceBeforeSquareBrackets",
709 Style.SpaceBeforeSquareBrackets);
710 IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing);
711 IO.mapOptional("Standard", Style.Standard);
712 IO.mapOptional("StatementMacros", Style.StatementMacros);
713 IO.mapOptional("TabWidth", Style.TabWidth);
714 IO.mapOptional("TypenameMacros", Style.TypenameMacros);
715 IO.mapOptional("UseCRLF", Style.UseCRLF);
716 IO.mapOptional("UseTab", Style.UseTab);
717 IO.mapOptional("WhitespaceSensitiveMacros",
718 Style.WhitespaceSensitiveMacros);
719 }
720 };
721
722 template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
mappingllvm::yaml::MappingTraits723 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
724 IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel);
725 IO.mapOptional("AfterClass", Wrapping.AfterClass);
726 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
727 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
728 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
729 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
730 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
731 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
732 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
733 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
734 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
735 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
736 IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody);
737 IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile);
738 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
739 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
740 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
741 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
742 }
743 };
744
745 template <> struct MappingTraits<FormatStyle::RawStringFormat> {
mappingllvm::yaml::MappingTraits746 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
747 IO.mapOptional("Language", Format.Language);
748 IO.mapOptional("Delimiters", Format.Delimiters);
749 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
750 IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
751 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
752 }
753 };
754
755 template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
mappingllvm::yaml::MappingTraits756 static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) {
757 // Transform the maximum to signed, to parse "-1" correctly
758 int signedMaximum = static_cast<int>(Space.Maximum);
759 IO.mapOptional("Minimum", Space.Minimum);
760 IO.mapOptional("Maximum", signedMaximum);
761 Space.Maximum = static_cast<unsigned>(signedMaximum);
762
763 if (Space.Maximum != -1u) {
764 Space.Minimum = std::min(Space.Minimum, Space.Maximum);
765 }
766 }
767 };
768
769 // Allows to read vector<FormatStyle> while keeping default values.
770 // IO.getContext() should contain a pointer to the FormatStyle structure, that
771 // will be used to get default values for missing keys.
772 // If the first element has no Language specified, it will be treated as the
773 // default one for the following elements.
774 template <> struct DocumentListTraits<std::vector<FormatStyle>> {
sizellvm::yaml::DocumentListTraits775 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
776 return Seq.size();
777 }
elementllvm::yaml::DocumentListTraits778 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
779 size_t Index) {
780 if (Index >= Seq.size()) {
781 assert(Index == Seq.size());
782 FormatStyle Template;
783 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
784 Template = Seq[0];
785 } else {
786 Template = *((const FormatStyle *)IO.getContext());
787 Template.Language = FormatStyle::LK_None;
788 }
789 Seq.resize(Index + 1, Template);
790 }
791 return Seq[Index];
792 }
793 };
794 } // namespace yaml
795 } // namespace llvm
796
797 namespace clang {
798 namespace format {
799
getParseCategory()800 const std::error_category &getParseCategory() {
801 static const ParseErrorCategory C{};
802 return C;
803 }
make_error_code(ParseError e)804 std::error_code make_error_code(ParseError e) {
805 return std::error_code(static_cast<int>(e), getParseCategory());
806 }
807
make_string_error(const llvm::Twine & Message)808 inline llvm::Error make_string_error(const llvm::Twine &Message) {
809 return llvm::make_error<llvm::StringError>(Message,
810 llvm::inconvertibleErrorCode());
811 }
812
name() const813 const char *ParseErrorCategory::name() const noexcept {
814 return "clang-format.parse_error";
815 }
816
message(int EV) const817 std::string ParseErrorCategory::message(int EV) const {
818 switch (static_cast<ParseError>(EV)) {
819 case ParseError::Success:
820 return "Success";
821 case ParseError::Error:
822 return "Invalid argument";
823 case ParseError::Unsuitable:
824 return "Unsuitable";
825 case ParseError::BinPackTrailingCommaConflict:
826 return "trailing comma insertion cannot be used with bin packing";
827 }
828 llvm_unreachable("unexpected parse error");
829 }
830
expandPresets(const FormatStyle & Style)831 static FormatStyle expandPresets(const FormatStyle &Style) {
832 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
833 return Style;
834 FormatStyle Expanded = Style;
835 Expanded.BraceWrapping = {/*AfterCaseLabel=*/false,
836 /*AfterClass=*/false,
837 /*AfterControlStatement=*/FormatStyle::BWACS_Never,
838 /*AfterEnum=*/false,
839 /*AfterFunction=*/false,
840 /*AfterNamespace=*/false,
841 /*AfterObjCDeclaration=*/false,
842 /*AfterStruct=*/false,
843 /*AfterUnion=*/false,
844 /*AfterExternBlock=*/false,
845 /*BeforeCatch=*/false,
846 /*BeforeElse=*/false,
847 /*BeforeLambdaBody=*/false,
848 /*BeforeWhile=*/false,
849 /*IndentBraces=*/false,
850 /*SplitEmptyFunction=*/true,
851 /*SplitEmptyRecord=*/true,
852 /*SplitEmptyNamespace=*/true};
853 switch (Style.BreakBeforeBraces) {
854 case FormatStyle::BS_Linux:
855 Expanded.BraceWrapping.AfterClass = true;
856 Expanded.BraceWrapping.AfterFunction = true;
857 Expanded.BraceWrapping.AfterNamespace = true;
858 break;
859 case FormatStyle::BS_Mozilla:
860 Expanded.BraceWrapping.AfterClass = true;
861 Expanded.BraceWrapping.AfterEnum = true;
862 Expanded.BraceWrapping.AfterFunction = true;
863 Expanded.BraceWrapping.AfterStruct = true;
864 Expanded.BraceWrapping.AfterUnion = true;
865 Expanded.BraceWrapping.AfterExternBlock = true;
866 Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
867 Expanded.BraceWrapping.SplitEmptyFunction = true;
868 Expanded.BraceWrapping.SplitEmptyRecord = false;
869 break;
870 case FormatStyle::BS_Stroustrup:
871 Expanded.BraceWrapping.AfterFunction = true;
872 Expanded.BraceWrapping.BeforeCatch = true;
873 Expanded.BraceWrapping.BeforeElse = true;
874 break;
875 case FormatStyle::BS_Allman:
876 Expanded.BraceWrapping.AfterCaseLabel = true;
877 Expanded.BraceWrapping.AfterClass = true;
878 Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
879 Expanded.BraceWrapping.AfterEnum = true;
880 Expanded.BraceWrapping.AfterFunction = true;
881 Expanded.BraceWrapping.AfterNamespace = true;
882 Expanded.BraceWrapping.AfterObjCDeclaration = true;
883 Expanded.BraceWrapping.AfterStruct = true;
884 Expanded.BraceWrapping.AfterUnion = true;
885 Expanded.BraceWrapping.AfterExternBlock = true;
886 Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
887 Expanded.BraceWrapping.BeforeCatch = true;
888 Expanded.BraceWrapping.BeforeElse = true;
889 Expanded.BraceWrapping.BeforeLambdaBody = true;
890 break;
891 case FormatStyle::BS_Whitesmiths:
892 Expanded.BraceWrapping.AfterCaseLabel = true;
893 Expanded.BraceWrapping.AfterClass = true;
894 Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
895 Expanded.BraceWrapping.AfterEnum = true;
896 Expanded.BraceWrapping.AfterFunction = true;
897 Expanded.BraceWrapping.AfterNamespace = true;
898 Expanded.BraceWrapping.AfterObjCDeclaration = true;
899 Expanded.BraceWrapping.AfterStruct = true;
900 Expanded.BraceWrapping.AfterExternBlock = true;
901 Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
902 Expanded.BraceWrapping.BeforeCatch = true;
903 Expanded.BraceWrapping.BeforeElse = true;
904 Expanded.BraceWrapping.BeforeLambdaBody = true;
905 break;
906 case FormatStyle::BS_GNU:
907 Expanded.BraceWrapping = {
908 /*AfterCaseLabel=*/true,
909 /*AfterClass=*/true,
910 /*AfterControlStatement=*/FormatStyle::BWACS_Always,
911 /*AfterEnum=*/true,
912 /*AfterFunction=*/true,
913 /*AfterNamespace=*/true,
914 /*AfterObjCDeclaration=*/true,
915 /*AfterStruct=*/true,
916 /*AfterUnion=*/true,
917 /*AfterExternBlock=*/true,
918 /*BeforeCatch=*/true,
919 /*BeforeElse=*/true,
920 /*BeforeLambdaBody=*/false,
921 /*BeforeWhile=*/true,
922 /*IndentBraces=*/true,
923 /*SplitEmptyFunction=*/true,
924 /*SplitEmptyRecord=*/true,
925 /*SplitEmptyNamespace=*/true};
926 Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
927 break;
928 case FormatStyle::BS_WebKit:
929 Expanded.BraceWrapping.AfterFunction = true;
930 break;
931 default:
932 break;
933 }
934 return Expanded;
935 }
936
getLLVMStyle(FormatStyle::LanguageKind Language)937 FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
938 FormatStyle LLVMStyle;
939 LLVMStyle.InheritsParentConfig = false;
940 LLVMStyle.Language = Language;
941 LLVMStyle.AccessModifierOffset = -2;
942 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
943 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
944 LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
945 LLVMStyle.AlignTrailingComments = true;
946 LLVMStyle.AlignConsecutiveAssignments = FormatStyle::ACS_None;
947 LLVMStyle.AlignConsecutiveBitFields = FormatStyle::ACS_None;
948 LLVMStyle.AlignConsecutiveDeclarations = FormatStyle::ACS_None;
949 LLVMStyle.AlignConsecutiveMacros = FormatStyle::ACS_None;
950 LLVMStyle.AllowAllArgumentsOnNextLine = true;
951 LLVMStyle.AllowAllConstructorInitializersOnNextLine = true;
952 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
953 LLVMStyle.AllowShortEnumsOnASingleLine = true;
954 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
955 LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
956 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
957 LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
958 LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
959 LLVMStyle.AllowShortLoopsOnASingleLine = false;
960 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
961 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
962 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
963 LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
964 LLVMStyle.AttributeMacros.push_back("__capability");
965 LLVMStyle.BinPackArguments = true;
966 LLVMStyle.BinPackParameters = true;
967 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
968 LLVMStyle.BreakBeforeConceptDeclarations = true;
969 LLVMStyle.BreakBeforeTernaryOperators = true;
970 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
971 LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
972 /*AfterClass=*/false,
973 /*AfterControlStatement=*/FormatStyle::BWACS_Never,
974 /*AfterEnum=*/false,
975 /*AfterFunction=*/false,
976 /*AfterNamespace=*/false,
977 /*AfterObjCDeclaration=*/false,
978 /*AfterStruct=*/false,
979 /*AfterUnion=*/false,
980 /*AfterExternBlock=*/false,
981 /*BeforeCatch=*/false,
982 /*BeforeElse=*/false,
983 /*BeforeLambdaBody=*/false,
984 /*BeforeWhile=*/false,
985 /*IndentBraces=*/false,
986 /*SplitEmptyFunction=*/true,
987 /*SplitEmptyRecord=*/true,
988 /*SplitEmptyNamespace=*/true};
989 LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
990 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
991 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
992 LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
993 LLVMStyle.BreakStringLiterals = true;
994 LLVMStyle.ColumnLimit = 80;
995 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
996 LLVMStyle.CompactNamespaces = false;
997 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
998 LLVMStyle.ConstructorInitializerIndentWidth = 4;
999 LLVMStyle.ContinuationIndentWidth = 4;
1000 LLVMStyle.Cpp11BracedListStyle = true;
1001 LLVMStyle.DeriveLineEnding = true;
1002 LLVMStyle.DerivePointerAlignment = false;
1003 LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
1004 LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
1005 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
1006 LLVMStyle.FixNamespaceComments = true;
1007 LLVMStyle.ForEachMacros.push_back("foreach");
1008 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
1009 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
1010 LLVMStyle.IncludeStyle.IncludeCategories = {
1011 {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0, false},
1012 {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0, false},
1013 {".*", 1, 0, false}};
1014 LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$";
1015 LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve;
1016 LLVMStyle.IndentAccessModifiers = false;
1017 LLVMStyle.IndentCaseLabels = false;
1018 LLVMStyle.IndentCaseBlocks = false;
1019 LLVMStyle.IndentGotoLabels = true;
1020 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
1021 LLVMStyle.IndentRequires = false;
1022 LLVMStyle.IndentWrappedFunctionNames = false;
1023 LLVMStyle.IndentWidth = 2;
1024 LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
1025 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
1026 LLVMStyle.JavaScriptWrapImports = true;
1027 LLVMStyle.TabWidth = 8;
1028 LLVMStyle.MaxEmptyLinesToKeep = 1;
1029 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
1030 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
1031 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
1032 LLVMStyle.ObjCBlockIndentWidth = 2;
1033 LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
1034 LLVMStyle.ObjCSpaceAfterProperty = false;
1035 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
1036 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
1037 LLVMStyle.ShortNamespaceLines = 1;
1038 LLVMStyle.SpacesBeforeTrailingComments = 1;
1039 LLVMStyle.Standard = FormatStyle::LS_Latest;
1040 LLVMStyle.UseCRLF = false;
1041 LLVMStyle.UseTab = FormatStyle::UT_Never;
1042 LLVMStyle.ReflowComments = true;
1043 LLVMStyle.SpacesInParentheses = false;
1044 LLVMStyle.SpacesInSquareBrackets = false;
1045 LLVMStyle.SpaceInEmptyBlock = false;
1046 LLVMStyle.SpaceInEmptyParentheses = false;
1047 LLVMStyle.SpacesInContainerLiterals = true;
1048 LLVMStyle.SpacesInCStyleCastParentheses = false;
1049 LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u};
1050 LLVMStyle.SpaceAfterCStyleCast = false;
1051 LLVMStyle.SpaceAfterLogicalNot = false;
1052 LLVMStyle.SpaceAfterTemplateKeyword = true;
1053 LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default;
1054 LLVMStyle.SpaceBeforeCaseColon = false;
1055 LLVMStyle.SpaceBeforeCtorInitializerColon = true;
1056 LLVMStyle.SpaceBeforeInheritanceColon = true;
1057 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
1058 LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
1059 LLVMStyle.SpaceBeforeAssignmentOperators = true;
1060 LLVMStyle.SpaceBeforeCpp11BracedList = false;
1061 LLVMStyle.SpaceBeforeSquareBrackets = false;
1062 LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
1063 LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
1064 LLVMStyle.SpacesInConditionalStatement = false;
1065
1066 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
1067 LLVMStyle.PenaltyBreakComment = 300;
1068 LLVMStyle.PenaltyBreakFirstLessLess = 120;
1069 LLVMStyle.PenaltyBreakString = 1000;
1070 LLVMStyle.PenaltyExcessCharacter = 1000000;
1071 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
1072 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
1073 LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
1074 LLVMStyle.PenaltyIndentedWhitespace = 0;
1075
1076 LLVMStyle.DisableFormat = false;
1077 LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive;
1078 LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
1079 LLVMStyle.SortUsingDeclarations = true;
1080 LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT");
1081 LLVMStyle.StatementMacros.push_back("Q_UNUSED");
1082 LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
1083 LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
1084 LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
1085 LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE");
1086 LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
1087 LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME");
1088
1089 // Defaults that differ when not C++.
1090 if (Language == FormatStyle::LK_TableGen) {
1091 LLVMStyle.SpacesInContainerLiterals = false;
1092 }
1093
1094 return LLVMStyle;
1095 }
1096
getGoogleStyle(FormatStyle::LanguageKind Language)1097 FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
1098 if (Language == FormatStyle::LK_TextProto) {
1099 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
1100 GoogleStyle.Language = FormatStyle::LK_TextProto;
1101
1102 return GoogleStyle;
1103 }
1104
1105 FormatStyle GoogleStyle = getLLVMStyle(Language);
1106
1107 GoogleStyle.AccessModifierOffset = -1;
1108 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
1109 GoogleStyle.AllowShortIfStatementsOnASingleLine =
1110 FormatStyle::SIS_WithoutElse;
1111 GoogleStyle.AllowShortLoopsOnASingleLine = true;
1112 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
1113 GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
1114 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
1115 GoogleStyle.DerivePointerAlignment = true;
1116 GoogleStyle.IncludeStyle.IncludeCategories = {{"^<ext/.*\\.h>", 2, 0, false},
1117 {"^<.*\\.h>", 1, 0, false},
1118 {"^<.*", 2, 0, false},
1119 {".*", 3, 0, false}};
1120 GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
1121 GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup;
1122 GoogleStyle.IndentCaseLabels = true;
1123 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
1124 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
1125 GoogleStyle.ObjCSpaceAfterProperty = false;
1126 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
1127 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
1128 GoogleStyle.RawStringFormats = {
1129 {
1130 FormatStyle::LK_Cpp,
1131 /*Delimiters=*/
1132 {
1133 "cc",
1134 "CC",
1135 "cpp",
1136 "Cpp",
1137 "CPP",
1138 "c++",
1139 "C++",
1140 },
1141 /*EnclosingFunctionNames=*/
1142 {},
1143 /*CanonicalDelimiter=*/"",
1144 /*BasedOnStyle=*/"google",
1145 },
1146 {
1147 FormatStyle::LK_TextProto,
1148 /*Delimiters=*/
1149 {
1150 "pb",
1151 "PB",
1152 "proto",
1153 "PROTO",
1154 },
1155 /*EnclosingFunctionNames=*/
1156 {
1157 "EqualsProto",
1158 "EquivToProto",
1159 "PARSE_PARTIAL_TEXT_PROTO",
1160 "PARSE_TEST_PROTO",
1161 "PARSE_TEXT_PROTO",
1162 "ParseTextOrDie",
1163 "ParseTextProtoOrDie",
1164 "ParseTestProto",
1165 "ParsePartialTestProto",
1166 },
1167 /*CanonicalDelimiter=*/"pb",
1168 /*BasedOnStyle=*/"google",
1169 },
1170 };
1171 GoogleStyle.SpacesBeforeTrailingComments = 2;
1172 GoogleStyle.Standard = FormatStyle::LS_Auto;
1173
1174 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
1175 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
1176
1177 if (Language == FormatStyle::LK_Java) {
1178 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
1179 GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
1180 GoogleStyle.AlignTrailingComments = false;
1181 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1182 GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1183 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1184 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
1185 GoogleStyle.ColumnLimit = 100;
1186 GoogleStyle.SpaceAfterCStyleCast = true;
1187 GoogleStyle.SpacesBeforeTrailingComments = 1;
1188 } else if (Language == FormatStyle::LK_JavaScript) {
1189 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
1190 GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
1191 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1192 // TODO: still under discussion whether to switch to SLS_All.
1193 GoogleStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty;
1194 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1195 GoogleStyle.BreakBeforeTernaryOperators = false;
1196 // taze:, triple slash directives (`/// <...`), tslint:, and @see, which is
1197 // commonly followed by overlong URLs.
1198 GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|tslint:|@see)";
1199 // TODO: enable once decided, in particular re disabling bin packing.
1200 // https://google.github.io/styleguide/jsguide.html#features-arrays-trailing-comma
1201 // GoogleStyle.InsertTrailingCommas = FormatStyle::TCS_Wrapped;
1202 GoogleStyle.MaxEmptyLinesToKeep = 3;
1203 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
1204 GoogleStyle.SpacesInContainerLiterals = false;
1205 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
1206 GoogleStyle.JavaScriptWrapImports = false;
1207 } else if (Language == FormatStyle::LK_Proto) {
1208 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1209 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1210 GoogleStyle.SpacesInContainerLiterals = false;
1211 GoogleStyle.Cpp11BracedListStyle = false;
1212 // This affects protocol buffer options specifications and text protos.
1213 // Text protos are currently mostly formatted inside C++ raw string literals
1214 // and often the current breaking behavior of string literals is not
1215 // beneficial there. Investigate turning this on once proper string reflow
1216 // has been implemented.
1217 GoogleStyle.BreakStringLiterals = false;
1218 } else if (Language == FormatStyle::LK_ObjC) {
1219 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
1220 GoogleStyle.ColumnLimit = 100;
1221 // "Regroup" doesn't work well for ObjC yet (main header heuristic,
1222 // relationship between ObjC standard library headers and other heades,
1223 // #imports, etc.)
1224 GoogleStyle.IncludeStyle.IncludeBlocks =
1225 tooling::IncludeStyle::IBS_Preserve;
1226 } else if (Language == FormatStyle::LK_CSharp) {
1227 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1228 GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1229 GoogleStyle.BreakStringLiterals = false;
1230 GoogleStyle.ColumnLimit = 100;
1231 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
1232 }
1233
1234 return GoogleStyle;
1235 }
1236
getChromiumStyle(FormatStyle::LanguageKind Language)1237 FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
1238 FormatStyle ChromiumStyle = getGoogleStyle(Language);
1239
1240 // Disable include reordering across blocks in Chromium code.
1241 // - clang-format tries to detect that foo.h is the "main" header for
1242 // foo.cc and foo_unittest.cc via IncludeIsMainRegex. However, Chromium
1243 // uses many other suffices (_win.cc, _mac.mm, _posix.cc, _browsertest.cc,
1244 // _private.cc, _impl.cc etc) in different permutations
1245 // (_win_browsertest.cc) so disable this until IncludeIsMainRegex has a
1246 // better default for Chromium code.
1247 // - The default for .cc and .mm files is different (r357695) for Google style
1248 // for the same reason. The plan is to unify this again once the main
1249 // header detection works for Google's ObjC code, but this hasn't happened
1250 // yet. Since Chromium has some ObjC code, switching Chromium is blocked
1251 // on that.
1252 // - Finally, "If include reordering is harmful, put things in different
1253 // blocks to prevent it" has been a recommendation for a long time that
1254 // people are used to. We'll need a dev education push to change this to
1255 // "If include reordering is harmful, put things in a different block and
1256 // _prepend that with a comment_ to prevent it" before changing behavior.
1257 ChromiumStyle.IncludeStyle.IncludeBlocks =
1258 tooling::IncludeStyle::IBS_Preserve;
1259
1260 if (Language == FormatStyle::LK_Java) {
1261 ChromiumStyle.AllowShortIfStatementsOnASingleLine =
1262 FormatStyle::SIS_WithoutElse;
1263 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
1264 ChromiumStyle.ContinuationIndentWidth = 8;
1265 ChromiumStyle.IndentWidth = 4;
1266 // See styleguide for import groups:
1267 // https://chromium.googlesource.com/chromium/src/+/master/styleguide/java/java.md#Import-Order
1268 ChromiumStyle.JavaImportGroups = {
1269 "android",
1270 "androidx",
1271 "com",
1272 "dalvik",
1273 "junit",
1274 "org",
1275 "com.google.android.apps.chrome",
1276 "org.chromium",
1277 "java",
1278 "javax",
1279 };
1280 ChromiumStyle.SortIncludes = FormatStyle::SI_CaseSensitive;
1281 } else if (Language == FormatStyle::LK_JavaScript) {
1282 ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1283 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
1284 } else {
1285 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
1286 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1287 ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1288 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
1289 ChromiumStyle.BinPackParameters = false;
1290 ChromiumStyle.DerivePointerAlignment = false;
1291 if (Language == FormatStyle::LK_ObjC)
1292 ChromiumStyle.ColumnLimit = 80;
1293 }
1294 return ChromiumStyle;
1295 }
1296
getMozillaStyle()1297 FormatStyle getMozillaStyle() {
1298 FormatStyle MozillaStyle = getLLVMStyle();
1299 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
1300 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1301 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
1302 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
1303 FormatStyle::DRTBS_TopLevel;
1304 MozillaStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
1305 MozillaStyle.BinPackParameters = false;
1306 MozillaStyle.BinPackArguments = false;
1307 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
1308 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
1309 MozillaStyle.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
1310 MozillaStyle.ConstructorInitializerIndentWidth = 2;
1311 MozillaStyle.ContinuationIndentWidth = 2;
1312 MozillaStyle.Cpp11BracedListStyle = false;
1313 MozillaStyle.FixNamespaceComments = false;
1314 MozillaStyle.IndentCaseLabels = true;
1315 MozillaStyle.ObjCSpaceAfterProperty = true;
1316 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
1317 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
1318 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
1319 MozillaStyle.SpaceAfterTemplateKeyword = false;
1320 return MozillaStyle;
1321 }
1322
getWebKitStyle()1323 FormatStyle getWebKitStyle() {
1324 FormatStyle Style = getLLVMStyle();
1325 Style.AccessModifierOffset = -4;
1326 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
1327 Style.AlignOperands = FormatStyle::OAS_DontAlign;
1328 Style.AlignTrailingComments = false;
1329 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
1330 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
1331 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
1332 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
1333 Style.Cpp11BracedListStyle = false;
1334 Style.ColumnLimit = 0;
1335 Style.FixNamespaceComments = false;
1336 Style.IndentWidth = 4;
1337 Style.NamespaceIndentation = FormatStyle::NI_Inner;
1338 Style.ObjCBlockIndentWidth = 4;
1339 Style.ObjCSpaceAfterProperty = true;
1340 Style.PointerAlignment = FormatStyle::PAS_Left;
1341 Style.SpaceBeforeCpp11BracedList = true;
1342 Style.SpaceInEmptyBlock = true;
1343 return Style;
1344 }
1345
getGNUStyle()1346 FormatStyle getGNUStyle() {
1347 FormatStyle Style = getLLVMStyle();
1348 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
1349 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
1350 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
1351 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
1352 Style.BreakBeforeTernaryOperators = true;
1353 Style.Cpp11BracedListStyle = false;
1354 Style.ColumnLimit = 79;
1355 Style.FixNamespaceComments = false;
1356 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
1357 Style.Standard = FormatStyle::LS_Cpp03;
1358 return Style;
1359 }
1360
getMicrosoftStyle(FormatStyle::LanguageKind Language)1361 FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) {
1362 FormatStyle Style = getLLVMStyle(Language);
1363 Style.ColumnLimit = 120;
1364 Style.TabWidth = 4;
1365 Style.IndentWidth = 4;
1366 Style.UseTab = FormatStyle::UT_Never;
1367 Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1368 Style.BraceWrapping.AfterClass = true;
1369 Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
1370 Style.BraceWrapping.AfterEnum = true;
1371 Style.BraceWrapping.AfterFunction = true;
1372 Style.BraceWrapping.AfterNamespace = true;
1373 Style.BraceWrapping.AfterObjCDeclaration = true;
1374 Style.BraceWrapping.AfterStruct = true;
1375 Style.BraceWrapping.AfterExternBlock = true;
1376 Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
1377 Style.BraceWrapping.BeforeCatch = true;
1378 Style.BraceWrapping.BeforeElse = true;
1379 Style.BraceWrapping.BeforeWhile = false;
1380 Style.PenaltyReturnTypeOnItsOwnLine = 1000;
1381 Style.AllowShortEnumsOnASingleLine = false;
1382 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
1383 Style.AllowShortCaseLabelsOnASingleLine = false;
1384 Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
1385 Style.AllowShortLoopsOnASingleLine = false;
1386 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
1387 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
1388 return Style;
1389 }
1390
getNoStyle()1391 FormatStyle getNoStyle() {
1392 FormatStyle NoStyle = getLLVMStyle();
1393 NoStyle.DisableFormat = true;
1394 NoStyle.SortIncludes = FormatStyle::SI_Never;
1395 NoStyle.SortUsingDeclarations = false;
1396 return NoStyle;
1397 }
1398
getPredefinedStyle(StringRef Name,FormatStyle::LanguageKind Language,FormatStyle * Style)1399 bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
1400 FormatStyle *Style) {
1401 if (Name.equals_lower("llvm")) {
1402 *Style = getLLVMStyle(Language);
1403 } else if (Name.equals_lower("chromium")) {
1404 *Style = getChromiumStyle(Language);
1405 } else if (Name.equals_lower("mozilla")) {
1406 *Style = getMozillaStyle();
1407 } else if (Name.equals_lower("google")) {
1408 *Style = getGoogleStyle(Language);
1409 } else if (Name.equals_lower("webkit")) {
1410 *Style = getWebKitStyle();
1411 } else if (Name.equals_lower("gnu")) {
1412 *Style = getGNUStyle();
1413 } else if (Name.equals_lower("microsoft")) {
1414 *Style = getMicrosoftStyle(Language);
1415 } else if (Name.equals_lower("none")) {
1416 *Style = getNoStyle();
1417 } else if (Name.equals_lower("inheritparentconfig")) {
1418 Style->InheritsParentConfig = true;
1419 } else {
1420 return false;
1421 }
1422
1423 Style->Language = Language;
1424 return true;
1425 }
1426
parseConfiguration(llvm::MemoryBufferRef Config,FormatStyle * Style,bool AllowUnknownOptions,llvm::SourceMgr::DiagHandlerTy DiagHandler,void * DiagHandlerCtxt)1427 std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
1428 FormatStyle *Style, bool AllowUnknownOptions,
1429 llvm::SourceMgr::DiagHandlerTy DiagHandler,
1430 void *DiagHandlerCtxt) {
1431 assert(Style);
1432 FormatStyle::LanguageKind Language = Style->Language;
1433 assert(Language != FormatStyle::LK_None);
1434 if (Config.getBuffer().trim().empty())
1435 return make_error_code(ParseError::Error);
1436 Style->StyleSet.Clear();
1437 std::vector<FormatStyle> Styles;
1438 llvm::yaml::Input Input(Config, /*Ctxt=*/nullptr, DiagHandler,
1439 DiagHandlerCtxt);
1440 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
1441 // values for the fields, keys for which are missing from the configuration.
1442 // Mapping also uses the context to get the language to find the correct
1443 // base style.
1444 Input.setContext(Style);
1445 Input.setAllowUnknownKeys(AllowUnknownOptions);
1446 Input >> Styles;
1447 if (Input.error())
1448 return Input.error();
1449
1450 for (unsigned i = 0; i < Styles.size(); ++i) {
1451 // Ensures that only the first configuration can skip the Language option.
1452 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
1453 return make_error_code(ParseError::Error);
1454 // Ensure that each language is configured at most once.
1455 for (unsigned j = 0; j < i; ++j) {
1456 if (Styles[i].Language == Styles[j].Language) {
1457 LLVM_DEBUG(llvm::dbgs()
1458 << "Duplicate languages in the config file on positions "
1459 << j << " and " << i << "\n");
1460 return make_error_code(ParseError::Error);
1461 }
1462 }
1463 }
1464 // Look for a suitable configuration starting from the end, so we can
1465 // find the configuration for the specific language first, and the default
1466 // configuration (which can only be at slot 0) after it.
1467 FormatStyle::FormatStyleSet StyleSet;
1468 bool LanguageFound = false;
1469 for (int i = Styles.size() - 1; i >= 0; --i) {
1470 if (Styles[i].Language != FormatStyle::LK_None)
1471 StyleSet.Add(Styles[i]);
1472 if (Styles[i].Language == Language)
1473 LanguageFound = true;
1474 }
1475 if (!LanguageFound) {
1476 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
1477 return make_error_code(ParseError::Unsuitable);
1478 FormatStyle DefaultStyle = Styles[0];
1479 DefaultStyle.Language = Language;
1480 StyleSet.Add(std::move(DefaultStyle));
1481 }
1482 *Style = *StyleSet.Get(Language);
1483 if (Style->InsertTrailingCommas != FormatStyle::TCS_None &&
1484 Style->BinPackArguments) {
1485 // See comment on FormatStyle::TSC_Wrapped.
1486 return make_error_code(ParseError::BinPackTrailingCommaConflict);
1487 }
1488 return make_error_code(ParseError::Success);
1489 }
1490
configurationAsText(const FormatStyle & Style)1491 std::string configurationAsText(const FormatStyle &Style) {
1492 std::string Text;
1493 llvm::raw_string_ostream Stream(Text);
1494 llvm::yaml::Output Output(Stream);
1495 // We use the same mapping method for input and output, so we need a non-const
1496 // reference here.
1497 FormatStyle NonConstStyle = expandPresets(Style);
1498 Output << NonConstStyle;
1499 return Stream.str();
1500 }
1501
1502 llvm::Optional<FormatStyle>
Get(FormatStyle::LanguageKind Language) const1503 FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
1504 if (!Styles)
1505 return None;
1506 auto It = Styles->find(Language);
1507 if (It == Styles->end())
1508 return None;
1509 FormatStyle Style = It->second;
1510 Style.StyleSet = *this;
1511 return Style;
1512 }
1513
Add(FormatStyle Style)1514 void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
1515 assert(Style.Language != LK_None &&
1516 "Cannot add a style for LK_None to a StyleSet");
1517 assert(
1518 !Style.StyleSet.Styles &&
1519 "Cannot add a style associated with an existing StyleSet to a StyleSet");
1520 if (!Styles)
1521 Styles = std::make_shared<MapType>();
1522 (*Styles)[Style.Language] = std::move(Style);
1523 }
1524
Clear()1525 void FormatStyle::FormatStyleSet::Clear() { Styles.reset(); }
1526
1527 llvm::Optional<FormatStyle>
GetLanguageStyle(FormatStyle::LanguageKind Language) const1528 FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
1529 return StyleSet.Get(Language);
1530 }
1531
1532 namespace {
1533
1534 class JavaScriptRequoter : public TokenAnalyzer {
1535 public:
JavaScriptRequoter(const Environment & Env,const FormatStyle & Style)1536 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
1537 : TokenAnalyzer(Env, Style) {}
1538
1539 std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)1540 analyze(TokenAnnotator &Annotator,
1541 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1542 FormatTokenLexer &Tokens) override {
1543 AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
1544 tooling::Replacements Result;
1545 requoteJSStringLiteral(AnnotatedLines, Result);
1546 return {Result, 0};
1547 }
1548
1549 private:
1550 // Replaces double/single-quoted string literal as appropriate, re-escaping
1551 // the contents in the process.
requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine * > & Lines,tooling::Replacements & Result)1552 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
1553 tooling::Replacements &Result) {
1554 for (AnnotatedLine *Line : Lines) {
1555 requoteJSStringLiteral(Line->Children, Result);
1556 if (!Line->Affected)
1557 continue;
1558 for (FormatToken *FormatTok = Line->First; FormatTok;
1559 FormatTok = FormatTok->Next) {
1560 StringRef Input = FormatTok->TokenText;
1561 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
1562 // NB: testing for not starting with a double quote to avoid
1563 // breaking `template strings`.
1564 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
1565 !Input.startswith("\"")) ||
1566 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
1567 !Input.startswith("\'")))
1568 continue;
1569
1570 // Change start and end quote.
1571 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
1572 SourceLocation Start = FormatTok->Tok.getLocation();
1573 auto Replace = [&](SourceLocation Start, unsigned Length,
1574 StringRef ReplacementText) {
1575 auto Err = Result.add(tooling::Replacement(
1576 Env.getSourceManager(), Start, Length, ReplacementText));
1577 // FIXME: handle error. For now, print error message and skip the
1578 // replacement for release version.
1579 if (Err) {
1580 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
1581 assert(false);
1582 }
1583 };
1584 Replace(Start, 1, IsSingle ? "'" : "\"");
1585 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1586 IsSingle ? "'" : "\"");
1587
1588 // Escape internal quotes.
1589 bool Escaped = false;
1590 for (size_t i = 1; i < Input.size() - 1; i++) {
1591 switch (Input[i]) {
1592 case '\\':
1593 if (!Escaped && i + 1 < Input.size() &&
1594 ((IsSingle && Input[i + 1] == '"') ||
1595 (!IsSingle && Input[i + 1] == '\''))) {
1596 // Remove this \, it's escaping a " or ' that no longer needs
1597 // escaping
1598 Replace(Start.getLocWithOffset(i), 1, "");
1599 continue;
1600 }
1601 Escaped = !Escaped;
1602 break;
1603 case '\"':
1604 case '\'':
1605 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1606 // Escape the quote.
1607 Replace(Start.getLocWithOffset(i), 0, "\\");
1608 }
1609 Escaped = false;
1610 break;
1611 default:
1612 Escaped = false;
1613 break;
1614 }
1615 }
1616 }
1617 }
1618 }
1619 };
1620
1621 class Formatter : public TokenAnalyzer {
1622 public:
Formatter(const Environment & Env,const FormatStyle & Style,FormattingAttemptStatus * Status)1623 Formatter(const Environment &Env, const FormatStyle &Style,
1624 FormattingAttemptStatus *Status)
1625 : TokenAnalyzer(Env, Style), Status(Status) {}
1626
1627 std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)1628 analyze(TokenAnnotator &Annotator,
1629 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1630 FormatTokenLexer &Tokens) override {
1631 tooling::Replacements Result;
1632 deriveLocalStyle(AnnotatedLines);
1633 AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
1634 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1635 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1636 }
1637 Annotator.setCommentLineLevels(AnnotatedLines);
1638
1639 WhitespaceManager Whitespaces(
1640 Env.getSourceManager(), Style,
1641 Style.DeriveLineEnding
1642 ? inputUsesCRLF(
1643 Env.getSourceManager().getBufferData(Env.getFileID()),
1644 Style.UseCRLF)
1645 : Style.UseCRLF);
1646 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1647 Env.getSourceManager(), Whitespaces, Encoding,
1648 BinPackInconclusiveFunctions);
1649 unsigned Penalty =
1650 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1651 Tokens.getKeywords(), Env.getSourceManager(),
1652 Status)
1653 .format(AnnotatedLines, /*DryRun=*/false,
1654 /*AdditionalIndent=*/0,
1655 /*FixBadIndentation=*/false,
1656 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1657 /*NextStartColumn=*/Env.getNextStartColumn(),
1658 /*LastStartColumn=*/Env.getLastStartColumn());
1659 for (const auto &R : Whitespaces.generateReplacements())
1660 if (Result.add(R))
1661 return std::make_pair(Result, 0);
1662 return std::make_pair(Result, Penalty);
1663 }
1664
1665 private:
inputUsesCRLF(StringRef Text,bool DefaultToCRLF)1666 static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF) {
1667 size_t LF = Text.count('\n');
1668 size_t CR = Text.count('\r') * 2;
1669 return LF == CR ? DefaultToCRLF : CR > LF;
1670 }
1671
1672 bool
hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine * > & Lines)1673 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1674 for (const AnnotatedLine *Line : Lines) {
1675 if (hasCpp03IncompatibleFormat(Line->Children))
1676 return true;
1677 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1678 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1679 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1680 return true;
1681 if (Tok->is(TT_TemplateCloser) &&
1682 Tok->Previous->is(TT_TemplateCloser))
1683 return true;
1684 }
1685 }
1686 }
1687 return false;
1688 }
1689
countVariableAlignments(const SmallVectorImpl<AnnotatedLine * > & Lines)1690 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1691 int AlignmentDiff = 0;
1692 for (const AnnotatedLine *Line : Lines) {
1693 AlignmentDiff += countVariableAlignments(Line->Children);
1694 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1695 if (!Tok->is(TT_PointerOrReference))
1696 continue;
1697 bool SpaceBefore =
1698 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1699 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1700 Tok->Next->WhitespaceRange.getEnd();
1701 if (SpaceBefore && !SpaceAfter)
1702 ++AlignmentDiff;
1703 if (!SpaceBefore && SpaceAfter)
1704 --AlignmentDiff;
1705 }
1706 }
1707 return AlignmentDiff;
1708 }
1709
1710 void
deriveLocalStyle(const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)1711 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1712 bool HasBinPackedFunction = false;
1713 bool HasOnePerLineFunction = false;
1714 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1715 if (!AnnotatedLines[i]->First->Next)
1716 continue;
1717 FormatToken *Tok = AnnotatedLines[i]->First->Next;
1718 while (Tok->Next) {
1719 if (Tok->is(PPK_BinPacked))
1720 HasBinPackedFunction = true;
1721 if (Tok->is(PPK_OnePerLine))
1722 HasOnePerLineFunction = true;
1723
1724 Tok = Tok->Next;
1725 }
1726 }
1727 if (Style.DerivePointerAlignment)
1728 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1729 ? FormatStyle::PAS_Left
1730 : FormatStyle::PAS_Right;
1731 if (Style.Standard == FormatStyle::LS_Auto)
1732 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1733 ? FormatStyle::LS_Latest
1734 : FormatStyle::LS_Cpp03;
1735 BinPackInconclusiveFunctions =
1736 HasBinPackedFunction || !HasOnePerLineFunction;
1737 }
1738
1739 bool BinPackInconclusiveFunctions;
1740 FormattingAttemptStatus *Status;
1741 };
1742
1743 /// TrailingCommaInserter inserts trailing commas into container literals.
1744 /// E.g.:
1745 /// const x = [
1746 /// 1,
1747 /// ];
1748 /// TrailingCommaInserter runs after formatting. To avoid causing a required
1749 /// reformatting (and thus reflow), it never inserts a comma that'd exceed the
1750 /// ColumnLimit.
1751 ///
1752 /// Because trailing commas disable binpacking of arrays, TrailingCommaInserter
1753 /// is conceptually incompatible with bin packing.
1754 class TrailingCommaInserter : public TokenAnalyzer {
1755 public:
TrailingCommaInserter(const Environment & Env,const FormatStyle & Style)1756 TrailingCommaInserter(const Environment &Env, const FormatStyle &Style)
1757 : TokenAnalyzer(Env, Style) {}
1758
1759 std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)1760 analyze(TokenAnnotator &Annotator,
1761 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1762 FormatTokenLexer &Tokens) override {
1763 AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
1764 tooling::Replacements Result;
1765 insertTrailingCommas(AnnotatedLines, Result);
1766 return {Result, 0};
1767 }
1768
1769 private:
1770 /// Inserts trailing commas in [] and {} initializers if they wrap over
1771 /// multiple lines.
insertTrailingCommas(SmallVectorImpl<AnnotatedLine * > & Lines,tooling::Replacements & Result)1772 void insertTrailingCommas(SmallVectorImpl<AnnotatedLine *> &Lines,
1773 tooling::Replacements &Result) {
1774 for (AnnotatedLine *Line : Lines) {
1775 insertTrailingCommas(Line->Children, Result);
1776 if (!Line->Affected)
1777 continue;
1778 for (FormatToken *FormatTok = Line->First; FormatTok;
1779 FormatTok = FormatTok->Next) {
1780 if (FormatTok->NewlinesBefore == 0)
1781 continue;
1782 FormatToken *Matching = FormatTok->MatchingParen;
1783 if (!Matching || !FormatTok->getPreviousNonComment())
1784 continue;
1785 if (!(FormatTok->is(tok::r_square) &&
1786 Matching->is(TT_ArrayInitializerLSquare)) &&
1787 !(FormatTok->is(tok::r_brace) && Matching->is(TT_DictLiteral)))
1788 continue;
1789 FormatToken *Prev = FormatTok->getPreviousNonComment();
1790 if (Prev->is(tok::comma) || Prev->is(tok::semi))
1791 continue;
1792 // getEndLoc is not reliably set during re-lexing, use text length
1793 // instead.
1794 SourceLocation Start =
1795 Prev->Tok.getLocation().getLocWithOffset(Prev->TokenText.size());
1796 // If inserting a comma would push the code over the column limit, skip
1797 // this location - it'd introduce an unstable formatting due to the
1798 // required reflow.
1799 unsigned ColumnNumber =
1800 Env.getSourceManager().getSpellingColumnNumber(Start);
1801 if (ColumnNumber > Style.ColumnLimit)
1802 continue;
1803 // Comma insertions cannot conflict with each other, and this pass has a
1804 // clean set of Replacements, so the operation below cannot fail.
1805 cantFail(Result.add(
1806 tooling::Replacement(Env.getSourceManager(), Start, 0, ",")));
1807 }
1808 }
1809 }
1810 };
1811
1812 // This class clean up the erroneous/redundant code around the given ranges in
1813 // file.
1814 class Cleaner : public TokenAnalyzer {
1815 public:
Cleaner(const Environment & Env,const FormatStyle & Style)1816 Cleaner(const Environment &Env, const FormatStyle &Style)
1817 : TokenAnalyzer(Env, Style),
1818 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1819
1820 // FIXME: eliminate unused parameters.
1821 std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)1822 analyze(TokenAnnotator &Annotator,
1823 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1824 FormatTokenLexer &Tokens) override {
1825 // FIXME: in the current implementation the granularity of affected range
1826 // is an annotated line. However, this is not sufficient. Furthermore,
1827 // redundant code introduced by replacements does not necessarily
1828 // intercept with ranges of replacements that result in the redundancy.
1829 // To determine if some redundant code is actually introduced by
1830 // replacements(e.g. deletions), we need to come up with a more
1831 // sophisticated way of computing affected ranges.
1832 AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
1833
1834 checkEmptyNamespace(AnnotatedLines);
1835
1836 for (auto *Line : AnnotatedLines)
1837 cleanupLine(Line);
1838
1839 return {generateFixes(), 0};
1840 }
1841
1842 private:
cleanupLine(AnnotatedLine * Line)1843 void cleanupLine(AnnotatedLine *Line) {
1844 for (auto *Child : Line->Children) {
1845 cleanupLine(Child);
1846 }
1847
1848 if (Line->Affected) {
1849 cleanupRight(Line->First, tok::comma, tok::comma);
1850 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
1851 cleanupRight(Line->First, tok::l_paren, tok::comma);
1852 cleanupLeft(Line->First, tok::comma, tok::r_paren);
1853 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1854 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
1855 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
1856 }
1857 }
1858
containsOnlyComments(const AnnotatedLine & Line)1859 bool containsOnlyComments(const AnnotatedLine &Line) {
1860 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1861 if (Tok->isNot(tok::comment))
1862 return false;
1863 }
1864 return true;
1865 }
1866
1867 // Iterate through all lines and remove any empty (nested) namespaces.
checkEmptyNamespace(SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)1868 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1869 std::set<unsigned> DeletedLines;
1870 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1871 auto &Line = *AnnotatedLines[i];
1872 if (Line.startsWithNamespace()) {
1873 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
1874 }
1875 }
1876
1877 for (auto Line : DeletedLines) {
1878 FormatToken *Tok = AnnotatedLines[Line]->First;
1879 while (Tok) {
1880 deleteToken(Tok);
1881 Tok = Tok->Next;
1882 }
1883 }
1884 }
1885
1886 // The function checks if the namespace, which starts from \p CurrentLine, and
1887 // its nested namespaces are empty and delete them if they are empty. It also
1888 // sets \p NewLine to the last line checked.
1889 // Returns true if the current namespace is empty.
checkEmptyNamespace(SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,unsigned CurrentLine,unsigned & NewLine,std::set<unsigned> & DeletedLines)1890 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1891 unsigned CurrentLine, unsigned &NewLine,
1892 std::set<unsigned> &DeletedLines) {
1893 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
1894 if (Style.BraceWrapping.AfterNamespace) {
1895 // If the left brace is in a new line, we should consume it first so that
1896 // it does not make the namespace non-empty.
1897 // FIXME: error handling if there is no left brace.
1898 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1899 NewLine = CurrentLine;
1900 return false;
1901 }
1902 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1903 return false;
1904 }
1905 while (++CurrentLine < End) {
1906 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1907 break;
1908
1909 if (AnnotatedLines[CurrentLine]->startsWithNamespace()) {
1910 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1911 DeletedLines))
1912 return false;
1913 CurrentLine = NewLine;
1914 continue;
1915 }
1916
1917 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1918 continue;
1919
1920 // If there is anything other than comments or nested namespaces in the
1921 // current namespace, the namespace cannot be empty.
1922 NewLine = CurrentLine;
1923 return false;
1924 }
1925
1926 NewLine = CurrentLine;
1927 if (CurrentLine >= End)
1928 return false;
1929
1930 // Check if the empty namespace is actually affected by changed ranges.
1931 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1932 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1933 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1934 return false;
1935
1936 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1937 DeletedLines.insert(i);
1938 }
1939
1940 return true;
1941 }
1942
1943 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1944 // of the token in the pair if the left token has \p LK token kind and the
1945 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1946 // is deleted on match; otherwise, the right token is deleted.
1947 template <typename LeftKind, typename RightKind>
cleanupPair(FormatToken * Start,LeftKind LK,RightKind RK,bool DeleteLeft)1948 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1949 bool DeleteLeft) {
1950 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1951 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1952 if (!Res->is(tok::comment) &&
1953 DeletedTokens.find(Res) == DeletedTokens.end())
1954 return Res;
1955 return nullptr;
1956 };
1957 for (auto *Left = Start; Left;) {
1958 auto *Right = NextNotDeleted(*Left);
1959 if (!Right)
1960 break;
1961 if (Left->is(LK) && Right->is(RK)) {
1962 deleteToken(DeleteLeft ? Left : Right);
1963 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1964 deleteToken(Tok);
1965 // If the right token is deleted, we should keep the left token
1966 // unchanged and pair it with the new right token.
1967 if (!DeleteLeft)
1968 continue;
1969 }
1970 Left = Right;
1971 }
1972 }
1973
1974 template <typename LeftKind, typename RightKind>
cleanupLeft(FormatToken * Start,LeftKind LK,RightKind RK)1975 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1976 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1977 }
1978
1979 template <typename LeftKind, typename RightKind>
cleanupRight(FormatToken * Start,LeftKind LK,RightKind RK)1980 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1981 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1982 }
1983
1984 // Delete the given token.
deleteToken(FormatToken * Tok)1985 inline void deleteToken(FormatToken *Tok) {
1986 if (Tok)
1987 DeletedTokens.insert(Tok);
1988 }
1989
generateFixes()1990 tooling::Replacements generateFixes() {
1991 tooling::Replacements Fixes;
1992 std::vector<FormatToken *> Tokens;
1993 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1994 std::back_inserter(Tokens));
1995
1996 // Merge multiple continuous token deletions into one big deletion so that
1997 // the number of replacements can be reduced. This makes computing affected
1998 // ranges more efficient when we run reformat on the changed code.
1999 unsigned Idx = 0;
2000 while (Idx < Tokens.size()) {
2001 unsigned St = Idx, End = Idx;
2002 while ((End + 1) < Tokens.size() &&
2003 Tokens[End]->Next == Tokens[End + 1]) {
2004 End++;
2005 }
2006 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
2007 Tokens[End]->Tok.getEndLoc());
2008 auto Err =
2009 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
2010 // FIXME: better error handling. for now just print error message and skip
2011 // for the release version.
2012 if (Err) {
2013 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
2014 assert(false && "Fixes must not conflict!");
2015 }
2016 Idx = End + 1;
2017 }
2018
2019 return Fixes;
2020 }
2021
2022 // Class for less-than inequality comparason for the set `RedundantTokens`.
2023 // We store tokens in the order they appear in the translation unit so that
2024 // we do not need to sort them in `generateFixes()`.
2025 struct FormatTokenLess {
FormatTokenLessclang::format::__anon29f0ecbc0111::Cleaner::FormatTokenLess2026 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
2027
operator ()clang::format::__anon29f0ecbc0111::Cleaner::FormatTokenLess2028 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
2029 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
2030 RHS->Tok.getLocation());
2031 }
2032 const SourceManager &SM;
2033 };
2034
2035 // Tokens to be deleted.
2036 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
2037 };
2038
2039 class ObjCHeaderStyleGuesser : public TokenAnalyzer {
2040 public:
ObjCHeaderStyleGuesser(const Environment & Env,const FormatStyle & Style)2041 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
2042 : TokenAnalyzer(Env, Style), IsObjC(false) {}
2043
2044 std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)2045 analyze(TokenAnnotator &Annotator,
2046 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2047 FormatTokenLexer &Tokens) override {
2048 assert(Style.Language == FormatStyle::LK_Cpp);
2049 IsObjC = guessIsObjC(Env.getSourceManager(), AnnotatedLines,
2050 Tokens.getKeywords());
2051 tooling::Replacements Result;
2052 return {Result, 0};
2053 }
2054
isObjC()2055 bool isObjC() { return IsObjC; }
2056
2057 private:
2058 static bool
guessIsObjC(const SourceManager & SourceManager,const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,const AdditionalKeywords & Keywords)2059 guessIsObjC(const SourceManager &SourceManager,
2060 const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2061 const AdditionalKeywords &Keywords) {
2062 // Keep this array sorted, since we are binary searching over it.
2063 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
2064 "CGFloat",
2065 "CGPoint",
2066 "CGPointMake",
2067 "CGPointZero",
2068 "CGRect",
2069 "CGRectEdge",
2070 "CGRectInfinite",
2071 "CGRectMake",
2072 "CGRectNull",
2073 "CGRectZero",
2074 "CGSize",
2075 "CGSizeMake",
2076 "CGVector",
2077 "CGVectorMake",
2078 "NSAffineTransform",
2079 "NSArray",
2080 "NSAttributedString",
2081 "NSBlockOperation",
2082 "NSBundle",
2083 "NSCache",
2084 "NSCalendar",
2085 "NSCharacterSet",
2086 "NSCountedSet",
2087 "NSData",
2088 "NSDataDetector",
2089 "NSDecimal",
2090 "NSDecimalNumber",
2091 "NSDictionary",
2092 "NSEdgeInsets",
2093 "NSHashTable",
2094 "NSIndexPath",
2095 "NSIndexSet",
2096 "NSInteger",
2097 "NSInvocationOperation",
2098 "NSLocale",
2099 "NSMapTable",
2100 "NSMutableArray",
2101 "NSMutableAttributedString",
2102 "NSMutableCharacterSet",
2103 "NSMutableData",
2104 "NSMutableDictionary",
2105 "NSMutableIndexSet",
2106 "NSMutableOrderedSet",
2107 "NSMutableSet",
2108 "NSMutableString",
2109 "NSNumber",
2110 "NSNumberFormatter",
2111 "NSObject",
2112 "NSOperation",
2113 "NSOperationQueue",
2114 "NSOperationQueuePriority",
2115 "NSOrderedSet",
2116 "NSPoint",
2117 "NSPointerArray",
2118 "NSQualityOfService",
2119 "NSRange",
2120 "NSRect",
2121 "NSRegularExpression",
2122 "NSSet",
2123 "NSSize",
2124 "NSString",
2125 "NSTimeZone",
2126 "NSUInteger",
2127 "NSURL",
2128 "NSURLComponents",
2129 "NSURLQueryItem",
2130 "NSUUID",
2131 "NSValue",
2132 "UIImage",
2133 "UIView",
2134 };
2135
2136 for (auto Line : AnnotatedLines) {
2137 if (Line->First && (Line->First->TokenText.startswith("#") ||
2138 Line->First->TokenText == "__pragma" ||
2139 Line->First->TokenText == "_Pragma"))
2140 continue;
2141 for (const FormatToken *FormatTok = Line->First; FormatTok;
2142 FormatTok = FormatTok->Next) {
2143 if ((FormatTok->Previous && FormatTok->Previous->is(tok::at) &&
2144 (FormatTok->Tok.getObjCKeywordID() != tok::objc_not_keyword ||
2145 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
2146 tok::l_brace))) ||
2147 (FormatTok->Tok.isAnyIdentifier() &&
2148 std::binary_search(std::begin(FoundationIdentifiers),
2149 std::end(FoundationIdentifiers),
2150 FormatTok->TokenText)) ||
2151 FormatTok->is(TT_ObjCStringLiteral) ||
2152 FormatTok->isOneOf(Keywords.kw_NS_CLOSED_ENUM, Keywords.kw_NS_ENUM,
2153 Keywords.kw_NS_OPTIONS, TT_ObjCBlockLBrace,
2154 TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCForIn,
2155 TT_ObjCMethodExpr, TT_ObjCMethodSpecifier,
2156 TT_ObjCProperty)) {
2157 LLVM_DEBUG(llvm::dbgs()
2158 << "Detected ObjC at location "
2159 << FormatTok->Tok.getLocation().printToString(
2160 SourceManager)
2161 << " token: " << FormatTok->TokenText << " token type: "
2162 << getTokenTypeName(FormatTok->getType()) << "\n");
2163 return true;
2164 }
2165 if (guessIsObjC(SourceManager, Line->Children, Keywords))
2166 return true;
2167 }
2168 }
2169 return false;
2170 }
2171
2172 bool IsObjC;
2173 };
2174
2175 struct IncludeDirective {
2176 StringRef Filename;
2177 StringRef Text;
2178 unsigned Offset;
2179 int Category;
2180 int Priority;
2181 };
2182
2183 struct JavaImportDirective {
2184 StringRef Identifier;
2185 StringRef Text;
2186 unsigned Offset;
2187 std::vector<StringRef> AssociatedCommentLines;
2188 bool IsStatic;
2189 };
2190
2191 } // end anonymous namespace
2192
2193 // Determines whether 'Ranges' intersects with ('Start', 'End').
affectsRange(ArrayRef<tooling::Range> Ranges,unsigned Start,unsigned End)2194 static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
2195 unsigned End) {
2196 for (auto Range : Ranges) {
2197 if (Range.getOffset() < End &&
2198 Range.getOffset() + Range.getLength() > Start)
2199 return true;
2200 }
2201 return false;
2202 }
2203
2204 // Returns a pair (Index, OffsetToEOL) describing the position of the cursor
2205 // before sorting/deduplicating. Index is the index of the include under the
2206 // cursor in the original set of includes. If this include has duplicates, it is
2207 // the index of the first of the duplicates as the others are going to be
2208 // removed. OffsetToEOL describes the cursor's position relative to the end of
2209 // its current line.
2210 // If `Cursor` is not on any #include, `Index` will be UINT_MAX.
2211 static std::pair<unsigned, unsigned>
FindCursorIndex(const SmallVectorImpl<IncludeDirective> & Includes,const SmallVectorImpl<unsigned> & Indices,unsigned Cursor)2212 FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
2213 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
2214 unsigned CursorIndex = UINT_MAX;
2215 unsigned OffsetToEOL = 0;
2216 for (int i = 0, e = Includes.size(); i != e; ++i) {
2217 unsigned Start = Includes[Indices[i]].Offset;
2218 unsigned End = Start + Includes[Indices[i]].Text.size();
2219 if (!(Cursor >= Start && Cursor < End))
2220 continue;
2221 CursorIndex = Indices[i];
2222 OffsetToEOL = End - Cursor;
2223 // Put the cursor on the only remaining #include among the duplicate
2224 // #includes.
2225 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
2226 CursorIndex = i;
2227 break;
2228 }
2229 return std::make_pair(CursorIndex, OffsetToEOL);
2230 }
2231
2232 // Replace all "\r\n" with "\n".
replaceCRLF(const std::string & Code)2233 std::string replaceCRLF(const std::string &Code) {
2234 std::string NewCode;
2235 size_t Pos = 0, LastPos = 0;
2236
2237 do {
2238 Pos = Code.find("\r\n", LastPos);
2239 if (Pos == LastPos) {
2240 LastPos++;
2241 continue;
2242 }
2243 if (Pos == std::string::npos) {
2244 NewCode += Code.substr(LastPos);
2245 break;
2246 }
2247 NewCode += Code.substr(LastPos, Pos - LastPos) + "\n";
2248 LastPos = Pos + 2;
2249 } while (Pos != std::string::npos);
2250
2251 return NewCode;
2252 }
2253
2254 // Sorts and deduplicate a block of includes given by 'Includes' alphabetically
2255 // adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
2256 // source order.
2257 // #include directives with the same text will be deduplicated, and only the
2258 // first #include in the duplicate #includes remains. If the `Cursor` is
2259 // provided and put on a deleted #include, it will be moved to the remaining
2260 // #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)2261 static void sortCppIncludes(const FormatStyle &Style,
2262 const SmallVectorImpl<IncludeDirective> &Includes,
2263 ArrayRef<tooling::Range> Ranges, StringRef FileName,
2264 StringRef Code, tooling::Replacements &Replaces,
2265 unsigned *Cursor) {
2266 tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName);
2267 unsigned IncludesBeginOffset = Includes.front().Offset;
2268 unsigned IncludesEndOffset =
2269 Includes.back().Offset + Includes.back().Text.size();
2270 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
2271 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
2272 return;
2273 SmallVector<unsigned, 16> Indices;
2274 for (unsigned i = 0, e = Includes.size(); i != e; ++i) {
2275 Indices.push_back(i);
2276 }
2277
2278 if (Style.SortIncludes == FormatStyle::SI_CaseInsensitive) {
2279 llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
2280 const auto LHSFilenameLower = Includes[LHSI].Filename.lower();
2281 const auto RHSFilenameLower = Includes[RHSI].Filename.lower();
2282 return std::tie(Includes[LHSI].Priority, LHSFilenameLower,
2283 Includes[LHSI].Filename) <
2284 std::tie(Includes[RHSI].Priority, RHSFilenameLower,
2285 Includes[RHSI].Filename);
2286 });
2287 } else {
2288 llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
2289 return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) <
2290 std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename);
2291 });
2292 }
2293
2294 // The index of the include on which the cursor will be put after
2295 // sorting/deduplicating.
2296 unsigned CursorIndex;
2297 // The offset from cursor to the end of line.
2298 unsigned CursorToEOLOffset;
2299 if (Cursor)
2300 std::tie(CursorIndex, CursorToEOLOffset) =
2301 FindCursorIndex(Includes, Indices, *Cursor);
2302
2303 // Deduplicate #includes.
2304 Indices.erase(std::unique(Indices.begin(), Indices.end(),
2305 [&](unsigned LHSI, unsigned RHSI) {
2306 return Includes[LHSI].Text.trim() ==
2307 Includes[RHSI].Text.trim();
2308 }),
2309 Indices.end());
2310
2311 int CurrentCategory = Includes.front().Category;
2312
2313 // If the #includes are out of order, we generate a single replacement fixing
2314 // the entire block. Otherwise, no replacement is generated.
2315 // In case Style.IncldueStyle.IncludeBlocks != IBS_Preserve, this check is not
2316 // enough as additional newlines might be added or removed across #include
2317 // blocks. This we handle below by generating the updated #imclude blocks and
2318 // comparing it to the original.
2319 if (Indices.size() == Includes.size() && llvm::is_sorted(Indices) &&
2320 Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Preserve)
2321 return;
2322
2323 std::string result;
2324 for (unsigned Index : Indices) {
2325 if (!result.empty()) {
2326 result += "\n";
2327 if (Style.IncludeStyle.IncludeBlocks ==
2328 tooling::IncludeStyle::IBS_Regroup &&
2329 CurrentCategory != Includes[Index].Category)
2330 result += "\n";
2331 }
2332 result += Includes[Index].Text;
2333 if (Cursor && CursorIndex == Index)
2334 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
2335 CurrentCategory = Includes[Index].Category;
2336 }
2337
2338 // If the #includes are out of order, we generate a single replacement fixing
2339 // the entire range of blocks. Otherwise, no replacement is generated.
2340 if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr(
2341 IncludesBeginOffset, IncludesBlockSize))))
2342 return;
2343
2344 auto Err = Replaces.add(tooling::Replacement(
2345 FileName, Includes.front().Offset, IncludesBlockSize, result));
2346 // FIXME: better error handling. For now, just skip the replacement for the
2347 // release version.
2348 if (Err) {
2349 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
2350 assert(false);
2351 }
2352 }
2353
2354 namespace {
2355
2356 const char CppIncludeRegexPattern[] =
2357 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
2358
2359 } // anonymous namespace
2360
sortCppIncludes(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName,tooling::Replacements & Replaces,unsigned * Cursor)2361 tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
2362 ArrayRef<tooling::Range> Ranges,
2363 StringRef FileName,
2364 tooling::Replacements &Replaces,
2365 unsigned *Cursor) {
2366 unsigned Prev = llvm::StringSwitch<size_t>(Code)
2367 .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
2368 .Default(0);
2369 unsigned SearchFrom = 0;
2370 llvm::Regex IncludeRegex(CppIncludeRegexPattern);
2371 SmallVector<StringRef, 4> Matches;
2372 SmallVector<IncludeDirective, 16> IncludesInBlock;
2373
2374 // In compiled files, consider the first #include to be the main #include of
2375 // the file if it is not a system #include. This ensures that the header
2376 // doesn't have hidden dependencies
2377 // (http://llvm.org/docs/CodingStandards.html#include-style).
2378 //
2379 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
2380 // cases where the first #include is unlikely to be the main header.
2381 tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName);
2382 bool FirstIncludeBlock = true;
2383 bool MainIncludeFound = false;
2384 bool FormattingOff = false;
2385
2386 for (;;) {
2387 auto Pos = Code.find('\n', SearchFrom);
2388 StringRef Line =
2389 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
2390
2391 StringRef Trimmed = Line.trim();
2392 if (Trimmed == "// clang-format off" || Trimmed == "/* clang-format off */")
2393 FormattingOff = true;
2394 else if (Trimmed == "// clang-format on" ||
2395 Trimmed == "/* clang-format on */")
2396 FormattingOff = false;
2397
2398 const bool EmptyLineSkipped =
2399 Trimmed.empty() &&
2400 (Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Merge ||
2401 Style.IncludeStyle.IncludeBlocks ==
2402 tooling::IncludeStyle::IBS_Regroup);
2403
2404 bool MergeWithNextLine = Trimmed.endswith("\\");
2405 if (!FormattingOff && !MergeWithNextLine) {
2406 if (IncludeRegex.match(Line, &Matches)) {
2407 StringRef IncludeName = Matches[2];
2408 int Category = Categories.getIncludePriority(
2409 IncludeName,
2410 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
2411 int Priority = Categories.getSortIncludePriority(
2412 IncludeName, !MainIncludeFound && FirstIncludeBlock);
2413 if (Category == 0)
2414 MainIncludeFound = true;
2415 IncludesInBlock.push_back(
2416 {IncludeName, Line, Prev, Category, Priority});
2417 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
2418 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code,
2419 Replaces, Cursor);
2420 IncludesInBlock.clear();
2421 if (Trimmed.startswith("#pragma hdrstop")) // Precompiled headers.
2422 FirstIncludeBlock = true;
2423 else
2424 FirstIncludeBlock = false;
2425 }
2426 }
2427 if (Pos == StringRef::npos || Pos + 1 == Code.size())
2428 break;
2429
2430 if (!MergeWithNextLine)
2431 Prev = Pos + 1;
2432 SearchFrom = Pos + 1;
2433 }
2434 if (!IncludesInBlock.empty()) {
2435 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces,
2436 Cursor);
2437 }
2438 return Replaces;
2439 }
2440
2441 // Returns group number to use as a first order sort on imports. Gives UINT_MAX
2442 // if the import does not match any given groups.
findJavaImportGroup(const FormatStyle & Style,StringRef ImportIdentifier)2443 static unsigned findJavaImportGroup(const FormatStyle &Style,
2444 StringRef ImportIdentifier) {
2445 unsigned LongestMatchIndex = UINT_MAX;
2446 unsigned LongestMatchLength = 0;
2447 for (unsigned I = 0; I < Style.JavaImportGroups.size(); I++) {
2448 std::string GroupPrefix = Style.JavaImportGroups[I];
2449 if (ImportIdentifier.startswith(GroupPrefix) &&
2450 GroupPrefix.length() > LongestMatchLength) {
2451 LongestMatchIndex = I;
2452 LongestMatchLength = GroupPrefix.length();
2453 }
2454 }
2455 return LongestMatchIndex;
2456 }
2457
2458 // Sorts and deduplicates a block of includes given by 'Imports' based on
2459 // JavaImportGroups, then adding the necessary replacement to 'Replaces'.
2460 // Import declarations with the same text will be deduplicated. Between each
2461 // import group, a newline is inserted, and within each import group, a
2462 // 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)2463 static void sortJavaImports(const FormatStyle &Style,
2464 const SmallVectorImpl<JavaImportDirective> &Imports,
2465 ArrayRef<tooling::Range> Ranges, StringRef FileName,
2466 StringRef Code, tooling::Replacements &Replaces) {
2467 unsigned ImportsBeginOffset = Imports.front().Offset;
2468 unsigned ImportsEndOffset =
2469 Imports.back().Offset + Imports.back().Text.size();
2470 unsigned ImportsBlockSize = ImportsEndOffset - ImportsBeginOffset;
2471 if (!affectsRange(Ranges, ImportsBeginOffset, ImportsEndOffset))
2472 return;
2473 SmallVector<unsigned, 16> Indices;
2474 SmallVector<unsigned, 16> JavaImportGroups;
2475 for (unsigned i = 0, e = Imports.size(); i != e; ++i) {
2476 Indices.push_back(i);
2477 JavaImportGroups.push_back(
2478 findJavaImportGroup(Style, Imports[i].Identifier));
2479 }
2480 bool StaticImportAfterNormalImport =
2481 Style.SortJavaStaticImport == FormatStyle::SJSIO_After;
2482 llvm::sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
2483 // Negating IsStatic to push static imports above non-static imports.
2484 return std::make_tuple(!Imports[LHSI].IsStatic ^
2485 StaticImportAfterNormalImport,
2486 JavaImportGroups[LHSI], Imports[LHSI].Identifier) <
2487 std::make_tuple(!Imports[RHSI].IsStatic ^
2488 StaticImportAfterNormalImport,
2489 JavaImportGroups[RHSI], Imports[RHSI].Identifier);
2490 });
2491
2492 // Deduplicate imports.
2493 Indices.erase(std::unique(Indices.begin(), Indices.end(),
2494 [&](unsigned LHSI, unsigned RHSI) {
2495 return Imports[LHSI].Text == Imports[RHSI].Text;
2496 }),
2497 Indices.end());
2498
2499 bool CurrentIsStatic = Imports[Indices.front()].IsStatic;
2500 unsigned CurrentImportGroup = JavaImportGroups[Indices.front()];
2501
2502 std::string result;
2503 for (unsigned Index : Indices) {
2504 if (!result.empty()) {
2505 result += "\n";
2506 if (CurrentIsStatic != Imports[Index].IsStatic ||
2507 CurrentImportGroup != JavaImportGroups[Index])
2508 result += "\n";
2509 }
2510 for (StringRef CommentLine : Imports[Index].AssociatedCommentLines) {
2511 result += CommentLine;
2512 result += "\n";
2513 }
2514 result += Imports[Index].Text;
2515 CurrentIsStatic = Imports[Index].IsStatic;
2516 CurrentImportGroup = JavaImportGroups[Index];
2517 }
2518
2519 // If the imports are out of order, we generate a single replacement fixing
2520 // the entire block. Otherwise, no replacement is generated.
2521 if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr(
2522 Imports.front().Offset, ImportsBlockSize))))
2523 return;
2524
2525 auto Err = Replaces.add(tooling::Replacement(FileName, Imports.front().Offset,
2526 ImportsBlockSize, result));
2527 // FIXME: better error handling. For now, just skip the replacement for the
2528 // release version.
2529 if (Err) {
2530 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
2531 assert(false);
2532 }
2533 }
2534
2535 namespace {
2536
2537 const char JavaImportRegexPattern[] =
2538 "^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
2539
2540 } // anonymous namespace
2541
sortJavaImports(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName,tooling::Replacements & Replaces)2542 tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
2543 ArrayRef<tooling::Range> Ranges,
2544 StringRef FileName,
2545 tooling::Replacements &Replaces) {
2546 unsigned Prev = 0;
2547 unsigned SearchFrom = 0;
2548 llvm::Regex ImportRegex(JavaImportRegexPattern);
2549 SmallVector<StringRef, 4> Matches;
2550 SmallVector<JavaImportDirective, 16> ImportsInBlock;
2551 std::vector<StringRef> AssociatedCommentLines;
2552
2553 bool FormattingOff = false;
2554
2555 for (;;) {
2556 auto Pos = Code.find('\n', SearchFrom);
2557 StringRef Line =
2558 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
2559
2560 StringRef Trimmed = Line.trim();
2561 if (Trimmed == "// clang-format off")
2562 FormattingOff = true;
2563 else if (Trimmed == "// clang-format on")
2564 FormattingOff = false;
2565
2566 if (ImportRegex.match(Line, &Matches)) {
2567 if (FormattingOff) {
2568 // If at least one import line has formatting turned off, turn off
2569 // formatting entirely.
2570 return Replaces;
2571 }
2572 StringRef Static = Matches[1];
2573 StringRef Identifier = Matches[2];
2574 bool IsStatic = false;
2575 if (Static.contains("static")) {
2576 IsStatic = true;
2577 }
2578 ImportsInBlock.push_back(
2579 {Identifier, Line, Prev, AssociatedCommentLines, IsStatic});
2580 AssociatedCommentLines.clear();
2581 } else if (Trimmed.size() > 0 && !ImportsInBlock.empty()) {
2582 // Associating comments within the imports with the nearest import below
2583 AssociatedCommentLines.push_back(Line);
2584 }
2585 Prev = Pos + 1;
2586 if (Pos == StringRef::npos || Pos + 1 == Code.size())
2587 break;
2588 SearchFrom = Pos + 1;
2589 }
2590 if (!ImportsInBlock.empty())
2591 sortJavaImports(Style, ImportsInBlock, Ranges, FileName, Code, Replaces);
2592 return Replaces;
2593 }
2594
isMpegTS(StringRef Code)2595 bool isMpegTS(StringRef Code) {
2596 // MPEG transport streams use the ".ts" file extension. clang-format should
2597 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
2598 // 189 bytes - detect that and return.
2599 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
2600 }
2601
isLikelyXml(StringRef Code)2602 bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
2603
sortIncludes(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName,unsigned * Cursor)2604 tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
2605 ArrayRef<tooling::Range> Ranges,
2606 StringRef FileName, unsigned *Cursor) {
2607 tooling::Replacements Replaces;
2608 if (!Style.SortIncludes || Style.DisableFormat)
2609 return Replaces;
2610 if (isLikelyXml(Code))
2611 return Replaces;
2612 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
2613 isMpegTS(Code))
2614 return Replaces;
2615 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
2616 return sortJavaScriptImports(Style, Code, Ranges, FileName);
2617 if (Style.Language == FormatStyle::LanguageKind::LK_Java)
2618 return sortJavaImports(Style, Code, Ranges, FileName, Replaces);
2619 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
2620 return Replaces;
2621 }
2622
2623 template <typename T>
2624 static llvm::Expected<tooling::Replacements>
processReplacements(T ProcessFunc,StringRef Code,const tooling::Replacements & Replaces,const FormatStyle & Style)2625 processReplacements(T ProcessFunc, StringRef Code,
2626 const tooling::Replacements &Replaces,
2627 const FormatStyle &Style) {
2628 if (Replaces.empty())
2629 return tooling::Replacements();
2630
2631 auto NewCode = applyAllReplacements(Code, Replaces);
2632 if (!NewCode)
2633 return NewCode.takeError();
2634 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
2635 StringRef FileName = Replaces.begin()->getFilePath();
2636
2637 tooling::Replacements FormatReplaces =
2638 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
2639
2640 return Replaces.merge(FormatReplaces);
2641 }
2642
2643 llvm::Expected<tooling::Replacements>
formatReplacements(StringRef Code,const tooling::Replacements & Replaces,const FormatStyle & Style)2644 formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
2645 const FormatStyle &Style) {
2646 // We need to use lambda function here since there are two versions of
2647 // `sortIncludes`.
2648 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
2649 std::vector<tooling::Range> Ranges,
2650 StringRef FileName) -> tooling::Replacements {
2651 return sortIncludes(Style, Code, Ranges, FileName);
2652 };
2653 auto SortedReplaces =
2654 processReplacements(SortIncludes, Code, Replaces, Style);
2655 if (!SortedReplaces)
2656 return SortedReplaces.takeError();
2657
2658 // We need to use lambda function here since there are two versions of
2659 // `reformat`.
2660 auto Reformat = [](const FormatStyle &Style, StringRef Code,
2661 std::vector<tooling::Range> Ranges,
2662 StringRef FileName) -> tooling::Replacements {
2663 return reformat(Style, Code, Ranges, FileName);
2664 };
2665 return processReplacements(Reformat, Code, *SortedReplaces, Style);
2666 }
2667
2668 namespace {
2669
isHeaderInsertion(const tooling::Replacement & Replace)2670 inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
2671 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
2672 llvm::Regex(CppIncludeRegexPattern)
2673 .match(Replace.getReplacementText());
2674 }
2675
isHeaderDeletion(const tooling::Replacement & Replace)2676 inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
2677 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
2678 }
2679
2680 // FIXME: insert empty lines between newly created blocks.
2681 tooling::Replacements
fixCppIncludeInsertions(StringRef Code,const tooling::Replacements & Replaces,const FormatStyle & Style)2682 fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
2683 const FormatStyle &Style) {
2684 if (!Style.isCpp())
2685 return Replaces;
2686
2687 tooling::Replacements HeaderInsertions;
2688 std::set<llvm::StringRef> HeadersToDelete;
2689 tooling::Replacements Result;
2690 for (const auto &R : Replaces) {
2691 if (isHeaderInsertion(R)) {
2692 // Replacements from \p Replaces must be conflict-free already, so we can
2693 // simply consume the error.
2694 llvm::consumeError(HeaderInsertions.add(R));
2695 } else if (isHeaderDeletion(R)) {
2696 HeadersToDelete.insert(R.getReplacementText());
2697 } else if (R.getOffset() == UINT_MAX) {
2698 llvm::errs() << "Insertions other than header #include insertion are "
2699 "not supported! "
2700 << R.getReplacementText() << "\n";
2701 } else {
2702 llvm::consumeError(Result.add(R));
2703 }
2704 }
2705 if (HeaderInsertions.empty() && HeadersToDelete.empty())
2706 return Replaces;
2707
2708 StringRef FileName = Replaces.begin()->getFilePath();
2709 tooling::HeaderIncludes Includes(FileName, Code, Style.IncludeStyle);
2710
2711 for (const auto &Header : HeadersToDelete) {
2712 tooling::Replacements Replaces =
2713 Includes.remove(Header.trim("\"<>"), Header.startswith("<"));
2714 for (const auto &R : Replaces) {
2715 auto Err = Result.add(R);
2716 if (Err) {
2717 // Ignore the deletion on conflict.
2718 llvm::errs() << "Failed to add header deletion replacement for "
2719 << Header << ": " << llvm::toString(std::move(Err))
2720 << "\n";
2721 }
2722 }
2723 }
2724
2725 llvm::Regex IncludeRegex = llvm::Regex(CppIncludeRegexPattern);
2726 llvm::SmallVector<StringRef, 4> Matches;
2727 for (const auto &R : HeaderInsertions) {
2728 auto IncludeDirective = R.getReplacementText();
2729 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2730 assert(Matched && "Header insertion replacement must have replacement text "
2731 "'#include ...'");
2732 (void)Matched;
2733 auto IncludeName = Matches[2];
2734 auto Replace =
2735 Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"));
2736 if (Replace) {
2737 auto Err = Result.add(*Replace);
2738 if (Err) {
2739 llvm::consumeError(std::move(Err));
2740 unsigned NewOffset =
2741 Result.getShiftedCodePosition(Replace->getOffset());
2742 auto Shifted = tooling::Replacement(FileName, NewOffset, 0,
2743 Replace->getReplacementText());
2744 Result = Result.merge(tooling::Replacements(Shifted));
2745 }
2746 }
2747 }
2748 return Result;
2749 }
2750
2751 } // anonymous namespace
2752
2753 llvm::Expected<tooling::Replacements>
cleanupAroundReplacements(StringRef Code,const tooling::Replacements & Replaces,const FormatStyle & Style)2754 cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2755 const FormatStyle &Style) {
2756 // We need to use lambda function here since there are two versions of
2757 // `cleanup`.
2758 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2759 std::vector<tooling::Range> Ranges,
2760 StringRef FileName) -> tooling::Replacements {
2761 return cleanup(Style, Code, Ranges, FileName);
2762 };
2763 // Make header insertion replacements insert new headers into correct blocks.
2764 tooling::Replacements NewReplaces =
2765 fixCppIncludeInsertions(Code, Replaces, Style);
2766 return processReplacements(Cleanup, Code, NewReplaces, Style);
2767 }
2768
2769 namespace internal {
2770 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)2771 reformat(const FormatStyle &Style, StringRef Code,
2772 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2773 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2774 FormattingAttemptStatus *Status) {
2775 FormatStyle Expanded = expandPresets(Style);
2776 if (Expanded.DisableFormat)
2777 return {tooling::Replacements(), 0};
2778 if (isLikelyXml(Code))
2779 return {tooling::Replacements(), 0};
2780 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
2781 return {tooling::Replacements(), 0};
2782
2783 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2784 const Environment &)>
2785 AnalyzerPass;
2786 SmallVector<AnalyzerPass, 4> Passes;
2787
2788 if (Style.Language == FormatStyle::LK_Cpp) {
2789 if (Style.FixNamespaceComments)
2790 Passes.emplace_back([&](const Environment &Env) {
2791 return NamespaceEndCommentsFixer(Env, Expanded).process();
2792 });
2793
2794 if (Style.SortUsingDeclarations)
2795 Passes.emplace_back([&](const Environment &Env) {
2796 return UsingDeclarationsSorter(Env, Expanded).process();
2797 });
2798 }
2799
2800 if (Style.Language == FormatStyle::LK_JavaScript &&
2801 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2802 Passes.emplace_back([&](const Environment &Env) {
2803 return JavaScriptRequoter(Env, Expanded).process();
2804 });
2805
2806 Passes.emplace_back([&](const Environment &Env) {
2807 return Formatter(Env, Expanded, Status).process();
2808 });
2809
2810 if (Style.Language == FormatStyle::LK_JavaScript &&
2811 Style.InsertTrailingCommas == FormatStyle::TCS_Wrapped)
2812 Passes.emplace_back([&](const Environment &Env) {
2813 return TrailingCommaInserter(Env, Expanded).process();
2814 });
2815
2816 auto Env =
2817 std::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn,
2818 NextStartColumn, LastStartColumn);
2819 llvm::Optional<std::string> CurrentCode = None;
2820 tooling::Replacements Fixes;
2821 unsigned Penalty = 0;
2822 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
2823 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
2824 auto NewCode = applyAllReplacements(
2825 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
2826 if (NewCode) {
2827 Fixes = Fixes.merge(PassFixes.first);
2828 Penalty += PassFixes.second;
2829 if (I + 1 < E) {
2830 CurrentCode = std::move(*NewCode);
2831 Env = std::make_unique<Environment>(
2832 *CurrentCode, FileName,
2833 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2834 FirstStartColumn, NextStartColumn, LastStartColumn);
2835 }
2836 }
2837 }
2838
2839 return {Fixes, Penalty};
2840 }
2841 } // namespace internal
2842
reformat(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName,FormattingAttemptStatus * Status)2843 tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2844 ArrayRef<tooling::Range> Ranges,
2845 StringRef FileName,
2846 FormattingAttemptStatus *Status) {
2847 return internal::reformat(Style, Code, Ranges,
2848 /*FirstStartColumn=*/0,
2849 /*NextStartColumn=*/0,
2850 /*LastStartColumn=*/0, FileName, Status)
2851 .first;
2852 }
2853
cleanup(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName)2854 tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2855 ArrayRef<tooling::Range> Ranges,
2856 StringRef FileName) {
2857 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2858 if (Style.Language != FormatStyle::LK_Cpp)
2859 return tooling::Replacements();
2860 return Cleaner(Environment(Code, FileName, Ranges), Style).process().first;
2861 }
2862
reformat(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName,bool * IncompleteFormat)2863 tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2864 ArrayRef<tooling::Range> Ranges,
2865 StringRef FileName, bool *IncompleteFormat) {
2866 FormattingAttemptStatus Status;
2867 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2868 if (!Status.FormatComplete)
2869 *IncompleteFormat = true;
2870 return Result;
2871 }
2872
fixNamespaceEndComments(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName)2873 tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2874 StringRef Code,
2875 ArrayRef<tooling::Range> Ranges,
2876 StringRef FileName) {
2877 return NamespaceEndCommentsFixer(Environment(Code, FileName, Ranges), Style)
2878 .process()
2879 .first;
2880 }
2881
sortUsingDeclarations(const FormatStyle & Style,StringRef Code,ArrayRef<tooling::Range> Ranges,StringRef FileName)2882 tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2883 StringRef Code,
2884 ArrayRef<tooling::Range> Ranges,
2885 StringRef FileName) {
2886 return UsingDeclarationsSorter(Environment(Code, FileName, Ranges), Style)
2887 .process()
2888 .first;
2889 }
2890
getFormattingLangOpts(const FormatStyle & Style)2891 LangOptions getFormattingLangOpts(const FormatStyle &Style) {
2892 LangOptions LangOpts;
2893
2894 FormatStyle::LanguageStandard LexingStd = Style.Standard;
2895 if (LexingStd == FormatStyle::LS_Auto)
2896 LexingStd = FormatStyle::LS_Latest;
2897 if (LexingStd == FormatStyle::LS_Latest)
2898 LexingStd = FormatStyle::LS_Cpp20;
2899 LangOpts.CPlusPlus = 1;
2900 LangOpts.CPlusPlus11 = LexingStd >= FormatStyle::LS_Cpp11;
2901 LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp14;
2902 LangOpts.CPlusPlus17 = LexingStd >= FormatStyle::LS_Cpp17;
2903 LangOpts.CPlusPlus20 = LexingStd >= FormatStyle::LS_Cpp20;
2904 LangOpts.Char8 = LexingStd >= FormatStyle::LS_Cpp20;
2905
2906 LangOpts.LineComment = 1;
2907 bool AlternativeOperators = Style.isCpp();
2908 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
2909 LangOpts.Bool = 1;
2910 LangOpts.ObjC = 1;
2911 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
2912 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
2913 LangOpts.C99 = 1; // To get kw_restrict for non-underscore-prefixed restrict.
2914 return LangOpts;
2915 }
2916
2917 const char *StyleOptionHelpDescription =
2918 "Coding style, currently supports:\n"
2919 " LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit.\n"
2920 "Use -style=file to load style configuration from\n"
2921 ".clang-format file located in one of the parent\n"
2922 "directories of the source file (or current\n"
2923 "directory for stdin).\n"
2924 "Use -style=\"{key: value, ...}\" to set specific\n"
2925 "parameters, e.g.:\n"
2926 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2927
getLanguageByFileName(StringRef FileName)2928 static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
2929 if (FileName.endswith(".java"))
2930 return FormatStyle::LK_Java;
2931 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".mjs") ||
2932 FileName.endswith_lower(".ts"))
2933 return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript.
2934 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2935 return FormatStyle::LK_ObjC;
2936 if (FileName.endswith_lower(".proto") ||
2937 FileName.endswith_lower(".protodevel"))
2938 return FormatStyle::LK_Proto;
2939 if (FileName.endswith_lower(".textpb") ||
2940 FileName.endswith_lower(".pb.txt") ||
2941 FileName.endswith_lower(".textproto") ||
2942 FileName.endswith_lower(".asciipb"))
2943 return FormatStyle::LK_TextProto;
2944 if (FileName.endswith_lower(".td"))
2945 return FormatStyle::LK_TableGen;
2946 if (FileName.endswith_lower(".cs"))
2947 return FormatStyle::LK_CSharp;
2948 return FormatStyle::LK_Cpp;
2949 }
2950
guessLanguage(StringRef FileName,StringRef Code)2951 FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
2952 const auto GuessedLanguage = getLanguageByFileName(FileName);
2953 if (GuessedLanguage == FormatStyle::LK_Cpp) {
2954 auto Extension = llvm::sys::path::extension(FileName);
2955 // If there's no file extension (or it's .h), we need to check the contents
2956 // of the code to see if it contains Objective-C.
2957 if (Extension.empty() || Extension == ".h") {
2958 auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
2959 Environment Env(Code, NonEmptyFileName, /*Ranges=*/{});
2960 ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle());
2961 Guesser.process();
2962 if (Guesser.isObjC())
2963 return FormatStyle::LK_ObjC;
2964 }
2965 }
2966 return GuessedLanguage;
2967 }
2968
2969 const char *DefaultFormatStyle = "file";
2970
2971 const char *DefaultFallbackStyle = "LLVM";
2972
getStyle(StringRef StyleName,StringRef FileName,StringRef FallbackStyleName,StringRef Code,llvm::vfs::FileSystem * FS,bool AllowUnknownOptions)2973 llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
2974 StringRef FallbackStyleName,
2975 StringRef Code, llvm::vfs::FileSystem *FS,
2976 bool AllowUnknownOptions) {
2977 if (!FS) {
2978 FS = llvm::vfs::getRealFileSystem().get();
2979 }
2980 FormatStyle Style = getLLVMStyle(guessLanguage(FileName, Code));
2981
2982 FormatStyle FallbackStyle = getNoStyle();
2983 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2984 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
2985
2986 llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1>
2987 ChildFormatTextToApply;
2988
2989 if (StyleName.startswith("{")) {
2990 // Parse YAML/JSON style from the command line.
2991 StringRef Source = "<command-line>";
2992 if (std::error_code ec =
2993 parseConfiguration(llvm::MemoryBufferRef(StyleName, Source), &Style,
2994 AllowUnknownOptions))
2995 return make_string_error("Error parsing -style: " + ec.message());
2996 if (Style.InheritsParentConfig)
2997 ChildFormatTextToApply.emplace_back(
2998 llvm::MemoryBuffer::getMemBuffer(StyleName, Source, false));
2999 else
3000 return Style;
3001 }
3002
3003 // If the style inherits the parent configuration it is a command line
3004 // configuration, which wants to inherit, so we have to skip the check of the
3005 // StyleName.
3006 if (!Style.InheritsParentConfig && !StyleName.equals_lower("file")) {
3007 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
3008 return make_string_error("Invalid value for -style");
3009 if (!Style.InheritsParentConfig)
3010 return Style;
3011 }
3012
3013 // Reset possible inheritance
3014 Style.InheritsParentConfig = false;
3015
3016 // Look for .clang-format/_clang-format file in the file's parent directories.
3017 SmallString<128> UnsuitableConfigFiles;
3018 SmallString<128> Path(FileName);
3019 if (std::error_code EC = FS->makeAbsolute(Path))
3020 return make_string_error(EC.message());
3021
3022 llvm::SmallVector<std::string, 2> FilesToLookFor;
3023 FilesToLookFor.push_back(".clang-format");
3024 FilesToLookFor.push_back("_clang-format");
3025
3026 auto dropDiagnosticHandler = [](const llvm::SMDiagnostic &, void *) {};
3027
3028 for (StringRef Directory = Path; !Directory.empty();
3029 Directory = llvm::sys::path::parent_path(Directory)) {
3030
3031 auto Status = FS->status(Directory);
3032 if (!Status ||
3033 Status->getType() != llvm::sys::fs::file_type::directory_file) {
3034 continue;
3035 }
3036
3037 for (const auto &F : FilesToLookFor) {
3038 SmallString<128> ConfigFile(Directory);
3039
3040 llvm::sys::path::append(ConfigFile, F);
3041 LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
3042
3043 Status = FS->status(ConfigFile.str());
3044
3045 if (Status &&
3046 (Status->getType() == llvm::sys::fs::file_type::regular_file)) {
3047 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
3048 FS->getBufferForFile(ConfigFile.str());
3049 if (std::error_code EC = Text.getError())
3050 return make_string_error(EC.message());
3051 if (std::error_code ec =
3052 parseConfiguration(*Text.get(), &Style, AllowUnknownOptions)) {
3053 if (ec == ParseError::Unsuitable) {
3054 if (!UnsuitableConfigFiles.empty())
3055 UnsuitableConfigFiles.append(", ");
3056 UnsuitableConfigFiles.append(ConfigFile);
3057 continue;
3058 }
3059 return make_string_error("Error reading " + ConfigFile + ": " +
3060 ec.message());
3061 }
3062 LLVM_DEBUG(llvm::dbgs()
3063 << "Using configuration file " << ConfigFile << "\n");
3064
3065 if (!Style.InheritsParentConfig) {
3066 if (ChildFormatTextToApply.empty())
3067 return Style;
3068
3069 LLVM_DEBUG(llvm::dbgs() << "Applying child configurations\n");
3070
3071 for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
3072 auto Ec = parseConfiguration(*MemBuf, &Style, AllowUnknownOptions,
3073 dropDiagnosticHandler);
3074 // It was already correctly parsed.
3075 assert(!Ec);
3076 static_cast<void>(Ec);
3077 }
3078
3079 return Style;
3080 }
3081
3082 LLVM_DEBUG(llvm::dbgs() << "Inherits parent configuration\n");
3083
3084 // Reset inheritance of style
3085 Style.InheritsParentConfig = false;
3086
3087 ChildFormatTextToApply.emplace_back(std::move(*Text));
3088
3089 // Breaking out of the inner loop, since we don't want to parse
3090 // .clang-format AND _clang-format, if both exist. Then we continue the
3091 // inner loop (parent directories) in search for the parent
3092 // configuration.
3093 break;
3094 }
3095 }
3096 }
3097 if (!UnsuitableConfigFiles.empty())
3098 return make_string_error("Configuration file(s) do(es) not support " +
3099 getLanguageName(Style.Language) + ": " +
3100 UnsuitableConfigFiles);
3101
3102 if (!ChildFormatTextToApply.empty()) {
3103 assert(ChildFormatTextToApply.size() == 1);
3104
3105 LLVM_DEBUG(llvm::dbgs()
3106 << "Applying child configuration on fallback style\n");
3107
3108 auto Ec =
3109 parseConfiguration(*ChildFormatTextToApply.front(), &FallbackStyle,
3110 AllowUnknownOptions, dropDiagnosticHandler);
3111 // It was already correctly parsed.
3112 assert(!Ec);
3113 static_cast<void>(Ec);
3114 }
3115
3116 return FallbackStyle;
3117 }
3118
3119 } // namespace format
3120 } // namespace clang
3121