blob: 5807db9407fb9ea53cea69786489afda14d06952 [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);
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000414 IO.mapOptional("SpaceBeforeCtorInitializerColon",
415 Style.SpaceBeforeCtorInitializerColon);
416 IO.mapOptional("SpaceBeforeInheritanceColon",
417 Style.SpaceBeforeInheritanceColon);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000418 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000419 IO.mapOptional("SpaceBeforeRangeBasedForLoopColon",
420 Style.SpaceBeforeRangeBasedForLoopColon);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000421 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
422 IO.mapOptional("SpacesBeforeTrailingComments",
423 Style.SpacesBeforeTrailingComments);
424 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
425 IO.mapOptional("SpacesInContainerLiterals",
426 Style.SpacesInContainerLiterals);
427 IO.mapOptional("SpacesInCStyleCastParentheses",
428 Style.SpacesInCStyleCastParentheses);
429 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
430 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
431 IO.mapOptional("Standard", Style.Standard);
432 IO.mapOptional("TabWidth", Style.TabWidth);
433 IO.mapOptional("UseTab", Style.UseTab);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000434 }
435};
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000436
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000437template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
438 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
439 IO.mapOptional("AfterClass", Wrapping.AfterClass);
440 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
441 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
442 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
443 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
444 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
445 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
446 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000447 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000448 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
449 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
450 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
Francois Ferrandad722562017-06-30 20:25:55 +0000451 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
452 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
453 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000454 }
455};
456
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000457template <> struct MappingTraits<FormatStyle::IncludeCategory> {
458 static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
459 IO.mapOptional("Regex", Category.Regex);
460 IO.mapOptional("Priority", Category.Priority);
461 }
462};
463
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000464template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> {
465 static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
466 IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve);
467 IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge);
468 IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup);
469 }
470};
471
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000472template <> struct MappingTraits<FormatStyle::RawStringFormat> {
473 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000474 IO.mapOptional("Language", Format.Language);
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000475 IO.mapOptional("Delimiters", Format.Delimiters);
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000476 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000477 IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000478 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
479 }
480};
481
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000482// Allows to read vector<FormatStyle> while keeping default values.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000483// IO.getContext() should contain a pointer to the FormatStyle structure, that
484// will be used to get default values for missing keys.
485// If the first element has no Language specified, it will be treated as the
486// default one for the following elements.
Jacques Pienaarfc275112015-02-18 23:48:37 +0000487template <> struct DocumentListTraits<std::vector<FormatStyle>> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000488 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
489 return Seq.size();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000490 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000491 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000492 size_t Index) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000493 if (Index >= Seq.size()) {
494 assert(Index == Seq.size());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000495 FormatStyle Template;
Krasimir Georgiev1696bb62017-11-09 15:12:17 +0000496 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000497 Template = Seq[0];
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000498 } else {
Daniel Jasperb05a81d2014-05-09 13:11:16 +0000499 Template = *((const FormatStyle *)IO.getContext());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000500 Template.Language = FormatStyle::LK_None;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000501 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000502 Seq.resize(Index + 1, Template);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000503 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000504 return Seq[Index];
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000505 }
506};
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000507} // namespace yaml
508} // namespace llvm
Alexander Kornienkod6538332013-05-07 15:32:14 +0000509
Daniel Jasperf7935112012-12-03 18:12:45 +0000510namespace clang {
511namespace format {
512
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000513const std::error_category &getParseCategory() {
Rafael Espindolad0136702014-06-12 02:50:04 +0000514 static ParseErrorCategory C;
515 return C;
516}
517std::error_code make_error_code(ParseError e) {
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000518 return std::error_code(static_cast<int>(e), getParseCategory());
Rafael Espindolad0136702014-06-12 02:50:04 +0000519}
520
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +0000521inline llvm::Error make_string_error(const llvm::Twine &Message) {
522 return llvm::make_error<llvm::StringError>(Message,
523 llvm::inconvertibleErrorCode());
524}
525
Reid Kleckner6432d452016-10-19 23:39:55 +0000526const char *ParseErrorCategory::name() const noexcept {
Rafael Espindolad0136702014-06-12 02:50:04 +0000527 return "clang-format.parse_error";
528}
529
530std::string ParseErrorCategory::message(int EV) const {
531 switch (static_cast<ParseError>(EV)) {
532 case ParseError::Success:
533 return "Success";
534 case ParseError::Error:
535 return "Invalid argument";
536 case ParseError::Unsuitable:
537 return "Unsuitable";
538 }
Saleem Abdulrasoolfbfbaf62014-06-12 19:33:26 +0000539 llvm_unreachable("unexpected parse error");
Rafael Espindolad0136702014-06-12 02:50:04 +0000540}
541
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000542static FormatStyle expandPresets(const FormatStyle &Style) {
Daniel Jasper55bbe662015-10-07 04:06:10 +0000543 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
544 return Style;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000545 FormatStyle Expanded = Style;
Manuel Klimek89628f62017-09-20 09:51:03 +0000546 Expanded.BraceWrapping = {false, false, false, false, false,
547 false, false, false, false, false,
548 false, false, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000549 switch (Style.BreakBeforeBraces) {
550 case FormatStyle::BS_Linux:
551 Expanded.BraceWrapping.AfterClass = true;
552 Expanded.BraceWrapping.AfterFunction = true;
553 Expanded.BraceWrapping.AfterNamespace = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000554 break;
555 case FormatStyle::BS_Mozilla:
556 Expanded.BraceWrapping.AfterClass = true;
557 Expanded.BraceWrapping.AfterEnum = true;
558 Expanded.BraceWrapping.AfterFunction = true;
559 Expanded.BraceWrapping.AfterStruct = true;
560 Expanded.BraceWrapping.AfterUnion = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000561 Expanded.BraceWrapping.AfterExternBlock = true;
Sylvestre Ledru82c9a0e2017-09-13 20:03:29 +0000562 Expanded.BraceWrapping.SplitEmptyFunction = true;
Francois Ferrandad722562017-06-30 20:25:55 +0000563 Expanded.BraceWrapping.SplitEmptyRecord = false;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000564 break;
565 case FormatStyle::BS_Stroustrup:
566 Expanded.BraceWrapping.AfterFunction = true;
567 Expanded.BraceWrapping.BeforeCatch = true;
568 Expanded.BraceWrapping.BeforeElse = true;
569 break;
570 case FormatStyle::BS_Allman:
571 Expanded.BraceWrapping.AfterClass = true;
572 Expanded.BraceWrapping.AfterControlStatement = true;
573 Expanded.BraceWrapping.AfterEnum = true;
574 Expanded.BraceWrapping.AfterFunction = true;
575 Expanded.BraceWrapping.AfterNamespace = true;
576 Expanded.BraceWrapping.AfterObjCDeclaration = true;
577 Expanded.BraceWrapping.AfterStruct = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000578 Expanded.BraceWrapping.AfterExternBlock = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000579 Expanded.BraceWrapping.BeforeCatch = true;
580 Expanded.BraceWrapping.BeforeElse = true;
581 break;
582 case FormatStyle::BS_GNU:
Manuel Klimek89628f62017-09-20 09:51:03 +0000583 Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
584 true, true, true, true, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000585 break;
586 case FormatStyle::BS_WebKit:
587 Expanded.BraceWrapping.AfterFunction = true;
588 break;
589 default:
590 break;
591 }
592 return Expanded;
593}
594
Daniel Jasperf7935112012-12-03 18:12:45 +0000595FormatStyle getLLVMStyle() {
596 FormatStyle LLVMStyle;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000597 LLVMStyle.Language = FormatStyle::LK_Cpp;
Daniel Jasperf7935112012-12-03 18:12:45 +0000598 LLVMStyle.AccessModifierOffset = -2;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000599 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000600 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
Daniel Jasper3219e432014-12-02 13:24:51 +0000601 LLVMStyle.AlignOperands = true;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000602 LLVMStyle.AlignTrailingComments = true;
Daniel Jaspera44991332015-04-29 13:06:49 +0000603 LLVMStyle.AlignConsecutiveAssignments = false;
Daniel Jaspere12597c2015-10-01 10:06:54 +0000604 LLVMStyle.AlignConsecutiveDeclarations = false;
Daniel Jasperf7db4332013-01-29 16:03:49 +0000605 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
Daniel Jasperd74cf402014-04-08 12:46:38 +0000606 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Daniel Jasper17605d32014-05-14 09:33:35 +0000607 LLVMStyle.AllowShortBlocksOnASingleLine = false;
Daniel Jasperb87899b2014-09-10 13:11:45 +0000608 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000609 LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper3a685df2013-05-16 12:12:21 +0000610 LLVMStyle.AllowShortLoopsOnASingleLine = false;
Zachary Turner448592e2015-12-18 22:20:15 +0000611 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000612 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Alexander Kornienko58611712013-07-04 12:02:44 +0000613 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000614 LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Daniel Jasper18210d72014-10-09 09:52:05 +0000615 LLVMStyle.BinPackArguments = true;
Francois Ferrande56a8292017-06-14 12:29:47 +0000616 LLVMStyle.BinPackParameters = true;
Daniel Jasperac043c92014-09-15 11:11:00 +0000617 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Daniel Jasper165b29e2013-11-08 00:57:11 +0000618 LLVMStyle.BreakBeforeTernaryOperators = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000619 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
Manuel Klimek89628f62017-09-20 09:51:03 +0000620 LLVMStyle.BraceWrapping = {false, false, false, false, false,
621 false, false, false, false, false,
622 false, false, true, true, true};
Nico Weber2cd92f12015-10-15 16:03:01 +0000623 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000624 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000625 LLVMStyle.BreakBeforeInheritanceComma = false;
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000626 LLVMStyle.BreakStringLiterals = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000627 LLVMStyle.ColumnLimit = 80;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000628 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
Francois Ferrande56a8292017-06-14 12:29:47 +0000629 LLVMStyle.CompactNamespaces = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000630 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
Daniel Jaspercdaffa42013-08-13 10:58:30 +0000631 LLVMStyle.ConstructorInitializerIndentWidth = 4;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000632 LLVMStyle.ContinuationIndentWidth = 4;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000633 LLVMStyle.Cpp11BracedListStyle = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000634 LLVMStyle.DerivePointerAlignment = false;
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000635 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000636 LLVMStyle.FixNamespaceComments = true;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000637 LLVMStyle.ForEachMacros.push_back("foreach");
638 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
639 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
Daniel Jasper85c472d2015-09-29 07:53:08 +0000640 LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
Chandler Carruthd676ab12017-06-29 23:20:54 +0000641 {"^(<|\"(gtest|gmock|isl|json)/)", 3},
Daniel Jasper85c472d2015-09-29 07:53:08 +0000642 {".*", 1}};
Chandler Carruthd676ab12017-06-29 23:20:54 +0000643 LLVMStyle.IncludeIsMainRegex = "(Test)?$";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000644 LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000645 LLVMStyle.IndentCaseLabels = false;
Krasimir Georgievad47c902017-08-30 14:34:57 +0000646 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
Daniel Jasperc75e1ef2014-07-09 08:42:42 +0000647 LLVMStyle.IndentWrappedFunctionNames = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000648 LLVMStyle.IndentWidth = 2;
Martin Probstfb2342d2016-06-13 17:50:10 +0000649 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
650 LLVMStyle.JavaScriptWrapImports = true;
Alexander Kornienkoebb43ca2013-09-05 14:08:34 +0000651 LLVMStyle.TabWidth = 8;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000652 LLVMStyle.MaxEmptyLinesToKeep = 1;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000653 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000654 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000655 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000656 LLVMStyle.ObjCBlockIndentWidth = 2;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000657 LLVMStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000658 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000659 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000660 LLVMStyle.SpacesBeforeTrailingComments = 1;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000661 LLVMStyle.Standard = FormatStyle::LS_Cpp11;
Alexander Kornienko3c3d09c2013-09-27 16:14:22 +0000662 LLVMStyle.UseTab = FormatStyle::UT_Never;
Daniel Jaspera0a50392015-12-01 13:28:53 +0000663 LLVMStyle.ReflowComments = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000664 LLVMStyle.SpacesInParentheses = false;
Daniel Jasperad981f82014-08-26 11:41:14 +0000665 LLVMStyle.SpacesInSquareBrackets = false;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000666 LLVMStyle.SpaceInEmptyParentheses = false;
Daniel Jasperb2e10a52014-01-15 15:09:08 +0000667 LLVMStyle.SpacesInContainerLiterals = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000668 LLVMStyle.SpacesInCStyleCastParentheses = false;
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000669 LLVMStyle.SpaceAfterCStyleCast = false;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000670 LLVMStyle.SpaceAfterTemplateKeyword = true;
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000671 LLVMStyle.SpaceBeforeCtorInitializerColon = true;
672 LLVMStyle.SpaceBeforeInheritanceColon = true;
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000673 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000674 LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
Daniel Jasperd94bff32013-09-25 15:15:02 +0000675 LLVMStyle.SpaceBeforeAssignmentOperators = true;
Daniel Jasperdd978ae2013-10-29 14:52:02 +0000676 LLVMStyle.SpacesInAngles = false;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000677
Francois Ferrand9976efa2017-05-22 08:28:17 +0000678 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
Daniel Jasper19a541e2013-12-19 16:45:34 +0000679 LLVMStyle.PenaltyBreakComment = 300;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000680 LLVMStyle.PenaltyBreakFirstLessLess = 120;
681 LLVMStyle.PenaltyBreakString = 1000;
682 LLVMStyle.PenaltyExcessCharacter = 1000000;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000683 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000684 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000685
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000686 LLVMStyle.DisableFormat = false;
Daniel Jasperda446772015-11-16 12:38:56 +0000687 LLVMStyle.SortIncludes = true;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000688 LLVMStyle.SortUsingDeclarations = true;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000689
Daniel Jasperf7935112012-12-03 18:12:45 +0000690 return LLVMStyle;
691}
692
Nico Weber514ecc82014-02-02 20:50:45 +0000693FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000694 if (Language == FormatStyle::LK_TextProto) {
695 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
696 GoogleStyle.Language = FormatStyle::LK_TextProto;
Krasimir Georgieveda222e2018-01-24 11:18:39 +0000697
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000698 return GoogleStyle;
699 }
700
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000701 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000702 GoogleStyle.Language = Language;
703
Daniel Jasperf7935112012-12-03 18:12:45 +0000704 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000705 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000706 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000707 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000708 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000709 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000710 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000711 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000712 GoogleStyle.IncludeCategories = {
713 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000714 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000715 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000716 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Ben Hamilton3a47fdd2018-02-08 01:49:10 +0000717 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000718 GoogleStyle.ObjCSpaceAfterProperty = false;
Ben Hamiltonf84f1182018-01-18 18:37:16 +0000719 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000720 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000721 GoogleStyle.RawStringFormats = {{
722 FormatStyle::LK_TextProto,
723 /*Delimiters=*/
724 {
725 "pb",
726 "PB",
Krasimir Georgiev2fac8d92018-02-16 12:10:06 +0000727 "proto",
728 "PROTO",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000729 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000730 /*EnclosingFunctionNames=*/
Krasimir Georgieva83d3c52018-01-29 19:28:05 +0000731 {},
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000732 /*CanonicalDelimiter=*/"",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000733 /*BasedOnStyle=*/"google",
734 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000735 GoogleStyle.SpacesBeforeTrailingComments = 2;
736 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000737
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000738 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000739 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000740
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000741 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000742 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000743 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000744 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000745 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000746 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000747 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000748 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
749 GoogleStyle.ColumnLimit = 100;
750 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000751 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000752 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000753 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000754 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000755 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000756 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000757 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000758 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
759 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
760 GoogleStyle.CommentPragmas =
761 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000762 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000763 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000764 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000765 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000766 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000767 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000768 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper783bac62014-04-15 09:54:30 +0000769 GoogleStyle.SpacesInContainerLiterals = false;
Krasimir Georgievc2091802018-01-31 10:14:10 +0000770 GoogleStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev374e6de2018-02-08 10:47:12 +0000771 // This affects protocol buffer options specifications and text protos.
772 // Text protos are currently mostly formatted inside C++ raw string literals
773 // and often the current breaking behavior of string literals is not
774 // beneficial there. Investigate turning this on once proper string reflow
775 // has been implemented.
776 GoogleStyle.BreakStringLiterals = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000777 } else if (Language == FormatStyle::LK_ObjC) {
778 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000779 }
780
Daniel Jasperf7935112012-12-03 18:12:45 +0000781 return GoogleStyle;
782}
783
Nico Weber514ecc82014-02-02 20:50:45 +0000784FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
785 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000786 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000787 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000788 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000789 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000790 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000791 } else if (Language == FormatStyle::LK_JavaScript) {
792 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
793 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000794 } else {
795 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
796 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
797 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
798 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
799 ChromiumStyle.BinPackParameters = false;
800 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000801 if (Language == FormatStyle::LK_ObjC)
802 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000803 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000804 return ChromiumStyle;
805}
806
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000807FormatStyle getMozillaStyle() {
808 FormatStyle MozillaStyle = getLLVMStyle();
809 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000810 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000811 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000812 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
813 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000814 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000815 MozillaStyle.BinPackParameters = false;
816 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000817 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000818 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000819 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000820 MozillaStyle.ConstructorInitializerIndentWidth = 2;
821 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000822 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000823 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000824 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000825 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000826 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
827 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000828 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000829 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000830 return MozillaStyle;
831}
832
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000833FormatStyle getWebKitStyle() {
834 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000835 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000836 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000837 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000838 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000839 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000840 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000841 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000842 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000843 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000844 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000845 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000846 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000847 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000848 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000849 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000850 return Style;
851}
852
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000853FormatStyle getGNUStyle() {
854 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000855 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000856 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000857 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000858 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000859 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000860 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000861 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000862 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000863 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000864 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000865 return Style;
866}
867
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000868FormatStyle getNoStyle() {
869 FormatStyle NoStyle = getLLVMStyle();
870 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000871 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000872 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000873 return NoStyle;
874}
875
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000876bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
877 FormatStyle *Style) {
878 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000879 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000880 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000881 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000882 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000883 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000884 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000885 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000886 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000887 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000888 } else if (Name.equals_lower("gnu")) {
889 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000890 } else if (Name.equals_lower("none")) {
891 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000892 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000893 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000894 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000895
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000896 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000897 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000898}
899
Rafael Espindolac0809172014-06-12 14:02:15 +0000900std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000901 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000902 FormatStyle::LanguageKind Language = Style->Language;
903 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000904 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000905 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000906 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000907 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000908 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000909 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
910 // values for the fields, keys for which are missing from the configuration.
911 // Mapping also uses the context to get the language to find the correct
912 // base style.
913 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000914 Input >> Styles;
915 if (Input.error())
916 return Input.error();
917
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000918 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000919 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000920 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000921 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000922 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000923 for (unsigned j = 0; j < i; ++j) {
924 if (Styles[i].Language == Styles[j].Language) {
925 DEBUG(llvm::dbgs()
926 << "Duplicate languages in the config file on positions " << j
927 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000928 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000929 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000930 }
931 }
932 // Look for a suitable configuration starting from the end, so we can
933 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000934 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000935 FormatStyle::FormatStyleSet StyleSet;
936 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000937 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000938 if (Styles[i].Language != FormatStyle::LK_None)
939 StyleSet.Add(Styles[i]);
940 if (Styles[i].Language == Language)
941 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000942 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000943 if (!LanguageFound) {
944 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
945 return make_error_code(ParseError::Unsuitable);
946 FormatStyle DefaultStyle = Styles[0];
947 DefaultStyle.Language = Language;
948 StyleSet.Add(std::move(DefaultStyle));
949 }
950 *Style = *StyleSet.Get(Language);
951 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000952}
953
954std::string configurationAsText(const FormatStyle &Style) {
955 std::string Text;
956 llvm::raw_string_ostream Stream(Text);
957 llvm::yaml::Output Output(Stream);
958 // We use the same mapping method for input and output, so we need a non-const
959 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000960 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000961 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000962 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000963}
964
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000965llvm::Optional<FormatStyle>
966FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
967 if (!Styles)
968 return None;
969 auto It = Styles->find(Language);
970 if (It == Styles->end())
971 return None;
972 FormatStyle Style = It->second;
973 Style.StyleSet = *this;
974 return Style;
975}
976
977void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
978 assert(Style.Language != LK_None &&
979 "Cannot add a style for LK_None to a StyleSet");
980 assert(
981 !Style.StyleSet.Styles &&
982 "Cannot add a style associated with an existing StyleSet to a StyleSet");
983 if (!Styles)
984 Styles = std::make_shared<MapType>();
985 (*Styles)[Style.Language] = std::move(Style);
986}
987
988void FormatStyle::FormatStyleSet::Clear() {
989 Styles.reset();
990}
991
992llvm::Optional<FormatStyle>
993FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
994 return StyleSet.Get(Language);
995}
996
Craig Topperaf35e852013-06-30 22:29:28 +0000997namespace {
998
Daniel Jasper496c1992016-09-07 22:48:53 +0000999class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001000public:
Daniel Jasper496c1992016-09-07 22:48:53 +00001001 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
1002 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001003
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001004 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001005 analyze(TokenAnnotator &Annotator,
1006 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001007 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001008 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1009 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +00001010 tooling::Replacements Result;
1011 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001012 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +00001013 }
1014
1015private:
Daniel Jasper496c1992016-09-07 22:48:53 +00001016 // Replaces double/single-quoted string literal as appropriate, re-escaping
1017 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +00001018 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +00001019 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +00001020 for (AnnotatedLine *Line : Lines) {
1021 requoteJSStringLiteral(Line->Children, Result);
1022 if (!Line->Affected)
1023 continue;
1024 for (FormatToken *FormatTok = Line->First; FormatTok;
1025 FormatTok = FormatTok->Next) {
1026 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001027 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001028 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001029 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001030 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001031 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001032 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001033 !Input.startswith("\'")))
1034 continue;
1035
1036 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001037 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001038 SourceLocation Start = FormatTok->Tok.getLocation();
1039 auto Replace = [&](SourceLocation Start, unsigned Length,
1040 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001041 auto Err = Result.add(tooling::Replacement(
1042 Env.getSourceManager(), Start, Length, ReplacementText));
1043 // FIXME: handle error. For now, print error message and skip the
1044 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001045 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001046 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001047 assert(false);
1048 }
Daniel Jasper97439922016-03-17 13:03:41 +00001049 };
1050 Replace(Start, 1, IsSingle ? "'" : "\"");
1051 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1052 IsSingle ? "'" : "\"");
1053
1054 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001055 bool Escaped = false;
1056 for (size_t i = 1; i < Input.size() - 1; i++) {
1057 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001058 case '\\':
1059 if (!Escaped && i + 1 < Input.size() &&
1060 ((IsSingle && Input[i + 1] == '"') ||
1061 (!IsSingle && Input[i + 1] == '\''))) {
1062 // Remove this \, it's escaping a " or ' that no longer needs
1063 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001064 Replace(Start.getLocWithOffset(i), 1, "");
1065 continue;
1066 }
1067 Escaped = !Escaped;
1068 break;
1069 case '\"':
1070 case '\'':
1071 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1072 // Escape the quote.
1073 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001074 }
1075 Escaped = false;
1076 break;
1077 default:
1078 Escaped = false;
1079 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001080 }
1081 }
Daniel Jasper97439922016-03-17 13:03:41 +00001082 }
1083 }
1084 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001085};
1086
1087class Formatter : public TokenAnalyzer {
1088public:
1089 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001090 FormattingAttemptStatus *Status)
1091 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001092
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001093 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001094 analyze(TokenAnnotator &Annotator,
1095 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1096 FormatTokenLexer &Tokens) override {
1097 tooling::Replacements Result;
1098 deriveLocalStyle(AnnotatedLines);
1099 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1100 AnnotatedLines.end());
1101 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1102 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1103 }
1104 Annotator.setCommentLineLevels(AnnotatedLines);
1105
1106 WhitespaceManager Whitespaces(
1107 Env.getSourceManager(), Style,
1108 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1109 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1110 Env.getSourceManager(), Whitespaces, Encoding,
1111 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001112 unsigned Penalty =
1113 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1114 Tokens.getKeywords(), Env.getSourceManager(),
1115 Status)
1116 .format(AnnotatedLines, /*DryRun=*/false,
1117 /*AdditionalIndent=*/0,
1118 /*FixBadIndentation=*/false,
1119 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1120 /*NextStartColumn=*/Env.getNextStartColumn(),
1121 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001122 for (const auto &R : Whitespaces.generateReplacements())
1123 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001124 return std::make_pair(Result, 0);
1125 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001126 }
1127
1128private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001129 static bool inputUsesCRLF(StringRef Text) {
1130 return Text.count('\r') * 2 > Text.count('\n');
1131 }
1132
Daniel Jasper352f0df2015-07-18 16:35:30 +00001133 bool
1134 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001135 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001136 if (hasCpp03IncompatibleFormat(Line->Children))
1137 return true;
1138 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1139 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1140 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1141 return true;
1142 if (Tok->is(TT_TemplateCloser) &&
1143 Tok->Previous->is(TT_TemplateCloser))
1144 return true;
1145 }
1146 }
1147 }
1148 return false;
1149 }
1150
1151 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1152 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001153 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001154 AlignmentDiff += countVariableAlignments(Line->Children);
1155 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1156 if (!Tok->is(TT_PointerOrReference))
1157 continue;
1158 bool SpaceBefore =
1159 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1160 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1161 Tok->Next->WhitespaceRange.getEnd();
1162 if (SpaceBefore && !SpaceAfter)
1163 ++AlignmentDiff;
1164 if (!SpaceBefore && SpaceAfter)
1165 --AlignmentDiff;
1166 }
1167 }
1168 return AlignmentDiff;
1169 }
1170
Manuel Klimek71814b42013-10-11 21:25:45 +00001171 void
1172 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001173 bool HasBinPackedFunction = false;
1174 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001175 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001176 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001177 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001178 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001179 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001180 if (Tok->PackingKind == PPK_BinPacked)
1181 HasBinPackedFunction = true;
1182 if (Tok->PackingKind == PPK_OnePerLine)
1183 HasOnePerLineFunction = true;
1184
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001185 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001186 }
1187 }
Eric Liu635423e2016-04-28 07:52:03 +00001188 if (Style.DerivePointerAlignment)
1189 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1190 ? FormatStyle::PAS_Left
1191 : FormatStyle::PAS_Right;
1192 if (Style.Standard == FormatStyle::LS_Auto)
1193 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1194 ? FormatStyle::LS_Cpp11
1195 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001196 BinPackInconclusiveFunctions =
1197 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001198 }
1199
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001200 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001201 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001202};
1203
1204// This class clean up the erroneous/redundant code around the given ranges in
1205// file.
1206class Cleaner : public TokenAnalyzer {
1207public:
Eric Liu635423e2016-04-28 07:52:03 +00001208 Cleaner(const Environment &Env, const FormatStyle &Style)
1209 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001210 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1211
1212 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001213 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001214 analyze(TokenAnnotator &Annotator,
1215 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001216 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001217 // FIXME: in the current implementation the granularity of affected range
1218 // is an annotated line. However, this is not sufficient. Furthermore,
1219 // redundant code introduced by replacements does not necessarily
1220 // intercept with ranges of replacements that result in the redundancy.
1221 // To determine if some redundant code is actually introduced by
1222 // replacements(e.g. deletions), we need to come up with a more
1223 // sophisticated way of computing affected ranges.
1224 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1225 AnnotatedLines.end());
1226
1227 checkEmptyNamespace(AnnotatedLines);
1228
Eric Liuce5e4bc2016-05-18 08:02:56 +00001229 for (auto &Line : AnnotatedLines) {
1230 if (Line->Affected) {
1231 cleanupRight(Line->First, tok::comma, tok::comma);
1232 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001233 cleanupRight(Line->First, tok::l_paren, tok::comma);
1234 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001235 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1236 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001237 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001238 }
1239 }
1240
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001241 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001242 }
1243
1244private:
1245 bool containsOnlyComments(const AnnotatedLine &Line) {
1246 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1247 if (Tok->isNot(tok::comment))
1248 return false;
1249 }
1250 return true;
1251 }
1252
1253 // Iterate through all lines and remove any empty (nested) namespaces.
1254 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001255 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001256 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1257 auto &Line = *AnnotatedLines[i];
1258 if (Line.startsWith(tok::kw_namespace) ||
1259 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001260 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001261 }
1262 }
1263
1264 for (auto Line : DeletedLines) {
1265 FormatToken *Tok = AnnotatedLines[Line]->First;
1266 while (Tok) {
1267 deleteToken(Tok);
1268 Tok = Tok->Next;
1269 }
1270 }
1271 }
1272
1273 // The function checks if the namespace, which starts from \p CurrentLine, and
1274 // its nested namespaces are empty and delete them if they are empty. It also
1275 // sets \p NewLine to the last line checked.
1276 // Returns true if the current namespace is empty.
1277 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001278 unsigned CurrentLine, unsigned &NewLine,
1279 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001280 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001281 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001282 // If the left brace is in a new line, we should consume it first so that
1283 // it does not make the namespace non-empty.
1284 // FIXME: error handling if there is no left brace.
1285 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1286 NewLine = CurrentLine;
1287 return false;
1288 }
1289 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1290 return false;
1291 }
1292 while (++CurrentLine < End) {
1293 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1294 break;
1295
1296 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1297 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1298 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001299 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1300 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001301 return false;
1302 CurrentLine = NewLine;
1303 continue;
1304 }
1305
1306 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1307 continue;
1308
1309 // If there is anything other than comments or nested namespaces in the
1310 // current namespace, the namespace cannot be empty.
1311 NewLine = CurrentLine;
1312 return false;
1313 }
1314
1315 NewLine = CurrentLine;
1316 if (CurrentLine >= End)
1317 return false;
1318
1319 // Check if the empty namespace is actually affected by changed ranges.
1320 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1321 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1322 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1323 return false;
1324
1325 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1326 DeletedLines.insert(i);
1327 }
1328
1329 return true;
1330 }
1331
Eric Liuce5e4bc2016-05-18 08:02:56 +00001332 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1333 // of the token in the pair if the left token has \p LK token kind and the
1334 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1335 // is deleted on match; otherwise, the right token is deleted.
1336 template <typename LeftKind, typename RightKind>
1337 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1338 bool DeleteLeft) {
1339 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1340 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1341 if (!Res->is(tok::comment) &&
1342 DeletedTokens.find(Res) == DeletedTokens.end())
1343 return Res;
1344 return nullptr;
1345 };
1346 for (auto *Left = Start; Left;) {
1347 auto *Right = NextNotDeleted(*Left);
1348 if (!Right)
1349 break;
1350 if (Left->is(LK) && Right->is(RK)) {
1351 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001352 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1353 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001354 // If the right token is deleted, we should keep the left token
1355 // unchanged and pair it with the new right token.
1356 if (!DeleteLeft)
1357 continue;
1358 }
1359 Left = Right;
1360 }
1361 }
1362
1363 template <typename LeftKind, typename RightKind>
1364 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1365 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1366 }
1367
1368 template <typename LeftKind, typename RightKind>
1369 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1370 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1371 }
1372
Eric Liu4cfb88a2016-04-25 15:09:22 +00001373 // Delete the given token.
1374 inline void deleteToken(FormatToken *Tok) {
1375 if (Tok)
1376 DeletedTokens.insert(Tok);
1377 }
1378
1379 tooling::Replacements generateFixes() {
1380 tooling::Replacements Fixes;
1381 std::vector<FormatToken *> Tokens;
1382 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1383 std::back_inserter(Tokens));
1384
1385 // Merge multiple continuous token deletions into one big deletion so that
1386 // the number of replacements can be reduced. This makes computing affected
1387 // ranges more efficient when we run reformat on the changed code.
1388 unsigned Idx = 0;
1389 while (Idx < Tokens.size()) {
1390 unsigned St = Idx, End = Idx;
1391 while ((End + 1) < Tokens.size() &&
1392 Tokens[End]->Next == Tokens[End + 1]) {
1393 End++;
1394 }
1395 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1396 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001397 auto Err =
1398 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1399 // FIXME: better error handling. for now just print error message and skip
1400 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001401 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001402 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001403 assert(false && "Fixes must not conflict!");
1404 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001405 Idx = End + 1;
1406 }
1407
1408 return Fixes;
1409 }
1410
1411 // Class for less-than inequality comparason for the set `RedundantTokens`.
1412 // We store tokens in the order they appear in the translation unit so that
1413 // we do not need to sort them in `generateFixes()`.
1414 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001415 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001416
Eric Liu2874ac32016-05-18 08:14:49 +00001417 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001418 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1419 RHS->Tok.getLocation());
1420 }
Eric Liu635423e2016-04-28 07:52:03 +00001421 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001422 };
1423
1424 // Tokens to be deleted.
1425 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001426};
1427
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001428class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1429public:
1430 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1431 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1432
1433 std::pair<tooling::Replacements, unsigned>
1434 analyze(TokenAnnotator &Annotator,
1435 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1436 FormatTokenLexer &Tokens) override {
1437 assert(Style.Language == FormatStyle::LK_Cpp);
1438 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1439 tooling::Replacements Result;
1440 return {Result, 0};
1441 }
1442
1443 bool isObjC() { return IsObjC; }
1444
1445private:
1446 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1447 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001448 // Keep this array sorted, since we are binary searching over it.
1449 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001450 "CGFloat",
1451 "NSAffineTransform",
1452 "NSArray",
1453 "NSAttributedString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001454 "NSBundle",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001455 "NSCache",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001456 "NSCalendar",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001457 "NSCharacterSet",
1458 "NSCountedSet",
1459 "NSData",
1460 "NSDataDetector",
1461 "NSDecimal",
1462 "NSDecimalNumber",
1463 "NSDictionary",
1464 "NSEdgeInsets",
1465 "NSHashTable",
1466 "NSIndexPath",
1467 "NSIndexSet",
1468 "NSInteger",
1469 "NSLocale",
1470 "NSMapTable",
1471 "NSMutableArray",
1472 "NSMutableAttributedString",
1473 "NSMutableCharacterSet",
1474 "NSMutableData",
1475 "NSMutableDictionary",
1476 "NSMutableIndexSet",
1477 "NSMutableOrderedSet",
1478 "NSMutableSet",
1479 "NSMutableString",
1480 "NSNumber",
1481 "NSNumberFormatter",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001482 "NSObject",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001483 "NSOrderedSet",
1484 "NSPoint",
1485 "NSPointerArray",
1486 "NSRange",
1487 "NSRect",
1488 "NSRegularExpression",
1489 "NSSet",
1490 "NSSize",
1491 "NSString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001492 "NSTimeZone",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001493 "NSUInteger",
1494 "NSURL",
1495 "NSURLComponents",
1496 "NSURLQueryItem",
1497 "NSUUID",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001498 "NSValue",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001499 };
1500
1501 for (auto &Line : AnnotatedLines) {
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001502 for (FormatToken *FormatTok = Line->First; FormatTok;
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001503 FormatTok = FormatTok->Next) {
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001504 if ((FormatTok->Previous && FormatTok->Previous->is(tok::at) &&
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001505 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1506 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1507 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1508 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1509 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1510 tok::l_brace))) ||
1511 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001512 std::binary_search(std::begin(FoundationIdentifiers),
1513 std::end(FoundationIdentifiers),
1514 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001515 FormatTok->is(TT_ObjCStringLiteral) ||
1516 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1517 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1518 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1519 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1520 return true;
1521 }
1522 }
1523 }
1524 return false;
1525 }
1526
1527 bool IsObjC;
1528};
1529
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001530struct IncludeDirective {
1531 StringRef Filename;
1532 StringRef Text;
1533 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001534 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001535};
1536
Craig Topperaf35e852013-06-30 22:29:28 +00001537} // end anonymous namespace
1538
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001539// Determines whether 'Ranges' intersects with ('Start', 'End').
1540static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1541 unsigned End) {
1542 for (auto Range : Ranges) {
1543 if (Range.getOffset() < End &&
1544 Range.getOffset() + Range.getLength() > Start)
1545 return true;
1546 }
1547 return false;
1548}
1549
Eric Liua992afe2016-08-10 09:32:23 +00001550// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1551// before sorting/deduplicating. Index is the index of the include under the
1552// cursor in the original set of includes. If this include has duplicates, it is
1553// the index of the first of the duplicates as the others are going to be
1554// removed. OffsetToEOL describes the cursor's position relative to the end of
1555// its current line.
1556// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1557static std::pair<unsigned, unsigned>
1558FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1559 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1560 unsigned CursorIndex = UINT_MAX;
1561 unsigned OffsetToEOL = 0;
1562 for (int i = 0, e = Includes.size(); i != e; ++i) {
1563 unsigned Start = Includes[Indices[i]].Offset;
1564 unsigned End = Start + Includes[Indices[i]].Text.size();
1565 if (!(Cursor >= Start && Cursor < End))
1566 continue;
1567 CursorIndex = Indices[i];
1568 OffsetToEOL = End - Cursor;
1569 // Put the cursor on the only remaining #include among the duplicate
1570 // #includes.
1571 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1572 CursorIndex = i;
1573 break;
1574 }
1575 return std::make_pair(CursorIndex, OffsetToEOL);
1576}
1577
1578// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1579// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1580// source order.
1581// #include directives with the same text will be deduplicated, and only the
1582// first #include in the duplicate #includes remains. If the `Cursor` is
1583// provided and put on a deleted #include, it will be moved to the remaining
1584// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001585static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001586 const SmallVectorImpl<IncludeDirective> &Includes,
1587 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1588 tooling::Replacements &Replaces, unsigned *Cursor) {
1589 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001590 unsigned IncludesEndOffset =
1591 Includes.back().Offset + Includes.back().Text.size();
1592 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1593 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001594 return;
1595 SmallVector<unsigned, 16> Indices;
1596 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1597 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001598 std::stable_sort(
1599 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1600 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1601 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1602 });
Eric Liua992afe2016-08-10 09:32:23 +00001603 // The index of the include on which the cursor will be put after
1604 // sorting/deduplicating.
1605 unsigned CursorIndex;
1606 // The offset from cursor to the end of line.
1607 unsigned CursorToEOLOffset;
1608 if (Cursor)
1609 std::tie(CursorIndex, CursorToEOLOffset) =
1610 FindCursorIndex(Includes, Indices, *Cursor);
1611
1612 // Deduplicate #includes.
1613 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1614 [&](unsigned LHSI, unsigned RHSI) {
1615 return Includes[LHSI].Text == Includes[RHSI].Text;
1616 }),
1617 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001618
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001619 int CurrentCategory = Includes.front().Category;
1620
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001621 // If the #includes are out of order, we generate a single replacement fixing
1622 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001623 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001624 std::is_sorted(Indices.begin(), Indices.end()) &&
1625 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001626 return;
1627
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001628 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001629 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001630 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001631 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001632 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1633 CurrentCategory != Includes[Index].Category)
1634 result += "\n";
1635 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001636 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001637 if (Cursor && CursorIndex == Index)
1638 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001639 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001640 }
1641
Eric Liu40ef2fb2016-08-01 10:16:37 +00001642 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001643 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001644 // FIXME: better error handling. For now, just skip the replacement for the
1645 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001646 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001647 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001648 assert(false);
1649 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001650}
1651
Eric Liu659afd52016-05-31 13:34:20 +00001652namespace {
1653
1654// This class manages priorities of #include categories and calculates
1655// priorities for headers.
1656class IncludeCategoryManager {
1657public:
1658 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1659 : Style(Style), FileName(FileName) {
1660 FileStem = llvm::sys::path::stem(FileName);
1661 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001662 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001663 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1664 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1665 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1666 FileName.endswith(".mm");
1667 }
1668
1669 // Returns the priority of the category which \p IncludeName belongs to.
1670 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1671 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1672 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1673 int Ret = INT_MAX;
1674 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1675 if (CategoryRegexs[i].match(IncludeName)) {
1676 Ret = Style.IncludeCategories[i].Priority;
1677 break;
1678 }
1679 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1680 Ret = 0;
1681 return Ret;
1682 }
1683
1684private:
1685 bool isMainHeader(StringRef IncludeName) const {
1686 if (!IncludeName.startswith("\""))
1687 return false;
1688 StringRef HeaderStem =
1689 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001690 if (FileStem.startswith(HeaderStem) ||
1691 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001692 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001693 (HeaderStem + Style.IncludeIsMainRegex).str(),
1694 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001695 if (MainIncludeRegex.match(FileStem))
1696 return true;
1697 }
1698 return false;
1699 }
1700
1701 const FormatStyle &Style;
1702 bool IsMainFile;
1703 StringRef FileName;
1704 StringRef FileStem;
1705 SmallVector<llvm::Regex, 4> CategoryRegexs;
1706};
1707
1708const char IncludeRegexPattern[] =
1709 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1710
1711} // anonymous namespace
1712
Martin Probstc4a0dd42016-05-20 11:24:24 +00001713tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1714 ArrayRef<tooling::Range> Ranges,
1715 StringRef FileName,
1716 tooling::Replacements &Replaces,
1717 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001718 unsigned Prev = 0;
1719 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001720 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001721 SmallVector<StringRef, 4> Matches;
1722 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001723
1724 // In compiled files, consider the first #include to be the main #include of
1725 // the file if it is not a system #include. This ensures that the header
1726 // doesn't have hidden dependencies
1727 // (http://llvm.org/docs/CodingStandards.html#include-style).
1728 //
1729 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1730 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001731 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001732 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001733 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001734 bool FormattingOff = false;
1735
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001736 for (;;) {
1737 auto Pos = Code.find('\n', SearchFrom);
1738 StringRef Line =
1739 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001740
1741 StringRef Trimmed = Line.trim();
1742 if (Trimmed == "// clang-format off")
1743 FormattingOff = true;
1744 else if (Trimmed == "// clang-format on")
1745 FormattingOff = false;
1746
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001747 const bool EmptyLineSkipped =
1748 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1749 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1750
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001751 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001752 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001753 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001754 int Category = Categories.getIncludePriority(
1755 IncludeName,
1756 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1757 if (Category == 0)
1758 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001759 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001760 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001761 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1762 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001763 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001764 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001765 }
1766 Prev = Pos + 1;
1767 }
1768 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1769 break;
1770 SearchFrom = Pos + 1;
1771 }
1772 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001773 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1774 return Replaces;
1775}
1776
Martin Probstfa37b182017-01-27 09:09:11 +00001777bool isMpegTS(StringRef Code) {
1778 // MPEG transport streams use the ".ts" file extension. clang-format should
1779 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1780 // 189 bytes - detect that and return.
1781 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1782}
1783
Manuel Klimek89628f62017-09-20 09:51:03 +00001784bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001785
Martin Probstc4a0dd42016-05-20 11:24:24 +00001786tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1787 ArrayRef<tooling::Range> Ranges,
1788 StringRef FileName, unsigned *Cursor) {
1789 tooling::Replacements Replaces;
1790 if (!Style.SortIncludes)
1791 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001792 if (isLikelyXml(Code))
1793 return Replaces;
1794 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1795 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001796 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001797 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1798 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1799 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001800 return Replaces;
1801}
1802
Eric Liu4cfb88a2016-04-25 15:09:22 +00001803template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001804static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001805processReplacements(T ProcessFunc, StringRef Code,
1806 const tooling::Replacements &Replaces,
1807 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001808 if (Replaces.empty())
1809 return tooling::Replacements();
1810
Eric Liu4f8d9942016-07-11 13:53:12 +00001811 auto NewCode = applyAllReplacements(Code, Replaces);
1812 if (!NewCode)
1813 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001814 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001815 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001816
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001817 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001818 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001819
Eric Liu40ef2fb2016-08-01 10:16:37 +00001820 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001821}
1822
Eric Liu4f8d9942016-07-11 13:53:12 +00001823llvm::Expected<tooling::Replacements>
1824formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1825 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001826 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001827 // `sortIncludes`.
1828 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1829 std::vector<tooling::Range> Ranges,
1830 StringRef FileName) -> tooling::Replacements {
1831 return sortIncludes(Style, Code, Ranges, FileName);
1832 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001833 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001834 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001835 if (!SortedReplaces)
1836 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001837
1838 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001839 // `reformat`.
1840 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1841 std::vector<tooling::Range> Ranges,
1842 StringRef FileName) -> tooling::Replacements {
1843 return reformat(Style, Code, Ranges, FileName);
1844 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001845 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001846}
1847
Eric Liu659afd52016-05-31 13:34:20 +00001848namespace {
1849
1850inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001851 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001852 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1853}
1854
Eric Liuc0d3a802016-09-23 15:10:56 +00001855inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1856 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1857}
1858
Eric Liu964782a2016-12-02 11:01:43 +00001859// Returns the offset after skipping a sequence of tokens, matched by \p
1860// GetOffsetAfterSequence, from the start of the code.
1861// \p GetOffsetAfterSequence should be a function that matches a sequence of
1862// tokens and returns an offset after the sequence.
1863unsigned getOffsetAfterTokenSequence(
1864 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001865 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1866 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001867 std::unique_ptr<Environment> Env =
1868 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1869 const SourceManager &SourceMgr = Env->getSourceManager();
1870 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1871 getFormattingLangOpts(Style));
1872 Token Tok;
1873 // Get the first token.
1874 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001875 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001876}
1877
1878// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1879// \p Tok will be the token after this directive; otherwise, it can be any token
1880// after the given \p Tok (including \p Tok).
1881bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1882 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1883 Tok.is(tok::raw_identifier) &&
1884 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001885 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001886 if (Matched)
1887 Lex.LexFromRawLexer(Tok);
1888 return Matched;
1889}
1890
Eric Liu964782a2016-12-02 11:01:43 +00001891void skipComments(Lexer &Lex, Token &Tok) {
1892 while (Tok.is(tok::comment))
1893 if (Lex.LexFromRawLexer(Tok))
1894 return;
1895}
1896
1897// Returns the offset after header guard directives and any comments
1898// before/after header guards. If no header guard presents in the code, this
1899// will returns the offset after skipping all comments from the start of the
1900// code.
Eric Liu35288322016-06-06 11:00:13 +00001901unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1902 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001903 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001904 return getOffsetAfterTokenSequence(
1905 FileName, Code, Style,
1906 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1907 skipComments(Lex, Tok);
1908 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1909 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1910 skipComments(Lex, Tok);
1911 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1912 return SM.getFileOffset(Tok.getLocation());
1913 }
1914 return InitialOffset;
1915 });
1916}
1917
1918// Check if a sequence of tokens is like
1919// "#include ("header.h" | <header.h>)".
1920// If it is, \p Tok will be the token after this directive; otherwise, it can be
1921// any token after the given \p Tok (including \p Tok).
1922bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1923 auto Matched = [&]() {
1924 Lex.LexFromRawLexer(Tok);
1925 return true;
1926 };
1927 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1928 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1929 if (Lex.LexFromRawLexer(Tok))
1930 return false;
1931 if (Tok.is(tok::string_literal))
1932 return Matched();
1933 if (Tok.is(tok::less)) {
1934 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1935 }
1936 if (Tok.is(tok::greater))
1937 return Matched();
1938 }
Eric Liu35288322016-06-06 11:00:13 +00001939 }
Eric Liu964782a2016-12-02 11:01:43 +00001940 return false;
1941}
1942
1943// Returns the offset of the last #include directive after which a new
1944// #include can be inserted. This ignores #include's after the #include block(s)
1945// in the beginning of a file to avoid inserting headers into code sections
1946// where new #include's should not be added by default.
1947// These code sections include:
1948// - raw string literals (containing #include).
1949// - #if blocks.
1950// - Special #include's among declarations (e.g. functions).
1951//
1952// If no #include after which a new #include can be inserted, this returns the
1953// offset after skipping all comments from the start of the code.
1954// Inserting after an #include is not allowed if it comes after code that is not
1955// #include (e.g. pre-processing directive that is not #include, declarations).
1956unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1957 const FormatStyle &Style) {
1958 return getOffsetAfterTokenSequence(
1959 FileName, Code, Style,
1960 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1961 skipComments(Lex, Tok);
1962 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1963 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1964 MaxOffset = SM.getFileOffset(Tok.getLocation());
1965 return MaxOffset;
1966 });
Eric Liu35288322016-06-06 11:00:13 +00001967}
1968
Eric Liuc0d3a802016-09-23 15:10:56 +00001969bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001970 const std::set<llvm::StringRef> &HeadersToDelete) {
1971 return HeadersToDelete.count(HeaderName) ||
1972 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001973}
1974
Eric Liu659afd52016-05-31 13:34:20 +00001975// FIXME: insert empty lines between newly created blocks.
1976tooling::Replacements
1977fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
1978 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00001979 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00001980 return Replaces;
1981
1982 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00001983 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00001984 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00001985 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001986 if (isHeaderInsertion(R)) {
1987 // Replacements from \p Replaces must be conflict-free already, so we can
1988 // simply consume the error.
1989 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00001990 } else if (isHeaderDeletion(R)) {
1991 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001992 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00001993 llvm::errs() << "Insertions other than header #include insertion are "
1994 "not supported! "
1995 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00001996 } else {
1997 llvm::consumeError(Result.add(R));
1998 }
Eric Liu659afd52016-05-31 13:34:20 +00001999 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002000 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00002001 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00002002
2003 llvm::Regex IncludeRegex(IncludeRegexPattern);
2004 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
2005 SmallVector<StringRef, 4> Matches;
2006
2007 StringRef FileName = Replaces.begin()->getFilePath();
2008 IncludeCategoryManager Categories(Style, FileName);
2009
2010 // Record the offset of the end of the last include in each category.
2011 std::map<int, int> CategoryEndOffsets;
2012 // All possible priorities.
2013 // Add 0 for main header and INT_MAX for headers that are not in any category.
2014 std::set<int> Priorities = {0, INT_MAX};
2015 for (const auto &Category : Style.IncludeCategories)
2016 Priorities.insert(Category.Priority);
2017 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00002018 // All new headers should be inserted after this offset.
2019 unsigned MinInsertOffset =
2020 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00002021 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00002022 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00002023 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00002024 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00002025 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00002026 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00002027 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00002028 unsigned Offset = MinInsertOffset;
2029 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002030 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002031 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002032 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002033 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002034 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002035 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002036 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002037 // Only record the offset of current #include if we can insert after it.
2038 if (Offset <= MaxInsertOffset) {
2039 int Category = Categories.getIncludePriority(
2040 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2041 CategoryEndOffsets[Category] = NextLineOffset;
2042 if (FirstIncludeOffset < 0)
2043 FirstIncludeOffset = Offset;
2044 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002045 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2046 // If this is the last line without trailing newline, we need to make
2047 // sure we don't delete across the file boundary.
2048 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2049 llvm::Error Err =
2050 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2051 if (Err) {
2052 // Ignore the deletion on conflict.
2053 llvm::errs() << "Failed to add header deletion replacement for "
2054 << IncludeName << ": " << llvm::toString(std::move(Err))
2055 << "\n";
2056 }
2057 }
Eric Liu659afd52016-05-31 13:34:20 +00002058 }
Eric Liu35288322016-06-06 11:00:13 +00002059 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002060 }
2061
2062 // Populate CategoryEndOfssets:
2063 // - Ensure that CategoryEndOffset[Highest] is always populated.
2064 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2065 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002066 auto Highest = Priorities.begin();
2067 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2068 if (FirstIncludeOffset >= 0)
2069 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2070 else
Eric Liu303baf52016-06-03 12:52:59 +00002071 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002072 }
2073 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2074 // - to an appropriate location before/after existing #includes, or
2075 // - to right after the header guard, or
2076 // - to the beginning of the file.
2077 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2078 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2079 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2080
Eric Liu11a42372016-10-05 15:42:19 +00002081 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002082 for (const auto &R : HeaderInsertions) {
2083 auto IncludeDirective = R.getReplacementText();
2084 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2085 assert(Matched && "Header insertion replacement must have replacement text "
2086 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002087 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002088 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002089 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2090 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2091 << "\n");
2092 continue;
2093 }
Eric Liu659afd52016-05-31 13:34:20 +00002094 int Category =
2095 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2096 Offset = CategoryEndOffsets[Category];
2097 std::string NewInclude = !IncludeDirective.endswith("\n")
2098 ? (IncludeDirective + "\n").str()
2099 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002100 // When inserting headers at end of the code, also append '\n' to the code
2101 // if it does not end with '\n'.
2102 if (NeedNewLineAtEnd && Offset == Code.size()) {
2103 NewInclude = "\n" + NewInclude;
2104 NeedNewLineAtEnd = false;
2105 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002106 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2107 auto Err = Result.add(NewReplace);
2108 if (Err) {
2109 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002110 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2111 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002112 Result = Result.merge(tooling::Replacements(NewReplace));
2113 }
Eric Liu659afd52016-05-31 13:34:20 +00002114 }
2115 return Result;
2116}
2117
2118} // anonymous namespace
2119
Eric Liu4f8d9942016-07-11 13:53:12 +00002120llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002121cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2122 const FormatStyle &Style) {
2123 // We need to use lambda function here since there are two versions of
2124 // `cleanup`.
2125 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2126 std::vector<tooling::Range> Ranges,
2127 StringRef FileName) -> tooling::Replacements {
2128 return cleanup(Style, Code, Ranges, FileName);
2129 };
Eric Liu659afd52016-05-31 13:34:20 +00002130 // Make header insertion replacements insert new headers into correct blocks.
2131 tooling::Replacements NewReplaces =
2132 fixCppIncludeInsertions(Code, Replaces, Style);
2133 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002134}
2135
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002136namespace internal {
2137std::pair<tooling::Replacements, unsigned>
2138reformat(const FormatStyle &Style, StringRef Code,
2139 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2140 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2141 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002142 FormatStyle Expanded = expandPresets(Style);
2143 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002144 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002145 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002146 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002147 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002148 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002149
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002150 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2151 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002152 AnalyzerPass;
2153 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002154
Krasimir Georgievac16a202017-06-23 11:46:03 +00002155 if (Style.Language == FormatStyle::LK_Cpp) {
2156 if (Style.FixNamespaceComments)
2157 Passes.emplace_back([&](const Environment &Env) {
2158 return NamespaceEndCommentsFixer(Env, Expanded).process();
2159 });
2160
2161 if (Style.SortUsingDeclarations)
2162 Passes.emplace_back([&](const Environment &Env) {
2163 return UsingDeclarationsSorter(Env, Expanded).process();
2164 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002165 }
2166
2167 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002168 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2169 Passes.emplace_back([&](const Environment &Env) {
2170 return JavaScriptRequoter(Env, Expanded).process();
2171 });
2172
2173 Passes.emplace_back([&](const Environment &Env) {
2174 return Formatter(Env, Expanded, Status).process();
2175 });
2176
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002177 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2178 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2179 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002180 llvm::Optional<std::string> CurrentCode = None;
2181 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002182 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002183 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002184 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002185 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002186 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002187 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002188 Fixes = Fixes.merge(PassFixes.first);
2189 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002190 if (I + 1 < E) {
2191 CurrentCode = std::move(*NewCode);
2192 Env = Environment::CreateVirtualEnvironment(
2193 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002194 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2195 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002196 }
2197 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002198 }
2199
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002200 return {Fixes, Penalty};
2201}
2202} // namespace internal
2203
2204tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2205 ArrayRef<tooling::Range> Ranges,
2206 StringRef FileName,
2207 FormattingAttemptStatus *Status) {
2208 return internal::reformat(Style, Code, Ranges,
2209 /*FirstStartColumn=*/0,
2210 /*NextStartColumn=*/0,
2211 /*LastStartColumn=*/0, FileName, Status)
2212 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002213}
2214
Eric Liu4cfb88a2016-04-25 15:09:22 +00002215tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2216 ArrayRef<tooling::Range> Ranges,
2217 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002218 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2219 if (Style.Language != FormatStyle::LK_Cpp)
2220 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002221 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002222 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2223 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002224 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002225}
2226
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002227tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2228 ArrayRef<tooling::Range> Ranges,
2229 StringRef FileName, bool *IncompleteFormat) {
2230 FormattingAttemptStatus Status;
2231 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2232 if (!Status.FormatComplete)
2233 *IncompleteFormat = true;
2234 return Result;
2235}
2236
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002237tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2238 StringRef Code,
2239 ArrayRef<tooling::Range> Ranges,
2240 StringRef FileName) {
2241 std::unique_ptr<Environment> Env =
2242 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2243 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002244 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002245}
2246
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002247tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2248 StringRef Code,
2249 ArrayRef<tooling::Range> Ranges,
2250 StringRef FileName) {
2251 std::unique_ptr<Environment> Env =
2252 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2253 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002254 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002255}
2256
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002257LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002258 LangOptions LangOpts;
2259 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002260 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2261 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002262 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002263 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002264 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002265 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002266 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002267 LangOpts.Bool = 1;
2268 LangOpts.ObjC1 = 1;
2269 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002270 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002271 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002272 return LangOpts;
2273}
2274
Edwin Vaned544aa72013-09-30 13:31:48 +00002275const char *StyleOptionHelpDescription =
2276 "Coding style, currently supports:\n"
2277 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2278 "Use -style=file to load style configuration from\n"
2279 ".clang-format file located in one of the parent\n"
2280 "directories of the source file (or current\n"
2281 "directory for stdin).\n"
2282 "Use -style=\"{key: value, ...}\" to set specific\n"
2283 "parameters, e.g.:\n"
2284 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2285
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002286static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002287 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002288 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002289 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2290 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002291 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2292 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002293 if (FileName.endswith_lower(".proto") ||
2294 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002295 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002296 if (FileName.endswith_lower(".textpb") ||
2297 FileName.endswith_lower(".pb.txt") ||
2298 FileName.endswith_lower(".textproto") ||
2299 FileName.endswith_lower(".asciipb"))
2300 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002301 if (FileName.endswith_lower(".td"))
2302 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002303 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002304}
2305
Ben Hamilton3b345c32018-02-21 15:54:31 +00002306FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
Ben Hamilton6e066352018-02-27 15:56:40 +00002307 const auto GuessedLanguage = getLanguageByFileName(FileName);
2308 if (GuessedLanguage == FormatStyle::LK_Cpp) {
Ben Hamilton07e58362018-02-21 21:27:27 +00002309 auto Extension = llvm::sys::path::extension(FileName);
Ben Hamilton3b345c32018-02-21 15:54:31 +00002310 // If there's no file extension (or it's .h), we need to check the contents
2311 // of the code to see if it contains Objective-C.
Ben Hamilton07e58362018-02-21 21:27:27 +00002312 if (Extension.empty() || Extension == ".h") {
2313 auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002314 std::unique_ptr<Environment> Env =
Ben Hamilton07e58362018-02-21 21:27:27 +00002315 Environment::CreateVirtualEnvironment(Code, NonEmptyFileName, /*Ranges=*/{});
Ben Hamilton3b345c32018-02-21 15:54:31 +00002316 ObjCHeaderStyleGuesser Guesser(*Env, getLLVMStyle());
2317 Guesser.process();
Ben Hamilton6e066352018-02-27 15:56:40 +00002318 if (Guesser.isObjC())
2319 return FormatStyle::LK_ObjC;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002320 }
2321 }
Ben Hamilton6e066352018-02-27 15:56:40 +00002322 return GuessedLanguage;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002323}
2324
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002325llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002326 StringRef FallbackStyleName,
2327 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002328 if (!FS) {
2329 FS = vfs::getRealFileSystem().get();
2330 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002331 FormatStyle Style = getLLVMStyle();
Ben Hamilton3b345c32018-02-21 15:54:31 +00002332 Style.Language = guessLanguage(FileName, Code);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002333
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002334 FormatStyle FallbackStyle = getNoStyle();
2335 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2336 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002337
2338 if (StyleName.startswith("{")) {
2339 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002340 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2341 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002342 return Style;
2343 }
2344
2345 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002346 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002347 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002348 return Style;
2349 }
2350
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002351 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002352 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002353 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002354 if (std::error_code EC = FS->makeAbsolute(Path))
2355 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002356
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002357 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002358 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002359
2360 auto Status = FS->status(Directory);
2361 if (!Status ||
2362 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002363 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002364 }
2365
Edwin Vaned544aa72013-09-30 13:31:48 +00002366 SmallString<128> ConfigFile(Directory);
2367
2368 llvm::sys::path::append(ConfigFile, ".clang-format");
2369 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002370
Eric Liu547d8792016-03-24 13:22:42 +00002371 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002372 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002373 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002374 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002375 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2376 ConfigFile = Directory;
2377 llvm::sys::path::append(ConfigFile, "_clang-format");
2378 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002379 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002380 FoundConfigFile = Status && (Status->getType() ==
2381 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002382 }
2383
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002384 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002385 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002386 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002387 if (std::error_code EC = Text.getError())
2388 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002389 if (std::error_code ec =
2390 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002391 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002392 if (!UnsuitableConfigFiles.empty())
2393 UnsuitableConfigFiles.append(", ");
2394 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002395 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002396 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002397 return make_string_error("Error reading " + ConfigFile + ": " +
2398 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002399 }
2400 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2401 return Style;
2402 }
2403 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002404 if (!UnsuitableConfigFiles.empty())
2405 return make_string_error("Configuration file(s) do(es) not support " +
2406 getLanguageName(Style.Language) + ": " +
2407 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002408 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002409}
2410
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002411} // namespace format
2412} // namespace clang