• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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