blob: 54b10f474c0509ad7641dacc4f77244b3187e4d5 [file] [log] [blame]
Daniel Jasperf7935112012-12-03 18:12:45 +00001//===--- Format.cpp - Format C++ code -------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements functions declared in Format.h. This will be
12/// split into separate files as we go.
13///
Daniel Jasperf7935112012-12-03 18:12:45 +000014//===----------------------------------------------------------------------===//
15
Daniel Jasper85c472d2015-09-29 07:53:08 +000016#include "clang/Format/Format.h"
Eric Liu4cfb88a2016-04-25 15:09:22 +000017#include "AffectedRangeManager.h"
Daniel Jasperde0328a2013-08-16 11:20:30 +000018#include "ContinuationIndenter.h"
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +000019#include "FormatInternal.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000020#include "FormatTokenLexer.h"
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +000021#include "NamespaceEndCommentsFixer.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000022#include "SortJavaScriptImports.h"
23#include "TokenAnalyzer.h"
Daniel Jasper7a6d09b2013-01-29 21:01:14 +000024#include "TokenAnnotator.h"
Daniel Jasper0df50932014-12-10 19:00:42 +000025#include "UnwrappedLineFormatter.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000026#include "UnwrappedLineParser.h"
Krasimir Georgievb03877a2017-06-21 12:03:12 +000027#include "UsingDeclarationsSorter.h"
Alexander Kornienkocb45bc12013-04-15 14:28:00 +000028#include "WhitespaceManager.h"
Daniel Jasperec04c0d2013-05-16 10:40:07 +000029#include "clang/Basic/Diagnostic.h"
Benjamin Kramerf3ca26982014-05-10 16:31:55 +000030#include "clang/Basic/DiagnosticOptions.h"
Chandler Carruth44eb4f62013-01-02 10:28:36 +000031#include "clang/Basic/SourceManager.h"
Marianne Mailhot-Sarrasin4988fa12016-04-14 14:47:37 +000032#include "clang/Basic/VirtualFileSystem.h"
Daniel Jasperf7935112012-12-03 18:12:45 +000033#include "clang/Lex/Lexer.h"
Alexander Kornienkoffd6d042013-03-27 11:52:18 +000034#include "llvm/ADT/STLExtras.h"
Ben Hamiltone2e3e672018-01-17 17:33:08 +000035#include "llvm/ADT/StringRef.h"
Manuel Klimek2ef908e2013-02-13 10:46:36 +000036#include "llvm/Support/Allocator.h"
Manuel Klimek24998102013-01-16 14:55:28 +000037#include "llvm/Support/Debug.h"
Edwin Vaned544aa72013-09-30 13:31:48 +000038#include "llvm/Support/Path.h"
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +000039#include "llvm/Support/Regex.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000040#include "llvm/Support/YAMLTraits.h"
Martin Probst081f1762016-06-01 15:19:53 +000041#include <algorithm>
Eric Liu4cfb88a2016-04-25 15:09:22 +000042#include <memory>
Daniel Jasper8b529712012-12-04 13:02:32 +000043#include <string>
44
Chandler Carruth10346662014-04-22 03:17:02 +000045#define DEBUG_TYPE "format-formatter"
46
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000047using clang::format::FormatStyle;
48
NAKAMURA Takumi057a9422017-11-01 04:43:22 +000049LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
50LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
Daniel Jaspere1e43192014-04-01 12:55:11 +000051
Alexander Kornienkod6538332013-05-07 15:32:14 +000052namespace llvm {
53namespace yaml {
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000054template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
55 static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
56 IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
Daniel Jasperc58c70e2014-09-15 11:21:46 +000057 IO.enumCase(Value, "Java", FormatStyle::LK_Java);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000058 IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
Daniel Jasper03a04fe2016-12-12 12:42:29 +000059 IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
Daniel Jasper7052ce62014-01-19 09:04:08 +000060 IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
Daniel Jasper498f5582015-12-25 08:53:31 +000061 IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
Krasimir Georgiev26b144c2017-07-03 15:05:14 +000062 IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000063 }
64};
65
66template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
67 static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
68 IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
69 IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
70 IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
71 IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
72 IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
73 }
74};
75
76template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
77 static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
78 IO.enumCase(Value, "Never", FormatStyle::UT_Never);
79 IO.enumCase(Value, "false", FormatStyle::UT_Never);
80 IO.enumCase(Value, "Always", FormatStyle::UT_Always);
81 IO.enumCase(Value, "true", FormatStyle::UT_Always);
82 IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
Marianne Mailhot-Sarrasin51fe2792016-04-14 14:52:26 +000083 IO.enumCase(Value, "ForContinuationAndIndentation",
84 FormatStyle::UT_ForContinuationAndIndentation);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000085 }
86};
87
Daniel Jasperabd1f572016-03-02 22:44:03 +000088template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
89 static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
90 IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
91 IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
92 IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
93 }
94};
95
Daniel Jasperd74cf402014-04-08 12:46:38 +000096template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
97 static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
98 IO.enumCase(Value, "None", FormatStyle::SFS_None);
99 IO.enumCase(Value, "false", FormatStyle::SFS_None);
100 IO.enumCase(Value, "All", FormatStyle::SFS_All);
101 IO.enumCase(Value, "true", FormatStyle::SFS_All);
102 IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
Francois Ferrandd3f0e3d2017-06-21 13:56:02 +0000103 IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
Daniel Jasper9e709352014-11-26 10:43:58 +0000104 IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
Daniel Jasperd74cf402014-04-08 12:46:38 +0000105 }
106};
107
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000108template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
109 static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
110 IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto);
111 IO.enumCase(Value, "Always", FormatStyle::BPS_Always);
112 IO.enumCase(Value, "Never", FormatStyle::BPS_Never);
113 }
114};
115
Daniel Jasperac043c92014-09-15 11:11:00 +0000116template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
117 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
118 IO.enumCase(Value, "All", FormatStyle::BOS_All);
119 IO.enumCase(Value, "true", FormatStyle::BOS_All);
120 IO.enumCase(Value, "None", FormatStyle::BOS_None);
121 IO.enumCase(Value, "false", FormatStyle::BOS_None);
122 IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
123 }
124};
125
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000126template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
127 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
128 IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
129 IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000130 IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000131 IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
132 IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000133 IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000134 IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000135 IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000136 }
137};
138
Manuel Klimek89628f62017-09-20 09:51:03 +0000139template <>
140struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
141 static void
142 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
Francois Ferranda6b6d512017-05-24 11:36:58 +0000143 IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
144 IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
145 IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
146 }
147};
148
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000149template <>
Krasimir Georgievad47c902017-08-30 14:34:57 +0000150struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
151 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
152 IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
153 IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
154 }
155};
156
157template <>
Zachary Turner448592e2015-12-18 22:20:15 +0000158struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
159 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
160 IO.enumCase(Value, "None", FormatStyle::RTBS_None);
161 IO.enumCase(Value, "All", FormatStyle::RTBS_All);
162 IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
163 IO.enumCase(Value, "TopLevelDefinitions",
164 FormatStyle::RTBS_TopLevelDefinitions);
165 IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
166 }
167};
168
169template <>
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000170struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
171 static void
172 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000173 IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
174 IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
175 IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
176
177 // For backward compatibility.
178 IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
179 IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
180 }
181};
182
Alexander Kornienkod6538332013-05-07 15:32:14 +0000183template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000184struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000185 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000186 FormatStyle::NamespaceIndentationKind &Value) {
187 IO.enumCase(Value, "None", FormatStyle::NI_None);
188 IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
189 IO.enumCase(Value, "All", FormatStyle::NI_All);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000190 }
191};
192
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000193template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
194 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
195 IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
196 IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
197 IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
198
199 // For backward compatibility.
200 IO.enumCase(Value, "true", FormatStyle::BAS_Align);
201 IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
202 }
203};
204
Manuel Klimek89628f62017-09-20 09:51:03 +0000205template <>
206struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
207 static void enumeration(IO &IO,
208 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000209 IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
210 IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
211 IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
212
213 // For backward compatibility.
214 IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
215 IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
216 }
217};
218
Jacques Pienaarfc275112015-02-18 23:48:37 +0000219template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
220 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
Daniel Jasper553d4872014-06-17 12:40:34 +0000221 IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
222 IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
223 IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
224
Alp Toker958027b2014-07-14 19:42:55 +0000225 // For backward compatibility.
Daniel Jasper553d4872014-06-17 12:40:34 +0000226 IO.enumCase(Value, "true", FormatStyle::PAS_Left);
227 IO.enumCase(Value, "false", FormatStyle::PAS_Right);
228 }
229};
230
231template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000232struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
Manuel Klimeka8eb9142013-05-13 12:51:40 +0000233 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000234 FormatStyle::SpaceBeforeParensOptions &Value) {
235 IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000236 IO.enumCase(Value, "ControlStatements",
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000237 FormatStyle::SBPO_ControlStatements);
238 IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000239
240 // For backward compatibility.
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000241 IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
242 IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000243 }
244};
245
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000246template <> struct MappingTraits<FormatStyle> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000247 static void mapping(IO &IO, FormatStyle &Style) {
248 // When reading, read the language first, we need it for getPredefinedStyle.
249 IO.mapOptional("Language", Style.Language);
250
Alexander Kornienko49149672013-05-10 11:56:10 +0000251 if (IO.outputting()) {
Jacques Pienaarfc275112015-02-18 23:48:37 +0000252 StringRef StylesArray[] = {"LLVM", "Google", "Chromium",
253 "Mozilla", "WebKit", "GNU"};
Alexander Kornienko49149672013-05-10 11:56:10 +0000254 ArrayRef<StringRef> Styles(StylesArray);
255 for (size_t i = 0, e = Styles.size(); i < e; ++i) {
256 StringRef StyleName(Styles[i]);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000257 FormatStyle PredefinedStyle;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000258 if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000259 Style == PredefinedStyle) {
Alexander Kornienko49149672013-05-10 11:56:10 +0000260 IO.mapOptional("# BasedOnStyle", StyleName);
261 break;
262 }
263 }
264 } else {
Alexander Kornienkod6538332013-05-07 15:32:14 +0000265 StringRef BasedOnStyle;
266 IO.mapOptional("BasedOnStyle", BasedOnStyle);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000267 if (!BasedOnStyle.empty()) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000268 FormatStyle::LanguageKind OldLanguage = Style.Language;
269 FormatStyle::LanguageKind Language =
270 ((FormatStyle *)IO.getContext())->Language;
271 if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000272 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
273 return;
274 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000275 Style.Language = OldLanguage;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000276 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000277 }
278
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000279 // For backward compatibility.
280 if (!IO.outputting()) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000281 IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000282 IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
283 IO.mapOptional("IndentFunctionDeclarationAfterType",
284 Style.IndentWrappedFunctionNames);
285 IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
286 IO.mapOptional("SpaceAfterControlStatementKeyword",
287 Style.SpaceBeforeParens);
288 }
289
Alexander Kornienkod6538332013-05-07 15:32:14 +0000290 IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
Daniel Jasper3aa9a6a2014-11-18 23:55:27 +0000291 IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000292 IO.mapOptional("AlignConsecutiveAssignments",
293 Style.AlignConsecutiveAssignments);
Daniel Jaspere12597c2015-10-01 10:06:54 +0000294 IO.mapOptional("AlignConsecutiveDeclarations",
295 Style.AlignConsecutiveDeclarations);
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000296 IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
Daniel Jasper3219e432014-12-02 13:24:51 +0000297 IO.mapOptional("AlignOperands", Style.AlignOperands);
Daniel Jasper552f4a72013-07-31 23:55:15 +0000298 IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000299 IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
300 Style.AllowAllParametersOfDeclarationOnNextLine);
Daniel Jasper17605d32014-05-14 09:33:35 +0000301 IO.mapOptional("AllowShortBlocksOnASingleLine",
302 Style.AllowShortBlocksOnASingleLine);
Daniel Jasperb87899b2014-09-10 13:11:45 +0000303 IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
304 Style.AllowShortCaseLabelsOnASingleLine);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000305 IO.mapOptional("AllowShortFunctionsOnASingleLine",
306 Style.AllowShortFunctionsOnASingleLine);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000307 IO.mapOptional("AllowShortIfStatementsOnASingleLine",
308 Style.AllowShortIfStatementsOnASingleLine);
Daniel Jasper3a685df2013-05-16 12:12:21 +0000309 IO.mapOptional("AllowShortLoopsOnASingleLine",
310 Style.AllowShortLoopsOnASingleLine);
Daniel Jasperca4ea1c2014-08-05 12:16:31 +0000311 IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
312 Style.AlwaysBreakAfterDefinitionReturnType);
Zachary Turner448592e2015-12-18 22:20:15 +0000313 IO.mapOptional("AlwaysBreakAfterReturnType",
314 Style.AlwaysBreakAfterReturnType);
315 // If AlwaysBreakAfterDefinitionReturnType was specified but
316 // AlwaysBreakAfterReturnType was not, initialize the latter from the
317 // former for backwards compatibility.
318 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
319 Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
320 if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
321 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
322 else if (Style.AlwaysBreakAfterDefinitionReturnType ==
323 FormatStyle::DRTBS_TopLevel)
324 Style.AlwaysBreakAfterReturnType =
325 FormatStyle::RTBS_TopLevelDefinitions;
326 }
327
Alexander Kornienko58611712013-07-04 12:02:44 +0000328 IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
329 Style.AlwaysBreakBeforeMultilineStrings);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000330 IO.mapOptional("AlwaysBreakTemplateDeclarations",
331 Style.AlwaysBreakTemplateDeclarations);
332 IO.mapOptional("BinPackArguments", Style.BinPackArguments);
333 IO.mapOptional("BinPackParameters", Style.BinPackParameters);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000334 IO.mapOptional("BraceWrapping", Style.BraceWrapping);
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000335 IO.mapOptional("BreakBeforeBinaryOperators",
336 Style.BreakBeforeBinaryOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000337 IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
Francois Ferrande56a8292017-06-14 12:29:47 +0000338 IO.mapOptional("BreakBeforeInheritanceComma",
339 Style.BreakBeforeInheritanceComma);
Daniel Jasper165b29e2013-11-08 00:57:11 +0000340 IO.mapOptional("BreakBeforeTernaryOperators",
341 Style.BreakBeforeTernaryOperators);
Francois Ferranda6b6d512017-05-24 11:36:58 +0000342
343 bool BreakConstructorInitializersBeforeComma = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000344 IO.mapOptional("BreakConstructorInitializersBeforeComma",
Francois Ferranda6b6d512017-05-24 11:36:58 +0000345 BreakConstructorInitializersBeforeComma);
346 IO.mapOptional("BreakConstructorInitializers",
347 Style.BreakConstructorInitializers);
348 // If BreakConstructorInitializersBeforeComma was specified but
349 // BreakConstructorInitializers was not, initialize the latter from the
350 // former for backwards compatibility.
351 if (BreakConstructorInitializersBeforeComma &&
352 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
353 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
354
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000355 IO.mapOptional("BreakAfterJavaFieldAnnotations",
356 Style.BreakAfterJavaFieldAnnotations);
357 IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000358 IO.mapOptional("ColumnLimit", Style.ColumnLimit);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000359 IO.mapOptional("CommentPragmas", Style.CommentPragmas);
Francois Ferrande56a8292017-06-14 12:29:47 +0000360 IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000361 IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
362 Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000363 IO.mapOptional("ConstructorInitializerIndentWidth",
364 Style.ConstructorInitializerIndentWidth);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000365 IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
366 IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
Daniel Jasper553d4872014-06-17 12:40:34 +0000367 IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000368 IO.mapOptional("DisableFormat", Style.DisableFormat);
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000369 IO.mapOptional("ExperimentalAutoDetectBinPacking",
370 Style.ExperimentalAutoDetectBinPacking);
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000371 IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000372 IO.mapOptional("ForEachMacros", Style.ForEachMacros);
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000373 IO.mapOptional("IncludeBlocks", Style.IncludeBlocks);
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000374 IO.mapOptional("IncludeCategories", Style.IncludeCategories);
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000375 IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000376 IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
Krasimir Georgievad47c902017-08-30 14:34:57 +0000377 IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000378 IO.mapOptional("IndentWidth", Style.IndentWidth);
379 IO.mapOptional("IndentWrappedFunctionNames",
380 Style.IndentWrappedFunctionNames);
Martin Probst0cd74ee2016-06-13 16:39:50 +0000381 IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
382 IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000383 IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
384 Style.KeepEmptyLinesAtTheStartOfBlocks);
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +0000385 IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
386 IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000387 IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
Daniel Jasper65ee3472013-07-31 23:16:02 +0000388 IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000389 IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000390 IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
Daniel Jaspere9beea22014-01-28 15:20:33 +0000391 IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000392 IO.mapOptional("ObjCSpaceBeforeProtocolList",
393 Style.ObjCSpaceBeforeProtocolList);
Manuel Klimek89628f62017-09-20 09:51:03 +0000394 IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
Daniel Jasper33b909c2013-10-25 14:29:37 +0000395 IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
396 Style.PenaltyBreakBeforeFirstCallParameter);
Alexander Kornienkodd7ece52013-06-07 16:02:52 +0000397 IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000398 IO.mapOptional("PenaltyBreakFirstLessLess",
399 Style.PenaltyBreakFirstLessLess);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000400 IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000401 IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
402 IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
403 Style.PenaltyReturnTypeOnItsOwnLine);
Daniel Jasper553d4872014-06-17 12:40:34 +0000404 IO.mapOptional("PointerAlignment", Style.PointerAlignment);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000405 IO.mapOptional("RawStringFormats", Style.RawStringFormats);
Daniel Jaspera0a50392015-12-01 13:28:53 +0000406 IO.mapOptional("ReflowComments", Style.ReflowComments);
407 IO.mapOptional("SortIncludes", Style.SortIncludes);
Krasimir Georgievac16a202017-06-23 11:46:03 +0000408 IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000409 IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
Manuel Klimek89628f62017-09-20 09:51:03 +0000410 IO.mapOptional("SpaceAfterTemplateKeyword",
411 Style.SpaceAfterTemplateKeyword);
Daniel Jasperd94bff32013-09-25 15:15:02 +0000412 IO.mapOptional("SpaceBeforeAssignmentOperators",
413 Style.SpaceBeforeAssignmentOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000414 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
415 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
416 IO.mapOptional("SpacesBeforeTrailingComments",
417 Style.SpacesBeforeTrailingComments);
418 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
419 IO.mapOptional("SpacesInContainerLiterals",
420 Style.SpacesInContainerLiterals);
421 IO.mapOptional("SpacesInCStyleCastParentheses",
422 Style.SpacesInCStyleCastParentheses);
423 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
424 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
425 IO.mapOptional("Standard", Style.Standard);
426 IO.mapOptional("TabWidth", Style.TabWidth);
427 IO.mapOptional("UseTab", Style.UseTab);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000428 }
429};
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000430
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000431template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
432 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
433 IO.mapOptional("AfterClass", Wrapping.AfterClass);
434 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
435 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
436 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
437 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
438 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
439 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
440 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000441 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000442 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
443 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
444 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
Francois Ferrandad722562017-06-30 20:25:55 +0000445 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
446 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
447 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000448 }
449};
450
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000451template <> struct MappingTraits<FormatStyle::IncludeCategory> {
452 static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
453 IO.mapOptional("Regex", Category.Regex);
454 IO.mapOptional("Priority", Category.Priority);
455 }
456};
457
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000458template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> {
459 static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
460 IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve);
461 IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge);
462 IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup);
463 }
464};
465
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000466template <> struct MappingTraits<FormatStyle::RawStringFormat> {
467 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000468 IO.mapOptional("Language", Format.Language);
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000469 IO.mapOptional("Delimiters", Format.Delimiters);
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000470 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000471 IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000472 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
473 }
474};
475
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000476// Allows to read vector<FormatStyle> while keeping default values.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000477// IO.getContext() should contain a pointer to the FormatStyle structure, that
478// will be used to get default values for missing keys.
479// If the first element has no Language specified, it will be treated as the
480// default one for the following elements.
Jacques Pienaarfc275112015-02-18 23:48:37 +0000481template <> struct DocumentListTraits<std::vector<FormatStyle>> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000482 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
483 return Seq.size();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000484 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000485 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000486 size_t Index) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000487 if (Index >= Seq.size()) {
488 assert(Index == Seq.size());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000489 FormatStyle Template;
Krasimir Georgiev1696bb62017-11-09 15:12:17 +0000490 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000491 Template = Seq[0];
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000492 } else {
Daniel Jasperb05a81d2014-05-09 13:11:16 +0000493 Template = *((const FormatStyle *)IO.getContext());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000494 Template.Language = FormatStyle::LK_None;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000495 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000496 Seq.resize(Index + 1, Template);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000497 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000498 return Seq[Index];
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000499 }
500};
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000501} // namespace yaml
502} // namespace llvm
Alexander Kornienkod6538332013-05-07 15:32:14 +0000503
Daniel Jasperf7935112012-12-03 18:12:45 +0000504namespace clang {
505namespace format {
506
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000507const std::error_category &getParseCategory() {
Rafael Espindolad0136702014-06-12 02:50:04 +0000508 static ParseErrorCategory C;
509 return C;
510}
511std::error_code make_error_code(ParseError e) {
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000512 return std::error_code(static_cast<int>(e), getParseCategory());
Rafael Espindolad0136702014-06-12 02:50:04 +0000513}
514
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +0000515inline llvm::Error make_string_error(const llvm::Twine &Message) {
516 return llvm::make_error<llvm::StringError>(Message,
517 llvm::inconvertibleErrorCode());
518}
519
Reid Kleckner6432d452016-10-19 23:39:55 +0000520const char *ParseErrorCategory::name() const noexcept {
Rafael Espindolad0136702014-06-12 02:50:04 +0000521 return "clang-format.parse_error";
522}
523
524std::string ParseErrorCategory::message(int EV) const {
525 switch (static_cast<ParseError>(EV)) {
526 case ParseError::Success:
527 return "Success";
528 case ParseError::Error:
529 return "Invalid argument";
530 case ParseError::Unsuitable:
531 return "Unsuitable";
532 }
Saleem Abdulrasoolfbfbaf62014-06-12 19:33:26 +0000533 llvm_unreachable("unexpected parse error");
Rafael Espindolad0136702014-06-12 02:50:04 +0000534}
535
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000536static FormatStyle expandPresets(const FormatStyle &Style) {
Daniel Jasper55bbe662015-10-07 04:06:10 +0000537 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
538 return Style;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000539 FormatStyle Expanded = Style;
Manuel Klimek89628f62017-09-20 09:51:03 +0000540 Expanded.BraceWrapping = {false, false, false, false, false,
541 false, false, false, false, false,
542 false, false, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000543 switch (Style.BreakBeforeBraces) {
544 case FormatStyle::BS_Linux:
545 Expanded.BraceWrapping.AfterClass = true;
546 Expanded.BraceWrapping.AfterFunction = true;
547 Expanded.BraceWrapping.AfterNamespace = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000548 break;
549 case FormatStyle::BS_Mozilla:
550 Expanded.BraceWrapping.AfterClass = true;
551 Expanded.BraceWrapping.AfterEnum = true;
552 Expanded.BraceWrapping.AfterFunction = true;
553 Expanded.BraceWrapping.AfterStruct = true;
554 Expanded.BraceWrapping.AfterUnion = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000555 Expanded.BraceWrapping.AfterExternBlock = true;
Sylvestre Ledru82c9a0e2017-09-13 20:03:29 +0000556 Expanded.BraceWrapping.SplitEmptyFunction = true;
Francois Ferrandad722562017-06-30 20:25:55 +0000557 Expanded.BraceWrapping.SplitEmptyRecord = false;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000558 break;
559 case FormatStyle::BS_Stroustrup:
560 Expanded.BraceWrapping.AfterFunction = true;
561 Expanded.BraceWrapping.BeforeCatch = true;
562 Expanded.BraceWrapping.BeforeElse = true;
563 break;
564 case FormatStyle::BS_Allman:
565 Expanded.BraceWrapping.AfterClass = true;
566 Expanded.BraceWrapping.AfterControlStatement = true;
567 Expanded.BraceWrapping.AfterEnum = true;
568 Expanded.BraceWrapping.AfterFunction = true;
569 Expanded.BraceWrapping.AfterNamespace = true;
570 Expanded.BraceWrapping.AfterObjCDeclaration = true;
571 Expanded.BraceWrapping.AfterStruct = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000572 Expanded.BraceWrapping.AfterExternBlock = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000573 Expanded.BraceWrapping.BeforeCatch = true;
574 Expanded.BraceWrapping.BeforeElse = true;
575 break;
576 case FormatStyle::BS_GNU:
Manuel Klimek89628f62017-09-20 09:51:03 +0000577 Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
578 true, true, true, true, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000579 break;
580 case FormatStyle::BS_WebKit:
581 Expanded.BraceWrapping.AfterFunction = true;
582 break;
583 default:
584 break;
585 }
586 return Expanded;
587}
588
Daniel Jasperf7935112012-12-03 18:12:45 +0000589FormatStyle getLLVMStyle() {
590 FormatStyle LLVMStyle;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000591 LLVMStyle.Language = FormatStyle::LK_Cpp;
Daniel Jasperf7935112012-12-03 18:12:45 +0000592 LLVMStyle.AccessModifierOffset = -2;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000593 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000594 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
Daniel Jasper3219e432014-12-02 13:24:51 +0000595 LLVMStyle.AlignOperands = true;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000596 LLVMStyle.AlignTrailingComments = true;
Daniel Jaspera44991332015-04-29 13:06:49 +0000597 LLVMStyle.AlignConsecutiveAssignments = false;
Daniel Jaspere12597c2015-10-01 10:06:54 +0000598 LLVMStyle.AlignConsecutiveDeclarations = false;
Daniel Jasperf7db4332013-01-29 16:03:49 +0000599 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
Daniel Jasperd74cf402014-04-08 12:46:38 +0000600 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Daniel Jasper17605d32014-05-14 09:33:35 +0000601 LLVMStyle.AllowShortBlocksOnASingleLine = false;
Daniel Jasperb87899b2014-09-10 13:11:45 +0000602 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000603 LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper3a685df2013-05-16 12:12:21 +0000604 LLVMStyle.AllowShortLoopsOnASingleLine = false;
Zachary Turner448592e2015-12-18 22:20:15 +0000605 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000606 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Alexander Kornienko58611712013-07-04 12:02:44 +0000607 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000608 LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Daniel Jasper18210d72014-10-09 09:52:05 +0000609 LLVMStyle.BinPackArguments = true;
Francois Ferrande56a8292017-06-14 12:29:47 +0000610 LLVMStyle.BinPackParameters = true;
Daniel Jasperac043c92014-09-15 11:11:00 +0000611 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Daniel Jasper165b29e2013-11-08 00:57:11 +0000612 LLVMStyle.BreakBeforeTernaryOperators = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000613 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
Manuel Klimek89628f62017-09-20 09:51:03 +0000614 LLVMStyle.BraceWrapping = {false, false, false, false, false,
615 false, false, false, false, false,
616 false, false, true, true, true};
Nico Weber2cd92f12015-10-15 16:03:01 +0000617 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000618 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000619 LLVMStyle.BreakBeforeInheritanceComma = false;
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000620 LLVMStyle.BreakStringLiterals = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000621 LLVMStyle.ColumnLimit = 80;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000622 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
Francois Ferrande56a8292017-06-14 12:29:47 +0000623 LLVMStyle.CompactNamespaces = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000624 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
Daniel Jaspercdaffa42013-08-13 10:58:30 +0000625 LLVMStyle.ConstructorInitializerIndentWidth = 4;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000626 LLVMStyle.ContinuationIndentWidth = 4;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000627 LLVMStyle.Cpp11BracedListStyle = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000628 LLVMStyle.DerivePointerAlignment = false;
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000629 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000630 LLVMStyle.FixNamespaceComments = true;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000631 LLVMStyle.ForEachMacros.push_back("foreach");
632 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
633 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
Daniel Jasper85c472d2015-09-29 07:53:08 +0000634 LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
Chandler Carruthd676ab12017-06-29 23:20:54 +0000635 {"^(<|\"(gtest|gmock|isl|json)/)", 3},
Daniel Jasper85c472d2015-09-29 07:53:08 +0000636 {".*", 1}};
Chandler Carruthd676ab12017-06-29 23:20:54 +0000637 LLVMStyle.IncludeIsMainRegex = "(Test)?$";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000638 LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000639 LLVMStyle.IndentCaseLabels = false;
Krasimir Georgievad47c902017-08-30 14:34:57 +0000640 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
Daniel Jasperc75e1ef2014-07-09 08:42:42 +0000641 LLVMStyle.IndentWrappedFunctionNames = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000642 LLVMStyle.IndentWidth = 2;
Martin Probstfb2342d2016-06-13 17:50:10 +0000643 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
644 LLVMStyle.JavaScriptWrapImports = true;
Alexander Kornienkoebb43ca2013-09-05 14:08:34 +0000645 LLVMStyle.TabWidth = 8;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000646 LLVMStyle.MaxEmptyLinesToKeep = 1;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000647 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000648 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000649 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000650 LLVMStyle.ObjCBlockIndentWidth = 2;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000651 LLVMStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000652 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000653 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000654 LLVMStyle.SpacesBeforeTrailingComments = 1;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000655 LLVMStyle.Standard = FormatStyle::LS_Cpp11;
Alexander Kornienko3c3d09c2013-09-27 16:14:22 +0000656 LLVMStyle.UseTab = FormatStyle::UT_Never;
Daniel Jaspera0a50392015-12-01 13:28:53 +0000657 LLVMStyle.ReflowComments = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000658 LLVMStyle.SpacesInParentheses = false;
Daniel Jasperad981f82014-08-26 11:41:14 +0000659 LLVMStyle.SpacesInSquareBrackets = false;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000660 LLVMStyle.SpaceInEmptyParentheses = false;
Daniel Jasperb2e10a52014-01-15 15:09:08 +0000661 LLVMStyle.SpacesInContainerLiterals = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000662 LLVMStyle.SpacesInCStyleCastParentheses = false;
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000663 LLVMStyle.SpaceAfterCStyleCast = false;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000664 LLVMStyle.SpaceAfterTemplateKeyword = true;
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000665 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
Daniel Jasperd94bff32013-09-25 15:15:02 +0000666 LLVMStyle.SpaceBeforeAssignmentOperators = true;
Daniel Jasperdd978ae2013-10-29 14:52:02 +0000667 LLVMStyle.SpacesInAngles = false;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000668
Francois Ferrand9976efa2017-05-22 08:28:17 +0000669 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
Daniel Jasper19a541e2013-12-19 16:45:34 +0000670 LLVMStyle.PenaltyBreakComment = 300;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000671 LLVMStyle.PenaltyBreakFirstLessLess = 120;
672 LLVMStyle.PenaltyBreakString = 1000;
673 LLVMStyle.PenaltyExcessCharacter = 1000000;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000674 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000675 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000676
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000677 LLVMStyle.DisableFormat = false;
Daniel Jasperda446772015-11-16 12:38:56 +0000678 LLVMStyle.SortIncludes = true;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000679 LLVMStyle.SortUsingDeclarations = true;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000680
Daniel Jasperf7935112012-12-03 18:12:45 +0000681 return LLVMStyle;
682}
683
Nico Weber514ecc82014-02-02 20:50:45 +0000684FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000685 if (Language == FormatStyle::LK_TextProto) {
686 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
687 GoogleStyle.Language = FormatStyle::LK_TextProto;
Krasimir Georgieveda222e2018-01-24 11:18:39 +0000688
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000689 return GoogleStyle;
690 }
691
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000692 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000693 GoogleStyle.Language = Language;
694
Daniel Jasperf7935112012-12-03 18:12:45 +0000695 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000696 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000697 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000698 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000699 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000700 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000701 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000702 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000703 GoogleStyle.IncludeCategories = {
704 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000705 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000706 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000707 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Ben Hamilton3a47fdd2018-02-08 01:49:10 +0000708 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000709 GoogleStyle.ObjCSpaceAfterProperty = false;
Ben Hamiltonf84f1182018-01-18 18:37:16 +0000710 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000711 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000712 GoogleStyle.RawStringFormats = {{
713 FormatStyle::LK_TextProto,
714 /*Delimiters=*/
715 {
716 "pb",
717 "PB",
Krasimir Georgiev2fac8d92018-02-16 12:10:06 +0000718 "proto",
719 "PROTO",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000720 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000721 /*EnclosingFunctionNames=*/
Krasimir Georgieva83d3c52018-01-29 19:28:05 +0000722 {},
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000723 /*CanonicalDelimiter=*/"",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000724 /*BasedOnStyle=*/"google",
725 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000726 GoogleStyle.SpacesBeforeTrailingComments = 2;
727 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000728
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000729 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000730 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000731
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000732 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000733 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000734 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000735 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000736 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000737 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000738 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000739 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
740 GoogleStyle.ColumnLimit = 100;
741 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000742 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000743 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000744 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000745 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000746 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000747 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000748 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000749 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
750 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
751 GoogleStyle.CommentPragmas =
752 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000753 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000754 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000755 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000756 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000757 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000758 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000759 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper783bac62014-04-15 09:54:30 +0000760 GoogleStyle.SpacesInContainerLiterals = false;
Krasimir Georgievc2091802018-01-31 10:14:10 +0000761 GoogleStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev374e6de2018-02-08 10:47:12 +0000762 // This affects protocol buffer options specifications and text protos.
763 // Text protos are currently mostly formatted inside C++ raw string literals
764 // and often the current breaking behavior of string literals is not
765 // beneficial there. Investigate turning this on once proper string reflow
766 // has been implemented.
767 GoogleStyle.BreakStringLiterals = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000768 } else if (Language == FormatStyle::LK_ObjC) {
769 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000770 }
771
Daniel Jasperf7935112012-12-03 18:12:45 +0000772 return GoogleStyle;
773}
774
Nico Weber514ecc82014-02-02 20:50:45 +0000775FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
776 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000777 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000778 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000779 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000780 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000781 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000782 } else if (Language == FormatStyle::LK_JavaScript) {
783 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
784 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000785 } else {
786 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
787 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
788 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
789 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
790 ChromiumStyle.BinPackParameters = false;
791 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000792 if (Language == FormatStyle::LK_ObjC)
793 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000794 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000795 return ChromiumStyle;
796}
797
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000798FormatStyle getMozillaStyle() {
799 FormatStyle MozillaStyle = getLLVMStyle();
800 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000801 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000802 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000803 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
804 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000805 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000806 MozillaStyle.BinPackParameters = false;
807 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000808 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000809 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000810 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000811 MozillaStyle.ConstructorInitializerIndentWidth = 2;
812 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000813 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000814 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000815 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000816 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000817 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
818 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000819 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000820 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000821 return MozillaStyle;
822}
823
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000824FormatStyle getWebKitStyle() {
825 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000826 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000827 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000828 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000829 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000830 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000831 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000832 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000833 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000834 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000835 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000836 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000837 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000838 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000839 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000840 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000841 return Style;
842}
843
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000844FormatStyle getGNUStyle() {
845 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000846 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000847 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000848 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000849 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000850 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000851 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000852 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000853 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000854 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000855 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000856 return Style;
857}
858
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000859FormatStyle getNoStyle() {
860 FormatStyle NoStyle = getLLVMStyle();
861 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000862 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000863 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000864 return NoStyle;
865}
866
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000867bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
868 FormatStyle *Style) {
869 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000870 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000871 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000872 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000873 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000874 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000875 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000876 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000877 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000878 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000879 } else if (Name.equals_lower("gnu")) {
880 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000881 } else if (Name.equals_lower("none")) {
882 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000883 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000884 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000885 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000886
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000887 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000888 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000889}
890
Rafael Espindolac0809172014-06-12 14:02:15 +0000891std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000892 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000893 FormatStyle::LanguageKind Language = Style->Language;
894 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000895 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000896 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000897 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000898 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000899 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000900 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
901 // values for the fields, keys for which are missing from the configuration.
902 // Mapping also uses the context to get the language to find the correct
903 // base style.
904 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000905 Input >> Styles;
906 if (Input.error())
907 return Input.error();
908
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000909 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000910 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000911 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000912 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000913 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000914 for (unsigned j = 0; j < i; ++j) {
915 if (Styles[i].Language == Styles[j].Language) {
916 DEBUG(llvm::dbgs()
917 << "Duplicate languages in the config file on positions " << j
918 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000919 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000920 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000921 }
922 }
923 // Look for a suitable configuration starting from the end, so we can
924 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000925 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000926 FormatStyle::FormatStyleSet StyleSet;
927 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000928 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000929 if (Styles[i].Language != FormatStyle::LK_None)
930 StyleSet.Add(Styles[i]);
931 if (Styles[i].Language == Language)
932 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000933 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000934 if (!LanguageFound) {
935 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
936 return make_error_code(ParseError::Unsuitable);
937 FormatStyle DefaultStyle = Styles[0];
938 DefaultStyle.Language = Language;
939 StyleSet.Add(std::move(DefaultStyle));
940 }
941 *Style = *StyleSet.Get(Language);
942 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000943}
944
945std::string configurationAsText(const FormatStyle &Style) {
946 std::string Text;
947 llvm::raw_string_ostream Stream(Text);
948 llvm::yaml::Output Output(Stream);
949 // We use the same mapping method for input and output, so we need a non-const
950 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000951 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000952 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000953 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000954}
955
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000956llvm::Optional<FormatStyle>
957FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
958 if (!Styles)
959 return None;
960 auto It = Styles->find(Language);
961 if (It == Styles->end())
962 return None;
963 FormatStyle Style = It->second;
964 Style.StyleSet = *this;
965 return Style;
966}
967
968void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
969 assert(Style.Language != LK_None &&
970 "Cannot add a style for LK_None to a StyleSet");
971 assert(
972 !Style.StyleSet.Styles &&
973 "Cannot add a style associated with an existing StyleSet to a StyleSet");
974 if (!Styles)
975 Styles = std::make_shared<MapType>();
976 (*Styles)[Style.Language] = std::move(Style);
977}
978
979void FormatStyle::FormatStyleSet::Clear() {
980 Styles.reset();
981}
982
983llvm::Optional<FormatStyle>
984FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
985 return StyleSet.Get(Language);
986}
987
Craig Topperaf35e852013-06-30 22:29:28 +0000988namespace {
989
Daniel Jasper496c1992016-09-07 22:48:53 +0000990class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000991public:
Daniel Jasper496c1992016-09-07 22:48:53 +0000992 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
993 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +0000994
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000995 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +0000996 analyze(TokenAnnotator &Annotator,
997 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +0000998 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +0000999 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1000 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +00001001 tooling::Replacements Result;
1002 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001003 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +00001004 }
1005
1006private:
Daniel Jasper496c1992016-09-07 22:48:53 +00001007 // Replaces double/single-quoted string literal as appropriate, re-escaping
1008 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +00001009 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +00001010 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +00001011 for (AnnotatedLine *Line : Lines) {
1012 requoteJSStringLiteral(Line->Children, Result);
1013 if (!Line->Affected)
1014 continue;
1015 for (FormatToken *FormatTok = Line->First; FormatTok;
1016 FormatTok = FormatTok->Next) {
1017 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001018 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001019 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001020 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001021 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001022 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001023 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001024 !Input.startswith("\'")))
1025 continue;
1026
1027 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001028 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001029 SourceLocation Start = FormatTok->Tok.getLocation();
1030 auto Replace = [&](SourceLocation Start, unsigned Length,
1031 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001032 auto Err = Result.add(tooling::Replacement(
1033 Env.getSourceManager(), Start, Length, ReplacementText));
1034 // FIXME: handle error. For now, print error message and skip the
1035 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001036 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001037 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001038 assert(false);
1039 }
Daniel Jasper97439922016-03-17 13:03:41 +00001040 };
1041 Replace(Start, 1, IsSingle ? "'" : "\"");
1042 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1043 IsSingle ? "'" : "\"");
1044
1045 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001046 bool Escaped = false;
1047 for (size_t i = 1; i < Input.size() - 1; i++) {
1048 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001049 case '\\':
1050 if (!Escaped && i + 1 < Input.size() &&
1051 ((IsSingle && Input[i + 1] == '"') ||
1052 (!IsSingle && Input[i + 1] == '\''))) {
1053 // Remove this \, it's escaping a " or ' that no longer needs
1054 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001055 Replace(Start.getLocWithOffset(i), 1, "");
1056 continue;
1057 }
1058 Escaped = !Escaped;
1059 break;
1060 case '\"':
1061 case '\'':
1062 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1063 // Escape the quote.
1064 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001065 }
1066 Escaped = false;
1067 break;
1068 default:
1069 Escaped = false;
1070 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001071 }
1072 }
Daniel Jasper97439922016-03-17 13:03:41 +00001073 }
1074 }
1075 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001076};
1077
1078class Formatter : public TokenAnalyzer {
1079public:
1080 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001081 FormattingAttemptStatus *Status)
1082 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001083
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001084 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001085 analyze(TokenAnnotator &Annotator,
1086 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1087 FormatTokenLexer &Tokens) override {
1088 tooling::Replacements Result;
1089 deriveLocalStyle(AnnotatedLines);
1090 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1091 AnnotatedLines.end());
1092 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1093 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1094 }
1095 Annotator.setCommentLineLevels(AnnotatedLines);
1096
1097 WhitespaceManager Whitespaces(
1098 Env.getSourceManager(), Style,
1099 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1100 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1101 Env.getSourceManager(), Whitespaces, Encoding,
1102 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001103 unsigned Penalty =
1104 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1105 Tokens.getKeywords(), Env.getSourceManager(),
1106 Status)
1107 .format(AnnotatedLines, /*DryRun=*/false,
1108 /*AdditionalIndent=*/0,
1109 /*FixBadIndentation=*/false,
1110 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1111 /*NextStartColumn=*/Env.getNextStartColumn(),
1112 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001113 for (const auto &R : Whitespaces.generateReplacements())
1114 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001115 return std::make_pair(Result, 0);
1116 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001117 }
1118
1119private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001120 static bool inputUsesCRLF(StringRef Text) {
1121 return Text.count('\r') * 2 > Text.count('\n');
1122 }
1123
Daniel Jasper352f0df2015-07-18 16:35:30 +00001124 bool
1125 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001126 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001127 if (hasCpp03IncompatibleFormat(Line->Children))
1128 return true;
1129 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1130 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1131 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1132 return true;
1133 if (Tok->is(TT_TemplateCloser) &&
1134 Tok->Previous->is(TT_TemplateCloser))
1135 return true;
1136 }
1137 }
1138 }
1139 return false;
1140 }
1141
1142 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1143 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001144 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001145 AlignmentDiff += countVariableAlignments(Line->Children);
1146 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1147 if (!Tok->is(TT_PointerOrReference))
1148 continue;
1149 bool SpaceBefore =
1150 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1151 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1152 Tok->Next->WhitespaceRange.getEnd();
1153 if (SpaceBefore && !SpaceAfter)
1154 ++AlignmentDiff;
1155 if (!SpaceBefore && SpaceAfter)
1156 --AlignmentDiff;
1157 }
1158 }
1159 return AlignmentDiff;
1160 }
1161
Manuel Klimek71814b42013-10-11 21:25:45 +00001162 void
1163 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001164 bool HasBinPackedFunction = false;
1165 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001166 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001167 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001168 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001169 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001170 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001171 if (Tok->PackingKind == PPK_BinPacked)
1172 HasBinPackedFunction = true;
1173 if (Tok->PackingKind == PPK_OnePerLine)
1174 HasOnePerLineFunction = true;
1175
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001176 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001177 }
1178 }
Eric Liu635423e2016-04-28 07:52:03 +00001179 if (Style.DerivePointerAlignment)
1180 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1181 ? FormatStyle::PAS_Left
1182 : FormatStyle::PAS_Right;
1183 if (Style.Standard == FormatStyle::LS_Auto)
1184 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1185 ? FormatStyle::LS_Cpp11
1186 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001187 BinPackInconclusiveFunctions =
1188 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001189 }
1190
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001191 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001192 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001193};
1194
1195// This class clean up the erroneous/redundant code around the given ranges in
1196// file.
1197class Cleaner : public TokenAnalyzer {
1198public:
Eric Liu635423e2016-04-28 07:52:03 +00001199 Cleaner(const Environment &Env, const FormatStyle &Style)
1200 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001201 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1202
1203 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001204 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001205 analyze(TokenAnnotator &Annotator,
1206 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001207 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001208 // FIXME: in the current implementation the granularity of affected range
1209 // is an annotated line. However, this is not sufficient. Furthermore,
1210 // redundant code introduced by replacements does not necessarily
1211 // intercept with ranges of replacements that result in the redundancy.
1212 // To determine if some redundant code is actually introduced by
1213 // replacements(e.g. deletions), we need to come up with a more
1214 // sophisticated way of computing affected ranges.
1215 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1216 AnnotatedLines.end());
1217
1218 checkEmptyNamespace(AnnotatedLines);
1219
Eric Liuce5e4bc2016-05-18 08:02:56 +00001220 for (auto &Line : AnnotatedLines) {
1221 if (Line->Affected) {
1222 cleanupRight(Line->First, tok::comma, tok::comma);
1223 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001224 cleanupRight(Line->First, tok::l_paren, tok::comma);
1225 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001226 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1227 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001228 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001229 }
1230 }
1231
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001232 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001233 }
1234
1235private:
1236 bool containsOnlyComments(const AnnotatedLine &Line) {
1237 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1238 if (Tok->isNot(tok::comment))
1239 return false;
1240 }
1241 return true;
1242 }
1243
1244 // Iterate through all lines and remove any empty (nested) namespaces.
1245 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001246 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001247 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1248 auto &Line = *AnnotatedLines[i];
1249 if (Line.startsWith(tok::kw_namespace) ||
1250 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001251 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001252 }
1253 }
1254
1255 for (auto Line : DeletedLines) {
1256 FormatToken *Tok = AnnotatedLines[Line]->First;
1257 while (Tok) {
1258 deleteToken(Tok);
1259 Tok = Tok->Next;
1260 }
1261 }
1262 }
1263
1264 // The function checks if the namespace, which starts from \p CurrentLine, and
1265 // its nested namespaces are empty and delete them if they are empty. It also
1266 // sets \p NewLine to the last line checked.
1267 // Returns true if the current namespace is empty.
1268 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001269 unsigned CurrentLine, unsigned &NewLine,
1270 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001271 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001272 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001273 // If the left brace is in a new line, we should consume it first so that
1274 // it does not make the namespace non-empty.
1275 // FIXME: error handling if there is no left brace.
1276 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1277 NewLine = CurrentLine;
1278 return false;
1279 }
1280 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1281 return false;
1282 }
1283 while (++CurrentLine < End) {
1284 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1285 break;
1286
1287 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1288 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1289 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001290 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1291 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001292 return false;
1293 CurrentLine = NewLine;
1294 continue;
1295 }
1296
1297 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1298 continue;
1299
1300 // If there is anything other than comments or nested namespaces in the
1301 // current namespace, the namespace cannot be empty.
1302 NewLine = CurrentLine;
1303 return false;
1304 }
1305
1306 NewLine = CurrentLine;
1307 if (CurrentLine >= End)
1308 return false;
1309
1310 // Check if the empty namespace is actually affected by changed ranges.
1311 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1312 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1313 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1314 return false;
1315
1316 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1317 DeletedLines.insert(i);
1318 }
1319
1320 return true;
1321 }
1322
Eric Liuce5e4bc2016-05-18 08:02:56 +00001323 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1324 // of the token in the pair if the left token has \p LK token kind and the
1325 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1326 // is deleted on match; otherwise, the right token is deleted.
1327 template <typename LeftKind, typename RightKind>
1328 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1329 bool DeleteLeft) {
1330 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1331 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1332 if (!Res->is(tok::comment) &&
1333 DeletedTokens.find(Res) == DeletedTokens.end())
1334 return Res;
1335 return nullptr;
1336 };
1337 for (auto *Left = Start; Left;) {
1338 auto *Right = NextNotDeleted(*Left);
1339 if (!Right)
1340 break;
1341 if (Left->is(LK) && Right->is(RK)) {
1342 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001343 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1344 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001345 // If the right token is deleted, we should keep the left token
1346 // unchanged and pair it with the new right token.
1347 if (!DeleteLeft)
1348 continue;
1349 }
1350 Left = Right;
1351 }
1352 }
1353
1354 template <typename LeftKind, typename RightKind>
1355 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1356 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1357 }
1358
1359 template <typename LeftKind, typename RightKind>
1360 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1361 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1362 }
1363
Eric Liu4cfb88a2016-04-25 15:09:22 +00001364 // Delete the given token.
1365 inline void deleteToken(FormatToken *Tok) {
1366 if (Tok)
1367 DeletedTokens.insert(Tok);
1368 }
1369
1370 tooling::Replacements generateFixes() {
1371 tooling::Replacements Fixes;
1372 std::vector<FormatToken *> Tokens;
1373 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1374 std::back_inserter(Tokens));
1375
1376 // Merge multiple continuous token deletions into one big deletion so that
1377 // the number of replacements can be reduced. This makes computing affected
1378 // ranges more efficient when we run reformat on the changed code.
1379 unsigned Idx = 0;
1380 while (Idx < Tokens.size()) {
1381 unsigned St = Idx, End = Idx;
1382 while ((End + 1) < Tokens.size() &&
1383 Tokens[End]->Next == Tokens[End + 1]) {
1384 End++;
1385 }
1386 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1387 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001388 auto Err =
1389 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1390 // FIXME: better error handling. for now just print error message and skip
1391 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001392 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001393 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001394 assert(false && "Fixes must not conflict!");
1395 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001396 Idx = End + 1;
1397 }
1398
1399 return Fixes;
1400 }
1401
1402 // Class for less-than inequality comparason for the set `RedundantTokens`.
1403 // We store tokens in the order they appear in the translation unit so that
1404 // we do not need to sort them in `generateFixes()`.
1405 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001406 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001407
Eric Liu2874ac32016-05-18 08:14:49 +00001408 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001409 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1410 RHS->Tok.getLocation());
1411 }
Eric Liu635423e2016-04-28 07:52:03 +00001412 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001413 };
1414
1415 // Tokens to be deleted.
1416 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001417};
1418
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001419class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1420public:
1421 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1422 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1423
1424 std::pair<tooling::Replacements, unsigned>
1425 analyze(TokenAnnotator &Annotator,
1426 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1427 FormatTokenLexer &Tokens) override {
1428 assert(Style.Language == FormatStyle::LK_Cpp);
1429 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1430 tooling::Replacements Result;
1431 return {Result, 0};
1432 }
1433
1434 bool isObjC() { return IsObjC; }
1435
1436private:
1437 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1438 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001439 // Keep this array sorted, since we are binary searching over it.
1440 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001441 "CGFloat",
1442 "NSAffineTransform",
1443 "NSArray",
1444 "NSAttributedString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001445 "NSBundle",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001446 "NSCache",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001447 "NSCalendar",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001448 "NSCharacterSet",
1449 "NSCountedSet",
1450 "NSData",
1451 "NSDataDetector",
1452 "NSDecimal",
1453 "NSDecimalNumber",
1454 "NSDictionary",
1455 "NSEdgeInsets",
1456 "NSHashTable",
1457 "NSIndexPath",
1458 "NSIndexSet",
1459 "NSInteger",
1460 "NSLocale",
1461 "NSMapTable",
1462 "NSMutableArray",
1463 "NSMutableAttributedString",
1464 "NSMutableCharacterSet",
1465 "NSMutableData",
1466 "NSMutableDictionary",
1467 "NSMutableIndexSet",
1468 "NSMutableOrderedSet",
1469 "NSMutableSet",
1470 "NSMutableString",
1471 "NSNumber",
1472 "NSNumberFormatter",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001473 "NSObject",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001474 "NSOrderedSet",
1475 "NSPoint",
1476 "NSPointerArray",
1477 "NSRange",
1478 "NSRect",
1479 "NSRegularExpression",
1480 "NSSet",
1481 "NSSize",
1482 "NSString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001483 "NSTimeZone",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001484 "NSUInteger",
1485 "NSURL",
1486 "NSURLComponents",
1487 "NSURLQueryItem",
1488 "NSUUID",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001489 "NSValue",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001490 };
1491
1492 for (auto &Line : AnnotatedLines) {
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001493 for (FormatToken *FormatTok = Line->First; FormatTok;
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001494 FormatTok = FormatTok->Next) {
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001495 if ((FormatTok->Previous && FormatTok->Previous->is(tok::at) &&
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001496 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1497 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1498 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1499 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1500 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1501 tok::l_brace))) ||
1502 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001503 std::binary_search(std::begin(FoundationIdentifiers),
1504 std::end(FoundationIdentifiers),
1505 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001506 FormatTok->is(TT_ObjCStringLiteral) ||
1507 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1508 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1509 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1510 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1511 return true;
1512 }
1513 }
1514 }
1515 return false;
1516 }
1517
1518 bool IsObjC;
1519};
1520
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001521struct IncludeDirective {
1522 StringRef Filename;
1523 StringRef Text;
1524 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001525 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001526};
1527
Craig Topperaf35e852013-06-30 22:29:28 +00001528} // end anonymous namespace
1529
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001530// Determines whether 'Ranges' intersects with ('Start', 'End').
1531static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1532 unsigned End) {
1533 for (auto Range : Ranges) {
1534 if (Range.getOffset() < End &&
1535 Range.getOffset() + Range.getLength() > Start)
1536 return true;
1537 }
1538 return false;
1539}
1540
Eric Liua992afe2016-08-10 09:32:23 +00001541// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1542// before sorting/deduplicating. Index is the index of the include under the
1543// cursor in the original set of includes. If this include has duplicates, it is
1544// the index of the first of the duplicates as the others are going to be
1545// removed. OffsetToEOL describes the cursor's position relative to the end of
1546// its current line.
1547// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1548static std::pair<unsigned, unsigned>
1549FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1550 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1551 unsigned CursorIndex = UINT_MAX;
1552 unsigned OffsetToEOL = 0;
1553 for (int i = 0, e = Includes.size(); i != e; ++i) {
1554 unsigned Start = Includes[Indices[i]].Offset;
1555 unsigned End = Start + Includes[Indices[i]].Text.size();
1556 if (!(Cursor >= Start && Cursor < End))
1557 continue;
1558 CursorIndex = Indices[i];
1559 OffsetToEOL = End - Cursor;
1560 // Put the cursor on the only remaining #include among the duplicate
1561 // #includes.
1562 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1563 CursorIndex = i;
1564 break;
1565 }
1566 return std::make_pair(CursorIndex, OffsetToEOL);
1567}
1568
1569// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1570// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1571// source order.
1572// #include directives with the same text will be deduplicated, and only the
1573// first #include in the duplicate #includes remains. If the `Cursor` is
1574// provided and put on a deleted #include, it will be moved to the remaining
1575// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001576static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001577 const SmallVectorImpl<IncludeDirective> &Includes,
1578 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1579 tooling::Replacements &Replaces, unsigned *Cursor) {
1580 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001581 unsigned IncludesEndOffset =
1582 Includes.back().Offset + Includes.back().Text.size();
1583 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1584 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001585 return;
1586 SmallVector<unsigned, 16> Indices;
1587 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1588 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001589 std::stable_sort(
1590 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1591 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1592 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1593 });
Eric Liua992afe2016-08-10 09:32:23 +00001594 // The index of the include on which the cursor will be put after
1595 // sorting/deduplicating.
1596 unsigned CursorIndex;
1597 // The offset from cursor to the end of line.
1598 unsigned CursorToEOLOffset;
1599 if (Cursor)
1600 std::tie(CursorIndex, CursorToEOLOffset) =
1601 FindCursorIndex(Includes, Indices, *Cursor);
1602
1603 // Deduplicate #includes.
1604 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1605 [&](unsigned LHSI, unsigned RHSI) {
1606 return Includes[LHSI].Text == Includes[RHSI].Text;
1607 }),
1608 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001609
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001610 int CurrentCategory = Includes.front().Category;
1611
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001612 // If the #includes are out of order, we generate a single replacement fixing
1613 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001614 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001615 std::is_sorted(Indices.begin(), Indices.end()) &&
1616 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001617 return;
1618
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001619 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001620 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001621 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001622 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001623 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1624 CurrentCategory != Includes[Index].Category)
1625 result += "\n";
1626 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001627 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001628 if (Cursor && CursorIndex == Index)
1629 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001630 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001631 }
1632
Eric Liu40ef2fb2016-08-01 10:16:37 +00001633 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001634 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001635 // FIXME: better error handling. For now, just skip the replacement for the
1636 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001637 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001638 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001639 assert(false);
1640 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001641}
1642
Eric Liu659afd52016-05-31 13:34:20 +00001643namespace {
1644
1645// This class manages priorities of #include categories and calculates
1646// priorities for headers.
1647class IncludeCategoryManager {
1648public:
1649 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1650 : Style(Style), FileName(FileName) {
1651 FileStem = llvm::sys::path::stem(FileName);
1652 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001653 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001654 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1655 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1656 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1657 FileName.endswith(".mm");
1658 }
1659
1660 // Returns the priority of the category which \p IncludeName belongs to.
1661 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1662 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1663 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1664 int Ret = INT_MAX;
1665 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1666 if (CategoryRegexs[i].match(IncludeName)) {
1667 Ret = Style.IncludeCategories[i].Priority;
1668 break;
1669 }
1670 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1671 Ret = 0;
1672 return Ret;
1673 }
1674
1675private:
1676 bool isMainHeader(StringRef IncludeName) const {
1677 if (!IncludeName.startswith("\""))
1678 return false;
1679 StringRef HeaderStem =
1680 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001681 if (FileStem.startswith(HeaderStem) ||
1682 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001683 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001684 (HeaderStem + Style.IncludeIsMainRegex).str(),
1685 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001686 if (MainIncludeRegex.match(FileStem))
1687 return true;
1688 }
1689 return false;
1690 }
1691
1692 const FormatStyle &Style;
1693 bool IsMainFile;
1694 StringRef FileName;
1695 StringRef FileStem;
1696 SmallVector<llvm::Regex, 4> CategoryRegexs;
1697};
1698
1699const char IncludeRegexPattern[] =
1700 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1701
1702} // anonymous namespace
1703
Martin Probstc4a0dd42016-05-20 11:24:24 +00001704tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1705 ArrayRef<tooling::Range> Ranges,
1706 StringRef FileName,
1707 tooling::Replacements &Replaces,
1708 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001709 unsigned Prev = 0;
1710 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001711 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001712 SmallVector<StringRef, 4> Matches;
1713 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001714
1715 // In compiled files, consider the first #include to be the main #include of
1716 // the file if it is not a system #include. This ensures that the header
1717 // doesn't have hidden dependencies
1718 // (http://llvm.org/docs/CodingStandards.html#include-style).
1719 //
1720 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1721 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001722 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001723 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001724 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001725 bool FormattingOff = false;
1726
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001727 for (;;) {
1728 auto Pos = Code.find('\n', SearchFrom);
1729 StringRef Line =
1730 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001731
1732 StringRef Trimmed = Line.trim();
1733 if (Trimmed == "// clang-format off")
1734 FormattingOff = true;
1735 else if (Trimmed == "// clang-format on")
1736 FormattingOff = false;
1737
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001738 const bool EmptyLineSkipped =
1739 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1740 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1741
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001742 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001743 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001744 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001745 int Category = Categories.getIncludePriority(
1746 IncludeName,
1747 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1748 if (Category == 0)
1749 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001750 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001751 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001752 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1753 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001754 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001755 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001756 }
1757 Prev = Pos + 1;
1758 }
1759 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1760 break;
1761 SearchFrom = Pos + 1;
1762 }
1763 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001764 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1765 return Replaces;
1766}
1767
Martin Probstfa37b182017-01-27 09:09:11 +00001768bool isMpegTS(StringRef Code) {
1769 // MPEG transport streams use the ".ts" file extension. clang-format should
1770 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1771 // 189 bytes - detect that and return.
1772 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1773}
1774
Manuel Klimek89628f62017-09-20 09:51:03 +00001775bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001776
Martin Probstc4a0dd42016-05-20 11:24:24 +00001777tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1778 ArrayRef<tooling::Range> Ranges,
1779 StringRef FileName, unsigned *Cursor) {
1780 tooling::Replacements Replaces;
1781 if (!Style.SortIncludes)
1782 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001783 if (isLikelyXml(Code))
1784 return Replaces;
1785 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1786 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001787 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001788 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1789 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1790 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001791 return Replaces;
1792}
1793
Eric Liu4cfb88a2016-04-25 15:09:22 +00001794template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001795static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001796processReplacements(T ProcessFunc, StringRef Code,
1797 const tooling::Replacements &Replaces,
1798 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001799 if (Replaces.empty())
1800 return tooling::Replacements();
1801
Eric Liu4f8d9942016-07-11 13:53:12 +00001802 auto NewCode = applyAllReplacements(Code, Replaces);
1803 if (!NewCode)
1804 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001805 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001806 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001807
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001808 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001809 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001810
Eric Liu40ef2fb2016-08-01 10:16:37 +00001811 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001812}
1813
Eric Liu4f8d9942016-07-11 13:53:12 +00001814llvm::Expected<tooling::Replacements>
1815formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1816 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001817 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001818 // `sortIncludes`.
1819 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1820 std::vector<tooling::Range> Ranges,
1821 StringRef FileName) -> tooling::Replacements {
1822 return sortIncludes(Style, Code, Ranges, FileName);
1823 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001824 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001825 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001826 if (!SortedReplaces)
1827 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001828
1829 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001830 // `reformat`.
1831 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1832 std::vector<tooling::Range> Ranges,
1833 StringRef FileName) -> tooling::Replacements {
1834 return reformat(Style, Code, Ranges, FileName);
1835 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001836 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001837}
1838
Eric Liu659afd52016-05-31 13:34:20 +00001839namespace {
1840
1841inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001842 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001843 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1844}
1845
Eric Liuc0d3a802016-09-23 15:10:56 +00001846inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1847 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1848}
1849
Eric Liu964782a2016-12-02 11:01:43 +00001850// Returns the offset after skipping a sequence of tokens, matched by \p
1851// GetOffsetAfterSequence, from the start of the code.
1852// \p GetOffsetAfterSequence should be a function that matches a sequence of
1853// tokens and returns an offset after the sequence.
1854unsigned getOffsetAfterTokenSequence(
1855 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001856 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1857 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001858 std::unique_ptr<Environment> Env =
1859 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1860 const SourceManager &SourceMgr = Env->getSourceManager();
1861 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1862 getFormattingLangOpts(Style));
1863 Token Tok;
1864 // Get the first token.
1865 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001866 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001867}
1868
1869// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1870// \p Tok will be the token after this directive; otherwise, it can be any token
1871// after the given \p Tok (including \p Tok).
1872bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1873 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1874 Tok.is(tok::raw_identifier) &&
1875 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001876 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001877 if (Matched)
1878 Lex.LexFromRawLexer(Tok);
1879 return Matched;
1880}
1881
Eric Liu964782a2016-12-02 11:01:43 +00001882void skipComments(Lexer &Lex, Token &Tok) {
1883 while (Tok.is(tok::comment))
1884 if (Lex.LexFromRawLexer(Tok))
1885 return;
1886}
1887
1888// Returns the offset after header guard directives and any comments
1889// before/after header guards. If no header guard presents in the code, this
1890// will returns the offset after skipping all comments from the start of the
1891// code.
Eric Liu35288322016-06-06 11:00:13 +00001892unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1893 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001894 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001895 return getOffsetAfterTokenSequence(
1896 FileName, Code, Style,
1897 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1898 skipComments(Lex, Tok);
1899 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1900 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1901 skipComments(Lex, Tok);
1902 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1903 return SM.getFileOffset(Tok.getLocation());
1904 }
1905 return InitialOffset;
1906 });
1907}
1908
1909// Check if a sequence of tokens is like
1910// "#include ("header.h" | <header.h>)".
1911// If it is, \p Tok will be the token after this directive; otherwise, it can be
1912// any token after the given \p Tok (including \p Tok).
1913bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1914 auto Matched = [&]() {
1915 Lex.LexFromRawLexer(Tok);
1916 return true;
1917 };
1918 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1919 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1920 if (Lex.LexFromRawLexer(Tok))
1921 return false;
1922 if (Tok.is(tok::string_literal))
1923 return Matched();
1924 if (Tok.is(tok::less)) {
1925 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1926 }
1927 if (Tok.is(tok::greater))
1928 return Matched();
1929 }
Eric Liu35288322016-06-06 11:00:13 +00001930 }
Eric Liu964782a2016-12-02 11:01:43 +00001931 return false;
1932}
1933
1934// Returns the offset of the last #include directive after which a new
1935// #include can be inserted. This ignores #include's after the #include block(s)
1936// in the beginning of a file to avoid inserting headers into code sections
1937// where new #include's should not be added by default.
1938// These code sections include:
1939// - raw string literals (containing #include).
1940// - #if blocks.
1941// - Special #include's among declarations (e.g. functions).
1942//
1943// If no #include after which a new #include can be inserted, this returns the
1944// offset after skipping all comments from the start of the code.
1945// Inserting after an #include is not allowed if it comes after code that is not
1946// #include (e.g. pre-processing directive that is not #include, declarations).
1947unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1948 const FormatStyle &Style) {
1949 return getOffsetAfterTokenSequence(
1950 FileName, Code, Style,
1951 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1952 skipComments(Lex, Tok);
1953 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1954 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1955 MaxOffset = SM.getFileOffset(Tok.getLocation());
1956 return MaxOffset;
1957 });
Eric Liu35288322016-06-06 11:00:13 +00001958}
1959
Eric Liuc0d3a802016-09-23 15:10:56 +00001960bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001961 const std::set<llvm::StringRef> &HeadersToDelete) {
1962 return HeadersToDelete.count(HeaderName) ||
1963 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001964}
1965
Eric Liu659afd52016-05-31 13:34:20 +00001966// FIXME: insert empty lines between newly created blocks.
1967tooling::Replacements
1968fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
1969 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00001970 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00001971 return Replaces;
1972
1973 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00001974 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00001975 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00001976 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001977 if (isHeaderInsertion(R)) {
1978 // Replacements from \p Replaces must be conflict-free already, so we can
1979 // simply consume the error.
1980 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00001981 } else if (isHeaderDeletion(R)) {
1982 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001983 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00001984 llvm::errs() << "Insertions other than header #include insertion are "
1985 "not supported! "
1986 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00001987 } else {
1988 llvm::consumeError(Result.add(R));
1989 }
Eric Liu659afd52016-05-31 13:34:20 +00001990 }
Eric Liuc0d3a802016-09-23 15:10:56 +00001991 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00001992 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00001993
1994 llvm::Regex IncludeRegex(IncludeRegexPattern);
1995 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1996 SmallVector<StringRef, 4> Matches;
1997
1998 StringRef FileName = Replaces.begin()->getFilePath();
1999 IncludeCategoryManager Categories(Style, FileName);
2000
2001 // Record the offset of the end of the last include in each category.
2002 std::map<int, int> CategoryEndOffsets;
2003 // All possible priorities.
2004 // Add 0 for main header and INT_MAX for headers that are not in any category.
2005 std::set<int> Priorities = {0, INT_MAX};
2006 for (const auto &Category : Style.IncludeCategories)
2007 Priorities.insert(Category.Priority);
2008 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00002009 // All new headers should be inserted after this offset.
2010 unsigned MinInsertOffset =
2011 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00002012 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00002013 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00002014 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00002015 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00002016 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00002017 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00002018 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00002019 unsigned Offset = MinInsertOffset;
2020 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002021 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002022 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002023 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002024 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002025 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002026 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002027 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002028 // Only record the offset of current #include if we can insert after it.
2029 if (Offset <= MaxInsertOffset) {
2030 int Category = Categories.getIncludePriority(
2031 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2032 CategoryEndOffsets[Category] = NextLineOffset;
2033 if (FirstIncludeOffset < 0)
2034 FirstIncludeOffset = Offset;
2035 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002036 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2037 // If this is the last line without trailing newline, we need to make
2038 // sure we don't delete across the file boundary.
2039 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2040 llvm::Error Err =
2041 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2042 if (Err) {
2043 // Ignore the deletion on conflict.
2044 llvm::errs() << "Failed to add header deletion replacement for "
2045 << IncludeName << ": " << llvm::toString(std::move(Err))
2046 << "\n";
2047 }
2048 }
Eric Liu659afd52016-05-31 13:34:20 +00002049 }
Eric Liu35288322016-06-06 11:00:13 +00002050 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002051 }
2052
2053 // Populate CategoryEndOfssets:
2054 // - Ensure that CategoryEndOffset[Highest] is always populated.
2055 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2056 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002057 auto Highest = Priorities.begin();
2058 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2059 if (FirstIncludeOffset >= 0)
2060 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2061 else
Eric Liu303baf52016-06-03 12:52:59 +00002062 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002063 }
2064 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2065 // - to an appropriate location before/after existing #includes, or
2066 // - to right after the header guard, or
2067 // - to the beginning of the file.
2068 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2069 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2070 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2071
Eric Liu11a42372016-10-05 15:42:19 +00002072 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002073 for (const auto &R : HeaderInsertions) {
2074 auto IncludeDirective = R.getReplacementText();
2075 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2076 assert(Matched && "Header insertion replacement must have replacement text "
2077 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002078 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002079 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002080 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2081 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2082 << "\n");
2083 continue;
2084 }
Eric Liu659afd52016-05-31 13:34:20 +00002085 int Category =
2086 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2087 Offset = CategoryEndOffsets[Category];
2088 std::string NewInclude = !IncludeDirective.endswith("\n")
2089 ? (IncludeDirective + "\n").str()
2090 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002091 // When inserting headers at end of the code, also append '\n' to the code
2092 // if it does not end with '\n'.
2093 if (NeedNewLineAtEnd && Offset == Code.size()) {
2094 NewInclude = "\n" + NewInclude;
2095 NeedNewLineAtEnd = false;
2096 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002097 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2098 auto Err = Result.add(NewReplace);
2099 if (Err) {
2100 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002101 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2102 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002103 Result = Result.merge(tooling::Replacements(NewReplace));
2104 }
Eric Liu659afd52016-05-31 13:34:20 +00002105 }
2106 return Result;
2107}
2108
2109} // anonymous namespace
2110
Eric Liu4f8d9942016-07-11 13:53:12 +00002111llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002112cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2113 const FormatStyle &Style) {
2114 // We need to use lambda function here since there are two versions of
2115 // `cleanup`.
2116 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2117 std::vector<tooling::Range> Ranges,
2118 StringRef FileName) -> tooling::Replacements {
2119 return cleanup(Style, Code, Ranges, FileName);
2120 };
Eric Liu659afd52016-05-31 13:34:20 +00002121 // Make header insertion replacements insert new headers into correct blocks.
2122 tooling::Replacements NewReplaces =
2123 fixCppIncludeInsertions(Code, Replaces, Style);
2124 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002125}
2126
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002127namespace internal {
2128std::pair<tooling::Replacements, unsigned>
2129reformat(const FormatStyle &Style, StringRef Code,
2130 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2131 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2132 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002133 FormatStyle Expanded = expandPresets(Style);
2134 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002135 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002136 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002137 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002138 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002139 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002140
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002141 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2142 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002143 AnalyzerPass;
2144 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002145
Krasimir Georgievac16a202017-06-23 11:46:03 +00002146 if (Style.Language == FormatStyle::LK_Cpp) {
2147 if (Style.FixNamespaceComments)
2148 Passes.emplace_back([&](const Environment &Env) {
2149 return NamespaceEndCommentsFixer(Env, Expanded).process();
2150 });
2151
2152 if (Style.SortUsingDeclarations)
2153 Passes.emplace_back([&](const Environment &Env) {
2154 return UsingDeclarationsSorter(Env, Expanded).process();
2155 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002156 }
2157
2158 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002159 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2160 Passes.emplace_back([&](const Environment &Env) {
2161 return JavaScriptRequoter(Env, Expanded).process();
2162 });
2163
2164 Passes.emplace_back([&](const Environment &Env) {
2165 return Formatter(Env, Expanded, Status).process();
2166 });
2167
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002168 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2169 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2170 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002171 llvm::Optional<std::string> CurrentCode = None;
2172 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002173 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002174 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002175 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002176 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002177 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002178 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002179 Fixes = Fixes.merge(PassFixes.first);
2180 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002181 if (I + 1 < E) {
2182 CurrentCode = std::move(*NewCode);
2183 Env = Environment::CreateVirtualEnvironment(
2184 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002185 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2186 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002187 }
2188 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002189 }
2190
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002191 return {Fixes, Penalty};
2192}
2193} // namespace internal
2194
2195tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2196 ArrayRef<tooling::Range> Ranges,
2197 StringRef FileName,
2198 FormattingAttemptStatus *Status) {
2199 return internal::reformat(Style, Code, Ranges,
2200 /*FirstStartColumn=*/0,
2201 /*NextStartColumn=*/0,
2202 /*LastStartColumn=*/0, FileName, Status)
2203 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002204}
2205
Eric Liu4cfb88a2016-04-25 15:09:22 +00002206tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2207 ArrayRef<tooling::Range> Ranges,
2208 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002209 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2210 if (Style.Language != FormatStyle::LK_Cpp)
2211 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002212 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002213 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2214 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002215 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002216}
2217
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002218tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2219 ArrayRef<tooling::Range> Ranges,
2220 StringRef FileName, bool *IncompleteFormat) {
2221 FormattingAttemptStatus Status;
2222 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2223 if (!Status.FormatComplete)
2224 *IncompleteFormat = true;
2225 return Result;
2226}
2227
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002228tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2229 StringRef Code,
2230 ArrayRef<tooling::Range> Ranges,
2231 StringRef FileName) {
2232 std::unique_ptr<Environment> Env =
2233 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2234 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002235 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002236}
2237
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002238tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2239 StringRef Code,
2240 ArrayRef<tooling::Range> Ranges,
2241 StringRef FileName) {
2242 std::unique_ptr<Environment> Env =
2243 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2244 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002245 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002246}
2247
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002248LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002249 LangOptions LangOpts;
2250 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002251 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2252 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002253 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002254 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002255 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002256 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002257 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002258 LangOpts.Bool = 1;
2259 LangOpts.ObjC1 = 1;
2260 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002261 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002262 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002263 return LangOpts;
2264}
2265
Edwin Vaned544aa72013-09-30 13:31:48 +00002266const char *StyleOptionHelpDescription =
2267 "Coding style, currently supports:\n"
2268 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2269 "Use -style=file to load style configuration from\n"
2270 ".clang-format file located in one of the parent\n"
2271 "directories of the source file (or current\n"
2272 "directory for stdin).\n"
2273 "Use -style=\"{key: value, ...}\" to set specific\n"
2274 "parameters, e.g.:\n"
2275 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2276
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002277static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002278 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002279 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002280 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2281 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002282 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2283 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002284 if (FileName.endswith_lower(".proto") ||
2285 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002286 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002287 if (FileName.endswith_lower(".textpb") ||
2288 FileName.endswith_lower(".pb.txt") ||
2289 FileName.endswith_lower(".textproto") ||
2290 FileName.endswith_lower(".asciipb"))
2291 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002292 if (FileName.endswith_lower(".td"))
2293 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002294 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002295}
2296
Ben Hamilton3b345c32018-02-21 15:54:31 +00002297FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
2298 FormatStyle::LanguageKind result = getLanguageByFileName(FileName);
2299 if (result == FormatStyle::LK_Cpp) {
2300 auto extension = llvm::sys::path::extension(FileName);
2301 // If there's no file extension (or it's .h), we need to check the contents
2302 // of the code to see if it contains Objective-C.
2303 if (extension.empty() || extension == ".h") {
2304 std::unique_ptr<Environment> Env =
2305 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
2306 ObjCHeaderStyleGuesser Guesser(*Env, getLLVMStyle());
2307 Guesser.process();
2308 if (Guesser.isObjC()) {
2309 result = FormatStyle::LK_ObjC;
2310 }
2311 }
2312 }
2313 return result;
2314}
2315
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002316llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002317 StringRef FallbackStyleName,
2318 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002319 if (!FS) {
2320 FS = vfs::getRealFileSystem().get();
2321 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002322 FormatStyle Style = getLLVMStyle();
Ben Hamilton3b345c32018-02-21 15:54:31 +00002323 Style.Language = guessLanguage(FileName, Code);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002324
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002325 FormatStyle FallbackStyle = getNoStyle();
2326 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2327 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002328
2329 if (StyleName.startswith("{")) {
2330 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002331 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2332 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002333 return Style;
2334 }
2335
2336 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002337 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002338 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002339 return Style;
2340 }
2341
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002342 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002343 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002344 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002345 if (std::error_code EC = FS->makeAbsolute(Path))
2346 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002347
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002348 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002349 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002350
2351 auto Status = FS->status(Directory);
2352 if (!Status ||
2353 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002354 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002355 }
2356
Edwin Vaned544aa72013-09-30 13:31:48 +00002357 SmallString<128> ConfigFile(Directory);
2358
2359 llvm::sys::path::append(ConfigFile, ".clang-format");
2360 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002361
Eric Liu547d8792016-03-24 13:22:42 +00002362 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002363 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002364 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002365 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002366 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2367 ConfigFile = Directory;
2368 llvm::sys::path::append(ConfigFile, "_clang-format");
2369 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002370 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002371 FoundConfigFile = Status && (Status->getType() ==
2372 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002373 }
2374
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002375 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002376 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002377 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002378 if (std::error_code EC = Text.getError())
2379 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002380 if (std::error_code ec =
2381 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002382 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002383 if (!UnsuitableConfigFiles.empty())
2384 UnsuitableConfigFiles.append(", ");
2385 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002386 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002387 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002388 return make_string_error("Error reading " + ConfigFile + ": " +
2389 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002390 }
2391 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2392 return Style;
2393 }
2394 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002395 if (!UnsuitableConfigFiles.empty())
2396 return make_string_error("Configuration file(s) do(es) not support " +
2397 getLanguageName(Style.Language) + ": " +
2398 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002399 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002400}
2401
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002402} // namespace format
2403} // namespace clang