blob: 90b14e74f9778d12962282535b35c7d1a5d8a497 [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
689 // Text protos are currently mostly formatted inside C++ raw string literals
690 // and often the current breaking behavior of string literals is not
691 // beneficial there. Investigate turning this on once proper string reflow
692 // has been implemented.
693 GoogleStyle.BreakStringLiterals = false;
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000694 return GoogleStyle;
695 }
696
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000697 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000698 GoogleStyle.Language = Language;
699
Daniel Jasperf7935112012-12-03 18:12:45 +0000700 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000701 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000702 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000703 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000704 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000705 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000706 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000707 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000708 GoogleStyle.IncludeCategories = {
709 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000710 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000711 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000712 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000713 GoogleStyle.ObjCSpaceAfterProperty = false;
Ben Hamiltonf84f1182018-01-18 18:37:16 +0000714 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000715 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000716 GoogleStyle.RawStringFormats = {{
717 FormatStyle::LK_TextProto,
718 /*Delimiters=*/
719 {
720 "pb",
721 "PB",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000722 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000723 /*EnclosingFunctionNames=*/
Krasimir Georgieva83d3c52018-01-29 19:28:05 +0000724 {},
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000725 /*CanonicalDelimiter=*/"",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000726 /*BasedOnStyle=*/"google",
727 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000728 GoogleStyle.SpacesBeforeTrailingComments = 2;
729 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000730
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000731 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000732 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000733
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000734 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000735 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000736 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000737 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000738 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000739 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000740 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000741 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
742 GoogleStyle.ColumnLimit = 100;
743 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000744 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000745 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000746 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000747 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000748 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000749 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000750 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000751 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
752 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
753 GoogleStyle.CommentPragmas =
754 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000755 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000756 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000757 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000758 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000759 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000760 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000761 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper783bac62014-04-15 09:54:30 +0000762 GoogleStyle.SpacesInContainerLiterals = false;
Krasimir Georgievc2091802018-01-31 10:14:10 +0000763 GoogleStyle.Cpp11BracedListStyle = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000764 } else if (Language == FormatStyle::LK_ObjC) {
765 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000766 }
767
Daniel Jasperf7935112012-12-03 18:12:45 +0000768 return GoogleStyle;
769}
770
Nico Weber514ecc82014-02-02 20:50:45 +0000771FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
772 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000773 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000774 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000775 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000776 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000777 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000778 } else if (Language == FormatStyle::LK_JavaScript) {
779 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
780 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000781 } else {
782 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
783 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
784 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
785 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
786 ChromiumStyle.BinPackParameters = false;
787 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000788 if (Language == FormatStyle::LK_ObjC)
789 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000790 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000791 return ChromiumStyle;
792}
793
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000794FormatStyle getMozillaStyle() {
795 FormatStyle MozillaStyle = getLLVMStyle();
796 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000797 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000798 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000799 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
800 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000801 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000802 MozillaStyle.BinPackParameters = false;
803 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000804 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000805 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000806 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000807 MozillaStyle.ConstructorInitializerIndentWidth = 2;
808 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000809 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000810 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000811 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000812 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000813 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
814 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000815 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000816 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000817 return MozillaStyle;
818}
819
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000820FormatStyle getWebKitStyle() {
821 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000822 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000823 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000824 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000825 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000826 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000827 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000828 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000829 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000830 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000831 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000832 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000833 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000834 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000835 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000836 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000837 return Style;
838}
839
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000840FormatStyle getGNUStyle() {
841 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000842 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000843 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000844 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000845 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000846 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000847 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000848 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000849 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000850 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000851 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000852 return Style;
853}
854
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000855FormatStyle getNoStyle() {
856 FormatStyle NoStyle = getLLVMStyle();
857 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000858 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000859 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000860 return NoStyle;
861}
862
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000863bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
864 FormatStyle *Style) {
865 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000866 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000867 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000868 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000869 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000870 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000871 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000872 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000873 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000874 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000875 } else if (Name.equals_lower("gnu")) {
876 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000877 } else if (Name.equals_lower("none")) {
878 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000879 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000880 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000881 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000882
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000883 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000884 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000885}
886
Rafael Espindolac0809172014-06-12 14:02:15 +0000887std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000888 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000889 FormatStyle::LanguageKind Language = Style->Language;
890 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000891 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000892 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000893 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000894 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000895 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000896 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
897 // values for the fields, keys for which are missing from the configuration.
898 // Mapping also uses the context to get the language to find the correct
899 // base style.
900 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000901 Input >> Styles;
902 if (Input.error())
903 return Input.error();
904
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000905 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000906 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000907 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000908 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000909 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000910 for (unsigned j = 0; j < i; ++j) {
911 if (Styles[i].Language == Styles[j].Language) {
912 DEBUG(llvm::dbgs()
913 << "Duplicate languages in the config file on positions " << j
914 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000915 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000916 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000917 }
918 }
919 // Look for a suitable configuration starting from the end, so we can
920 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000921 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000922 FormatStyle::FormatStyleSet StyleSet;
923 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000924 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000925 if (Styles[i].Language != FormatStyle::LK_None)
926 StyleSet.Add(Styles[i]);
927 if (Styles[i].Language == Language)
928 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000929 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000930 if (!LanguageFound) {
931 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
932 return make_error_code(ParseError::Unsuitable);
933 FormatStyle DefaultStyle = Styles[0];
934 DefaultStyle.Language = Language;
935 StyleSet.Add(std::move(DefaultStyle));
936 }
937 *Style = *StyleSet.Get(Language);
938 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000939}
940
941std::string configurationAsText(const FormatStyle &Style) {
942 std::string Text;
943 llvm::raw_string_ostream Stream(Text);
944 llvm::yaml::Output Output(Stream);
945 // We use the same mapping method for input and output, so we need a non-const
946 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000947 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000948 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000949 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000950}
951
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000952llvm::Optional<FormatStyle>
953FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
954 if (!Styles)
955 return None;
956 auto It = Styles->find(Language);
957 if (It == Styles->end())
958 return None;
959 FormatStyle Style = It->second;
960 Style.StyleSet = *this;
961 return Style;
962}
963
964void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
965 assert(Style.Language != LK_None &&
966 "Cannot add a style for LK_None to a StyleSet");
967 assert(
968 !Style.StyleSet.Styles &&
969 "Cannot add a style associated with an existing StyleSet to a StyleSet");
970 if (!Styles)
971 Styles = std::make_shared<MapType>();
972 (*Styles)[Style.Language] = std::move(Style);
973}
974
975void FormatStyle::FormatStyleSet::Clear() {
976 Styles.reset();
977}
978
979llvm::Optional<FormatStyle>
980FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
981 return StyleSet.Get(Language);
982}
983
Craig Topperaf35e852013-06-30 22:29:28 +0000984namespace {
985
Daniel Jasper496c1992016-09-07 22:48:53 +0000986class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000987public:
Daniel Jasper496c1992016-09-07 22:48:53 +0000988 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
989 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +0000990
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000991 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +0000992 analyze(TokenAnnotator &Annotator,
993 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +0000994 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000995 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
996 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +0000997 tooling::Replacements Result;
998 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000999 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +00001000 }
1001
1002private:
Daniel Jasper496c1992016-09-07 22:48:53 +00001003 // Replaces double/single-quoted string literal as appropriate, re-escaping
1004 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +00001005 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +00001006 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +00001007 for (AnnotatedLine *Line : Lines) {
1008 requoteJSStringLiteral(Line->Children, Result);
1009 if (!Line->Affected)
1010 continue;
1011 for (FormatToken *FormatTok = Line->First; FormatTok;
1012 FormatTok = FormatTok->Next) {
1013 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001014 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001015 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001016 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001017 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001018 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001019 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001020 !Input.startswith("\'")))
1021 continue;
1022
1023 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001024 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001025 SourceLocation Start = FormatTok->Tok.getLocation();
1026 auto Replace = [&](SourceLocation Start, unsigned Length,
1027 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001028 auto Err = Result.add(tooling::Replacement(
1029 Env.getSourceManager(), Start, Length, ReplacementText));
1030 // FIXME: handle error. For now, print error message and skip the
1031 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001032 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001033 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001034 assert(false);
1035 }
Daniel Jasper97439922016-03-17 13:03:41 +00001036 };
1037 Replace(Start, 1, IsSingle ? "'" : "\"");
1038 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1039 IsSingle ? "'" : "\"");
1040
1041 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001042 bool Escaped = false;
1043 for (size_t i = 1; i < Input.size() - 1; i++) {
1044 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001045 case '\\':
1046 if (!Escaped && i + 1 < Input.size() &&
1047 ((IsSingle && Input[i + 1] == '"') ||
1048 (!IsSingle && Input[i + 1] == '\''))) {
1049 // Remove this \, it's escaping a " or ' that no longer needs
1050 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001051 Replace(Start.getLocWithOffset(i), 1, "");
1052 continue;
1053 }
1054 Escaped = !Escaped;
1055 break;
1056 case '\"':
1057 case '\'':
1058 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1059 // Escape the quote.
1060 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001061 }
1062 Escaped = false;
1063 break;
1064 default:
1065 Escaped = false;
1066 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001067 }
1068 }
Daniel Jasper97439922016-03-17 13:03:41 +00001069 }
1070 }
1071 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001072};
1073
1074class Formatter : public TokenAnalyzer {
1075public:
1076 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001077 FormattingAttemptStatus *Status)
1078 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001079
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001080 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001081 analyze(TokenAnnotator &Annotator,
1082 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1083 FormatTokenLexer &Tokens) override {
1084 tooling::Replacements Result;
1085 deriveLocalStyle(AnnotatedLines);
1086 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1087 AnnotatedLines.end());
1088 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1089 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1090 }
1091 Annotator.setCommentLineLevels(AnnotatedLines);
1092
1093 WhitespaceManager Whitespaces(
1094 Env.getSourceManager(), Style,
1095 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1096 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1097 Env.getSourceManager(), Whitespaces, Encoding,
1098 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001099 unsigned Penalty =
1100 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1101 Tokens.getKeywords(), Env.getSourceManager(),
1102 Status)
1103 .format(AnnotatedLines, /*DryRun=*/false,
1104 /*AdditionalIndent=*/0,
1105 /*FixBadIndentation=*/false,
1106 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1107 /*NextStartColumn=*/Env.getNextStartColumn(),
1108 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001109 for (const auto &R : Whitespaces.generateReplacements())
1110 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001111 return std::make_pair(Result, 0);
1112 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001113 }
1114
1115private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001116 static bool inputUsesCRLF(StringRef Text) {
1117 return Text.count('\r') * 2 > Text.count('\n');
1118 }
1119
Daniel Jasper352f0df2015-07-18 16:35:30 +00001120 bool
1121 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001122 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001123 if (hasCpp03IncompatibleFormat(Line->Children))
1124 return true;
1125 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1126 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1127 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1128 return true;
1129 if (Tok->is(TT_TemplateCloser) &&
1130 Tok->Previous->is(TT_TemplateCloser))
1131 return true;
1132 }
1133 }
1134 }
1135 return false;
1136 }
1137
1138 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1139 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001140 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001141 AlignmentDiff += countVariableAlignments(Line->Children);
1142 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1143 if (!Tok->is(TT_PointerOrReference))
1144 continue;
1145 bool SpaceBefore =
1146 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1147 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1148 Tok->Next->WhitespaceRange.getEnd();
1149 if (SpaceBefore && !SpaceAfter)
1150 ++AlignmentDiff;
1151 if (!SpaceBefore && SpaceAfter)
1152 --AlignmentDiff;
1153 }
1154 }
1155 return AlignmentDiff;
1156 }
1157
Manuel Klimek71814b42013-10-11 21:25:45 +00001158 void
1159 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001160 bool HasBinPackedFunction = false;
1161 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001162 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001163 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001164 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001165 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001166 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001167 if (Tok->PackingKind == PPK_BinPacked)
1168 HasBinPackedFunction = true;
1169 if (Tok->PackingKind == PPK_OnePerLine)
1170 HasOnePerLineFunction = true;
1171
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001172 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001173 }
1174 }
Eric Liu635423e2016-04-28 07:52:03 +00001175 if (Style.DerivePointerAlignment)
1176 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1177 ? FormatStyle::PAS_Left
1178 : FormatStyle::PAS_Right;
1179 if (Style.Standard == FormatStyle::LS_Auto)
1180 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1181 ? FormatStyle::LS_Cpp11
1182 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001183 BinPackInconclusiveFunctions =
1184 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001185 }
1186
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001187 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001188 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001189};
1190
1191// This class clean up the erroneous/redundant code around the given ranges in
1192// file.
1193class Cleaner : public TokenAnalyzer {
1194public:
Eric Liu635423e2016-04-28 07:52:03 +00001195 Cleaner(const Environment &Env, const FormatStyle &Style)
1196 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001197 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1198
1199 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001200 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001201 analyze(TokenAnnotator &Annotator,
1202 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001203 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001204 // FIXME: in the current implementation the granularity of affected range
1205 // is an annotated line. However, this is not sufficient. Furthermore,
1206 // redundant code introduced by replacements does not necessarily
1207 // intercept with ranges of replacements that result in the redundancy.
1208 // To determine if some redundant code is actually introduced by
1209 // replacements(e.g. deletions), we need to come up with a more
1210 // sophisticated way of computing affected ranges.
1211 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1212 AnnotatedLines.end());
1213
1214 checkEmptyNamespace(AnnotatedLines);
1215
Eric Liuce5e4bc2016-05-18 08:02:56 +00001216 for (auto &Line : AnnotatedLines) {
1217 if (Line->Affected) {
1218 cleanupRight(Line->First, tok::comma, tok::comma);
1219 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001220 cleanupRight(Line->First, tok::l_paren, tok::comma);
1221 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001222 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1223 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001224 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001225 }
1226 }
1227
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001228 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001229 }
1230
1231private:
1232 bool containsOnlyComments(const AnnotatedLine &Line) {
1233 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1234 if (Tok->isNot(tok::comment))
1235 return false;
1236 }
1237 return true;
1238 }
1239
1240 // Iterate through all lines and remove any empty (nested) namespaces.
1241 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001242 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001243 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1244 auto &Line = *AnnotatedLines[i];
1245 if (Line.startsWith(tok::kw_namespace) ||
1246 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001247 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001248 }
1249 }
1250
1251 for (auto Line : DeletedLines) {
1252 FormatToken *Tok = AnnotatedLines[Line]->First;
1253 while (Tok) {
1254 deleteToken(Tok);
1255 Tok = Tok->Next;
1256 }
1257 }
1258 }
1259
1260 // The function checks if the namespace, which starts from \p CurrentLine, and
1261 // its nested namespaces are empty and delete them if they are empty. It also
1262 // sets \p NewLine to the last line checked.
1263 // Returns true if the current namespace is empty.
1264 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001265 unsigned CurrentLine, unsigned &NewLine,
1266 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001267 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001268 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001269 // If the left brace is in a new line, we should consume it first so that
1270 // it does not make the namespace non-empty.
1271 // FIXME: error handling if there is no left brace.
1272 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1273 NewLine = CurrentLine;
1274 return false;
1275 }
1276 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1277 return false;
1278 }
1279 while (++CurrentLine < End) {
1280 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1281 break;
1282
1283 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1284 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1285 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001286 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1287 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001288 return false;
1289 CurrentLine = NewLine;
1290 continue;
1291 }
1292
1293 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1294 continue;
1295
1296 // If there is anything other than comments or nested namespaces in the
1297 // current namespace, the namespace cannot be empty.
1298 NewLine = CurrentLine;
1299 return false;
1300 }
1301
1302 NewLine = CurrentLine;
1303 if (CurrentLine >= End)
1304 return false;
1305
1306 // Check if the empty namespace is actually affected by changed ranges.
1307 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1308 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1309 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1310 return false;
1311
1312 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1313 DeletedLines.insert(i);
1314 }
1315
1316 return true;
1317 }
1318
Eric Liuce5e4bc2016-05-18 08:02:56 +00001319 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1320 // of the token in the pair if the left token has \p LK token kind and the
1321 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1322 // is deleted on match; otherwise, the right token is deleted.
1323 template <typename LeftKind, typename RightKind>
1324 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1325 bool DeleteLeft) {
1326 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1327 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1328 if (!Res->is(tok::comment) &&
1329 DeletedTokens.find(Res) == DeletedTokens.end())
1330 return Res;
1331 return nullptr;
1332 };
1333 for (auto *Left = Start; Left;) {
1334 auto *Right = NextNotDeleted(*Left);
1335 if (!Right)
1336 break;
1337 if (Left->is(LK) && Right->is(RK)) {
1338 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001339 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1340 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001341 // If the right token is deleted, we should keep the left token
1342 // unchanged and pair it with the new right token.
1343 if (!DeleteLeft)
1344 continue;
1345 }
1346 Left = Right;
1347 }
1348 }
1349
1350 template <typename LeftKind, typename RightKind>
1351 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1352 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1353 }
1354
1355 template <typename LeftKind, typename RightKind>
1356 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1357 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1358 }
1359
Eric Liu4cfb88a2016-04-25 15:09:22 +00001360 // Delete the given token.
1361 inline void deleteToken(FormatToken *Tok) {
1362 if (Tok)
1363 DeletedTokens.insert(Tok);
1364 }
1365
1366 tooling::Replacements generateFixes() {
1367 tooling::Replacements Fixes;
1368 std::vector<FormatToken *> Tokens;
1369 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1370 std::back_inserter(Tokens));
1371
1372 // Merge multiple continuous token deletions into one big deletion so that
1373 // the number of replacements can be reduced. This makes computing affected
1374 // ranges more efficient when we run reformat on the changed code.
1375 unsigned Idx = 0;
1376 while (Idx < Tokens.size()) {
1377 unsigned St = Idx, End = Idx;
1378 while ((End + 1) < Tokens.size() &&
1379 Tokens[End]->Next == Tokens[End + 1]) {
1380 End++;
1381 }
1382 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1383 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001384 auto Err =
1385 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1386 // FIXME: better error handling. for now just print error message and skip
1387 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001388 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001389 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001390 assert(false && "Fixes must not conflict!");
1391 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001392 Idx = End + 1;
1393 }
1394
1395 return Fixes;
1396 }
1397
1398 // Class for less-than inequality comparason for the set `RedundantTokens`.
1399 // We store tokens in the order they appear in the translation unit so that
1400 // we do not need to sort them in `generateFixes()`.
1401 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001402 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001403
Eric Liu2874ac32016-05-18 08:14:49 +00001404 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001405 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1406 RHS->Tok.getLocation());
1407 }
Eric Liu635423e2016-04-28 07:52:03 +00001408 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001409 };
1410
1411 // Tokens to be deleted.
1412 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001413};
1414
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001415class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1416public:
1417 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1418 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1419
1420 std::pair<tooling::Replacements, unsigned>
1421 analyze(TokenAnnotator &Annotator,
1422 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1423 FormatTokenLexer &Tokens) override {
1424 assert(Style.Language == FormatStyle::LK_Cpp);
1425 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1426 tooling::Replacements Result;
1427 return {Result, 0};
1428 }
1429
1430 bool isObjC() { return IsObjC; }
1431
1432private:
1433 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1434 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001435 // Keep this array sorted, since we are binary searching over it.
1436 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001437 "CGFloat",
1438 "NSAffineTransform",
1439 "NSArray",
1440 "NSAttributedString",
1441 "NSCache",
1442 "NSCharacterSet",
1443 "NSCountedSet",
1444 "NSData",
1445 "NSDataDetector",
1446 "NSDecimal",
1447 "NSDecimalNumber",
1448 "NSDictionary",
1449 "NSEdgeInsets",
1450 "NSHashTable",
1451 "NSIndexPath",
1452 "NSIndexSet",
1453 "NSInteger",
1454 "NSLocale",
1455 "NSMapTable",
1456 "NSMutableArray",
1457 "NSMutableAttributedString",
1458 "NSMutableCharacterSet",
1459 "NSMutableData",
1460 "NSMutableDictionary",
1461 "NSMutableIndexSet",
1462 "NSMutableOrderedSet",
1463 "NSMutableSet",
1464 "NSMutableString",
1465 "NSNumber",
1466 "NSNumberFormatter",
1467 "NSOrderedSet",
1468 "NSPoint",
1469 "NSPointerArray",
1470 "NSRange",
1471 "NSRect",
1472 "NSRegularExpression",
1473 "NSSet",
1474 "NSSize",
1475 "NSString",
1476 "NSUInteger",
1477 "NSURL",
1478 "NSURLComponents",
1479 "NSURLQueryItem",
1480 "NSUUID",
1481 };
1482
1483 for (auto &Line : AnnotatedLines) {
1484 for (FormatToken *FormatTok = Line->First->Next; FormatTok;
1485 FormatTok = FormatTok->Next) {
1486 if ((FormatTok->Previous->is(tok::at) &&
1487 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1488 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1489 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1490 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1491 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1492 tok::l_brace))) ||
1493 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001494 std::binary_search(std::begin(FoundationIdentifiers),
1495 std::end(FoundationIdentifiers),
1496 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001497 FormatTok->is(TT_ObjCStringLiteral) ||
1498 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1499 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1500 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1501 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1502 return true;
1503 }
1504 }
1505 }
1506 return false;
1507 }
1508
1509 bool IsObjC;
1510};
1511
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001512struct IncludeDirective {
1513 StringRef Filename;
1514 StringRef Text;
1515 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001516 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001517};
1518
Craig Topperaf35e852013-06-30 22:29:28 +00001519} // end anonymous namespace
1520
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001521// Determines whether 'Ranges' intersects with ('Start', 'End').
1522static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1523 unsigned End) {
1524 for (auto Range : Ranges) {
1525 if (Range.getOffset() < End &&
1526 Range.getOffset() + Range.getLength() > Start)
1527 return true;
1528 }
1529 return false;
1530}
1531
Eric Liua992afe2016-08-10 09:32:23 +00001532// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1533// before sorting/deduplicating. Index is the index of the include under the
1534// cursor in the original set of includes. If this include has duplicates, it is
1535// the index of the first of the duplicates as the others are going to be
1536// removed. OffsetToEOL describes the cursor's position relative to the end of
1537// its current line.
1538// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1539static std::pair<unsigned, unsigned>
1540FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1541 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1542 unsigned CursorIndex = UINT_MAX;
1543 unsigned OffsetToEOL = 0;
1544 for (int i = 0, e = Includes.size(); i != e; ++i) {
1545 unsigned Start = Includes[Indices[i]].Offset;
1546 unsigned End = Start + Includes[Indices[i]].Text.size();
1547 if (!(Cursor >= Start && Cursor < End))
1548 continue;
1549 CursorIndex = Indices[i];
1550 OffsetToEOL = End - Cursor;
1551 // Put the cursor on the only remaining #include among the duplicate
1552 // #includes.
1553 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1554 CursorIndex = i;
1555 break;
1556 }
1557 return std::make_pair(CursorIndex, OffsetToEOL);
1558}
1559
1560// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1561// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1562// source order.
1563// #include directives with the same text will be deduplicated, and only the
1564// first #include in the duplicate #includes remains. If the `Cursor` is
1565// provided and put on a deleted #include, it will be moved to the remaining
1566// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001567static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001568 const SmallVectorImpl<IncludeDirective> &Includes,
1569 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1570 tooling::Replacements &Replaces, unsigned *Cursor) {
1571 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001572 unsigned IncludesEndOffset =
1573 Includes.back().Offset + Includes.back().Text.size();
1574 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1575 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001576 return;
1577 SmallVector<unsigned, 16> Indices;
1578 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1579 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001580 std::stable_sort(
1581 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1582 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1583 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1584 });
Eric Liua992afe2016-08-10 09:32:23 +00001585 // The index of the include on which the cursor will be put after
1586 // sorting/deduplicating.
1587 unsigned CursorIndex;
1588 // The offset from cursor to the end of line.
1589 unsigned CursorToEOLOffset;
1590 if (Cursor)
1591 std::tie(CursorIndex, CursorToEOLOffset) =
1592 FindCursorIndex(Includes, Indices, *Cursor);
1593
1594 // Deduplicate #includes.
1595 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1596 [&](unsigned LHSI, unsigned RHSI) {
1597 return Includes[LHSI].Text == Includes[RHSI].Text;
1598 }),
1599 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001600
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001601 int CurrentCategory = Includes.front().Category;
1602
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001603 // If the #includes are out of order, we generate a single replacement fixing
1604 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001605 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001606 std::is_sorted(Indices.begin(), Indices.end()) &&
1607 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001608 return;
1609
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001610 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001611 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001612 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001613 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001614 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1615 CurrentCategory != Includes[Index].Category)
1616 result += "\n";
1617 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001618 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001619 if (Cursor && CursorIndex == Index)
1620 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001621 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001622 }
1623
Eric Liu40ef2fb2016-08-01 10:16:37 +00001624 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001625 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001626 // FIXME: better error handling. For now, just skip the replacement for the
1627 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001628 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001629 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001630 assert(false);
1631 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001632}
1633
Eric Liu659afd52016-05-31 13:34:20 +00001634namespace {
1635
1636// This class manages priorities of #include categories and calculates
1637// priorities for headers.
1638class IncludeCategoryManager {
1639public:
1640 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1641 : Style(Style), FileName(FileName) {
1642 FileStem = llvm::sys::path::stem(FileName);
1643 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001644 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001645 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1646 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1647 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1648 FileName.endswith(".mm");
1649 }
1650
1651 // Returns the priority of the category which \p IncludeName belongs to.
1652 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1653 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1654 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1655 int Ret = INT_MAX;
1656 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1657 if (CategoryRegexs[i].match(IncludeName)) {
1658 Ret = Style.IncludeCategories[i].Priority;
1659 break;
1660 }
1661 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1662 Ret = 0;
1663 return Ret;
1664 }
1665
1666private:
1667 bool isMainHeader(StringRef IncludeName) const {
1668 if (!IncludeName.startswith("\""))
1669 return false;
1670 StringRef HeaderStem =
1671 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001672 if (FileStem.startswith(HeaderStem) ||
1673 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001674 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001675 (HeaderStem + Style.IncludeIsMainRegex).str(),
1676 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001677 if (MainIncludeRegex.match(FileStem))
1678 return true;
1679 }
1680 return false;
1681 }
1682
1683 const FormatStyle &Style;
1684 bool IsMainFile;
1685 StringRef FileName;
1686 StringRef FileStem;
1687 SmallVector<llvm::Regex, 4> CategoryRegexs;
1688};
1689
1690const char IncludeRegexPattern[] =
1691 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1692
1693} // anonymous namespace
1694
Martin Probstc4a0dd42016-05-20 11:24:24 +00001695tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1696 ArrayRef<tooling::Range> Ranges,
1697 StringRef FileName,
1698 tooling::Replacements &Replaces,
1699 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001700 unsigned Prev = 0;
1701 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001702 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001703 SmallVector<StringRef, 4> Matches;
1704 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001705
1706 // In compiled files, consider the first #include to be the main #include of
1707 // the file if it is not a system #include. This ensures that the header
1708 // doesn't have hidden dependencies
1709 // (http://llvm.org/docs/CodingStandards.html#include-style).
1710 //
1711 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1712 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001713 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001714 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001715 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001716 bool FormattingOff = false;
1717
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001718 for (;;) {
1719 auto Pos = Code.find('\n', SearchFrom);
1720 StringRef Line =
1721 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001722
1723 StringRef Trimmed = Line.trim();
1724 if (Trimmed == "// clang-format off")
1725 FormattingOff = true;
1726 else if (Trimmed == "// clang-format on")
1727 FormattingOff = false;
1728
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001729 const bool EmptyLineSkipped =
1730 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1731 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1732
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001733 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001734 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001735 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001736 int Category = Categories.getIncludePriority(
1737 IncludeName,
1738 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1739 if (Category == 0)
1740 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001741 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001742 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001743 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1744 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001745 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001746 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001747 }
1748 Prev = Pos + 1;
1749 }
1750 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1751 break;
1752 SearchFrom = Pos + 1;
1753 }
1754 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001755 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1756 return Replaces;
1757}
1758
Martin Probstfa37b182017-01-27 09:09:11 +00001759bool isMpegTS(StringRef Code) {
1760 // MPEG transport streams use the ".ts" file extension. clang-format should
1761 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1762 // 189 bytes - detect that and return.
1763 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1764}
1765
Manuel Klimek89628f62017-09-20 09:51:03 +00001766bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001767
Martin Probstc4a0dd42016-05-20 11:24:24 +00001768tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1769 ArrayRef<tooling::Range> Ranges,
1770 StringRef FileName, unsigned *Cursor) {
1771 tooling::Replacements Replaces;
1772 if (!Style.SortIncludes)
1773 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001774 if (isLikelyXml(Code))
1775 return Replaces;
1776 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1777 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001778 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001779 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1780 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1781 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001782 return Replaces;
1783}
1784
Eric Liu4cfb88a2016-04-25 15:09:22 +00001785template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001786static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001787processReplacements(T ProcessFunc, StringRef Code,
1788 const tooling::Replacements &Replaces,
1789 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001790 if (Replaces.empty())
1791 return tooling::Replacements();
1792
Eric Liu4f8d9942016-07-11 13:53:12 +00001793 auto NewCode = applyAllReplacements(Code, Replaces);
1794 if (!NewCode)
1795 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001796 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001797 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001798
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001799 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001800 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001801
Eric Liu40ef2fb2016-08-01 10:16:37 +00001802 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001803}
1804
Eric Liu4f8d9942016-07-11 13:53:12 +00001805llvm::Expected<tooling::Replacements>
1806formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1807 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001808 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001809 // `sortIncludes`.
1810 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1811 std::vector<tooling::Range> Ranges,
1812 StringRef FileName) -> tooling::Replacements {
1813 return sortIncludes(Style, Code, Ranges, FileName);
1814 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001815 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001816 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001817 if (!SortedReplaces)
1818 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001819
1820 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001821 // `reformat`.
1822 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1823 std::vector<tooling::Range> Ranges,
1824 StringRef FileName) -> tooling::Replacements {
1825 return reformat(Style, Code, Ranges, FileName);
1826 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001827 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001828}
1829
Eric Liu659afd52016-05-31 13:34:20 +00001830namespace {
1831
1832inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001833 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001834 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1835}
1836
Eric Liuc0d3a802016-09-23 15:10:56 +00001837inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1838 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1839}
1840
Eric Liu964782a2016-12-02 11:01:43 +00001841// Returns the offset after skipping a sequence of tokens, matched by \p
1842// GetOffsetAfterSequence, from the start of the code.
1843// \p GetOffsetAfterSequence should be a function that matches a sequence of
1844// tokens and returns an offset after the sequence.
1845unsigned getOffsetAfterTokenSequence(
1846 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001847 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1848 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001849 std::unique_ptr<Environment> Env =
1850 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1851 const SourceManager &SourceMgr = Env->getSourceManager();
1852 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1853 getFormattingLangOpts(Style));
1854 Token Tok;
1855 // Get the first token.
1856 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001857 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001858}
1859
1860// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1861// \p Tok will be the token after this directive; otherwise, it can be any token
1862// after the given \p Tok (including \p Tok).
1863bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1864 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1865 Tok.is(tok::raw_identifier) &&
1866 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001867 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001868 if (Matched)
1869 Lex.LexFromRawLexer(Tok);
1870 return Matched;
1871}
1872
Eric Liu964782a2016-12-02 11:01:43 +00001873void skipComments(Lexer &Lex, Token &Tok) {
1874 while (Tok.is(tok::comment))
1875 if (Lex.LexFromRawLexer(Tok))
1876 return;
1877}
1878
1879// Returns the offset after header guard directives and any comments
1880// before/after header guards. If no header guard presents in the code, this
1881// will returns the offset after skipping all comments from the start of the
1882// code.
Eric Liu35288322016-06-06 11:00:13 +00001883unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1884 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001885 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001886 return getOffsetAfterTokenSequence(
1887 FileName, Code, Style,
1888 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1889 skipComments(Lex, Tok);
1890 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1891 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1892 skipComments(Lex, Tok);
1893 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1894 return SM.getFileOffset(Tok.getLocation());
1895 }
1896 return InitialOffset;
1897 });
1898}
1899
1900// Check if a sequence of tokens is like
1901// "#include ("header.h" | <header.h>)".
1902// If it is, \p Tok will be the token after this directive; otherwise, it can be
1903// any token after the given \p Tok (including \p Tok).
1904bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1905 auto Matched = [&]() {
1906 Lex.LexFromRawLexer(Tok);
1907 return true;
1908 };
1909 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1910 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1911 if (Lex.LexFromRawLexer(Tok))
1912 return false;
1913 if (Tok.is(tok::string_literal))
1914 return Matched();
1915 if (Tok.is(tok::less)) {
1916 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1917 }
1918 if (Tok.is(tok::greater))
1919 return Matched();
1920 }
Eric Liu35288322016-06-06 11:00:13 +00001921 }
Eric Liu964782a2016-12-02 11:01:43 +00001922 return false;
1923}
1924
1925// Returns the offset of the last #include directive after which a new
1926// #include can be inserted. This ignores #include's after the #include block(s)
1927// in the beginning of a file to avoid inserting headers into code sections
1928// where new #include's should not be added by default.
1929// These code sections include:
1930// - raw string literals (containing #include).
1931// - #if blocks.
1932// - Special #include's among declarations (e.g. functions).
1933//
1934// If no #include after which a new #include can be inserted, this returns the
1935// offset after skipping all comments from the start of the code.
1936// Inserting after an #include is not allowed if it comes after code that is not
1937// #include (e.g. pre-processing directive that is not #include, declarations).
1938unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1939 const FormatStyle &Style) {
1940 return getOffsetAfterTokenSequence(
1941 FileName, Code, Style,
1942 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1943 skipComments(Lex, Tok);
1944 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1945 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1946 MaxOffset = SM.getFileOffset(Tok.getLocation());
1947 return MaxOffset;
1948 });
Eric Liu35288322016-06-06 11:00:13 +00001949}
1950
Eric Liuc0d3a802016-09-23 15:10:56 +00001951bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001952 const std::set<llvm::StringRef> &HeadersToDelete) {
1953 return HeadersToDelete.count(HeaderName) ||
1954 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001955}
1956
Eric Liu659afd52016-05-31 13:34:20 +00001957// FIXME: insert empty lines between newly created blocks.
1958tooling::Replacements
1959fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
1960 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00001961 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00001962 return Replaces;
1963
1964 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00001965 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00001966 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00001967 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001968 if (isHeaderInsertion(R)) {
1969 // Replacements from \p Replaces must be conflict-free already, so we can
1970 // simply consume the error.
1971 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00001972 } else if (isHeaderDeletion(R)) {
1973 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001974 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00001975 llvm::errs() << "Insertions other than header #include insertion are "
1976 "not supported! "
1977 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00001978 } else {
1979 llvm::consumeError(Result.add(R));
1980 }
Eric Liu659afd52016-05-31 13:34:20 +00001981 }
Eric Liuc0d3a802016-09-23 15:10:56 +00001982 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00001983 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00001984
1985 llvm::Regex IncludeRegex(IncludeRegexPattern);
1986 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1987 SmallVector<StringRef, 4> Matches;
1988
1989 StringRef FileName = Replaces.begin()->getFilePath();
1990 IncludeCategoryManager Categories(Style, FileName);
1991
1992 // Record the offset of the end of the last include in each category.
1993 std::map<int, int> CategoryEndOffsets;
1994 // All possible priorities.
1995 // Add 0 for main header and INT_MAX for headers that are not in any category.
1996 std::set<int> Priorities = {0, INT_MAX};
1997 for (const auto &Category : Style.IncludeCategories)
1998 Priorities.insert(Category.Priority);
1999 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00002000 // All new headers should be inserted after this offset.
2001 unsigned MinInsertOffset =
2002 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00002003 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00002004 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00002005 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00002006 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00002007 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00002008 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00002009 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00002010 unsigned Offset = MinInsertOffset;
2011 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002012 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002013 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002014 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002015 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002016 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002017 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002018 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002019 // Only record the offset of current #include if we can insert after it.
2020 if (Offset <= MaxInsertOffset) {
2021 int Category = Categories.getIncludePriority(
2022 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2023 CategoryEndOffsets[Category] = NextLineOffset;
2024 if (FirstIncludeOffset < 0)
2025 FirstIncludeOffset = Offset;
2026 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002027 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2028 // If this is the last line without trailing newline, we need to make
2029 // sure we don't delete across the file boundary.
2030 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2031 llvm::Error Err =
2032 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2033 if (Err) {
2034 // Ignore the deletion on conflict.
2035 llvm::errs() << "Failed to add header deletion replacement for "
2036 << IncludeName << ": " << llvm::toString(std::move(Err))
2037 << "\n";
2038 }
2039 }
Eric Liu659afd52016-05-31 13:34:20 +00002040 }
Eric Liu35288322016-06-06 11:00:13 +00002041 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002042 }
2043
2044 // Populate CategoryEndOfssets:
2045 // - Ensure that CategoryEndOffset[Highest] is always populated.
2046 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2047 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002048 auto Highest = Priorities.begin();
2049 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2050 if (FirstIncludeOffset >= 0)
2051 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2052 else
Eric Liu303baf52016-06-03 12:52:59 +00002053 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002054 }
2055 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2056 // - to an appropriate location before/after existing #includes, or
2057 // - to right after the header guard, or
2058 // - to the beginning of the file.
2059 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2060 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2061 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2062
Eric Liu11a42372016-10-05 15:42:19 +00002063 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002064 for (const auto &R : HeaderInsertions) {
2065 auto IncludeDirective = R.getReplacementText();
2066 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2067 assert(Matched && "Header insertion replacement must have replacement text "
2068 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002069 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002070 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002071 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2072 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2073 << "\n");
2074 continue;
2075 }
Eric Liu659afd52016-05-31 13:34:20 +00002076 int Category =
2077 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2078 Offset = CategoryEndOffsets[Category];
2079 std::string NewInclude = !IncludeDirective.endswith("\n")
2080 ? (IncludeDirective + "\n").str()
2081 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002082 // When inserting headers at end of the code, also append '\n' to the code
2083 // if it does not end with '\n'.
2084 if (NeedNewLineAtEnd && Offset == Code.size()) {
2085 NewInclude = "\n" + NewInclude;
2086 NeedNewLineAtEnd = false;
2087 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002088 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2089 auto Err = Result.add(NewReplace);
2090 if (Err) {
2091 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002092 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2093 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002094 Result = Result.merge(tooling::Replacements(NewReplace));
2095 }
Eric Liu659afd52016-05-31 13:34:20 +00002096 }
2097 return Result;
2098}
2099
2100} // anonymous namespace
2101
Eric Liu4f8d9942016-07-11 13:53:12 +00002102llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002103cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2104 const FormatStyle &Style) {
2105 // We need to use lambda function here since there are two versions of
2106 // `cleanup`.
2107 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2108 std::vector<tooling::Range> Ranges,
2109 StringRef FileName) -> tooling::Replacements {
2110 return cleanup(Style, Code, Ranges, FileName);
2111 };
Eric Liu659afd52016-05-31 13:34:20 +00002112 // Make header insertion replacements insert new headers into correct blocks.
2113 tooling::Replacements NewReplaces =
2114 fixCppIncludeInsertions(Code, Replaces, Style);
2115 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002116}
2117
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002118namespace internal {
2119std::pair<tooling::Replacements, unsigned>
2120reformat(const FormatStyle &Style, StringRef Code,
2121 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2122 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2123 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002124 FormatStyle Expanded = expandPresets(Style);
2125 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002126 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002127 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002128 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002129 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002130 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002131
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002132 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2133 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002134 AnalyzerPass;
2135 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002136
Krasimir Georgievac16a202017-06-23 11:46:03 +00002137 if (Style.Language == FormatStyle::LK_Cpp) {
2138 if (Style.FixNamespaceComments)
2139 Passes.emplace_back([&](const Environment &Env) {
2140 return NamespaceEndCommentsFixer(Env, Expanded).process();
2141 });
2142
2143 if (Style.SortUsingDeclarations)
2144 Passes.emplace_back([&](const Environment &Env) {
2145 return UsingDeclarationsSorter(Env, Expanded).process();
2146 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002147 }
2148
2149 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002150 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2151 Passes.emplace_back([&](const Environment &Env) {
2152 return JavaScriptRequoter(Env, Expanded).process();
2153 });
2154
2155 Passes.emplace_back([&](const Environment &Env) {
2156 return Formatter(Env, Expanded, Status).process();
2157 });
2158
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002159 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2160 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2161 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002162 llvm::Optional<std::string> CurrentCode = None;
2163 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002164 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002165 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002166 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002167 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002168 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002169 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002170 Fixes = Fixes.merge(PassFixes.first);
2171 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002172 if (I + 1 < E) {
2173 CurrentCode = std::move(*NewCode);
2174 Env = Environment::CreateVirtualEnvironment(
2175 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002176 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2177 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002178 }
2179 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002180 }
2181
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002182 return {Fixes, Penalty};
2183}
2184} // namespace internal
2185
2186tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2187 ArrayRef<tooling::Range> Ranges,
2188 StringRef FileName,
2189 FormattingAttemptStatus *Status) {
2190 return internal::reformat(Style, Code, Ranges,
2191 /*FirstStartColumn=*/0,
2192 /*NextStartColumn=*/0,
2193 /*LastStartColumn=*/0, FileName, Status)
2194 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002195}
2196
Eric Liu4cfb88a2016-04-25 15:09:22 +00002197tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2198 ArrayRef<tooling::Range> Ranges,
2199 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002200 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2201 if (Style.Language != FormatStyle::LK_Cpp)
2202 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002203 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002204 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2205 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002206 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002207}
2208
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002209tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2210 ArrayRef<tooling::Range> Ranges,
2211 StringRef FileName, bool *IncompleteFormat) {
2212 FormattingAttemptStatus Status;
2213 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2214 if (!Status.FormatComplete)
2215 *IncompleteFormat = true;
2216 return Result;
2217}
2218
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002219tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2220 StringRef Code,
2221 ArrayRef<tooling::Range> Ranges,
2222 StringRef FileName) {
2223 std::unique_ptr<Environment> Env =
2224 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2225 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002226 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002227}
2228
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002229tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2230 StringRef Code,
2231 ArrayRef<tooling::Range> Ranges,
2232 StringRef FileName) {
2233 std::unique_ptr<Environment> Env =
2234 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2235 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002236 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002237}
2238
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002239LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002240 LangOptions LangOpts;
2241 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002242 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2243 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002244 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002245 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002246 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002247 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002248 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002249 LangOpts.Bool = 1;
2250 LangOpts.ObjC1 = 1;
2251 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002252 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002253 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002254 return LangOpts;
2255}
2256
Edwin Vaned544aa72013-09-30 13:31:48 +00002257const char *StyleOptionHelpDescription =
2258 "Coding style, currently supports:\n"
2259 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2260 "Use -style=file to load style configuration from\n"
2261 ".clang-format file located in one of the parent\n"
2262 "directories of the source file (or current\n"
2263 "directory for stdin).\n"
2264 "Use -style=\"{key: value, ...}\" to set specific\n"
2265 "parameters, e.g.:\n"
2266 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2267
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002268static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002269 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002270 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002271 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2272 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002273 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2274 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002275 if (FileName.endswith_lower(".proto") ||
2276 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002277 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002278 if (FileName.endswith_lower(".textpb") ||
2279 FileName.endswith_lower(".pb.txt") ||
2280 FileName.endswith_lower(".textproto") ||
2281 FileName.endswith_lower(".asciipb"))
2282 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002283 if (FileName.endswith_lower(".td"))
2284 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002285 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002286}
2287
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002288llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002289 StringRef FallbackStyleName,
2290 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002291 if (!FS) {
2292 FS = vfs::getRealFileSystem().get();
2293 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002294 FormatStyle Style = getLLVMStyle();
2295 Style.Language = getLanguageByFileName(FileName);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002296
Ben Hamiltone2e3e672018-01-17 17:33:08 +00002297 if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h")) {
2298 std::unique_ptr<Environment> Env =
2299 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
2300 ObjCHeaderStyleGuesser Guesser(*Env, Style);
2301 Guesser.process();
2302 if (Guesser.isObjC()) {
2303 Style.Language = FormatStyle::LK_ObjC;
2304 }
2305 }
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002306
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002307 FormatStyle FallbackStyle = getNoStyle();
2308 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2309 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002310
2311 if (StyleName.startswith("{")) {
2312 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002313 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2314 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002315 return Style;
2316 }
2317
2318 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002319 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002320 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002321 return Style;
2322 }
2323
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002324 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002325 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002326 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002327 if (std::error_code EC = FS->makeAbsolute(Path))
2328 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002329
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002330 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002331 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002332
2333 auto Status = FS->status(Directory);
2334 if (!Status ||
2335 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002336 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002337 }
2338
Edwin Vaned544aa72013-09-30 13:31:48 +00002339 SmallString<128> ConfigFile(Directory);
2340
2341 llvm::sys::path::append(ConfigFile, ".clang-format");
2342 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002343
Eric Liu547d8792016-03-24 13:22:42 +00002344 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002345 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002346 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002347 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002348 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2349 ConfigFile = Directory;
2350 llvm::sys::path::append(ConfigFile, "_clang-format");
2351 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002352 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002353 FoundConfigFile = Status && (Status->getType() ==
2354 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002355 }
2356
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002357 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002358 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002359 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002360 if (std::error_code EC = Text.getError())
2361 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002362 if (std::error_code ec =
2363 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002364 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002365 if (!UnsuitableConfigFiles.empty())
2366 UnsuitableConfigFiles.append(", ");
2367 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002368 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002369 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002370 return make_string_error("Error reading " + ConfigFile + ": " +
2371 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002372 }
2373 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2374 return Style;
2375 }
2376 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002377 if (!UnsuitableConfigFiles.empty())
2378 return make_string_error("Configuration file(s) do(es) not support " +
2379 getLanguageName(Style.Language) + ": " +
2380 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002381 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002382}
2383
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002384} // namespace format
2385} // namespace clang