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