blob: 3044b3a56e2fedb2dffca66d8c2b538586950669 [file] [log] [blame]
Daniel Jasperf7935112012-12-03 18:12:45 +00001//===--- Format.cpp - Format C++ code -------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements functions declared in Format.h. This will be
12/// split into separate files as we go.
13///
Daniel Jasperf7935112012-12-03 18:12:45 +000014//===----------------------------------------------------------------------===//
15
Daniel Jasper85c472d2015-09-29 07:53:08 +000016#include "clang/Format/Format.h"
Eric Liu4cfb88a2016-04-25 15:09:22 +000017#include "AffectedRangeManager.h"
Daniel Jasperde0328a2013-08-16 11:20:30 +000018#include "ContinuationIndenter.h"
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +000019#include "FormatInternal.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000020#include "FormatTokenLexer.h"
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +000021#include "NamespaceEndCommentsFixer.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000022#include "SortJavaScriptImports.h"
23#include "TokenAnalyzer.h"
Daniel Jasper7a6d09b2013-01-29 21:01:14 +000024#include "TokenAnnotator.h"
Daniel Jasper0df50932014-12-10 19:00:42 +000025#include "UnwrappedLineFormatter.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000026#include "UnwrappedLineParser.h"
Krasimir Georgievb03877a2017-06-21 12:03:12 +000027#include "UsingDeclarationsSorter.h"
Alexander Kornienkocb45bc12013-04-15 14:28:00 +000028#include "WhitespaceManager.h"
Daniel Jasperec04c0d2013-05-16 10:40:07 +000029#include "clang/Basic/Diagnostic.h"
Benjamin Kramerf3ca26982014-05-10 16:31:55 +000030#include "clang/Basic/DiagnosticOptions.h"
Chandler Carruth44eb4f62013-01-02 10:28:36 +000031#include "clang/Basic/SourceManager.h"
Marianne Mailhot-Sarrasin4988fa12016-04-14 14:47:37 +000032#include "clang/Basic/VirtualFileSystem.h"
Daniel Jasperf7935112012-12-03 18:12:45 +000033#include "clang/Lex/Lexer.h"
Alexander Kornienkoffd6d042013-03-27 11:52:18 +000034#include "llvm/ADT/STLExtras.h"
Ben Hamiltone2e3e672018-01-17 17:33:08 +000035#include "llvm/ADT/StringRef.h"
Manuel Klimek2ef908e2013-02-13 10:46:36 +000036#include "llvm/Support/Allocator.h"
Manuel Klimek24998102013-01-16 14:55:28 +000037#include "llvm/Support/Debug.h"
Edwin Vaned544aa72013-09-30 13:31:48 +000038#include "llvm/Support/Path.h"
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +000039#include "llvm/Support/Regex.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000040#include "llvm/Support/YAMLTraits.h"
Martin Probst081f1762016-06-01 15:19:53 +000041#include <algorithm>
Eric Liu4cfb88a2016-04-25 15:09:22 +000042#include <memory>
Daniel Jasper8b529712012-12-04 13:02:32 +000043#include <string>
44
Chandler Carruth10346662014-04-22 03:17:02 +000045#define DEBUG_TYPE "format-formatter"
46
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000047using clang::format::FormatStyle;
48
NAKAMURA Takumi057a9422017-11-01 04:43:22 +000049LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
50LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
Daniel Jaspere1e43192014-04-01 12:55:11 +000051
Alexander Kornienkod6538332013-05-07 15:32:14 +000052namespace llvm {
53namespace yaml {
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000054template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
55 static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
56 IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
Daniel Jasperc58c70e2014-09-15 11:21:46 +000057 IO.enumCase(Value, "Java", FormatStyle::LK_Java);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000058 IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
Daniel Jasper03a04fe2016-12-12 12:42:29 +000059 IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
Daniel Jasper7052ce62014-01-19 09:04:08 +000060 IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
Daniel Jasper498f5582015-12-25 08:53:31 +000061 IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
Krasimir Georgiev26b144c2017-07-03 15:05:14 +000062 IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000063 }
64};
65
66template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
67 static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
68 IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
69 IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
70 IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
71 IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
72 IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
73 }
74};
75
76template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
77 static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
78 IO.enumCase(Value, "Never", FormatStyle::UT_Never);
79 IO.enumCase(Value, "false", FormatStyle::UT_Never);
80 IO.enumCase(Value, "Always", FormatStyle::UT_Always);
81 IO.enumCase(Value, "true", FormatStyle::UT_Always);
82 IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
Marianne Mailhot-Sarrasin51fe2792016-04-14 14:52:26 +000083 IO.enumCase(Value, "ForContinuationAndIndentation",
84 FormatStyle::UT_ForContinuationAndIndentation);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000085 }
86};
87
Daniel Jasperabd1f572016-03-02 22:44:03 +000088template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
89 static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
90 IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
91 IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
92 IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
93 }
94};
95
Daniel Jasperd74cf402014-04-08 12:46:38 +000096template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
97 static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
98 IO.enumCase(Value, "None", FormatStyle::SFS_None);
99 IO.enumCase(Value, "false", FormatStyle::SFS_None);
100 IO.enumCase(Value, "All", FormatStyle::SFS_All);
101 IO.enumCase(Value, "true", FormatStyle::SFS_All);
102 IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
Francois Ferrandd3f0e3d2017-06-21 13:56:02 +0000103 IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
Daniel Jasper9e709352014-11-26 10:43:58 +0000104 IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
Daniel Jasperd74cf402014-04-08 12:46:38 +0000105 }
106};
107
Daniel Jasperac043c92014-09-15 11:11:00 +0000108template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
109 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
110 IO.enumCase(Value, "All", FormatStyle::BOS_All);
111 IO.enumCase(Value, "true", FormatStyle::BOS_All);
112 IO.enumCase(Value, "None", FormatStyle::BOS_None);
113 IO.enumCase(Value, "false", FormatStyle::BOS_None);
114 IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
115 }
116};
117
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000118template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
119 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
120 IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
121 IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000122 IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000123 IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
124 IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000125 IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000126 IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000127 IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000128 }
129};
130
Manuel Klimek89628f62017-09-20 09:51:03 +0000131template <>
132struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
133 static void
134 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
Francois Ferranda6b6d512017-05-24 11:36:58 +0000135 IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
136 IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
137 IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
138 }
139};
140
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000141template <>
Krasimir Georgievad47c902017-08-30 14:34:57 +0000142struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
143 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
144 IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
145 IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
146 }
147};
148
149template <>
Zachary Turner448592e2015-12-18 22:20:15 +0000150struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
151 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
152 IO.enumCase(Value, "None", FormatStyle::RTBS_None);
153 IO.enumCase(Value, "All", FormatStyle::RTBS_All);
154 IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
155 IO.enumCase(Value, "TopLevelDefinitions",
156 FormatStyle::RTBS_TopLevelDefinitions);
157 IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
158 }
159};
160
161template <>
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000162struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
163 static void
164 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000165 IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
166 IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
167 IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
168
169 // For backward compatibility.
170 IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
171 IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
172 }
173};
174
Alexander Kornienkod6538332013-05-07 15:32:14 +0000175template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000176struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000177 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000178 FormatStyle::NamespaceIndentationKind &Value) {
179 IO.enumCase(Value, "None", FormatStyle::NI_None);
180 IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
181 IO.enumCase(Value, "All", FormatStyle::NI_All);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000182 }
183};
184
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000185template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
186 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
187 IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
188 IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
189 IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
190
191 // For backward compatibility.
192 IO.enumCase(Value, "true", FormatStyle::BAS_Align);
193 IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
194 }
195};
196
Manuel Klimek89628f62017-09-20 09:51:03 +0000197template <>
198struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
199 static void enumeration(IO &IO,
200 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000201 IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
202 IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
203 IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
204
205 // For backward compatibility.
206 IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
207 IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
208 }
209};
210
Jacques Pienaarfc275112015-02-18 23:48:37 +0000211template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
212 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
Daniel Jasper553d4872014-06-17 12:40:34 +0000213 IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
214 IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
215 IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
216
Alp Toker958027b2014-07-14 19:42:55 +0000217 // For backward compatibility.
Daniel Jasper553d4872014-06-17 12:40:34 +0000218 IO.enumCase(Value, "true", FormatStyle::PAS_Left);
219 IO.enumCase(Value, "false", FormatStyle::PAS_Right);
220 }
221};
222
223template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000224struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
Manuel Klimeka8eb9142013-05-13 12:51:40 +0000225 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000226 FormatStyle::SpaceBeforeParensOptions &Value) {
227 IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000228 IO.enumCase(Value, "ControlStatements",
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000229 FormatStyle::SBPO_ControlStatements);
230 IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000231
232 // For backward compatibility.
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000233 IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
234 IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000235 }
236};
237
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000238template <> struct MappingTraits<FormatStyle> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000239 static void mapping(IO &IO, FormatStyle &Style) {
240 // When reading, read the language first, we need it for getPredefinedStyle.
241 IO.mapOptional("Language", Style.Language);
242
Alexander Kornienko49149672013-05-10 11:56:10 +0000243 if (IO.outputting()) {
Jacques Pienaarfc275112015-02-18 23:48:37 +0000244 StringRef StylesArray[] = {"LLVM", "Google", "Chromium",
245 "Mozilla", "WebKit", "GNU"};
Alexander Kornienko49149672013-05-10 11:56:10 +0000246 ArrayRef<StringRef> Styles(StylesArray);
247 for (size_t i = 0, e = Styles.size(); i < e; ++i) {
248 StringRef StyleName(Styles[i]);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000249 FormatStyle PredefinedStyle;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000250 if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000251 Style == PredefinedStyle) {
Alexander Kornienko49149672013-05-10 11:56:10 +0000252 IO.mapOptional("# BasedOnStyle", StyleName);
253 break;
254 }
255 }
256 } else {
Alexander Kornienkod6538332013-05-07 15:32:14 +0000257 StringRef BasedOnStyle;
258 IO.mapOptional("BasedOnStyle", BasedOnStyle);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000259 if (!BasedOnStyle.empty()) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000260 FormatStyle::LanguageKind OldLanguage = Style.Language;
261 FormatStyle::LanguageKind Language =
262 ((FormatStyle *)IO.getContext())->Language;
263 if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000264 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
265 return;
266 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000267 Style.Language = OldLanguage;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000268 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000269 }
270
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000271 // For backward compatibility.
272 if (!IO.outputting()) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000273 IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000274 IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
275 IO.mapOptional("IndentFunctionDeclarationAfterType",
276 Style.IndentWrappedFunctionNames);
277 IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
278 IO.mapOptional("SpaceAfterControlStatementKeyword",
279 Style.SpaceBeforeParens);
280 }
281
Alexander Kornienkod6538332013-05-07 15:32:14 +0000282 IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
Daniel Jasper3aa9a6a2014-11-18 23:55:27 +0000283 IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000284 IO.mapOptional("AlignConsecutiveAssignments",
285 Style.AlignConsecutiveAssignments);
Daniel Jaspere12597c2015-10-01 10:06:54 +0000286 IO.mapOptional("AlignConsecutiveDeclarations",
287 Style.AlignConsecutiveDeclarations);
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000288 IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
Daniel Jasper3219e432014-12-02 13:24:51 +0000289 IO.mapOptional("AlignOperands", Style.AlignOperands);
Daniel Jasper552f4a72013-07-31 23:55:15 +0000290 IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000291 IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
292 Style.AllowAllParametersOfDeclarationOnNextLine);
Daniel Jasper17605d32014-05-14 09:33:35 +0000293 IO.mapOptional("AllowShortBlocksOnASingleLine",
294 Style.AllowShortBlocksOnASingleLine);
Daniel Jasperb87899b2014-09-10 13:11:45 +0000295 IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
296 Style.AllowShortCaseLabelsOnASingleLine);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000297 IO.mapOptional("AllowShortFunctionsOnASingleLine",
298 Style.AllowShortFunctionsOnASingleLine);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000299 IO.mapOptional("AllowShortIfStatementsOnASingleLine",
300 Style.AllowShortIfStatementsOnASingleLine);
Daniel Jasper3a685df2013-05-16 12:12:21 +0000301 IO.mapOptional("AllowShortLoopsOnASingleLine",
302 Style.AllowShortLoopsOnASingleLine);
Daniel Jasperca4ea1c2014-08-05 12:16:31 +0000303 IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
304 Style.AlwaysBreakAfterDefinitionReturnType);
Zachary Turner448592e2015-12-18 22:20:15 +0000305 IO.mapOptional("AlwaysBreakAfterReturnType",
306 Style.AlwaysBreakAfterReturnType);
307 // If AlwaysBreakAfterDefinitionReturnType was specified but
308 // AlwaysBreakAfterReturnType was not, initialize the latter from the
309 // former for backwards compatibility.
310 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
311 Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
312 if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
313 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
314 else if (Style.AlwaysBreakAfterDefinitionReturnType ==
315 FormatStyle::DRTBS_TopLevel)
316 Style.AlwaysBreakAfterReturnType =
317 FormatStyle::RTBS_TopLevelDefinitions;
318 }
319
Alexander Kornienko58611712013-07-04 12:02:44 +0000320 IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
321 Style.AlwaysBreakBeforeMultilineStrings);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000322 IO.mapOptional("AlwaysBreakTemplateDeclarations",
323 Style.AlwaysBreakTemplateDeclarations);
324 IO.mapOptional("BinPackArguments", Style.BinPackArguments);
325 IO.mapOptional("BinPackParameters", Style.BinPackParameters);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000326 IO.mapOptional("BraceWrapping", Style.BraceWrapping);
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000327 IO.mapOptional("BreakBeforeBinaryOperators",
328 Style.BreakBeforeBinaryOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000329 IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
Francois Ferrande56a8292017-06-14 12:29:47 +0000330 IO.mapOptional("BreakBeforeInheritanceComma",
331 Style.BreakBeforeInheritanceComma);
Daniel Jasper165b29e2013-11-08 00:57:11 +0000332 IO.mapOptional("BreakBeforeTernaryOperators",
333 Style.BreakBeforeTernaryOperators);
Francois Ferranda6b6d512017-05-24 11:36:58 +0000334
335 bool BreakConstructorInitializersBeforeComma = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000336 IO.mapOptional("BreakConstructorInitializersBeforeComma",
Francois Ferranda6b6d512017-05-24 11:36:58 +0000337 BreakConstructorInitializersBeforeComma);
338 IO.mapOptional("BreakConstructorInitializers",
339 Style.BreakConstructorInitializers);
340 // If BreakConstructorInitializersBeforeComma was specified but
341 // BreakConstructorInitializers was not, initialize the latter from the
342 // former for backwards compatibility.
343 if (BreakConstructorInitializersBeforeComma &&
344 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
345 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
346
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000347 IO.mapOptional("BreakAfterJavaFieldAnnotations",
348 Style.BreakAfterJavaFieldAnnotations);
349 IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000350 IO.mapOptional("ColumnLimit", Style.ColumnLimit);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000351 IO.mapOptional("CommentPragmas", Style.CommentPragmas);
Francois Ferrande56a8292017-06-14 12:29:47 +0000352 IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000353 IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
354 Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000355 IO.mapOptional("ConstructorInitializerIndentWidth",
356 Style.ConstructorInitializerIndentWidth);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000357 IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
358 IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
Daniel Jasper553d4872014-06-17 12:40:34 +0000359 IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000360 IO.mapOptional("DisableFormat", Style.DisableFormat);
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000361 IO.mapOptional("ExperimentalAutoDetectBinPacking",
362 Style.ExperimentalAutoDetectBinPacking);
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000363 IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000364 IO.mapOptional("ForEachMacros", Style.ForEachMacros);
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000365 IO.mapOptional("IncludeBlocks", Style.IncludeBlocks);
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000366 IO.mapOptional("IncludeCategories", Style.IncludeCategories);
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000367 IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000368 IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
Krasimir Georgievad47c902017-08-30 14:34:57 +0000369 IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000370 IO.mapOptional("IndentWidth", Style.IndentWidth);
371 IO.mapOptional("IndentWrappedFunctionNames",
372 Style.IndentWrappedFunctionNames);
Martin Probst0cd74ee2016-06-13 16:39:50 +0000373 IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
374 IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000375 IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
376 Style.KeepEmptyLinesAtTheStartOfBlocks);
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +0000377 IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
378 IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000379 IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
Daniel Jasper65ee3472013-07-31 23:16:02 +0000380 IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000381 IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
Daniel Jaspere9beea22014-01-28 15:20:33 +0000382 IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000383 IO.mapOptional("ObjCSpaceBeforeProtocolList",
384 Style.ObjCSpaceBeforeProtocolList);
Manuel Klimek89628f62017-09-20 09:51:03 +0000385 IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
Daniel Jasper33b909c2013-10-25 14:29:37 +0000386 IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
387 Style.PenaltyBreakBeforeFirstCallParameter);
Alexander Kornienkodd7ece52013-06-07 16:02:52 +0000388 IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000389 IO.mapOptional("PenaltyBreakFirstLessLess",
390 Style.PenaltyBreakFirstLessLess);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000391 IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000392 IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
393 IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
394 Style.PenaltyReturnTypeOnItsOwnLine);
Daniel Jasper553d4872014-06-17 12:40:34 +0000395 IO.mapOptional("PointerAlignment", Style.PointerAlignment);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000396 IO.mapOptional("RawStringFormats", Style.RawStringFormats);
Daniel Jaspera0a50392015-12-01 13:28:53 +0000397 IO.mapOptional("ReflowComments", Style.ReflowComments);
398 IO.mapOptional("SortIncludes", Style.SortIncludes);
Krasimir Georgievac16a202017-06-23 11:46:03 +0000399 IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000400 IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
Manuel Klimek89628f62017-09-20 09:51:03 +0000401 IO.mapOptional("SpaceAfterTemplateKeyword",
402 Style.SpaceAfterTemplateKeyword);
Daniel Jasperd94bff32013-09-25 15:15:02 +0000403 IO.mapOptional("SpaceBeforeAssignmentOperators",
404 Style.SpaceBeforeAssignmentOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000405 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
406 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
407 IO.mapOptional("SpacesBeforeTrailingComments",
408 Style.SpacesBeforeTrailingComments);
409 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
410 IO.mapOptional("SpacesInContainerLiterals",
411 Style.SpacesInContainerLiterals);
412 IO.mapOptional("SpacesInCStyleCastParentheses",
413 Style.SpacesInCStyleCastParentheses);
414 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
415 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
416 IO.mapOptional("Standard", Style.Standard);
417 IO.mapOptional("TabWidth", Style.TabWidth);
418 IO.mapOptional("UseTab", Style.UseTab);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000419 }
420};
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000421
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000422template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
423 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
424 IO.mapOptional("AfterClass", Wrapping.AfterClass);
425 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
426 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
427 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
428 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
429 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
430 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
431 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000432 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000433 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
434 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
435 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
Francois Ferrandad722562017-06-30 20:25:55 +0000436 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
437 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
438 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000439 }
440};
441
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000442template <> struct MappingTraits<FormatStyle::IncludeCategory> {
443 static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
444 IO.mapOptional("Regex", Category.Regex);
445 IO.mapOptional("Priority", Category.Priority);
446 }
447};
448
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000449template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> {
450 static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
451 IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve);
452 IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge);
453 IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup);
454 }
455};
456
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000457template <> struct MappingTraits<FormatStyle::RawStringFormat> {
458 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000459 IO.mapOptional("Language", Format.Language);
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000460 IO.mapOptional("Delimiters", Format.Delimiters);
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000461 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000462 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
463 }
464};
465
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000466// Allows to read vector<FormatStyle> while keeping default values.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000467// IO.getContext() should contain a pointer to the FormatStyle structure, that
468// will be used to get default values for missing keys.
469// If the first element has no Language specified, it will be treated as the
470// default one for the following elements.
Jacques Pienaarfc275112015-02-18 23:48:37 +0000471template <> struct DocumentListTraits<std::vector<FormatStyle>> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000472 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
473 return Seq.size();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000474 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000475 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000476 size_t Index) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000477 if (Index >= Seq.size()) {
478 assert(Index == Seq.size());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000479 FormatStyle Template;
Krasimir Georgiev1696bb62017-11-09 15:12:17 +0000480 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000481 Template = Seq[0];
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000482 } else {
Daniel Jasperb05a81d2014-05-09 13:11:16 +0000483 Template = *((const FormatStyle *)IO.getContext());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000484 Template.Language = FormatStyle::LK_None;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000485 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000486 Seq.resize(Index + 1, Template);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000487 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000488 return Seq[Index];
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000489 }
490};
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000491} // namespace yaml
492} // namespace llvm
Alexander Kornienkod6538332013-05-07 15:32:14 +0000493
Daniel Jasperf7935112012-12-03 18:12:45 +0000494namespace clang {
495namespace format {
496
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000497const std::error_category &getParseCategory() {
Rafael Espindolad0136702014-06-12 02:50:04 +0000498 static ParseErrorCategory C;
499 return C;
500}
501std::error_code make_error_code(ParseError e) {
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000502 return std::error_code(static_cast<int>(e), getParseCategory());
Rafael Espindolad0136702014-06-12 02:50:04 +0000503}
504
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +0000505inline llvm::Error make_string_error(const llvm::Twine &Message) {
506 return llvm::make_error<llvm::StringError>(Message,
507 llvm::inconvertibleErrorCode());
508}
509
Reid Kleckner6432d452016-10-19 23:39:55 +0000510const char *ParseErrorCategory::name() const noexcept {
Rafael Espindolad0136702014-06-12 02:50:04 +0000511 return "clang-format.parse_error";
512}
513
514std::string ParseErrorCategory::message(int EV) const {
515 switch (static_cast<ParseError>(EV)) {
516 case ParseError::Success:
517 return "Success";
518 case ParseError::Error:
519 return "Invalid argument";
520 case ParseError::Unsuitable:
521 return "Unsuitable";
522 }
Saleem Abdulrasoolfbfbaf62014-06-12 19:33:26 +0000523 llvm_unreachable("unexpected parse error");
Rafael Espindolad0136702014-06-12 02:50:04 +0000524}
525
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000526static FormatStyle expandPresets(const FormatStyle &Style) {
Daniel Jasper55bbe662015-10-07 04:06:10 +0000527 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
528 return Style;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000529 FormatStyle Expanded = Style;
Manuel Klimek89628f62017-09-20 09:51:03 +0000530 Expanded.BraceWrapping = {false, false, false, false, false,
531 false, false, false, false, false,
532 false, false, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000533 switch (Style.BreakBeforeBraces) {
534 case FormatStyle::BS_Linux:
535 Expanded.BraceWrapping.AfterClass = true;
536 Expanded.BraceWrapping.AfterFunction = true;
537 Expanded.BraceWrapping.AfterNamespace = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000538 break;
539 case FormatStyle::BS_Mozilla:
540 Expanded.BraceWrapping.AfterClass = true;
541 Expanded.BraceWrapping.AfterEnum = true;
542 Expanded.BraceWrapping.AfterFunction = true;
543 Expanded.BraceWrapping.AfterStruct = true;
544 Expanded.BraceWrapping.AfterUnion = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000545 Expanded.BraceWrapping.AfterExternBlock = true;
Sylvestre Ledru82c9a0e2017-09-13 20:03:29 +0000546 Expanded.BraceWrapping.SplitEmptyFunction = true;
Francois Ferrandad722562017-06-30 20:25:55 +0000547 Expanded.BraceWrapping.SplitEmptyRecord = false;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000548 break;
549 case FormatStyle::BS_Stroustrup:
550 Expanded.BraceWrapping.AfterFunction = true;
551 Expanded.BraceWrapping.BeforeCatch = true;
552 Expanded.BraceWrapping.BeforeElse = true;
553 break;
554 case FormatStyle::BS_Allman:
555 Expanded.BraceWrapping.AfterClass = true;
556 Expanded.BraceWrapping.AfterControlStatement = true;
557 Expanded.BraceWrapping.AfterEnum = true;
558 Expanded.BraceWrapping.AfterFunction = true;
559 Expanded.BraceWrapping.AfterNamespace = true;
560 Expanded.BraceWrapping.AfterObjCDeclaration = true;
561 Expanded.BraceWrapping.AfterStruct = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000562 Expanded.BraceWrapping.AfterExternBlock = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000563 Expanded.BraceWrapping.BeforeCatch = true;
564 Expanded.BraceWrapping.BeforeElse = true;
565 break;
566 case FormatStyle::BS_GNU:
Manuel Klimek89628f62017-09-20 09:51:03 +0000567 Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
568 true, true, true, true, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000569 break;
570 case FormatStyle::BS_WebKit:
571 Expanded.BraceWrapping.AfterFunction = true;
572 break;
573 default:
574 break;
575 }
576 return Expanded;
577}
578
Daniel Jasperf7935112012-12-03 18:12:45 +0000579FormatStyle getLLVMStyle() {
580 FormatStyle LLVMStyle;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000581 LLVMStyle.Language = FormatStyle::LK_Cpp;
Daniel Jasperf7935112012-12-03 18:12:45 +0000582 LLVMStyle.AccessModifierOffset = -2;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000583 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000584 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
Daniel Jasper3219e432014-12-02 13:24:51 +0000585 LLVMStyle.AlignOperands = true;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000586 LLVMStyle.AlignTrailingComments = true;
Daniel Jaspera44991332015-04-29 13:06:49 +0000587 LLVMStyle.AlignConsecutiveAssignments = false;
Daniel Jaspere12597c2015-10-01 10:06:54 +0000588 LLVMStyle.AlignConsecutiveDeclarations = false;
Daniel Jasperf7db4332013-01-29 16:03:49 +0000589 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
Daniel Jasperd74cf402014-04-08 12:46:38 +0000590 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Daniel Jasper17605d32014-05-14 09:33:35 +0000591 LLVMStyle.AllowShortBlocksOnASingleLine = false;
Daniel Jasperb87899b2014-09-10 13:11:45 +0000592 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000593 LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper3a685df2013-05-16 12:12:21 +0000594 LLVMStyle.AllowShortLoopsOnASingleLine = false;
Zachary Turner448592e2015-12-18 22:20:15 +0000595 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000596 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Alexander Kornienko58611712013-07-04 12:02:44 +0000597 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000598 LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Daniel Jasper18210d72014-10-09 09:52:05 +0000599 LLVMStyle.BinPackArguments = true;
Francois Ferrande56a8292017-06-14 12:29:47 +0000600 LLVMStyle.BinPackParameters = true;
Daniel Jasperac043c92014-09-15 11:11:00 +0000601 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Daniel Jasper165b29e2013-11-08 00:57:11 +0000602 LLVMStyle.BreakBeforeTernaryOperators = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000603 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
Manuel Klimek89628f62017-09-20 09:51:03 +0000604 LLVMStyle.BraceWrapping = {false, false, false, false, false,
605 false, false, false, false, false,
606 false, false, true, true, true};
Nico Weber2cd92f12015-10-15 16:03:01 +0000607 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000608 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000609 LLVMStyle.BreakBeforeInheritanceComma = false;
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000610 LLVMStyle.BreakStringLiterals = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000611 LLVMStyle.ColumnLimit = 80;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000612 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
Francois Ferrande56a8292017-06-14 12:29:47 +0000613 LLVMStyle.CompactNamespaces = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000614 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
Daniel Jaspercdaffa42013-08-13 10:58:30 +0000615 LLVMStyle.ConstructorInitializerIndentWidth = 4;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000616 LLVMStyle.ContinuationIndentWidth = 4;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000617 LLVMStyle.Cpp11BracedListStyle = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000618 LLVMStyle.DerivePointerAlignment = false;
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000619 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000620 LLVMStyle.FixNamespaceComments = true;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000621 LLVMStyle.ForEachMacros.push_back("foreach");
622 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
623 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
Daniel Jasper85c472d2015-09-29 07:53:08 +0000624 LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
Chandler Carruthd676ab12017-06-29 23:20:54 +0000625 {"^(<|\"(gtest|gmock|isl|json)/)", 3},
Daniel Jasper85c472d2015-09-29 07:53:08 +0000626 {".*", 1}};
Chandler Carruthd676ab12017-06-29 23:20:54 +0000627 LLVMStyle.IncludeIsMainRegex = "(Test)?$";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000628 LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000629 LLVMStyle.IndentCaseLabels = false;
Krasimir Georgievad47c902017-08-30 14:34:57 +0000630 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
Daniel Jasperc75e1ef2014-07-09 08:42:42 +0000631 LLVMStyle.IndentWrappedFunctionNames = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000632 LLVMStyle.IndentWidth = 2;
Martin Probstfb2342d2016-06-13 17:50:10 +0000633 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
634 LLVMStyle.JavaScriptWrapImports = true;
Alexander Kornienkoebb43ca2013-09-05 14:08:34 +0000635 LLVMStyle.TabWidth = 8;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000636 LLVMStyle.MaxEmptyLinesToKeep = 1;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000637 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000638 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000639 LLVMStyle.ObjCBlockIndentWidth = 2;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000640 LLVMStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000641 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000642 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000643 LLVMStyle.SpacesBeforeTrailingComments = 1;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000644 LLVMStyle.Standard = FormatStyle::LS_Cpp11;
Alexander Kornienko3c3d09c2013-09-27 16:14:22 +0000645 LLVMStyle.UseTab = FormatStyle::UT_Never;
Daniel Jaspera0a50392015-12-01 13:28:53 +0000646 LLVMStyle.ReflowComments = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000647 LLVMStyle.SpacesInParentheses = false;
Daniel Jasperad981f82014-08-26 11:41:14 +0000648 LLVMStyle.SpacesInSquareBrackets = false;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000649 LLVMStyle.SpaceInEmptyParentheses = false;
Daniel Jasperb2e10a52014-01-15 15:09:08 +0000650 LLVMStyle.SpacesInContainerLiterals = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000651 LLVMStyle.SpacesInCStyleCastParentheses = false;
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000652 LLVMStyle.SpaceAfterCStyleCast = false;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000653 LLVMStyle.SpaceAfterTemplateKeyword = true;
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000654 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
Daniel Jasperd94bff32013-09-25 15:15:02 +0000655 LLVMStyle.SpaceBeforeAssignmentOperators = true;
Daniel Jasperdd978ae2013-10-29 14:52:02 +0000656 LLVMStyle.SpacesInAngles = false;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000657
Francois Ferrand9976efa2017-05-22 08:28:17 +0000658 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
Daniel Jasper19a541e2013-12-19 16:45:34 +0000659 LLVMStyle.PenaltyBreakComment = 300;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000660 LLVMStyle.PenaltyBreakFirstLessLess = 120;
661 LLVMStyle.PenaltyBreakString = 1000;
662 LLVMStyle.PenaltyExcessCharacter = 1000000;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000663 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000664 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000665
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000666 LLVMStyle.DisableFormat = false;
Daniel Jasperda446772015-11-16 12:38:56 +0000667 LLVMStyle.SortIncludes = true;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000668 LLVMStyle.SortUsingDeclarations = true;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000669
Daniel Jasperf7935112012-12-03 18:12:45 +0000670 return LLVMStyle;
671}
672
Nico Weber514ecc82014-02-02 20:50:45 +0000673FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000674 if (Language == FormatStyle::LK_TextProto) {
675 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
676 GoogleStyle.Language = FormatStyle::LK_TextProto;
677 return GoogleStyle;
678 }
679
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000680 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000681 GoogleStyle.Language = Language;
682
Daniel Jasperf7935112012-12-03 18:12:45 +0000683 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000684 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000685 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000686 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000687 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000688 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000689 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000690 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000691 GoogleStyle.IncludeCategories = {
692 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000693 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000694 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000695 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000696 GoogleStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000697 GoogleStyle.ObjCSpaceBeforeProtocolList = false;
Daniel Jasper553d4872014-06-17 12:40:34 +0000698 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000699 GoogleStyle.RawStringFormats = {{
700 FormatStyle::LK_TextProto,
701 /*Delimiters=*/
702 {
703 "pb",
704 "PB",
705 "proto",
706 "PROTO",
707 "textproto",
708 "TEXTPROTO",
709 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000710 /*EnclosingFunctionNames=*/
711 {
712 "EqualsProto",
713 "PARSE_TEXT_PROTO",
714 "ParseTextProto",
715 },
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000716 /*BasedOnStyle=*/"google",
717 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000718 GoogleStyle.SpacesBeforeTrailingComments = 2;
719 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000720
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000721 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000722 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000723
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000724 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000725 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000726 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000727 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000728 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000729 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000730 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000731 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
732 GoogleStyle.ColumnLimit = 100;
733 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000734 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000735 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000736 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000737 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000738 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000739 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000740 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000741 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
742 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
743 GoogleStyle.CommentPragmas =
744 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000745 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000746 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000747 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000748 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000749 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000750 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000751 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper783bac62014-04-15 09:54:30 +0000752 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000753 } else if (Language == FormatStyle::LK_ObjC) {
754 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000755 }
756
Daniel Jasperf7935112012-12-03 18:12:45 +0000757 return GoogleStyle;
758}
759
Nico Weber514ecc82014-02-02 20:50:45 +0000760FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
761 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000762 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000763 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000764 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000765 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000766 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000767 } else if (Language == FormatStyle::LK_JavaScript) {
768 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
769 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000770 } else {
771 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
772 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
773 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
774 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
775 ChromiumStyle.BinPackParameters = false;
776 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000777 if (Language == FormatStyle::LK_ObjC)
778 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000779 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000780 return ChromiumStyle;
781}
782
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000783FormatStyle getMozillaStyle() {
784 FormatStyle MozillaStyle = getLLVMStyle();
785 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000786 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000787 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000788 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
789 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000790 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000791 MozillaStyle.BinPackParameters = false;
792 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000793 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000794 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000795 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000796 MozillaStyle.ConstructorInitializerIndentWidth = 2;
797 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000798 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000799 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000800 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000801 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000802 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
803 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000804 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000805 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000806 return MozillaStyle;
807}
808
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000809FormatStyle getWebKitStyle() {
810 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000811 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000812 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000813 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000814 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000815 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000816 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000817 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000818 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000819 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000820 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000821 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000822 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000823 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000824 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000825 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000826 return Style;
827}
828
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000829FormatStyle getGNUStyle() {
830 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000831 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000832 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000833 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000834 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000835 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000836 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000837 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000838 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000839 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000840 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000841 return Style;
842}
843
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000844FormatStyle getNoStyle() {
845 FormatStyle NoStyle = getLLVMStyle();
846 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000847 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000848 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000849 return NoStyle;
850}
851
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000852bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
853 FormatStyle *Style) {
854 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000855 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000856 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000857 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000858 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000859 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000860 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000861 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000862 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000863 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000864 } else if (Name.equals_lower("gnu")) {
865 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000866 } else if (Name.equals_lower("none")) {
867 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000868 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000869 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000870 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000871
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000872 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000873 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000874}
875
Rafael Espindolac0809172014-06-12 14:02:15 +0000876std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000877 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000878 FormatStyle::LanguageKind Language = Style->Language;
879 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000880 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000881 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000882 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000883 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000884 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000885 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
886 // values for the fields, keys for which are missing from the configuration.
887 // Mapping also uses the context to get the language to find the correct
888 // base style.
889 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000890 Input >> Styles;
891 if (Input.error())
892 return Input.error();
893
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000894 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000895 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000896 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000897 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000898 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000899 for (unsigned j = 0; j < i; ++j) {
900 if (Styles[i].Language == Styles[j].Language) {
901 DEBUG(llvm::dbgs()
902 << "Duplicate languages in the config file on positions " << j
903 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000904 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000905 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000906 }
907 }
908 // Look for a suitable configuration starting from the end, so we can
909 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000910 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000911 FormatStyle::FormatStyleSet StyleSet;
912 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000913 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000914 if (Styles[i].Language != FormatStyle::LK_None)
915 StyleSet.Add(Styles[i]);
916 if (Styles[i].Language == Language)
917 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000918 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000919 if (!LanguageFound) {
920 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
921 return make_error_code(ParseError::Unsuitable);
922 FormatStyle DefaultStyle = Styles[0];
923 DefaultStyle.Language = Language;
924 StyleSet.Add(std::move(DefaultStyle));
925 }
926 *Style = *StyleSet.Get(Language);
927 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000928}
929
930std::string configurationAsText(const FormatStyle &Style) {
931 std::string Text;
932 llvm::raw_string_ostream Stream(Text);
933 llvm::yaml::Output Output(Stream);
934 // We use the same mapping method for input and output, so we need a non-const
935 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000936 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000937 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000938 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000939}
940
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000941llvm::Optional<FormatStyle>
942FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
943 if (!Styles)
944 return None;
945 auto It = Styles->find(Language);
946 if (It == Styles->end())
947 return None;
948 FormatStyle Style = It->second;
949 Style.StyleSet = *this;
950 return Style;
951}
952
953void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
954 assert(Style.Language != LK_None &&
955 "Cannot add a style for LK_None to a StyleSet");
956 assert(
957 !Style.StyleSet.Styles &&
958 "Cannot add a style associated with an existing StyleSet to a StyleSet");
959 if (!Styles)
960 Styles = std::make_shared<MapType>();
961 (*Styles)[Style.Language] = std::move(Style);
962}
963
964void FormatStyle::FormatStyleSet::Clear() {
965 Styles.reset();
966}
967
968llvm::Optional<FormatStyle>
969FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
970 return StyleSet.Get(Language);
971}
972
Craig Topperaf35e852013-06-30 22:29:28 +0000973namespace {
974
Daniel Jasper496c1992016-09-07 22:48:53 +0000975class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000976public:
Daniel Jasper496c1992016-09-07 22:48:53 +0000977 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
978 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +0000979
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000980 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +0000981 analyze(TokenAnnotator &Annotator,
982 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +0000983 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000984 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
985 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +0000986 tooling::Replacements Result;
987 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000988 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +0000989 }
990
991private:
Daniel Jasper496c1992016-09-07 22:48:53 +0000992 // Replaces double/single-quoted string literal as appropriate, re-escaping
993 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +0000994 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +0000995 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +0000996 for (AnnotatedLine *Line : Lines) {
997 requoteJSStringLiteral(Line->Children, Result);
998 if (!Line->Affected)
999 continue;
1000 for (FormatToken *FormatTok = Line->First; FormatTok;
1001 FormatTok = FormatTok->Next) {
1002 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001003 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001004 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001005 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001006 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001007 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001008 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001009 !Input.startswith("\'")))
1010 continue;
1011
1012 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001013 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001014 SourceLocation Start = FormatTok->Tok.getLocation();
1015 auto Replace = [&](SourceLocation Start, unsigned Length,
1016 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001017 auto Err = Result.add(tooling::Replacement(
1018 Env.getSourceManager(), Start, Length, ReplacementText));
1019 // FIXME: handle error. For now, print error message and skip the
1020 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001021 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001022 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001023 assert(false);
1024 }
Daniel Jasper97439922016-03-17 13:03:41 +00001025 };
1026 Replace(Start, 1, IsSingle ? "'" : "\"");
1027 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1028 IsSingle ? "'" : "\"");
1029
1030 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001031 bool Escaped = false;
1032 for (size_t i = 1; i < Input.size() - 1; i++) {
1033 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001034 case '\\':
1035 if (!Escaped && i + 1 < Input.size() &&
1036 ((IsSingle && Input[i + 1] == '"') ||
1037 (!IsSingle && Input[i + 1] == '\''))) {
1038 // Remove this \, it's escaping a " or ' that no longer needs
1039 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001040 Replace(Start.getLocWithOffset(i), 1, "");
1041 continue;
1042 }
1043 Escaped = !Escaped;
1044 break;
1045 case '\"':
1046 case '\'':
1047 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1048 // Escape the quote.
1049 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001050 }
1051 Escaped = false;
1052 break;
1053 default:
1054 Escaped = false;
1055 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001056 }
1057 }
Daniel Jasper97439922016-03-17 13:03:41 +00001058 }
1059 }
1060 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001061};
1062
1063class Formatter : public TokenAnalyzer {
1064public:
1065 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001066 FormattingAttemptStatus *Status)
1067 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001068
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001069 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001070 analyze(TokenAnnotator &Annotator,
1071 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1072 FormatTokenLexer &Tokens) override {
1073 tooling::Replacements Result;
1074 deriveLocalStyle(AnnotatedLines);
1075 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1076 AnnotatedLines.end());
1077 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1078 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1079 }
1080 Annotator.setCommentLineLevels(AnnotatedLines);
1081
1082 WhitespaceManager Whitespaces(
1083 Env.getSourceManager(), Style,
1084 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1085 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1086 Env.getSourceManager(), Whitespaces, Encoding,
1087 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001088 unsigned Penalty =
1089 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1090 Tokens.getKeywords(), Env.getSourceManager(),
1091 Status)
1092 .format(AnnotatedLines, /*DryRun=*/false,
1093 /*AdditionalIndent=*/0,
1094 /*FixBadIndentation=*/false,
1095 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1096 /*NextStartColumn=*/Env.getNextStartColumn(),
1097 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001098 for (const auto &R : Whitespaces.generateReplacements())
1099 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001100 return std::make_pair(Result, 0);
1101 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001102 }
1103
1104private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001105 static bool inputUsesCRLF(StringRef Text) {
1106 return Text.count('\r') * 2 > Text.count('\n');
1107 }
1108
Daniel Jasper352f0df2015-07-18 16:35:30 +00001109 bool
1110 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001111 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001112 if (hasCpp03IncompatibleFormat(Line->Children))
1113 return true;
1114 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1115 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1116 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1117 return true;
1118 if (Tok->is(TT_TemplateCloser) &&
1119 Tok->Previous->is(TT_TemplateCloser))
1120 return true;
1121 }
1122 }
1123 }
1124 return false;
1125 }
1126
1127 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1128 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001129 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001130 AlignmentDiff += countVariableAlignments(Line->Children);
1131 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1132 if (!Tok->is(TT_PointerOrReference))
1133 continue;
1134 bool SpaceBefore =
1135 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1136 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1137 Tok->Next->WhitespaceRange.getEnd();
1138 if (SpaceBefore && !SpaceAfter)
1139 ++AlignmentDiff;
1140 if (!SpaceBefore && SpaceAfter)
1141 --AlignmentDiff;
1142 }
1143 }
1144 return AlignmentDiff;
1145 }
1146
Manuel Klimek71814b42013-10-11 21:25:45 +00001147 void
1148 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001149 bool HasBinPackedFunction = false;
1150 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001151 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001152 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001153 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001154 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001155 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001156 if (Tok->PackingKind == PPK_BinPacked)
1157 HasBinPackedFunction = true;
1158 if (Tok->PackingKind == PPK_OnePerLine)
1159 HasOnePerLineFunction = true;
1160
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001161 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001162 }
1163 }
Eric Liu635423e2016-04-28 07:52:03 +00001164 if (Style.DerivePointerAlignment)
1165 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1166 ? FormatStyle::PAS_Left
1167 : FormatStyle::PAS_Right;
1168 if (Style.Standard == FormatStyle::LS_Auto)
1169 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1170 ? FormatStyle::LS_Cpp11
1171 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001172 BinPackInconclusiveFunctions =
1173 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001174 }
1175
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001176 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001177 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001178};
1179
1180// This class clean up the erroneous/redundant code around the given ranges in
1181// file.
1182class Cleaner : public TokenAnalyzer {
1183public:
Eric Liu635423e2016-04-28 07:52:03 +00001184 Cleaner(const Environment &Env, const FormatStyle &Style)
1185 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001186 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1187
1188 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001189 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001190 analyze(TokenAnnotator &Annotator,
1191 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001192 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001193 // FIXME: in the current implementation the granularity of affected range
1194 // is an annotated line. However, this is not sufficient. Furthermore,
1195 // redundant code introduced by replacements does not necessarily
1196 // intercept with ranges of replacements that result in the redundancy.
1197 // To determine if some redundant code is actually introduced by
1198 // replacements(e.g. deletions), we need to come up with a more
1199 // sophisticated way of computing affected ranges.
1200 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1201 AnnotatedLines.end());
1202
1203 checkEmptyNamespace(AnnotatedLines);
1204
Eric Liuce5e4bc2016-05-18 08:02:56 +00001205 for (auto &Line : AnnotatedLines) {
1206 if (Line->Affected) {
1207 cleanupRight(Line->First, tok::comma, tok::comma);
1208 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001209 cleanupRight(Line->First, tok::l_paren, tok::comma);
1210 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001211 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1212 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001213 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001214 }
1215 }
1216
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001217 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001218 }
1219
1220private:
1221 bool containsOnlyComments(const AnnotatedLine &Line) {
1222 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1223 if (Tok->isNot(tok::comment))
1224 return false;
1225 }
1226 return true;
1227 }
1228
1229 // Iterate through all lines and remove any empty (nested) namespaces.
1230 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001231 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001232 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1233 auto &Line = *AnnotatedLines[i];
1234 if (Line.startsWith(tok::kw_namespace) ||
1235 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001236 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001237 }
1238 }
1239
1240 for (auto Line : DeletedLines) {
1241 FormatToken *Tok = AnnotatedLines[Line]->First;
1242 while (Tok) {
1243 deleteToken(Tok);
1244 Tok = Tok->Next;
1245 }
1246 }
1247 }
1248
1249 // The function checks if the namespace, which starts from \p CurrentLine, and
1250 // its nested namespaces are empty and delete them if they are empty. It also
1251 // sets \p NewLine to the last line checked.
1252 // Returns true if the current namespace is empty.
1253 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001254 unsigned CurrentLine, unsigned &NewLine,
1255 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001256 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001257 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001258 // If the left brace is in a new line, we should consume it first so that
1259 // it does not make the namespace non-empty.
1260 // FIXME: error handling if there is no left brace.
1261 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1262 NewLine = CurrentLine;
1263 return false;
1264 }
1265 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1266 return false;
1267 }
1268 while (++CurrentLine < End) {
1269 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1270 break;
1271
1272 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1273 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1274 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001275 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1276 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001277 return false;
1278 CurrentLine = NewLine;
1279 continue;
1280 }
1281
1282 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1283 continue;
1284
1285 // If there is anything other than comments or nested namespaces in the
1286 // current namespace, the namespace cannot be empty.
1287 NewLine = CurrentLine;
1288 return false;
1289 }
1290
1291 NewLine = CurrentLine;
1292 if (CurrentLine >= End)
1293 return false;
1294
1295 // Check if the empty namespace is actually affected by changed ranges.
1296 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1297 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1298 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1299 return false;
1300
1301 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1302 DeletedLines.insert(i);
1303 }
1304
1305 return true;
1306 }
1307
Eric Liuce5e4bc2016-05-18 08:02:56 +00001308 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1309 // of the token in the pair if the left token has \p LK token kind and the
1310 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1311 // is deleted on match; otherwise, the right token is deleted.
1312 template <typename LeftKind, typename RightKind>
1313 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1314 bool DeleteLeft) {
1315 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1316 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1317 if (!Res->is(tok::comment) &&
1318 DeletedTokens.find(Res) == DeletedTokens.end())
1319 return Res;
1320 return nullptr;
1321 };
1322 for (auto *Left = Start; Left;) {
1323 auto *Right = NextNotDeleted(*Left);
1324 if (!Right)
1325 break;
1326 if (Left->is(LK) && Right->is(RK)) {
1327 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001328 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1329 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001330 // If the right token is deleted, we should keep the left token
1331 // unchanged and pair it with the new right token.
1332 if (!DeleteLeft)
1333 continue;
1334 }
1335 Left = Right;
1336 }
1337 }
1338
1339 template <typename LeftKind, typename RightKind>
1340 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1341 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1342 }
1343
1344 template <typename LeftKind, typename RightKind>
1345 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1346 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1347 }
1348
Eric Liu4cfb88a2016-04-25 15:09:22 +00001349 // Delete the given token.
1350 inline void deleteToken(FormatToken *Tok) {
1351 if (Tok)
1352 DeletedTokens.insert(Tok);
1353 }
1354
1355 tooling::Replacements generateFixes() {
1356 tooling::Replacements Fixes;
1357 std::vector<FormatToken *> Tokens;
1358 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1359 std::back_inserter(Tokens));
1360
1361 // Merge multiple continuous token deletions into one big deletion so that
1362 // the number of replacements can be reduced. This makes computing affected
1363 // ranges more efficient when we run reformat on the changed code.
1364 unsigned Idx = 0;
1365 while (Idx < Tokens.size()) {
1366 unsigned St = Idx, End = Idx;
1367 while ((End + 1) < Tokens.size() &&
1368 Tokens[End]->Next == Tokens[End + 1]) {
1369 End++;
1370 }
1371 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1372 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001373 auto Err =
1374 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1375 // FIXME: better error handling. for now just print error message and skip
1376 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001377 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001378 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001379 assert(false && "Fixes must not conflict!");
1380 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001381 Idx = End + 1;
1382 }
1383
1384 return Fixes;
1385 }
1386
1387 // Class for less-than inequality comparason for the set `RedundantTokens`.
1388 // We store tokens in the order they appear in the translation unit so that
1389 // we do not need to sort them in `generateFixes()`.
1390 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001391 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001392
Eric Liu2874ac32016-05-18 08:14:49 +00001393 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001394 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1395 RHS->Tok.getLocation());
1396 }
Eric Liu635423e2016-04-28 07:52:03 +00001397 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001398 };
1399
1400 // Tokens to be deleted.
1401 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001402};
1403
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001404class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1405public:
1406 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1407 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1408
1409 std::pair<tooling::Replacements, unsigned>
1410 analyze(TokenAnnotator &Annotator,
1411 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1412 FormatTokenLexer &Tokens) override {
1413 assert(Style.Language == FormatStyle::LK_Cpp);
1414 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1415 tooling::Replacements Result;
1416 return {Result, 0};
1417 }
1418
1419 bool isObjC() { return IsObjC; }
1420
1421private:
1422 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1423 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001424 // Keep this array sorted, since we are binary searching over it.
1425 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001426 "CGFloat",
1427 "NSAffineTransform",
1428 "NSArray",
1429 "NSAttributedString",
1430 "NSCache",
1431 "NSCharacterSet",
1432 "NSCountedSet",
1433 "NSData",
1434 "NSDataDetector",
1435 "NSDecimal",
1436 "NSDecimalNumber",
1437 "NSDictionary",
1438 "NSEdgeInsets",
1439 "NSHashTable",
1440 "NSIndexPath",
1441 "NSIndexSet",
1442 "NSInteger",
1443 "NSLocale",
1444 "NSMapTable",
1445 "NSMutableArray",
1446 "NSMutableAttributedString",
1447 "NSMutableCharacterSet",
1448 "NSMutableData",
1449 "NSMutableDictionary",
1450 "NSMutableIndexSet",
1451 "NSMutableOrderedSet",
1452 "NSMutableSet",
1453 "NSMutableString",
1454 "NSNumber",
1455 "NSNumberFormatter",
1456 "NSOrderedSet",
1457 "NSPoint",
1458 "NSPointerArray",
1459 "NSRange",
1460 "NSRect",
1461 "NSRegularExpression",
1462 "NSSet",
1463 "NSSize",
1464 "NSString",
1465 "NSUInteger",
1466 "NSURL",
1467 "NSURLComponents",
1468 "NSURLQueryItem",
1469 "NSUUID",
1470 };
1471
1472 for (auto &Line : AnnotatedLines) {
1473 for (FormatToken *FormatTok = Line->First->Next; FormatTok;
1474 FormatTok = FormatTok->Next) {
1475 if ((FormatTok->Previous->is(tok::at) &&
1476 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1477 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1478 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1479 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1480 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1481 tok::l_brace))) ||
1482 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001483 std::binary_search(std::begin(FoundationIdentifiers),
1484 std::end(FoundationIdentifiers),
1485 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001486 FormatTok->is(TT_ObjCStringLiteral) ||
1487 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1488 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1489 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1490 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1491 return true;
1492 }
1493 }
1494 }
1495 return false;
1496 }
1497
1498 bool IsObjC;
1499};
1500
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001501struct IncludeDirective {
1502 StringRef Filename;
1503 StringRef Text;
1504 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001505 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001506};
1507
Craig Topperaf35e852013-06-30 22:29:28 +00001508} // end anonymous namespace
1509
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001510// Determines whether 'Ranges' intersects with ('Start', 'End').
1511static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1512 unsigned End) {
1513 for (auto Range : Ranges) {
1514 if (Range.getOffset() < End &&
1515 Range.getOffset() + Range.getLength() > Start)
1516 return true;
1517 }
1518 return false;
1519}
1520
Eric Liua992afe2016-08-10 09:32:23 +00001521// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1522// before sorting/deduplicating. Index is the index of the include under the
1523// cursor in the original set of includes. If this include has duplicates, it is
1524// the index of the first of the duplicates as the others are going to be
1525// removed. OffsetToEOL describes the cursor's position relative to the end of
1526// its current line.
1527// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1528static std::pair<unsigned, unsigned>
1529FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1530 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1531 unsigned CursorIndex = UINT_MAX;
1532 unsigned OffsetToEOL = 0;
1533 for (int i = 0, e = Includes.size(); i != e; ++i) {
1534 unsigned Start = Includes[Indices[i]].Offset;
1535 unsigned End = Start + Includes[Indices[i]].Text.size();
1536 if (!(Cursor >= Start && Cursor < End))
1537 continue;
1538 CursorIndex = Indices[i];
1539 OffsetToEOL = End - Cursor;
1540 // Put the cursor on the only remaining #include among the duplicate
1541 // #includes.
1542 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1543 CursorIndex = i;
1544 break;
1545 }
1546 return std::make_pair(CursorIndex, OffsetToEOL);
1547}
1548
1549// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1550// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1551// source order.
1552// #include directives with the same text will be deduplicated, and only the
1553// first #include in the duplicate #includes remains. If the `Cursor` is
1554// provided and put on a deleted #include, it will be moved to the remaining
1555// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001556static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001557 const SmallVectorImpl<IncludeDirective> &Includes,
1558 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1559 tooling::Replacements &Replaces, unsigned *Cursor) {
1560 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001561 unsigned IncludesEndOffset =
1562 Includes.back().Offset + Includes.back().Text.size();
1563 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1564 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001565 return;
1566 SmallVector<unsigned, 16> Indices;
1567 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1568 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001569 std::stable_sort(
1570 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1571 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1572 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1573 });
Eric Liua992afe2016-08-10 09:32:23 +00001574 // The index of the include on which the cursor will be put after
1575 // sorting/deduplicating.
1576 unsigned CursorIndex;
1577 // The offset from cursor to the end of line.
1578 unsigned CursorToEOLOffset;
1579 if (Cursor)
1580 std::tie(CursorIndex, CursorToEOLOffset) =
1581 FindCursorIndex(Includes, Indices, *Cursor);
1582
1583 // Deduplicate #includes.
1584 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1585 [&](unsigned LHSI, unsigned RHSI) {
1586 return Includes[LHSI].Text == Includes[RHSI].Text;
1587 }),
1588 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001589
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001590 int CurrentCategory = Includes.front().Category;
1591
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001592 // If the #includes are out of order, we generate a single replacement fixing
1593 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001594 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001595 std::is_sorted(Indices.begin(), Indices.end()) &&
1596 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001597 return;
1598
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001599 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001600 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001601 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001602 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001603 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1604 CurrentCategory != Includes[Index].Category)
1605 result += "\n";
1606 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001607 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001608 if (Cursor && CursorIndex == Index)
1609 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001610 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001611 }
1612
Eric Liu40ef2fb2016-08-01 10:16:37 +00001613 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001614 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001615 // FIXME: better error handling. For now, just skip the replacement for the
1616 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001617 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001618 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001619 assert(false);
1620 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001621}
1622
Eric Liu659afd52016-05-31 13:34:20 +00001623namespace {
1624
1625// This class manages priorities of #include categories and calculates
1626// priorities for headers.
1627class IncludeCategoryManager {
1628public:
1629 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1630 : Style(Style), FileName(FileName) {
1631 FileStem = llvm::sys::path::stem(FileName);
1632 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001633 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001634 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1635 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1636 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1637 FileName.endswith(".mm");
1638 }
1639
1640 // Returns the priority of the category which \p IncludeName belongs to.
1641 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1642 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1643 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1644 int Ret = INT_MAX;
1645 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1646 if (CategoryRegexs[i].match(IncludeName)) {
1647 Ret = Style.IncludeCategories[i].Priority;
1648 break;
1649 }
1650 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1651 Ret = 0;
1652 return Ret;
1653 }
1654
1655private:
1656 bool isMainHeader(StringRef IncludeName) const {
1657 if (!IncludeName.startswith("\""))
1658 return false;
1659 StringRef HeaderStem =
1660 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001661 if (FileStem.startswith(HeaderStem) ||
1662 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001663 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001664 (HeaderStem + Style.IncludeIsMainRegex).str(),
1665 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001666 if (MainIncludeRegex.match(FileStem))
1667 return true;
1668 }
1669 return false;
1670 }
1671
1672 const FormatStyle &Style;
1673 bool IsMainFile;
1674 StringRef FileName;
1675 StringRef FileStem;
1676 SmallVector<llvm::Regex, 4> CategoryRegexs;
1677};
1678
1679const char IncludeRegexPattern[] =
1680 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1681
1682} // anonymous namespace
1683
Martin Probstc4a0dd42016-05-20 11:24:24 +00001684tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1685 ArrayRef<tooling::Range> Ranges,
1686 StringRef FileName,
1687 tooling::Replacements &Replaces,
1688 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001689 unsigned Prev = 0;
1690 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001691 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001692 SmallVector<StringRef, 4> Matches;
1693 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001694
1695 // In compiled files, consider the first #include to be the main #include of
1696 // the file if it is not a system #include. This ensures that the header
1697 // doesn't have hidden dependencies
1698 // (http://llvm.org/docs/CodingStandards.html#include-style).
1699 //
1700 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1701 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001702 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001703 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001704 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001705 bool FormattingOff = false;
1706
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001707 for (;;) {
1708 auto Pos = Code.find('\n', SearchFrom);
1709 StringRef Line =
1710 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001711
1712 StringRef Trimmed = Line.trim();
1713 if (Trimmed == "// clang-format off")
1714 FormattingOff = true;
1715 else if (Trimmed == "// clang-format on")
1716 FormattingOff = false;
1717
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001718 const bool EmptyLineSkipped =
1719 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1720 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1721
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001722 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001723 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001724 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001725 int Category = Categories.getIncludePriority(
1726 IncludeName,
1727 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1728 if (Category == 0)
1729 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001730 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001731 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001732 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1733 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001734 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001735 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001736 }
1737 Prev = Pos + 1;
1738 }
1739 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1740 break;
1741 SearchFrom = Pos + 1;
1742 }
1743 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001744 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1745 return Replaces;
1746}
1747
Martin Probstfa37b182017-01-27 09:09:11 +00001748bool isMpegTS(StringRef Code) {
1749 // MPEG transport streams use the ".ts" file extension. clang-format should
1750 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1751 // 189 bytes - detect that and return.
1752 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1753}
1754
Manuel Klimek89628f62017-09-20 09:51:03 +00001755bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001756
Martin Probstc4a0dd42016-05-20 11:24:24 +00001757tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1758 ArrayRef<tooling::Range> Ranges,
1759 StringRef FileName, unsigned *Cursor) {
1760 tooling::Replacements Replaces;
1761 if (!Style.SortIncludes)
1762 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001763 if (isLikelyXml(Code))
1764 return Replaces;
1765 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1766 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001767 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001768 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1769 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1770 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001771 return Replaces;
1772}
1773
Eric Liu4cfb88a2016-04-25 15:09:22 +00001774template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001775static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001776processReplacements(T ProcessFunc, StringRef Code,
1777 const tooling::Replacements &Replaces,
1778 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001779 if (Replaces.empty())
1780 return tooling::Replacements();
1781
Eric Liu4f8d9942016-07-11 13:53:12 +00001782 auto NewCode = applyAllReplacements(Code, Replaces);
1783 if (!NewCode)
1784 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001785 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001786 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001787
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001788 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001789 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001790
Eric Liu40ef2fb2016-08-01 10:16:37 +00001791 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001792}
1793
Eric Liu4f8d9942016-07-11 13:53:12 +00001794llvm::Expected<tooling::Replacements>
1795formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1796 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001797 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001798 // `sortIncludes`.
1799 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1800 std::vector<tooling::Range> Ranges,
1801 StringRef FileName) -> tooling::Replacements {
1802 return sortIncludes(Style, Code, Ranges, FileName);
1803 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001804 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001805 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001806 if (!SortedReplaces)
1807 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001808
1809 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001810 // `reformat`.
1811 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1812 std::vector<tooling::Range> Ranges,
1813 StringRef FileName) -> tooling::Replacements {
1814 return reformat(Style, Code, Ranges, FileName);
1815 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001816 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001817}
1818
Eric Liu659afd52016-05-31 13:34:20 +00001819namespace {
1820
1821inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001822 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001823 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1824}
1825
Eric Liuc0d3a802016-09-23 15:10:56 +00001826inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1827 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1828}
1829
Eric Liu964782a2016-12-02 11:01:43 +00001830// Returns the offset after skipping a sequence of tokens, matched by \p
1831// GetOffsetAfterSequence, from the start of the code.
1832// \p GetOffsetAfterSequence should be a function that matches a sequence of
1833// tokens and returns an offset after the sequence.
1834unsigned getOffsetAfterTokenSequence(
1835 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001836 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1837 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001838 std::unique_ptr<Environment> Env =
1839 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1840 const SourceManager &SourceMgr = Env->getSourceManager();
1841 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1842 getFormattingLangOpts(Style));
1843 Token Tok;
1844 // Get the first token.
1845 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001846 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001847}
1848
1849// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1850// \p Tok will be the token after this directive; otherwise, it can be any token
1851// after the given \p Tok (including \p Tok).
1852bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1853 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1854 Tok.is(tok::raw_identifier) &&
1855 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001856 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001857 if (Matched)
1858 Lex.LexFromRawLexer(Tok);
1859 return Matched;
1860}
1861
Eric Liu964782a2016-12-02 11:01:43 +00001862void skipComments(Lexer &Lex, Token &Tok) {
1863 while (Tok.is(tok::comment))
1864 if (Lex.LexFromRawLexer(Tok))
1865 return;
1866}
1867
1868// Returns the offset after header guard directives and any comments
1869// before/after header guards. If no header guard presents in the code, this
1870// will returns the offset after skipping all comments from the start of the
1871// code.
Eric Liu35288322016-06-06 11:00:13 +00001872unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1873 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001874 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001875 return getOffsetAfterTokenSequence(
1876 FileName, Code, Style,
1877 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1878 skipComments(Lex, Tok);
1879 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1880 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1881 skipComments(Lex, Tok);
1882 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1883 return SM.getFileOffset(Tok.getLocation());
1884 }
1885 return InitialOffset;
1886 });
1887}
1888
1889// Check if a sequence of tokens is like
1890// "#include ("header.h" | <header.h>)".
1891// If it is, \p Tok will be the token after this directive; otherwise, it can be
1892// any token after the given \p Tok (including \p Tok).
1893bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1894 auto Matched = [&]() {
1895 Lex.LexFromRawLexer(Tok);
1896 return true;
1897 };
1898 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1899 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1900 if (Lex.LexFromRawLexer(Tok))
1901 return false;
1902 if (Tok.is(tok::string_literal))
1903 return Matched();
1904 if (Tok.is(tok::less)) {
1905 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1906 }
1907 if (Tok.is(tok::greater))
1908 return Matched();
1909 }
Eric Liu35288322016-06-06 11:00:13 +00001910 }
Eric Liu964782a2016-12-02 11:01:43 +00001911 return false;
1912}
1913
1914// Returns the offset of the last #include directive after which a new
1915// #include can be inserted. This ignores #include's after the #include block(s)
1916// in the beginning of a file to avoid inserting headers into code sections
1917// where new #include's should not be added by default.
1918// These code sections include:
1919// - raw string literals (containing #include).
1920// - #if blocks.
1921// - Special #include's among declarations (e.g. functions).
1922//
1923// If no #include after which a new #include can be inserted, this returns the
1924// offset after skipping all comments from the start of the code.
1925// Inserting after an #include is not allowed if it comes after code that is not
1926// #include (e.g. pre-processing directive that is not #include, declarations).
1927unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1928 const FormatStyle &Style) {
1929 return getOffsetAfterTokenSequence(
1930 FileName, Code, Style,
1931 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1932 skipComments(Lex, Tok);
1933 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1934 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1935 MaxOffset = SM.getFileOffset(Tok.getLocation());
1936 return MaxOffset;
1937 });
Eric Liu35288322016-06-06 11:00:13 +00001938}
1939
Eric Liuc0d3a802016-09-23 15:10:56 +00001940bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001941 const std::set<llvm::StringRef> &HeadersToDelete) {
1942 return HeadersToDelete.count(HeaderName) ||
1943 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001944}
1945
Eric Liu659afd52016-05-31 13:34:20 +00001946// FIXME: insert empty lines between newly created blocks.
1947tooling::Replacements
1948fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
1949 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00001950 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00001951 return Replaces;
1952
1953 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00001954 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00001955 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00001956 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001957 if (isHeaderInsertion(R)) {
1958 // Replacements from \p Replaces must be conflict-free already, so we can
1959 // simply consume the error.
1960 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00001961 } else if (isHeaderDeletion(R)) {
1962 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001963 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00001964 llvm::errs() << "Insertions other than header #include insertion are "
1965 "not supported! "
1966 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00001967 } else {
1968 llvm::consumeError(Result.add(R));
1969 }
Eric Liu659afd52016-05-31 13:34:20 +00001970 }
Eric Liuc0d3a802016-09-23 15:10:56 +00001971 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00001972 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00001973
1974 llvm::Regex IncludeRegex(IncludeRegexPattern);
1975 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1976 SmallVector<StringRef, 4> Matches;
1977
1978 StringRef FileName = Replaces.begin()->getFilePath();
1979 IncludeCategoryManager Categories(Style, FileName);
1980
1981 // Record the offset of the end of the last include in each category.
1982 std::map<int, int> CategoryEndOffsets;
1983 // All possible priorities.
1984 // Add 0 for main header and INT_MAX for headers that are not in any category.
1985 std::set<int> Priorities = {0, INT_MAX};
1986 for (const auto &Category : Style.IncludeCategories)
1987 Priorities.insert(Category.Priority);
1988 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00001989 // All new headers should be inserted after this offset.
1990 unsigned MinInsertOffset =
1991 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00001992 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00001993 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00001994 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00001995 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00001996 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00001997 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00001998 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00001999 unsigned Offset = MinInsertOffset;
2000 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002001 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002002 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002003 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002004 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002005 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002006 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002007 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002008 // Only record the offset of current #include if we can insert after it.
2009 if (Offset <= MaxInsertOffset) {
2010 int Category = Categories.getIncludePriority(
2011 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2012 CategoryEndOffsets[Category] = NextLineOffset;
2013 if (FirstIncludeOffset < 0)
2014 FirstIncludeOffset = Offset;
2015 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002016 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2017 // If this is the last line without trailing newline, we need to make
2018 // sure we don't delete across the file boundary.
2019 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2020 llvm::Error Err =
2021 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2022 if (Err) {
2023 // Ignore the deletion on conflict.
2024 llvm::errs() << "Failed to add header deletion replacement for "
2025 << IncludeName << ": " << llvm::toString(std::move(Err))
2026 << "\n";
2027 }
2028 }
Eric Liu659afd52016-05-31 13:34:20 +00002029 }
Eric Liu35288322016-06-06 11:00:13 +00002030 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002031 }
2032
2033 // Populate CategoryEndOfssets:
2034 // - Ensure that CategoryEndOffset[Highest] is always populated.
2035 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2036 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002037 auto Highest = Priorities.begin();
2038 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2039 if (FirstIncludeOffset >= 0)
2040 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2041 else
Eric Liu303baf52016-06-03 12:52:59 +00002042 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002043 }
2044 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2045 // - to an appropriate location before/after existing #includes, or
2046 // - to right after the header guard, or
2047 // - to the beginning of the file.
2048 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2049 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2050 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2051
Eric Liu11a42372016-10-05 15:42:19 +00002052 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002053 for (const auto &R : HeaderInsertions) {
2054 auto IncludeDirective = R.getReplacementText();
2055 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2056 assert(Matched && "Header insertion replacement must have replacement text "
2057 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002058 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002059 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002060 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2061 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2062 << "\n");
2063 continue;
2064 }
Eric Liu659afd52016-05-31 13:34:20 +00002065 int Category =
2066 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2067 Offset = CategoryEndOffsets[Category];
2068 std::string NewInclude = !IncludeDirective.endswith("\n")
2069 ? (IncludeDirective + "\n").str()
2070 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002071 // When inserting headers at end of the code, also append '\n' to the code
2072 // if it does not end with '\n'.
2073 if (NeedNewLineAtEnd && Offset == Code.size()) {
2074 NewInclude = "\n" + NewInclude;
2075 NeedNewLineAtEnd = false;
2076 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002077 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2078 auto Err = Result.add(NewReplace);
2079 if (Err) {
2080 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002081 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2082 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002083 Result = Result.merge(tooling::Replacements(NewReplace));
2084 }
Eric Liu659afd52016-05-31 13:34:20 +00002085 }
2086 return Result;
2087}
2088
2089} // anonymous namespace
2090
Eric Liu4f8d9942016-07-11 13:53:12 +00002091llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002092cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2093 const FormatStyle &Style) {
2094 // We need to use lambda function here since there are two versions of
2095 // `cleanup`.
2096 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2097 std::vector<tooling::Range> Ranges,
2098 StringRef FileName) -> tooling::Replacements {
2099 return cleanup(Style, Code, Ranges, FileName);
2100 };
Eric Liu659afd52016-05-31 13:34:20 +00002101 // Make header insertion replacements insert new headers into correct blocks.
2102 tooling::Replacements NewReplaces =
2103 fixCppIncludeInsertions(Code, Replaces, Style);
2104 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002105}
2106
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002107namespace internal {
2108std::pair<tooling::Replacements, unsigned>
2109reformat(const FormatStyle &Style, StringRef Code,
2110 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2111 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2112 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002113 FormatStyle Expanded = expandPresets(Style);
2114 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002115 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002116 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002117 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002118 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002119 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002120
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002121 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2122 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002123 AnalyzerPass;
2124 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002125
Krasimir Georgievac16a202017-06-23 11:46:03 +00002126 if (Style.Language == FormatStyle::LK_Cpp) {
2127 if (Style.FixNamespaceComments)
2128 Passes.emplace_back([&](const Environment &Env) {
2129 return NamespaceEndCommentsFixer(Env, Expanded).process();
2130 });
2131
2132 if (Style.SortUsingDeclarations)
2133 Passes.emplace_back([&](const Environment &Env) {
2134 return UsingDeclarationsSorter(Env, Expanded).process();
2135 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002136 }
2137
2138 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002139 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2140 Passes.emplace_back([&](const Environment &Env) {
2141 return JavaScriptRequoter(Env, Expanded).process();
2142 });
2143
2144 Passes.emplace_back([&](const Environment &Env) {
2145 return Formatter(Env, Expanded, Status).process();
2146 });
2147
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002148 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2149 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2150 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002151 llvm::Optional<std::string> CurrentCode = None;
2152 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002153 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002154 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002155 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002156 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002157 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002158 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002159 Fixes = Fixes.merge(PassFixes.first);
2160 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002161 if (I + 1 < E) {
2162 CurrentCode = std::move(*NewCode);
2163 Env = Environment::CreateVirtualEnvironment(
2164 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002165 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2166 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002167 }
2168 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002169 }
2170
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002171 return {Fixes, Penalty};
2172}
2173} // namespace internal
2174
2175tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2176 ArrayRef<tooling::Range> Ranges,
2177 StringRef FileName,
2178 FormattingAttemptStatus *Status) {
2179 return internal::reformat(Style, Code, Ranges,
2180 /*FirstStartColumn=*/0,
2181 /*NextStartColumn=*/0,
2182 /*LastStartColumn=*/0, FileName, Status)
2183 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002184}
2185
Eric Liu4cfb88a2016-04-25 15:09:22 +00002186tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2187 ArrayRef<tooling::Range> Ranges,
2188 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002189 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2190 if (Style.Language != FormatStyle::LK_Cpp)
2191 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002192 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002193 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2194 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002195 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002196}
2197
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002198tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2199 ArrayRef<tooling::Range> Ranges,
2200 StringRef FileName, bool *IncompleteFormat) {
2201 FormattingAttemptStatus Status;
2202 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2203 if (!Status.FormatComplete)
2204 *IncompleteFormat = true;
2205 return Result;
2206}
2207
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002208tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2209 StringRef Code,
2210 ArrayRef<tooling::Range> Ranges,
2211 StringRef FileName) {
2212 std::unique_ptr<Environment> Env =
2213 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2214 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002215 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002216}
2217
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002218tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2219 StringRef Code,
2220 ArrayRef<tooling::Range> Ranges,
2221 StringRef FileName) {
2222 std::unique_ptr<Environment> Env =
2223 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2224 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002225 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002226}
2227
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002228LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002229 LangOptions LangOpts;
2230 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002231 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2232 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002233 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002234 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002235 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002236 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002237 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002238 LangOpts.Bool = 1;
2239 LangOpts.ObjC1 = 1;
2240 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002241 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002242 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002243 return LangOpts;
2244}
2245
Edwin Vaned544aa72013-09-30 13:31:48 +00002246const char *StyleOptionHelpDescription =
2247 "Coding style, currently supports:\n"
2248 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2249 "Use -style=file to load style configuration from\n"
2250 ".clang-format file located in one of the parent\n"
2251 "directories of the source file (or current\n"
2252 "directory for stdin).\n"
2253 "Use -style=\"{key: value, ...}\" to set specific\n"
2254 "parameters, e.g.:\n"
2255 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2256
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002257static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002258 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002259 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002260 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2261 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002262 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2263 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002264 if (FileName.endswith_lower(".proto") ||
2265 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002266 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002267 if (FileName.endswith_lower(".textpb") ||
2268 FileName.endswith_lower(".pb.txt") ||
2269 FileName.endswith_lower(".textproto") ||
2270 FileName.endswith_lower(".asciipb"))
2271 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002272 if (FileName.endswith_lower(".td"))
2273 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002274 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002275}
2276
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002277llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002278 StringRef FallbackStyleName,
2279 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002280 if (!FS) {
2281 FS = vfs::getRealFileSystem().get();
2282 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002283 FormatStyle Style = getLLVMStyle();
2284 Style.Language = getLanguageByFileName(FileName);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002285
Ben Hamiltone2e3e672018-01-17 17:33:08 +00002286 if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h")) {
2287 std::unique_ptr<Environment> Env =
2288 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
2289 ObjCHeaderStyleGuesser Guesser(*Env, Style);
2290 Guesser.process();
2291 if (Guesser.isObjC()) {
2292 Style.Language = FormatStyle::LK_ObjC;
2293 }
2294 }
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002295
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002296 FormatStyle FallbackStyle = getNoStyle();
2297 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2298 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002299
2300 if (StyleName.startswith("{")) {
2301 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002302 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2303 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002304 return Style;
2305 }
2306
2307 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002308 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002309 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002310 return Style;
2311 }
2312
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002313 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002314 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002315 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002316 if (std::error_code EC = FS->makeAbsolute(Path))
2317 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002318
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002319 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002320 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002321
2322 auto Status = FS->status(Directory);
2323 if (!Status ||
2324 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002325 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002326 }
2327
Edwin Vaned544aa72013-09-30 13:31:48 +00002328 SmallString<128> ConfigFile(Directory);
2329
2330 llvm::sys::path::append(ConfigFile, ".clang-format");
2331 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002332
Eric Liu547d8792016-03-24 13:22:42 +00002333 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002334 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002335 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002336 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002337 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2338 ConfigFile = Directory;
2339 llvm::sys::path::append(ConfigFile, "_clang-format");
2340 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002341 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002342 FoundConfigFile = Status && (Status->getType() ==
2343 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002344 }
2345
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002346 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002347 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002348 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002349 if (std::error_code EC = Text.getError())
2350 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002351 if (std::error_code ec =
2352 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002353 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002354 if (!UnsuitableConfigFiles.empty())
2355 UnsuitableConfigFiles.append(", ");
2356 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002357 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002358 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002359 return make_string_error("Error reading " + ConfigFile + ": " +
2360 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002361 }
2362 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2363 return Style;
2364 }
2365 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002366 if (!UnsuitableConfigFiles.empty())
2367 return make_string_error("Configuration file(s) do(es) not support " +
2368 getLanguageName(Style.Language) + ": " +
2369 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002370 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002371}
2372
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002373} // namespace format
2374} // namespace clang