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