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