blob: ff437f119e91c6beb750524bb7a92859d67ca5f4 [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
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000108template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
109 static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
110 IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto);
111 IO.enumCase(Value, "Always", FormatStyle::BPS_Always);
112 IO.enumCase(Value, "Never", FormatStyle::BPS_Never);
113 }
114};
115
Daniel Jasperac043c92014-09-15 11:11:00 +0000116template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
117 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
118 IO.enumCase(Value, "All", FormatStyle::BOS_All);
119 IO.enumCase(Value, "true", FormatStyle::BOS_All);
120 IO.enumCase(Value, "None", FormatStyle::BOS_None);
121 IO.enumCase(Value, "false", FormatStyle::BOS_None);
122 IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
123 }
124};
125
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000126template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
127 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
128 IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
129 IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000130 IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000131 IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
132 IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000133 IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000134 IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000135 IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000136 }
137};
138
Manuel Klimek89628f62017-09-20 09:51:03 +0000139template <>
140struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
141 static void
142 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
Francois Ferranda6b6d512017-05-24 11:36:58 +0000143 IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
144 IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
145 IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
146 }
147};
148
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000149template <>
Krasimir Georgievad47c902017-08-30 14:34:57 +0000150struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
151 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
152 IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
153 IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
154 }
155};
156
157template <>
Zachary Turner448592e2015-12-18 22:20:15 +0000158struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
159 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
160 IO.enumCase(Value, "None", FormatStyle::RTBS_None);
161 IO.enumCase(Value, "All", FormatStyle::RTBS_All);
162 IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
163 IO.enumCase(Value, "TopLevelDefinitions",
164 FormatStyle::RTBS_TopLevelDefinitions);
165 IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
166 }
167};
168
169template <>
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000170struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
171 static void
172 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000173 IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
174 IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
175 IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
176
177 // For backward compatibility.
178 IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
179 IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
180 }
181};
182
Alexander Kornienkod6538332013-05-07 15:32:14 +0000183template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000184struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000185 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000186 FormatStyle::NamespaceIndentationKind &Value) {
187 IO.enumCase(Value, "None", FormatStyle::NI_None);
188 IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
189 IO.enumCase(Value, "All", FormatStyle::NI_All);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000190 }
191};
192
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000193template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
194 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
195 IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
196 IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
197 IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
198
199 // For backward compatibility.
200 IO.enumCase(Value, "true", FormatStyle::BAS_Align);
201 IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
202 }
203};
204
Manuel Klimek89628f62017-09-20 09:51:03 +0000205template <>
206struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
207 static void enumeration(IO &IO,
208 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000209 IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
210 IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
211 IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
212
213 // For backward compatibility.
214 IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
215 IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
216 }
217};
218
Jacques Pienaarfc275112015-02-18 23:48:37 +0000219template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
220 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
Daniel Jasper553d4872014-06-17 12:40:34 +0000221 IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
222 IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
223 IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
224
Alp Toker958027b2014-07-14 19:42:55 +0000225 // For backward compatibility.
Daniel Jasper553d4872014-06-17 12:40:34 +0000226 IO.enumCase(Value, "true", FormatStyle::PAS_Left);
227 IO.enumCase(Value, "false", FormatStyle::PAS_Right);
228 }
229};
230
231template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000232struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
Manuel Klimeka8eb9142013-05-13 12:51:40 +0000233 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000234 FormatStyle::SpaceBeforeParensOptions &Value) {
235 IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000236 IO.enumCase(Value, "ControlStatements",
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000237 FormatStyle::SBPO_ControlStatements);
238 IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000239
240 // For backward compatibility.
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000241 IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
242 IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000243 }
244};
245
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000246template <> struct MappingTraits<FormatStyle> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000247 static void mapping(IO &IO, FormatStyle &Style) {
248 // When reading, read the language first, we need it for getPredefinedStyle.
249 IO.mapOptional("Language", Style.Language);
250
Alexander Kornienko49149672013-05-10 11:56:10 +0000251 if (IO.outputting()) {
Jacques Pienaarfc275112015-02-18 23:48:37 +0000252 StringRef StylesArray[] = {"LLVM", "Google", "Chromium",
253 "Mozilla", "WebKit", "GNU"};
Alexander Kornienko49149672013-05-10 11:56:10 +0000254 ArrayRef<StringRef> Styles(StylesArray);
255 for (size_t i = 0, e = Styles.size(); i < e; ++i) {
256 StringRef StyleName(Styles[i]);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000257 FormatStyle PredefinedStyle;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000258 if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000259 Style == PredefinedStyle) {
Alexander Kornienko49149672013-05-10 11:56:10 +0000260 IO.mapOptional("# BasedOnStyle", StyleName);
261 break;
262 }
263 }
264 } else {
Alexander Kornienkod6538332013-05-07 15:32:14 +0000265 StringRef BasedOnStyle;
266 IO.mapOptional("BasedOnStyle", BasedOnStyle);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000267 if (!BasedOnStyle.empty()) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000268 FormatStyle::LanguageKind OldLanguage = Style.Language;
269 FormatStyle::LanguageKind Language =
270 ((FormatStyle *)IO.getContext())->Language;
271 if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000272 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
273 return;
274 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000275 Style.Language = OldLanguage;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000276 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000277 }
278
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000279 // For backward compatibility.
280 if (!IO.outputting()) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000281 IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000282 IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
283 IO.mapOptional("IndentFunctionDeclarationAfterType",
284 Style.IndentWrappedFunctionNames);
285 IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
286 IO.mapOptional("SpaceAfterControlStatementKeyword",
287 Style.SpaceBeforeParens);
288 }
289
Alexander Kornienkod6538332013-05-07 15:32:14 +0000290 IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
Daniel Jasper3aa9a6a2014-11-18 23:55:27 +0000291 IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000292 IO.mapOptional("AlignConsecutiveAssignments",
293 Style.AlignConsecutiveAssignments);
Daniel Jaspere12597c2015-10-01 10:06:54 +0000294 IO.mapOptional("AlignConsecutiveDeclarations",
295 Style.AlignConsecutiveDeclarations);
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000296 IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
Daniel Jasper3219e432014-12-02 13:24:51 +0000297 IO.mapOptional("AlignOperands", Style.AlignOperands);
Daniel Jasper552f4a72013-07-31 23:55:15 +0000298 IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000299 IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
300 Style.AllowAllParametersOfDeclarationOnNextLine);
Daniel Jasper17605d32014-05-14 09:33:35 +0000301 IO.mapOptional("AllowShortBlocksOnASingleLine",
302 Style.AllowShortBlocksOnASingleLine);
Daniel Jasperb87899b2014-09-10 13:11:45 +0000303 IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
304 Style.AllowShortCaseLabelsOnASingleLine);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000305 IO.mapOptional("AllowShortFunctionsOnASingleLine",
306 Style.AllowShortFunctionsOnASingleLine);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000307 IO.mapOptional("AllowShortIfStatementsOnASingleLine",
308 Style.AllowShortIfStatementsOnASingleLine);
Daniel Jasper3a685df2013-05-16 12:12:21 +0000309 IO.mapOptional("AllowShortLoopsOnASingleLine",
310 Style.AllowShortLoopsOnASingleLine);
Daniel Jasperca4ea1c2014-08-05 12:16:31 +0000311 IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
312 Style.AlwaysBreakAfterDefinitionReturnType);
Zachary Turner448592e2015-12-18 22:20:15 +0000313 IO.mapOptional("AlwaysBreakAfterReturnType",
314 Style.AlwaysBreakAfterReturnType);
315 // If AlwaysBreakAfterDefinitionReturnType was specified but
316 // AlwaysBreakAfterReturnType was not, initialize the latter from the
317 // former for backwards compatibility.
318 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
319 Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
320 if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
321 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
322 else if (Style.AlwaysBreakAfterDefinitionReturnType ==
323 FormatStyle::DRTBS_TopLevel)
324 Style.AlwaysBreakAfterReturnType =
325 FormatStyle::RTBS_TopLevelDefinitions;
326 }
327
Alexander Kornienko58611712013-07-04 12:02:44 +0000328 IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
329 Style.AlwaysBreakBeforeMultilineStrings);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000330 IO.mapOptional("AlwaysBreakTemplateDeclarations",
331 Style.AlwaysBreakTemplateDeclarations);
332 IO.mapOptional("BinPackArguments", Style.BinPackArguments);
333 IO.mapOptional("BinPackParameters", Style.BinPackParameters);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000334 IO.mapOptional("BraceWrapping", Style.BraceWrapping);
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000335 IO.mapOptional("BreakBeforeBinaryOperators",
336 Style.BreakBeforeBinaryOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000337 IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
Francois Ferrande56a8292017-06-14 12:29:47 +0000338 IO.mapOptional("BreakBeforeInheritanceComma",
339 Style.BreakBeforeInheritanceComma);
Daniel Jasper165b29e2013-11-08 00:57:11 +0000340 IO.mapOptional("BreakBeforeTernaryOperators",
341 Style.BreakBeforeTernaryOperators);
Francois Ferranda6b6d512017-05-24 11:36:58 +0000342
343 bool BreakConstructorInitializersBeforeComma = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000344 IO.mapOptional("BreakConstructorInitializersBeforeComma",
Francois Ferranda6b6d512017-05-24 11:36:58 +0000345 BreakConstructorInitializersBeforeComma);
346 IO.mapOptional("BreakConstructorInitializers",
347 Style.BreakConstructorInitializers);
348 // If BreakConstructorInitializersBeforeComma was specified but
349 // BreakConstructorInitializers was not, initialize the latter from the
350 // former for backwards compatibility.
351 if (BreakConstructorInitializersBeforeComma &&
352 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
353 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
354
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000355 IO.mapOptional("BreakAfterJavaFieldAnnotations",
356 Style.BreakAfterJavaFieldAnnotations);
357 IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000358 IO.mapOptional("ColumnLimit", Style.ColumnLimit);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000359 IO.mapOptional("CommentPragmas", Style.CommentPragmas);
Francois Ferrande56a8292017-06-14 12:29:47 +0000360 IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000361 IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
362 Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000363 IO.mapOptional("ConstructorInitializerIndentWidth",
364 Style.ConstructorInitializerIndentWidth);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000365 IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
366 IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
Daniel Jasper553d4872014-06-17 12:40:34 +0000367 IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000368 IO.mapOptional("DisableFormat", Style.DisableFormat);
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000369 IO.mapOptional("ExperimentalAutoDetectBinPacking",
370 Style.ExperimentalAutoDetectBinPacking);
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000371 IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000372 IO.mapOptional("ForEachMacros", Style.ForEachMacros);
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000373 IO.mapOptional("IncludeBlocks", Style.IncludeBlocks);
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000374 IO.mapOptional("IncludeCategories", Style.IncludeCategories);
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000375 IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000376 IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
Krasimir Georgievad47c902017-08-30 14:34:57 +0000377 IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000378 IO.mapOptional("IndentWidth", Style.IndentWidth);
379 IO.mapOptional("IndentWrappedFunctionNames",
380 Style.IndentWrappedFunctionNames);
Martin Probst0cd74ee2016-06-13 16:39:50 +0000381 IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
382 IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000383 IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
384 Style.KeepEmptyLinesAtTheStartOfBlocks);
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +0000385 IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
386 IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000387 IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
Daniel Jasper65ee3472013-07-31 23:16:02 +0000388 IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000389 IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000390 IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
Daniel Jaspere9beea22014-01-28 15:20:33 +0000391 IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000392 IO.mapOptional("ObjCSpaceBeforeProtocolList",
393 Style.ObjCSpaceBeforeProtocolList);
Manuel Klimek89628f62017-09-20 09:51:03 +0000394 IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
Daniel Jasper33b909c2013-10-25 14:29:37 +0000395 IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
396 Style.PenaltyBreakBeforeFirstCallParameter);
Alexander Kornienkodd7ece52013-06-07 16:02:52 +0000397 IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000398 IO.mapOptional("PenaltyBreakFirstLessLess",
399 Style.PenaltyBreakFirstLessLess);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000400 IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000401 IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
402 IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
403 Style.PenaltyReturnTypeOnItsOwnLine);
Daniel Jasper553d4872014-06-17 12:40:34 +0000404 IO.mapOptional("PointerAlignment", Style.PointerAlignment);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000405 IO.mapOptional("RawStringFormats", Style.RawStringFormats);
Daniel Jaspera0a50392015-12-01 13:28:53 +0000406 IO.mapOptional("ReflowComments", Style.ReflowComments);
407 IO.mapOptional("SortIncludes", Style.SortIncludes);
Krasimir Georgievac16a202017-06-23 11:46:03 +0000408 IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000409 IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
Manuel Klimek89628f62017-09-20 09:51:03 +0000410 IO.mapOptional("SpaceAfterTemplateKeyword",
411 Style.SpaceAfterTemplateKeyword);
Daniel Jasperd94bff32013-09-25 15:15:02 +0000412 IO.mapOptional("SpaceBeforeAssignmentOperators",
413 Style.SpaceBeforeAssignmentOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000414 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
415 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
416 IO.mapOptional("SpacesBeforeTrailingComments",
417 Style.SpacesBeforeTrailingComments);
418 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
419 IO.mapOptional("SpacesInContainerLiterals",
420 Style.SpacesInContainerLiterals);
421 IO.mapOptional("SpacesInCStyleCastParentheses",
422 Style.SpacesInCStyleCastParentheses);
423 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
424 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
425 IO.mapOptional("Standard", Style.Standard);
426 IO.mapOptional("TabWidth", Style.TabWidth);
427 IO.mapOptional("UseTab", Style.UseTab);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000428 }
429};
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000430
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000431template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
432 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
433 IO.mapOptional("AfterClass", Wrapping.AfterClass);
434 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
435 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
436 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
437 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
438 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
439 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
440 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000441 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000442 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
443 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
444 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
Francois Ferrandad722562017-06-30 20:25:55 +0000445 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
446 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
447 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000448 }
449};
450
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000451template <> struct MappingTraits<FormatStyle::IncludeCategory> {
452 static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
453 IO.mapOptional("Regex", Category.Regex);
454 IO.mapOptional("Priority", Category.Priority);
455 }
456};
457
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000458template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> {
459 static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
460 IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve);
461 IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge);
462 IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup);
463 }
464};
465
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000466template <> struct MappingTraits<FormatStyle::RawStringFormat> {
467 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000468 IO.mapOptional("Language", Format.Language);
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000469 IO.mapOptional("Delimiters", Format.Delimiters);
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000470 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000471 IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000472 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
473 }
474};
475
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000476// Allows to read vector<FormatStyle> while keeping default values.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000477// IO.getContext() should contain a pointer to the FormatStyle structure, that
478// will be used to get default values for missing keys.
479// If the first element has no Language specified, it will be treated as the
480// default one for the following elements.
Jacques Pienaarfc275112015-02-18 23:48:37 +0000481template <> struct DocumentListTraits<std::vector<FormatStyle>> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000482 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
483 return Seq.size();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000484 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000485 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000486 size_t Index) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000487 if (Index >= Seq.size()) {
488 assert(Index == Seq.size());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000489 FormatStyle Template;
Krasimir Georgiev1696bb62017-11-09 15:12:17 +0000490 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000491 Template = Seq[0];
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000492 } else {
Daniel Jasperb05a81d2014-05-09 13:11:16 +0000493 Template = *((const FormatStyle *)IO.getContext());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000494 Template.Language = FormatStyle::LK_None;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000495 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000496 Seq.resize(Index + 1, Template);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000497 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000498 return Seq[Index];
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000499 }
500};
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000501} // namespace yaml
502} // namespace llvm
Alexander Kornienkod6538332013-05-07 15:32:14 +0000503
Daniel Jasperf7935112012-12-03 18:12:45 +0000504namespace clang {
505namespace format {
506
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000507const std::error_category &getParseCategory() {
Rafael Espindolad0136702014-06-12 02:50:04 +0000508 static ParseErrorCategory C;
509 return C;
510}
511std::error_code make_error_code(ParseError e) {
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000512 return std::error_code(static_cast<int>(e), getParseCategory());
Rafael Espindolad0136702014-06-12 02:50:04 +0000513}
514
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +0000515inline llvm::Error make_string_error(const llvm::Twine &Message) {
516 return llvm::make_error<llvm::StringError>(Message,
517 llvm::inconvertibleErrorCode());
518}
519
Reid Kleckner6432d452016-10-19 23:39:55 +0000520const char *ParseErrorCategory::name() const noexcept {
Rafael Espindolad0136702014-06-12 02:50:04 +0000521 return "clang-format.parse_error";
522}
523
524std::string ParseErrorCategory::message(int EV) const {
525 switch (static_cast<ParseError>(EV)) {
526 case ParseError::Success:
527 return "Success";
528 case ParseError::Error:
529 return "Invalid argument";
530 case ParseError::Unsuitable:
531 return "Unsuitable";
532 }
Saleem Abdulrasoolfbfbaf62014-06-12 19:33:26 +0000533 llvm_unreachable("unexpected parse error");
Rafael Espindolad0136702014-06-12 02:50:04 +0000534}
535
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000536static FormatStyle expandPresets(const FormatStyle &Style) {
Daniel Jasper55bbe662015-10-07 04:06:10 +0000537 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
538 return Style;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000539 FormatStyle Expanded = Style;
Manuel Klimek89628f62017-09-20 09:51:03 +0000540 Expanded.BraceWrapping = {false, false, false, false, false,
541 false, false, false, false, false,
542 false, false, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000543 switch (Style.BreakBeforeBraces) {
544 case FormatStyle::BS_Linux:
545 Expanded.BraceWrapping.AfterClass = true;
546 Expanded.BraceWrapping.AfterFunction = true;
547 Expanded.BraceWrapping.AfterNamespace = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000548 break;
549 case FormatStyle::BS_Mozilla:
550 Expanded.BraceWrapping.AfterClass = true;
551 Expanded.BraceWrapping.AfterEnum = true;
552 Expanded.BraceWrapping.AfterFunction = true;
553 Expanded.BraceWrapping.AfterStruct = true;
554 Expanded.BraceWrapping.AfterUnion = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000555 Expanded.BraceWrapping.AfterExternBlock = true;
Sylvestre Ledru82c9a0e2017-09-13 20:03:29 +0000556 Expanded.BraceWrapping.SplitEmptyFunction = true;
Francois Ferrandad722562017-06-30 20:25:55 +0000557 Expanded.BraceWrapping.SplitEmptyRecord = false;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000558 break;
559 case FormatStyle::BS_Stroustrup:
560 Expanded.BraceWrapping.AfterFunction = true;
561 Expanded.BraceWrapping.BeforeCatch = true;
562 Expanded.BraceWrapping.BeforeElse = true;
563 break;
564 case FormatStyle::BS_Allman:
565 Expanded.BraceWrapping.AfterClass = true;
566 Expanded.BraceWrapping.AfterControlStatement = true;
567 Expanded.BraceWrapping.AfterEnum = true;
568 Expanded.BraceWrapping.AfterFunction = true;
569 Expanded.BraceWrapping.AfterNamespace = true;
570 Expanded.BraceWrapping.AfterObjCDeclaration = true;
571 Expanded.BraceWrapping.AfterStruct = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000572 Expanded.BraceWrapping.AfterExternBlock = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000573 Expanded.BraceWrapping.BeforeCatch = true;
574 Expanded.BraceWrapping.BeforeElse = true;
575 break;
576 case FormatStyle::BS_GNU:
Manuel Klimek89628f62017-09-20 09:51:03 +0000577 Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
578 true, true, true, true, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000579 break;
580 case FormatStyle::BS_WebKit:
581 Expanded.BraceWrapping.AfterFunction = true;
582 break;
583 default:
584 break;
585 }
586 return Expanded;
587}
588
Daniel Jasperf7935112012-12-03 18:12:45 +0000589FormatStyle getLLVMStyle() {
590 FormatStyle LLVMStyle;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000591 LLVMStyle.Language = FormatStyle::LK_Cpp;
Daniel Jasperf7935112012-12-03 18:12:45 +0000592 LLVMStyle.AccessModifierOffset = -2;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000593 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000594 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
Daniel Jasper3219e432014-12-02 13:24:51 +0000595 LLVMStyle.AlignOperands = true;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000596 LLVMStyle.AlignTrailingComments = true;
Daniel Jaspera44991332015-04-29 13:06:49 +0000597 LLVMStyle.AlignConsecutiveAssignments = false;
Daniel Jaspere12597c2015-10-01 10:06:54 +0000598 LLVMStyle.AlignConsecutiveDeclarations = false;
Daniel Jasperf7db4332013-01-29 16:03:49 +0000599 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
Daniel Jasperd74cf402014-04-08 12:46:38 +0000600 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Daniel Jasper17605d32014-05-14 09:33:35 +0000601 LLVMStyle.AllowShortBlocksOnASingleLine = false;
Daniel Jasperb87899b2014-09-10 13:11:45 +0000602 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000603 LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper3a685df2013-05-16 12:12:21 +0000604 LLVMStyle.AllowShortLoopsOnASingleLine = false;
Zachary Turner448592e2015-12-18 22:20:15 +0000605 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000606 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Alexander Kornienko58611712013-07-04 12:02:44 +0000607 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000608 LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Daniel Jasper18210d72014-10-09 09:52:05 +0000609 LLVMStyle.BinPackArguments = true;
Francois Ferrande56a8292017-06-14 12:29:47 +0000610 LLVMStyle.BinPackParameters = true;
Daniel Jasperac043c92014-09-15 11:11:00 +0000611 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Daniel Jasper165b29e2013-11-08 00:57:11 +0000612 LLVMStyle.BreakBeforeTernaryOperators = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000613 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
Manuel Klimek89628f62017-09-20 09:51:03 +0000614 LLVMStyle.BraceWrapping = {false, false, false, false, false,
615 false, false, false, false, false,
616 false, false, true, true, true};
Nico Weber2cd92f12015-10-15 16:03:01 +0000617 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000618 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000619 LLVMStyle.BreakBeforeInheritanceComma = false;
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000620 LLVMStyle.BreakStringLiterals = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000621 LLVMStyle.ColumnLimit = 80;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000622 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
Francois Ferrande56a8292017-06-14 12:29:47 +0000623 LLVMStyle.CompactNamespaces = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000624 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
Daniel Jaspercdaffa42013-08-13 10:58:30 +0000625 LLVMStyle.ConstructorInitializerIndentWidth = 4;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000626 LLVMStyle.ContinuationIndentWidth = 4;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000627 LLVMStyle.Cpp11BracedListStyle = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000628 LLVMStyle.DerivePointerAlignment = false;
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000629 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000630 LLVMStyle.FixNamespaceComments = true;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000631 LLVMStyle.ForEachMacros.push_back("foreach");
632 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
633 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
Daniel Jasper85c472d2015-09-29 07:53:08 +0000634 LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
Chandler Carruthd676ab12017-06-29 23:20:54 +0000635 {"^(<|\"(gtest|gmock|isl|json)/)", 3},
Daniel Jasper85c472d2015-09-29 07:53:08 +0000636 {".*", 1}};
Chandler Carruthd676ab12017-06-29 23:20:54 +0000637 LLVMStyle.IncludeIsMainRegex = "(Test)?$";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000638 LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000639 LLVMStyle.IndentCaseLabels = false;
Krasimir Georgievad47c902017-08-30 14:34:57 +0000640 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
Daniel Jasperc75e1ef2014-07-09 08:42:42 +0000641 LLVMStyle.IndentWrappedFunctionNames = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000642 LLVMStyle.IndentWidth = 2;
Martin Probstfb2342d2016-06-13 17:50:10 +0000643 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
644 LLVMStyle.JavaScriptWrapImports = true;
Alexander Kornienkoebb43ca2013-09-05 14:08:34 +0000645 LLVMStyle.TabWidth = 8;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000646 LLVMStyle.MaxEmptyLinesToKeep = 1;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000647 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000648 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000649 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000650 LLVMStyle.ObjCBlockIndentWidth = 2;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000651 LLVMStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000652 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000653 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000654 LLVMStyle.SpacesBeforeTrailingComments = 1;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000655 LLVMStyle.Standard = FormatStyle::LS_Cpp11;
Alexander Kornienko3c3d09c2013-09-27 16:14:22 +0000656 LLVMStyle.UseTab = FormatStyle::UT_Never;
Daniel Jaspera0a50392015-12-01 13:28:53 +0000657 LLVMStyle.ReflowComments = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000658 LLVMStyle.SpacesInParentheses = false;
Daniel Jasperad981f82014-08-26 11:41:14 +0000659 LLVMStyle.SpacesInSquareBrackets = false;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000660 LLVMStyle.SpaceInEmptyParentheses = false;
Daniel Jasperb2e10a52014-01-15 15:09:08 +0000661 LLVMStyle.SpacesInContainerLiterals = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000662 LLVMStyle.SpacesInCStyleCastParentheses = false;
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000663 LLVMStyle.SpaceAfterCStyleCast = false;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000664 LLVMStyle.SpaceAfterTemplateKeyword = true;
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000665 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
Daniel Jasperd94bff32013-09-25 15:15:02 +0000666 LLVMStyle.SpaceBeforeAssignmentOperators = true;
Daniel Jasperdd978ae2013-10-29 14:52:02 +0000667 LLVMStyle.SpacesInAngles = false;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000668
Francois Ferrand9976efa2017-05-22 08:28:17 +0000669 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
Daniel Jasper19a541e2013-12-19 16:45:34 +0000670 LLVMStyle.PenaltyBreakComment = 300;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000671 LLVMStyle.PenaltyBreakFirstLessLess = 120;
672 LLVMStyle.PenaltyBreakString = 1000;
673 LLVMStyle.PenaltyExcessCharacter = 1000000;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000674 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000675 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000676
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000677 LLVMStyle.DisableFormat = false;
Daniel Jasperda446772015-11-16 12:38:56 +0000678 LLVMStyle.SortIncludes = true;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000679 LLVMStyle.SortUsingDeclarations = true;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000680
Daniel Jasperf7935112012-12-03 18:12:45 +0000681 return LLVMStyle;
682}
683
Nico Weber514ecc82014-02-02 20:50:45 +0000684FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000685 if (Language == FormatStyle::LK_TextProto) {
686 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
687 GoogleStyle.Language = FormatStyle::LK_TextProto;
Krasimir Georgieveda222e2018-01-24 11:18:39 +0000688
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000689 return GoogleStyle;
690 }
691
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000692 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000693 GoogleStyle.Language = Language;
694
Daniel Jasperf7935112012-12-03 18:12:45 +0000695 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000696 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000697 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000698 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000699 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000700 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000701 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000702 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000703 GoogleStyle.IncludeCategories = {
704 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000705 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000706 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000707 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Ben Hamilton3a47fdd2018-02-08 01:49:10 +0000708 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000709 GoogleStyle.ObjCSpaceAfterProperty = false;
Ben Hamiltonf84f1182018-01-18 18:37:16 +0000710 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000711 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000712 GoogleStyle.RawStringFormats = {{
713 FormatStyle::LK_TextProto,
714 /*Delimiters=*/
715 {
716 "pb",
717 "PB",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000718 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000719 /*EnclosingFunctionNames=*/
Krasimir Georgieva83d3c52018-01-29 19:28:05 +0000720 {},
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000721 /*CanonicalDelimiter=*/"",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000722 /*BasedOnStyle=*/"google",
723 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000724 GoogleStyle.SpacesBeforeTrailingComments = 2;
725 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000726
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000727 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000728 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000729
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000730 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000731 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000732 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000733 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000734 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000735 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000736 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000737 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
738 GoogleStyle.ColumnLimit = 100;
739 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000740 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000741 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000742 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000743 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000744 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000745 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000746 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000747 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
748 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
749 GoogleStyle.CommentPragmas =
750 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000751 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000752 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000753 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000754 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000755 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000756 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000757 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper783bac62014-04-15 09:54:30 +0000758 GoogleStyle.SpacesInContainerLiterals = false;
Krasimir Georgievc2091802018-01-31 10:14:10 +0000759 GoogleStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev374e6de2018-02-08 10:47:12 +0000760 // This affects protocol buffer options specifications and text protos.
761 // Text protos are currently mostly formatted inside C++ raw string literals
762 // and often the current breaking behavior of string literals is not
763 // beneficial there. Investigate turning this on once proper string reflow
764 // has been implemented.
765 GoogleStyle.BreakStringLiterals = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000766 } else if (Language == FormatStyle::LK_ObjC) {
767 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000768 }
769
Daniel Jasperf7935112012-12-03 18:12:45 +0000770 return GoogleStyle;
771}
772
Nico Weber514ecc82014-02-02 20:50:45 +0000773FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
774 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000775 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000776 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000777 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000778 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000779 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000780 } else if (Language == FormatStyle::LK_JavaScript) {
781 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
782 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000783 } else {
784 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
785 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
786 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
787 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
788 ChromiumStyle.BinPackParameters = false;
789 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000790 if (Language == FormatStyle::LK_ObjC)
791 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000792 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000793 return ChromiumStyle;
794}
795
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000796FormatStyle getMozillaStyle() {
797 FormatStyle MozillaStyle = getLLVMStyle();
798 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000799 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000800 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000801 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
802 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000803 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000804 MozillaStyle.BinPackParameters = false;
805 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000806 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000807 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000808 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000809 MozillaStyle.ConstructorInitializerIndentWidth = 2;
810 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000811 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000812 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000813 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000814 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000815 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
816 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000817 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000818 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000819 return MozillaStyle;
820}
821
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000822FormatStyle getWebKitStyle() {
823 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000824 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000825 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000826 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000827 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000828 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000829 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000830 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000831 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000832 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000833 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000834 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000835 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000836 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000837 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000838 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000839 return Style;
840}
841
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000842FormatStyle getGNUStyle() {
843 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000844 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000845 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000846 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000847 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000848 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000849 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000850 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000851 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000852 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000853 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000854 return Style;
855}
856
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000857FormatStyle getNoStyle() {
858 FormatStyle NoStyle = getLLVMStyle();
859 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000860 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000861 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000862 return NoStyle;
863}
864
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000865bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
866 FormatStyle *Style) {
867 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000868 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000869 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000870 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000871 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000872 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000873 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000874 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000875 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000876 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000877 } else if (Name.equals_lower("gnu")) {
878 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000879 } else if (Name.equals_lower("none")) {
880 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000881 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000882 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000883 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000884
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000885 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000886 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000887}
888
Rafael Espindolac0809172014-06-12 14:02:15 +0000889std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000890 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000891 FormatStyle::LanguageKind Language = Style->Language;
892 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000893 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000894 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000895 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000896 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000897 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000898 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
899 // values for the fields, keys for which are missing from the configuration.
900 // Mapping also uses the context to get the language to find the correct
901 // base style.
902 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000903 Input >> Styles;
904 if (Input.error())
905 return Input.error();
906
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000907 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000908 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000909 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000910 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000911 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000912 for (unsigned j = 0; j < i; ++j) {
913 if (Styles[i].Language == Styles[j].Language) {
914 DEBUG(llvm::dbgs()
915 << "Duplicate languages in the config file on positions " << j
916 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000917 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000918 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000919 }
920 }
921 // Look for a suitable configuration starting from the end, so we can
922 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000923 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000924 FormatStyle::FormatStyleSet StyleSet;
925 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000926 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000927 if (Styles[i].Language != FormatStyle::LK_None)
928 StyleSet.Add(Styles[i]);
929 if (Styles[i].Language == Language)
930 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000931 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000932 if (!LanguageFound) {
933 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
934 return make_error_code(ParseError::Unsuitable);
935 FormatStyle DefaultStyle = Styles[0];
936 DefaultStyle.Language = Language;
937 StyleSet.Add(std::move(DefaultStyle));
938 }
939 *Style = *StyleSet.Get(Language);
940 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000941}
942
943std::string configurationAsText(const FormatStyle &Style) {
944 std::string Text;
945 llvm::raw_string_ostream Stream(Text);
946 llvm::yaml::Output Output(Stream);
947 // We use the same mapping method for input and output, so we need a non-const
948 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000949 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000950 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000951 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000952}
953
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000954llvm::Optional<FormatStyle>
955FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
956 if (!Styles)
957 return None;
958 auto It = Styles->find(Language);
959 if (It == Styles->end())
960 return None;
961 FormatStyle Style = It->second;
962 Style.StyleSet = *this;
963 return Style;
964}
965
966void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
967 assert(Style.Language != LK_None &&
968 "Cannot add a style for LK_None to a StyleSet");
969 assert(
970 !Style.StyleSet.Styles &&
971 "Cannot add a style associated with an existing StyleSet to a StyleSet");
972 if (!Styles)
973 Styles = std::make_shared<MapType>();
974 (*Styles)[Style.Language] = std::move(Style);
975}
976
977void FormatStyle::FormatStyleSet::Clear() {
978 Styles.reset();
979}
980
981llvm::Optional<FormatStyle>
982FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
983 return StyleSet.Get(Language);
984}
985
Craig Topperaf35e852013-06-30 22:29:28 +0000986namespace {
987
Daniel Jasper496c1992016-09-07 22:48:53 +0000988class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000989public:
Daniel Jasper496c1992016-09-07 22:48:53 +0000990 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
991 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +0000992
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000993 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +0000994 analyze(TokenAnnotator &Annotator,
995 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +0000996 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000997 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
998 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +0000999 tooling::Replacements Result;
1000 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001001 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +00001002 }
1003
1004private:
Daniel Jasper496c1992016-09-07 22:48:53 +00001005 // Replaces double/single-quoted string literal as appropriate, re-escaping
1006 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +00001007 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +00001008 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +00001009 for (AnnotatedLine *Line : Lines) {
1010 requoteJSStringLiteral(Line->Children, Result);
1011 if (!Line->Affected)
1012 continue;
1013 for (FormatToken *FormatTok = Line->First; FormatTok;
1014 FormatTok = FormatTok->Next) {
1015 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001016 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001017 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001018 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001019 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001020 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001021 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001022 !Input.startswith("\'")))
1023 continue;
1024
1025 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001026 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001027 SourceLocation Start = FormatTok->Tok.getLocation();
1028 auto Replace = [&](SourceLocation Start, unsigned Length,
1029 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001030 auto Err = Result.add(tooling::Replacement(
1031 Env.getSourceManager(), Start, Length, ReplacementText));
1032 // FIXME: handle error. For now, print error message and skip the
1033 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001034 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001035 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001036 assert(false);
1037 }
Daniel Jasper97439922016-03-17 13:03:41 +00001038 };
1039 Replace(Start, 1, IsSingle ? "'" : "\"");
1040 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1041 IsSingle ? "'" : "\"");
1042
1043 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001044 bool Escaped = false;
1045 for (size_t i = 1; i < Input.size() - 1; i++) {
1046 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001047 case '\\':
1048 if (!Escaped && i + 1 < Input.size() &&
1049 ((IsSingle && Input[i + 1] == '"') ||
1050 (!IsSingle && Input[i + 1] == '\''))) {
1051 // Remove this \, it's escaping a " or ' that no longer needs
1052 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001053 Replace(Start.getLocWithOffset(i), 1, "");
1054 continue;
1055 }
1056 Escaped = !Escaped;
1057 break;
1058 case '\"':
1059 case '\'':
1060 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1061 // Escape the quote.
1062 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001063 }
1064 Escaped = false;
1065 break;
1066 default:
1067 Escaped = false;
1068 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001069 }
1070 }
Daniel Jasper97439922016-03-17 13:03:41 +00001071 }
1072 }
1073 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001074};
1075
1076class Formatter : public TokenAnalyzer {
1077public:
1078 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001079 FormattingAttemptStatus *Status)
1080 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001081
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001082 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001083 analyze(TokenAnnotator &Annotator,
1084 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1085 FormatTokenLexer &Tokens) override {
1086 tooling::Replacements Result;
1087 deriveLocalStyle(AnnotatedLines);
1088 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1089 AnnotatedLines.end());
1090 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1091 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1092 }
1093 Annotator.setCommentLineLevels(AnnotatedLines);
1094
1095 WhitespaceManager Whitespaces(
1096 Env.getSourceManager(), Style,
1097 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1098 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1099 Env.getSourceManager(), Whitespaces, Encoding,
1100 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001101 unsigned Penalty =
1102 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1103 Tokens.getKeywords(), Env.getSourceManager(),
1104 Status)
1105 .format(AnnotatedLines, /*DryRun=*/false,
1106 /*AdditionalIndent=*/0,
1107 /*FixBadIndentation=*/false,
1108 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1109 /*NextStartColumn=*/Env.getNextStartColumn(),
1110 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001111 for (const auto &R : Whitespaces.generateReplacements())
1112 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001113 return std::make_pair(Result, 0);
1114 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001115 }
1116
1117private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001118 static bool inputUsesCRLF(StringRef Text) {
1119 return Text.count('\r') * 2 > Text.count('\n');
1120 }
1121
Daniel Jasper352f0df2015-07-18 16:35:30 +00001122 bool
1123 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001124 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001125 if (hasCpp03IncompatibleFormat(Line->Children))
1126 return true;
1127 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1128 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1129 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1130 return true;
1131 if (Tok->is(TT_TemplateCloser) &&
1132 Tok->Previous->is(TT_TemplateCloser))
1133 return true;
1134 }
1135 }
1136 }
1137 return false;
1138 }
1139
1140 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1141 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001142 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001143 AlignmentDiff += countVariableAlignments(Line->Children);
1144 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1145 if (!Tok->is(TT_PointerOrReference))
1146 continue;
1147 bool SpaceBefore =
1148 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1149 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1150 Tok->Next->WhitespaceRange.getEnd();
1151 if (SpaceBefore && !SpaceAfter)
1152 ++AlignmentDiff;
1153 if (!SpaceBefore && SpaceAfter)
1154 --AlignmentDiff;
1155 }
1156 }
1157 return AlignmentDiff;
1158 }
1159
Manuel Klimek71814b42013-10-11 21:25:45 +00001160 void
1161 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001162 bool HasBinPackedFunction = false;
1163 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001164 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001165 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001166 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001167 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001168 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001169 if (Tok->PackingKind == PPK_BinPacked)
1170 HasBinPackedFunction = true;
1171 if (Tok->PackingKind == PPK_OnePerLine)
1172 HasOnePerLineFunction = true;
1173
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001174 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001175 }
1176 }
Eric Liu635423e2016-04-28 07:52:03 +00001177 if (Style.DerivePointerAlignment)
1178 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1179 ? FormatStyle::PAS_Left
1180 : FormatStyle::PAS_Right;
1181 if (Style.Standard == FormatStyle::LS_Auto)
1182 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1183 ? FormatStyle::LS_Cpp11
1184 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001185 BinPackInconclusiveFunctions =
1186 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001187 }
1188
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001189 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001190 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001191};
1192
1193// This class clean up the erroneous/redundant code around the given ranges in
1194// file.
1195class Cleaner : public TokenAnalyzer {
1196public:
Eric Liu635423e2016-04-28 07:52:03 +00001197 Cleaner(const Environment &Env, const FormatStyle &Style)
1198 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001199 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1200
1201 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001202 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001203 analyze(TokenAnnotator &Annotator,
1204 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001205 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001206 // FIXME: in the current implementation the granularity of affected range
1207 // is an annotated line. However, this is not sufficient. Furthermore,
1208 // redundant code introduced by replacements does not necessarily
1209 // intercept with ranges of replacements that result in the redundancy.
1210 // To determine if some redundant code is actually introduced by
1211 // replacements(e.g. deletions), we need to come up with a more
1212 // sophisticated way of computing affected ranges.
1213 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1214 AnnotatedLines.end());
1215
1216 checkEmptyNamespace(AnnotatedLines);
1217
Eric Liuce5e4bc2016-05-18 08:02:56 +00001218 for (auto &Line : AnnotatedLines) {
1219 if (Line->Affected) {
1220 cleanupRight(Line->First, tok::comma, tok::comma);
1221 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001222 cleanupRight(Line->First, tok::l_paren, tok::comma);
1223 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001224 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1225 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001226 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001227 }
1228 }
1229
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001230 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001231 }
1232
1233private:
1234 bool containsOnlyComments(const AnnotatedLine &Line) {
1235 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1236 if (Tok->isNot(tok::comment))
1237 return false;
1238 }
1239 return true;
1240 }
1241
1242 // Iterate through all lines and remove any empty (nested) namespaces.
1243 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001244 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001245 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1246 auto &Line = *AnnotatedLines[i];
1247 if (Line.startsWith(tok::kw_namespace) ||
1248 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001249 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001250 }
1251 }
1252
1253 for (auto Line : DeletedLines) {
1254 FormatToken *Tok = AnnotatedLines[Line]->First;
1255 while (Tok) {
1256 deleteToken(Tok);
1257 Tok = Tok->Next;
1258 }
1259 }
1260 }
1261
1262 // The function checks if the namespace, which starts from \p CurrentLine, and
1263 // its nested namespaces are empty and delete them if they are empty. It also
1264 // sets \p NewLine to the last line checked.
1265 // Returns true if the current namespace is empty.
1266 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001267 unsigned CurrentLine, unsigned &NewLine,
1268 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001269 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001270 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001271 // If the left brace is in a new line, we should consume it first so that
1272 // it does not make the namespace non-empty.
1273 // FIXME: error handling if there is no left brace.
1274 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1275 NewLine = CurrentLine;
1276 return false;
1277 }
1278 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1279 return false;
1280 }
1281 while (++CurrentLine < End) {
1282 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1283 break;
1284
1285 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1286 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1287 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001288 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1289 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001290 return false;
1291 CurrentLine = NewLine;
1292 continue;
1293 }
1294
1295 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1296 continue;
1297
1298 // If there is anything other than comments or nested namespaces in the
1299 // current namespace, the namespace cannot be empty.
1300 NewLine = CurrentLine;
1301 return false;
1302 }
1303
1304 NewLine = CurrentLine;
1305 if (CurrentLine >= End)
1306 return false;
1307
1308 // Check if the empty namespace is actually affected by changed ranges.
1309 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1310 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1311 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1312 return false;
1313
1314 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1315 DeletedLines.insert(i);
1316 }
1317
1318 return true;
1319 }
1320
Eric Liuce5e4bc2016-05-18 08:02:56 +00001321 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1322 // of the token in the pair if the left token has \p LK token kind and the
1323 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1324 // is deleted on match; otherwise, the right token is deleted.
1325 template <typename LeftKind, typename RightKind>
1326 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1327 bool DeleteLeft) {
1328 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1329 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1330 if (!Res->is(tok::comment) &&
1331 DeletedTokens.find(Res) == DeletedTokens.end())
1332 return Res;
1333 return nullptr;
1334 };
1335 for (auto *Left = Start; Left;) {
1336 auto *Right = NextNotDeleted(*Left);
1337 if (!Right)
1338 break;
1339 if (Left->is(LK) && Right->is(RK)) {
1340 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001341 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1342 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001343 // If the right token is deleted, we should keep the left token
1344 // unchanged and pair it with the new right token.
1345 if (!DeleteLeft)
1346 continue;
1347 }
1348 Left = Right;
1349 }
1350 }
1351
1352 template <typename LeftKind, typename RightKind>
1353 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1354 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1355 }
1356
1357 template <typename LeftKind, typename RightKind>
1358 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1359 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1360 }
1361
Eric Liu4cfb88a2016-04-25 15:09:22 +00001362 // Delete the given token.
1363 inline void deleteToken(FormatToken *Tok) {
1364 if (Tok)
1365 DeletedTokens.insert(Tok);
1366 }
1367
1368 tooling::Replacements generateFixes() {
1369 tooling::Replacements Fixes;
1370 std::vector<FormatToken *> Tokens;
1371 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1372 std::back_inserter(Tokens));
1373
1374 // Merge multiple continuous token deletions into one big deletion so that
1375 // the number of replacements can be reduced. This makes computing affected
1376 // ranges more efficient when we run reformat on the changed code.
1377 unsigned Idx = 0;
1378 while (Idx < Tokens.size()) {
1379 unsigned St = Idx, End = Idx;
1380 while ((End + 1) < Tokens.size() &&
1381 Tokens[End]->Next == Tokens[End + 1]) {
1382 End++;
1383 }
1384 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1385 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001386 auto Err =
1387 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1388 // FIXME: better error handling. for now just print error message and skip
1389 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001390 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001391 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001392 assert(false && "Fixes must not conflict!");
1393 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001394 Idx = End + 1;
1395 }
1396
1397 return Fixes;
1398 }
1399
1400 // Class for less-than inequality comparason for the set `RedundantTokens`.
1401 // We store tokens in the order they appear in the translation unit so that
1402 // we do not need to sort them in `generateFixes()`.
1403 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001404 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001405
Eric Liu2874ac32016-05-18 08:14:49 +00001406 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001407 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1408 RHS->Tok.getLocation());
1409 }
Eric Liu635423e2016-04-28 07:52:03 +00001410 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001411 };
1412
1413 // Tokens to be deleted.
1414 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001415};
1416
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001417class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1418public:
1419 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1420 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1421
1422 std::pair<tooling::Replacements, unsigned>
1423 analyze(TokenAnnotator &Annotator,
1424 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1425 FormatTokenLexer &Tokens) override {
1426 assert(Style.Language == FormatStyle::LK_Cpp);
1427 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1428 tooling::Replacements Result;
1429 return {Result, 0};
1430 }
1431
1432 bool isObjC() { return IsObjC; }
1433
1434private:
1435 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1436 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001437 // Keep this array sorted, since we are binary searching over it.
1438 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001439 "CGFloat",
1440 "NSAffineTransform",
1441 "NSArray",
1442 "NSAttributedString",
1443 "NSCache",
1444 "NSCharacterSet",
1445 "NSCountedSet",
1446 "NSData",
1447 "NSDataDetector",
1448 "NSDecimal",
1449 "NSDecimalNumber",
1450 "NSDictionary",
1451 "NSEdgeInsets",
1452 "NSHashTable",
1453 "NSIndexPath",
1454 "NSIndexSet",
1455 "NSInteger",
1456 "NSLocale",
1457 "NSMapTable",
1458 "NSMutableArray",
1459 "NSMutableAttributedString",
1460 "NSMutableCharacterSet",
1461 "NSMutableData",
1462 "NSMutableDictionary",
1463 "NSMutableIndexSet",
1464 "NSMutableOrderedSet",
1465 "NSMutableSet",
1466 "NSMutableString",
1467 "NSNumber",
1468 "NSNumberFormatter",
1469 "NSOrderedSet",
1470 "NSPoint",
1471 "NSPointerArray",
1472 "NSRange",
1473 "NSRect",
1474 "NSRegularExpression",
1475 "NSSet",
1476 "NSSize",
1477 "NSString",
1478 "NSUInteger",
1479 "NSURL",
1480 "NSURLComponents",
1481 "NSURLQueryItem",
1482 "NSUUID",
1483 };
1484
1485 for (auto &Line : AnnotatedLines) {
1486 for (FormatToken *FormatTok = Line->First->Next; FormatTok;
1487 FormatTok = FormatTok->Next) {
1488 if ((FormatTok->Previous->is(tok::at) &&
1489 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1490 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1491 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1492 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1493 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1494 tok::l_brace))) ||
1495 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001496 std::binary_search(std::begin(FoundationIdentifiers),
1497 std::end(FoundationIdentifiers),
1498 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001499 FormatTok->is(TT_ObjCStringLiteral) ||
1500 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1501 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1502 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1503 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1504 return true;
1505 }
1506 }
1507 }
1508 return false;
1509 }
1510
1511 bool IsObjC;
1512};
1513
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001514struct IncludeDirective {
1515 StringRef Filename;
1516 StringRef Text;
1517 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001518 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001519};
1520
Craig Topperaf35e852013-06-30 22:29:28 +00001521} // end anonymous namespace
1522
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001523// Determines whether 'Ranges' intersects with ('Start', 'End').
1524static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1525 unsigned End) {
1526 for (auto Range : Ranges) {
1527 if (Range.getOffset() < End &&
1528 Range.getOffset() + Range.getLength() > Start)
1529 return true;
1530 }
1531 return false;
1532}
1533
Eric Liua992afe2016-08-10 09:32:23 +00001534// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1535// before sorting/deduplicating. Index is the index of the include under the
1536// cursor in the original set of includes. If this include has duplicates, it is
1537// the index of the first of the duplicates as the others are going to be
1538// removed. OffsetToEOL describes the cursor's position relative to the end of
1539// its current line.
1540// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1541static std::pair<unsigned, unsigned>
1542FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1543 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1544 unsigned CursorIndex = UINT_MAX;
1545 unsigned OffsetToEOL = 0;
1546 for (int i = 0, e = Includes.size(); i != e; ++i) {
1547 unsigned Start = Includes[Indices[i]].Offset;
1548 unsigned End = Start + Includes[Indices[i]].Text.size();
1549 if (!(Cursor >= Start && Cursor < End))
1550 continue;
1551 CursorIndex = Indices[i];
1552 OffsetToEOL = End - Cursor;
1553 // Put the cursor on the only remaining #include among the duplicate
1554 // #includes.
1555 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1556 CursorIndex = i;
1557 break;
1558 }
1559 return std::make_pair(CursorIndex, OffsetToEOL);
1560}
1561
1562// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1563// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1564// source order.
1565// #include directives with the same text will be deduplicated, and only the
1566// first #include in the duplicate #includes remains. If the `Cursor` is
1567// provided and put on a deleted #include, it will be moved to the remaining
1568// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001569static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001570 const SmallVectorImpl<IncludeDirective> &Includes,
1571 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1572 tooling::Replacements &Replaces, unsigned *Cursor) {
1573 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001574 unsigned IncludesEndOffset =
1575 Includes.back().Offset + Includes.back().Text.size();
1576 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1577 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001578 return;
1579 SmallVector<unsigned, 16> Indices;
1580 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1581 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001582 std::stable_sort(
1583 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1584 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1585 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1586 });
Eric Liua992afe2016-08-10 09:32:23 +00001587 // The index of the include on which the cursor will be put after
1588 // sorting/deduplicating.
1589 unsigned CursorIndex;
1590 // The offset from cursor to the end of line.
1591 unsigned CursorToEOLOffset;
1592 if (Cursor)
1593 std::tie(CursorIndex, CursorToEOLOffset) =
1594 FindCursorIndex(Includes, Indices, *Cursor);
1595
1596 // Deduplicate #includes.
1597 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1598 [&](unsigned LHSI, unsigned RHSI) {
1599 return Includes[LHSI].Text == Includes[RHSI].Text;
1600 }),
1601 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001602
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001603 int CurrentCategory = Includes.front().Category;
1604
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001605 // If the #includes are out of order, we generate a single replacement fixing
1606 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001607 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001608 std::is_sorted(Indices.begin(), Indices.end()) &&
1609 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001610 return;
1611
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001612 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001613 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001614 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001615 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001616 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1617 CurrentCategory != Includes[Index].Category)
1618 result += "\n";
1619 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001620 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001621 if (Cursor && CursorIndex == Index)
1622 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001623 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001624 }
1625
Eric Liu40ef2fb2016-08-01 10:16:37 +00001626 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001627 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001628 // FIXME: better error handling. For now, just skip the replacement for the
1629 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001630 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001631 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001632 assert(false);
1633 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001634}
1635
Eric Liu659afd52016-05-31 13:34:20 +00001636namespace {
1637
1638// This class manages priorities of #include categories and calculates
1639// priorities for headers.
1640class IncludeCategoryManager {
1641public:
1642 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1643 : Style(Style), FileName(FileName) {
1644 FileStem = llvm::sys::path::stem(FileName);
1645 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001646 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001647 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1648 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1649 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1650 FileName.endswith(".mm");
1651 }
1652
1653 // Returns the priority of the category which \p IncludeName belongs to.
1654 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1655 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1656 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1657 int Ret = INT_MAX;
1658 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1659 if (CategoryRegexs[i].match(IncludeName)) {
1660 Ret = Style.IncludeCategories[i].Priority;
1661 break;
1662 }
1663 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1664 Ret = 0;
1665 return Ret;
1666 }
1667
1668private:
1669 bool isMainHeader(StringRef IncludeName) const {
1670 if (!IncludeName.startswith("\""))
1671 return false;
1672 StringRef HeaderStem =
1673 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001674 if (FileStem.startswith(HeaderStem) ||
1675 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001676 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001677 (HeaderStem + Style.IncludeIsMainRegex).str(),
1678 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001679 if (MainIncludeRegex.match(FileStem))
1680 return true;
1681 }
1682 return false;
1683 }
1684
1685 const FormatStyle &Style;
1686 bool IsMainFile;
1687 StringRef FileName;
1688 StringRef FileStem;
1689 SmallVector<llvm::Regex, 4> CategoryRegexs;
1690};
1691
1692const char IncludeRegexPattern[] =
1693 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1694
1695} // anonymous namespace
1696
Martin Probstc4a0dd42016-05-20 11:24:24 +00001697tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1698 ArrayRef<tooling::Range> Ranges,
1699 StringRef FileName,
1700 tooling::Replacements &Replaces,
1701 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001702 unsigned Prev = 0;
1703 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001704 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001705 SmallVector<StringRef, 4> Matches;
1706 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001707
1708 // In compiled files, consider the first #include to be the main #include of
1709 // the file if it is not a system #include. This ensures that the header
1710 // doesn't have hidden dependencies
1711 // (http://llvm.org/docs/CodingStandards.html#include-style).
1712 //
1713 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1714 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001715 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001716 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001717 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001718 bool FormattingOff = false;
1719
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001720 for (;;) {
1721 auto Pos = Code.find('\n', SearchFrom);
1722 StringRef Line =
1723 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001724
1725 StringRef Trimmed = Line.trim();
1726 if (Trimmed == "// clang-format off")
1727 FormattingOff = true;
1728 else if (Trimmed == "// clang-format on")
1729 FormattingOff = false;
1730
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001731 const bool EmptyLineSkipped =
1732 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1733 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1734
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001735 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001736 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001737 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001738 int Category = Categories.getIncludePriority(
1739 IncludeName,
1740 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1741 if (Category == 0)
1742 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001743 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001744 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001745 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1746 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001747 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001748 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001749 }
1750 Prev = Pos + 1;
1751 }
1752 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1753 break;
1754 SearchFrom = Pos + 1;
1755 }
1756 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001757 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1758 return Replaces;
1759}
1760
Martin Probstfa37b182017-01-27 09:09:11 +00001761bool isMpegTS(StringRef Code) {
1762 // MPEG transport streams use the ".ts" file extension. clang-format should
1763 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1764 // 189 bytes - detect that and return.
1765 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1766}
1767
Manuel Klimek89628f62017-09-20 09:51:03 +00001768bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001769
Martin Probstc4a0dd42016-05-20 11:24:24 +00001770tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1771 ArrayRef<tooling::Range> Ranges,
1772 StringRef FileName, unsigned *Cursor) {
1773 tooling::Replacements Replaces;
1774 if (!Style.SortIncludes)
1775 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001776 if (isLikelyXml(Code))
1777 return Replaces;
1778 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1779 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001780 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001781 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1782 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1783 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001784 return Replaces;
1785}
1786
Eric Liu4cfb88a2016-04-25 15:09:22 +00001787template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001788static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001789processReplacements(T ProcessFunc, StringRef Code,
1790 const tooling::Replacements &Replaces,
1791 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001792 if (Replaces.empty())
1793 return tooling::Replacements();
1794
Eric Liu4f8d9942016-07-11 13:53:12 +00001795 auto NewCode = applyAllReplacements(Code, Replaces);
1796 if (!NewCode)
1797 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001798 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001799 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001800
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001801 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001802 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001803
Eric Liu40ef2fb2016-08-01 10:16:37 +00001804 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001805}
1806
Eric Liu4f8d9942016-07-11 13:53:12 +00001807llvm::Expected<tooling::Replacements>
1808formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1809 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001810 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001811 // `sortIncludes`.
1812 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1813 std::vector<tooling::Range> Ranges,
1814 StringRef FileName) -> tooling::Replacements {
1815 return sortIncludes(Style, Code, Ranges, FileName);
1816 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001817 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001818 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001819 if (!SortedReplaces)
1820 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001821
1822 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001823 // `reformat`.
1824 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1825 std::vector<tooling::Range> Ranges,
1826 StringRef FileName) -> tooling::Replacements {
1827 return reformat(Style, Code, Ranges, FileName);
1828 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001829 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001830}
1831
Eric Liu659afd52016-05-31 13:34:20 +00001832namespace {
1833
1834inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001835 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001836 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1837}
1838
Eric Liuc0d3a802016-09-23 15:10:56 +00001839inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1840 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1841}
1842
Eric Liu964782a2016-12-02 11:01:43 +00001843// Returns the offset after skipping a sequence of tokens, matched by \p
1844// GetOffsetAfterSequence, from the start of the code.
1845// \p GetOffsetAfterSequence should be a function that matches a sequence of
1846// tokens and returns an offset after the sequence.
1847unsigned getOffsetAfterTokenSequence(
1848 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001849 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1850 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001851 std::unique_ptr<Environment> Env =
1852 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1853 const SourceManager &SourceMgr = Env->getSourceManager();
1854 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1855 getFormattingLangOpts(Style));
1856 Token Tok;
1857 // Get the first token.
1858 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001859 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001860}
1861
1862// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1863// \p Tok will be the token after this directive; otherwise, it can be any token
1864// after the given \p Tok (including \p Tok).
1865bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1866 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1867 Tok.is(tok::raw_identifier) &&
1868 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001869 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001870 if (Matched)
1871 Lex.LexFromRawLexer(Tok);
1872 return Matched;
1873}
1874
Eric Liu964782a2016-12-02 11:01:43 +00001875void skipComments(Lexer &Lex, Token &Tok) {
1876 while (Tok.is(tok::comment))
1877 if (Lex.LexFromRawLexer(Tok))
1878 return;
1879}
1880
1881// Returns the offset after header guard directives and any comments
1882// before/after header guards. If no header guard presents in the code, this
1883// will returns the offset after skipping all comments from the start of the
1884// code.
Eric Liu35288322016-06-06 11:00:13 +00001885unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1886 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001887 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001888 return getOffsetAfterTokenSequence(
1889 FileName, Code, Style,
1890 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1891 skipComments(Lex, Tok);
1892 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1893 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1894 skipComments(Lex, Tok);
1895 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1896 return SM.getFileOffset(Tok.getLocation());
1897 }
1898 return InitialOffset;
1899 });
1900}
1901
1902// Check if a sequence of tokens is like
1903// "#include ("header.h" | <header.h>)".
1904// If it is, \p Tok will be the token after this directive; otherwise, it can be
1905// any token after the given \p Tok (including \p Tok).
1906bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1907 auto Matched = [&]() {
1908 Lex.LexFromRawLexer(Tok);
1909 return true;
1910 };
1911 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1912 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1913 if (Lex.LexFromRawLexer(Tok))
1914 return false;
1915 if (Tok.is(tok::string_literal))
1916 return Matched();
1917 if (Tok.is(tok::less)) {
1918 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1919 }
1920 if (Tok.is(tok::greater))
1921 return Matched();
1922 }
Eric Liu35288322016-06-06 11:00:13 +00001923 }
Eric Liu964782a2016-12-02 11:01:43 +00001924 return false;
1925}
1926
1927// Returns the offset of the last #include directive after which a new
1928// #include can be inserted. This ignores #include's after the #include block(s)
1929// in the beginning of a file to avoid inserting headers into code sections
1930// where new #include's should not be added by default.
1931// These code sections include:
1932// - raw string literals (containing #include).
1933// - #if blocks.
1934// - Special #include's among declarations (e.g. functions).
1935//
1936// If no #include after which a new #include can be inserted, this returns the
1937// offset after skipping all comments from the start of the code.
1938// Inserting after an #include is not allowed if it comes after code that is not
1939// #include (e.g. pre-processing directive that is not #include, declarations).
1940unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1941 const FormatStyle &Style) {
1942 return getOffsetAfterTokenSequence(
1943 FileName, Code, Style,
1944 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1945 skipComments(Lex, Tok);
1946 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1947 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1948 MaxOffset = SM.getFileOffset(Tok.getLocation());
1949 return MaxOffset;
1950 });
Eric Liu35288322016-06-06 11:00:13 +00001951}
1952
Eric Liuc0d3a802016-09-23 15:10:56 +00001953bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001954 const std::set<llvm::StringRef> &HeadersToDelete) {
1955 return HeadersToDelete.count(HeaderName) ||
1956 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001957}
1958
Eric Liu659afd52016-05-31 13:34:20 +00001959// FIXME: insert empty lines between newly created blocks.
1960tooling::Replacements
1961fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
1962 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00001963 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00001964 return Replaces;
1965
1966 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00001967 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00001968 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00001969 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001970 if (isHeaderInsertion(R)) {
1971 // Replacements from \p Replaces must be conflict-free already, so we can
1972 // simply consume the error.
1973 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00001974 } else if (isHeaderDeletion(R)) {
1975 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001976 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00001977 llvm::errs() << "Insertions other than header #include insertion are "
1978 "not supported! "
1979 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00001980 } else {
1981 llvm::consumeError(Result.add(R));
1982 }
Eric Liu659afd52016-05-31 13:34:20 +00001983 }
Eric Liuc0d3a802016-09-23 15:10:56 +00001984 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00001985 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00001986
1987 llvm::Regex IncludeRegex(IncludeRegexPattern);
1988 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1989 SmallVector<StringRef, 4> Matches;
1990
1991 StringRef FileName = Replaces.begin()->getFilePath();
1992 IncludeCategoryManager Categories(Style, FileName);
1993
1994 // Record the offset of the end of the last include in each category.
1995 std::map<int, int> CategoryEndOffsets;
1996 // All possible priorities.
1997 // Add 0 for main header and INT_MAX for headers that are not in any category.
1998 std::set<int> Priorities = {0, INT_MAX};
1999 for (const auto &Category : Style.IncludeCategories)
2000 Priorities.insert(Category.Priority);
2001 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00002002 // All new headers should be inserted after this offset.
2003 unsigned MinInsertOffset =
2004 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00002005 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00002006 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00002007 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00002008 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00002009 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00002010 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00002011 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00002012 unsigned Offset = MinInsertOffset;
2013 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002014 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002015 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002016 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002017 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002018 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002019 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002020 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002021 // Only record the offset of current #include if we can insert after it.
2022 if (Offset <= MaxInsertOffset) {
2023 int Category = Categories.getIncludePriority(
2024 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2025 CategoryEndOffsets[Category] = NextLineOffset;
2026 if (FirstIncludeOffset < 0)
2027 FirstIncludeOffset = Offset;
2028 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002029 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2030 // If this is the last line without trailing newline, we need to make
2031 // sure we don't delete across the file boundary.
2032 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2033 llvm::Error Err =
2034 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2035 if (Err) {
2036 // Ignore the deletion on conflict.
2037 llvm::errs() << "Failed to add header deletion replacement for "
2038 << IncludeName << ": " << llvm::toString(std::move(Err))
2039 << "\n";
2040 }
2041 }
Eric Liu659afd52016-05-31 13:34:20 +00002042 }
Eric Liu35288322016-06-06 11:00:13 +00002043 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002044 }
2045
2046 // Populate CategoryEndOfssets:
2047 // - Ensure that CategoryEndOffset[Highest] is always populated.
2048 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2049 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002050 auto Highest = Priorities.begin();
2051 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2052 if (FirstIncludeOffset >= 0)
2053 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2054 else
Eric Liu303baf52016-06-03 12:52:59 +00002055 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002056 }
2057 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2058 // - to an appropriate location before/after existing #includes, or
2059 // - to right after the header guard, or
2060 // - to the beginning of the file.
2061 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2062 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2063 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2064
Eric Liu11a42372016-10-05 15:42:19 +00002065 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002066 for (const auto &R : HeaderInsertions) {
2067 auto IncludeDirective = R.getReplacementText();
2068 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2069 assert(Matched && "Header insertion replacement must have replacement text "
2070 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002071 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002072 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002073 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2074 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2075 << "\n");
2076 continue;
2077 }
Eric Liu659afd52016-05-31 13:34:20 +00002078 int Category =
2079 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2080 Offset = CategoryEndOffsets[Category];
2081 std::string NewInclude = !IncludeDirective.endswith("\n")
2082 ? (IncludeDirective + "\n").str()
2083 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002084 // When inserting headers at end of the code, also append '\n' to the code
2085 // if it does not end with '\n'.
2086 if (NeedNewLineAtEnd && Offset == Code.size()) {
2087 NewInclude = "\n" + NewInclude;
2088 NeedNewLineAtEnd = false;
2089 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002090 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2091 auto Err = Result.add(NewReplace);
2092 if (Err) {
2093 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002094 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2095 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002096 Result = Result.merge(tooling::Replacements(NewReplace));
2097 }
Eric Liu659afd52016-05-31 13:34:20 +00002098 }
2099 return Result;
2100}
2101
2102} // anonymous namespace
2103
Eric Liu4f8d9942016-07-11 13:53:12 +00002104llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002105cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2106 const FormatStyle &Style) {
2107 // We need to use lambda function here since there are two versions of
2108 // `cleanup`.
2109 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2110 std::vector<tooling::Range> Ranges,
2111 StringRef FileName) -> tooling::Replacements {
2112 return cleanup(Style, Code, Ranges, FileName);
2113 };
Eric Liu659afd52016-05-31 13:34:20 +00002114 // Make header insertion replacements insert new headers into correct blocks.
2115 tooling::Replacements NewReplaces =
2116 fixCppIncludeInsertions(Code, Replaces, Style);
2117 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002118}
2119
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002120namespace internal {
2121std::pair<tooling::Replacements, unsigned>
2122reformat(const FormatStyle &Style, StringRef Code,
2123 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2124 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2125 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002126 FormatStyle Expanded = expandPresets(Style);
2127 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002128 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002129 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002130 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002131 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002132 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002133
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002134 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2135 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002136 AnalyzerPass;
2137 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002138
Krasimir Georgievac16a202017-06-23 11:46:03 +00002139 if (Style.Language == FormatStyle::LK_Cpp) {
2140 if (Style.FixNamespaceComments)
2141 Passes.emplace_back([&](const Environment &Env) {
2142 return NamespaceEndCommentsFixer(Env, Expanded).process();
2143 });
2144
2145 if (Style.SortUsingDeclarations)
2146 Passes.emplace_back([&](const Environment &Env) {
2147 return UsingDeclarationsSorter(Env, Expanded).process();
2148 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002149 }
2150
2151 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002152 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2153 Passes.emplace_back([&](const Environment &Env) {
2154 return JavaScriptRequoter(Env, Expanded).process();
2155 });
2156
2157 Passes.emplace_back([&](const Environment &Env) {
2158 return Formatter(Env, Expanded, Status).process();
2159 });
2160
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002161 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2162 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2163 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002164 llvm::Optional<std::string> CurrentCode = None;
2165 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002166 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002167 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002168 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002169 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002170 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002171 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002172 Fixes = Fixes.merge(PassFixes.first);
2173 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002174 if (I + 1 < E) {
2175 CurrentCode = std::move(*NewCode);
2176 Env = Environment::CreateVirtualEnvironment(
2177 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002178 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2179 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002180 }
2181 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002182 }
2183
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002184 return {Fixes, Penalty};
2185}
2186} // namespace internal
2187
2188tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2189 ArrayRef<tooling::Range> Ranges,
2190 StringRef FileName,
2191 FormattingAttemptStatus *Status) {
2192 return internal::reformat(Style, Code, Ranges,
2193 /*FirstStartColumn=*/0,
2194 /*NextStartColumn=*/0,
2195 /*LastStartColumn=*/0, FileName, Status)
2196 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002197}
2198
Eric Liu4cfb88a2016-04-25 15:09:22 +00002199tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2200 ArrayRef<tooling::Range> Ranges,
2201 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002202 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2203 if (Style.Language != FormatStyle::LK_Cpp)
2204 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002205 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002206 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2207 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002208 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002209}
2210
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002211tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2212 ArrayRef<tooling::Range> Ranges,
2213 StringRef FileName, bool *IncompleteFormat) {
2214 FormattingAttemptStatus Status;
2215 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2216 if (!Status.FormatComplete)
2217 *IncompleteFormat = true;
2218 return Result;
2219}
2220
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002221tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2222 StringRef Code,
2223 ArrayRef<tooling::Range> Ranges,
2224 StringRef FileName) {
2225 std::unique_ptr<Environment> Env =
2226 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2227 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002228 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002229}
2230
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002231tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2232 StringRef Code,
2233 ArrayRef<tooling::Range> Ranges,
2234 StringRef FileName) {
2235 std::unique_ptr<Environment> Env =
2236 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2237 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002238 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002239}
2240
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002241LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002242 LangOptions LangOpts;
2243 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002244 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2245 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002246 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002247 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002248 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002249 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002250 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002251 LangOpts.Bool = 1;
2252 LangOpts.ObjC1 = 1;
2253 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002254 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002255 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002256 return LangOpts;
2257}
2258
Edwin Vaned544aa72013-09-30 13:31:48 +00002259const char *StyleOptionHelpDescription =
2260 "Coding style, currently supports:\n"
2261 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2262 "Use -style=file to load style configuration from\n"
2263 ".clang-format file located in one of the parent\n"
2264 "directories of the source file (or current\n"
2265 "directory for stdin).\n"
2266 "Use -style=\"{key: value, ...}\" to set specific\n"
2267 "parameters, e.g.:\n"
2268 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2269
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002270static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002271 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002272 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002273 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2274 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002275 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2276 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002277 if (FileName.endswith_lower(".proto") ||
2278 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002279 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002280 if (FileName.endswith_lower(".textpb") ||
2281 FileName.endswith_lower(".pb.txt") ||
2282 FileName.endswith_lower(".textproto") ||
2283 FileName.endswith_lower(".asciipb"))
2284 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002285 if (FileName.endswith_lower(".td"))
2286 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002287 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002288}
2289
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002290llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002291 StringRef FallbackStyleName,
2292 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002293 if (!FS) {
2294 FS = vfs::getRealFileSystem().get();
2295 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002296 FormatStyle Style = getLLVMStyle();
2297 Style.Language = getLanguageByFileName(FileName);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002298
Ben Hamiltone2e3e672018-01-17 17:33:08 +00002299 if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h")) {
2300 std::unique_ptr<Environment> Env =
2301 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
2302 ObjCHeaderStyleGuesser Guesser(*Env, Style);
2303 Guesser.process();
2304 if (Guesser.isObjC()) {
2305 Style.Language = FormatStyle::LK_ObjC;
2306 }
2307 }
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002308
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002309 FormatStyle FallbackStyle = getNoStyle();
2310 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2311 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002312
2313 if (StyleName.startswith("{")) {
2314 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002315 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2316 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002317 return Style;
2318 }
2319
2320 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002321 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002322 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002323 return Style;
2324 }
2325
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002326 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002327 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002328 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002329 if (std::error_code EC = FS->makeAbsolute(Path))
2330 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002331
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002332 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002333 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002334
2335 auto Status = FS->status(Directory);
2336 if (!Status ||
2337 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002338 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002339 }
2340
Edwin Vaned544aa72013-09-30 13:31:48 +00002341 SmallString<128> ConfigFile(Directory);
2342
2343 llvm::sys::path::append(ConfigFile, ".clang-format");
2344 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002345
Eric Liu547d8792016-03-24 13:22:42 +00002346 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002347 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002348 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002349 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002350 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2351 ConfigFile = Directory;
2352 llvm::sys::path::append(ConfigFile, "_clang-format");
2353 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002354 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002355 FoundConfigFile = Status && (Status->getType() ==
2356 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002357 }
2358
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002359 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002360 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002361 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002362 if (std::error_code EC = Text.getError())
2363 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002364 if (std::error_code ec =
2365 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002366 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002367 if (!UnsuitableConfigFiles.empty())
2368 UnsuitableConfigFiles.append(", ");
2369 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002370 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002371 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002372 return make_string_error("Error reading " + ConfigFile + ": " +
2373 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002374 }
2375 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2376 return Style;
2377 }
2378 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002379 if (!UnsuitableConfigFiles.empty())
2380 return make_string_error("Configuration file(s) do(es) not support " +
2381 getLanguageName(Style.Language) + ": " +
2382 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002383 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002384}
2385
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002386} // namespace format
2387} // namespace clang