blob: ac22d6b4501b541ce5f8c19af794af0efd5c9d33 [file] [log] [blame]
Daniel Jasperf7935112012-12-03 18:12:45 +00001//===--- Format.cpp - Format C++ code -------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements functions declared in Format.h. This will be
12/// split into separate files as we go.
13///
Daniel Jasperf7935112012-12-03 18:12:45 +000014//===----------------------------------------------------------------------===//
15
Daniel Jasper85c472d2015-09-29 07:53:08 +000016#include "clang/Format/Format.h"
Eric Liu4cfb88a2016-04-25 15:09:22 +000017#include "AffectedRangeManager.h"
Daniel Jasperde0328a2013-08-16 11:20:30 +000018#include "ContinuationIndenter.h"
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +000019#include "FormatInternal.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000020#include "FormatTokenLexer.h"
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +000021#include "NamespaceEndCommentsFixer.h"
Martin Probstc4a0dd42016-05-20 11:24:24 +000022#include "SortJavaScriptImports.h"
23#include "TokenAnalyzer.h"
Daniel Jasper7a6d09b2013-01-29 21:01:14 +000024#include "TokenAnnotator.h"
Daniel Jasper0df50932014-12-10 19:00:42 +000025#include "UnwrappedLineFormatter.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000026#include "UnwrappedLineParser.h"
Krasimir Georgievb03877a2017-06-21 12:03:12 +000027#include "UsingDeclarationsSorter.h"
Alexander Kornienkocb45bc12013-04-15 14:28:00 +000028#include "WhitespaceManager.h"
Daniel Jasperec04c0d2013-05-16 10:40:07 +000029#include "clang/Basic/Diagnostic.h"
Benjamin Kramerf3ca26982014-05-10 16:31:55 +000030#include "clang/Basic/DiagnosticOptions.h"
Chandler Carruth44eb4f62013-01-02 10:28:36 +000031#include "clang/Basic/SourceManager.h"
Marianne Mailhot-Sarrasin4988fa12016-04-14 14:47:37 +000032#include "clang/Basic/VirtualFileSystem.h"
Daniel Jasperf7935112012-12-03 18:12:45 +000033#include "clang/Lex/Lexer.h"
Alexander Kornienkoffd6d042013-03-27 11:52:18 +000034#include "llvm/ADT/STLExtras.h"
Ben Hamiltone2e3e672018-01-17 17:33:08 +000035#include "llvm/ADT/StringRef.h"
Manuel Klimek2ef908e2013-02-13 10:46:36 +000036#include "llvm/Support/Allocator.h"
Manuel Klimek24998102013-01-16 14:55:28 +000037#include "llvm/Support/Debug.h"
Edwin Vaned544aa72013-09-30 13:31:48 +000038#include "llvm/Support/Path.h"
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +000039#include "llvm/Support/Regex.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000040#include "llvm/Support/YAMLTraits.h"
Martin Probst081f1762016-06-01 15:19:53 +000041#include <algorithm>
Eric Liu4cfb88a2016-04-25 15:09:22 +000042#include <memory>
Daniel Jasper8b529712012-12-04 13:02:32 +000043#include <string>
44
Chandler Carruth10346662014-04-22 03:17:02 +000045#define DEBUG_TYPE "format-formatter"
46
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000047using clang::format::FormatStyle;
48
NAKAMURA Takumi057a9422017-11-01 04:43:22 +000049LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
50LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
Daniel Jaspere1e43192014-04-01 12:55:11 +000051
Alexander Kornienkod6538332013-05-07 15:32:14 +000052namespace llvm {
53namespace yaml {
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000054template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
55 static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
56 IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
Daniel Jasperc58c70e2014-09-15 11:21:46 +000057 IO.enumCase(Value, "Java", FormatStyle::LK_Java);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000058 IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
Daniel Jasper03a04fe2016-12-12 12:42:29 +000059 IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
Daniel Jasper7052ce62014-01-19 09:04:08 +000060 IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
Daniel Jasper498f5582015-12-25 08:53:31 +000061 IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
Krasimir Georgiev26b144c2017-07-03 15:05:14 +000062 IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000063 }
64};
65
66template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
67 static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
68 IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
69 IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
70 IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
71 IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
72 IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
73 }
74};
75
76template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
77 static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
78 IO.enumCase(Value, "Never", FormatStyle::UT_Never);
79 IO.enumCase(Value, "false", FormatStyle::UT_Never);
80 IO.enumCase(Value, "Always", FormatStyle::UT_Always);
81 IO.enumCase(Value, "true", FormatStyle::UT_Always);
82 IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
Marianne Mailhot-Sarrasin51fe2792016-04-14 14:52:26 +000083 IO.enumCase(Value, "ForContinuationAndIndentation",
84 FormatStyle::UT_ForContinuationAndIndentation);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +000085 }
86};
87
Daniel Jasperabd1f572016-03-02 22:44:03 +000088template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
89 static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
90 IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
91 IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
92 IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
93 }
94};
95
Daniel Jasperd74cf402014-04-08 12:46:38 +000096template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
97 static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
98 IO.enumCase(Value, "None", FormatStyle::SFS_None);
99 IO.enumCase(Value, "false", FormatStyle::SFS_None);
100 IO.enumCase(Value, "All", FormatStyle::SFS_All);
101 IO.enumCase(Value, "true", FormatStyle::SFS_All);
102 IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
Francois Ferrandd3f0e3d2017-06-21 13:56:02 +0000103 IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
Daniel Jasper9e709352014-11-26 10:43:58 +0000104 IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
Daniel Jasperd74cf402014-04-08 12:46:38 +0000105 }
106};
107
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000108template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
109 static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
110 IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto);
111 IO.enumCase(Value, "Always", FormatStyle::BPS_Always);
112 IO.enumCase(Value, "Never", FormatStyle::BPS_Never);
113 }
114};
115
Daniel Jasperac043c92014-09-15 11:11:00 +0000116template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
117 static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
118 IO.enumCase(Value, "All", FormatStyle::BOS_All);
119 IO.enumCase(Value, "true", FormatStyle::BOS_All);
120 IO.enumCase(Value, "None", FormatStyle::BOS_None);
121 IO.enumCase(Value, "false", FormatStyle::BOS_None);
122 IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
123 }
124};
125
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000126template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
127 static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
128 IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
129 IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000130 IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000131 IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
132 IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000133 IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000134 IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000135 IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000136 }
137};
138
Manuel Klimek89628f62017-09-20 09:51:03 +0000139template <>
140struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
141 static void
142 enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
Francois Ferranda6b6d512017-05-24 11:36:58 +0000143 IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
144 IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
145 IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
146 }
147};
148
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000149template <>
Krasimir Georgievad47c902017-08-30 14:34:57 +0000150struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
151 static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
152 IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
153 IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
154 }
155};
156
157template <>
Zachary Turner448592e2015-12-18 22:20:15 +0000158struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
159 static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
160 IO.enumCase(Value, "None", FormatStyle::RTBS_None);
161 IO.enumCase(Value, "All", FormatStyle::RTBS_All);
162 IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
163 IO.enumCase(Value, "TopLevelDefinitions",
164 FormatStyle::RTBS_TopLevelDefinitions);
165 IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
166 }
167};
168
169template <>
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000170struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
171 static void
172 enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000173 IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
174 IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
175 IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
176
177 // For backward compatibility.
178 IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
179 IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
180 }
181};
182
Alexander Kornienkod6538332013-05-07 15:32:14 +0000183template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000184struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000185 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000186 FormatStyle::NamespaceIndentationKind &Value) {
187 IO.enumCase(Value, "None", FormatStyle::NI_None);
188 IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
189 IO.enumCase(Value, "All", FormatStyle::NI_All);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000190 }
191};
192
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000193template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
194 static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
195 IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
196 IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
197 IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
198
199 // For backward compatibility.
200 IO.enumCase(Value, "true", FormatStyle::BAS_Align);
201 IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
202 }
203};
204
Manuel Klimek89628f62017-09-20 09:51:03 +0000205template <>
206struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
207 static void enumeration(IO &IO,
208 FormatStyle::EscapedNewlineAlignmentStyle &Value) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000209 IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
210 IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
211 IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
212
213 // For backward compatibility.
214 IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
215 IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
216 }
217};
218
Jacques Pienaarfc275112015-02-18 23:48:37 +0000219template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
220 static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
Daniel Jasper553d4872014-06-17 12:40:34 +0000221 IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
222 IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
223 IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
224
Alp Toker958027b2014-07-14 19:42:55 +0000225 // For backward compatibility.
Daniel Jasper553d4872014-06-17 12:40:34 +0000226 IO.enumCase(Value, "true", FormatStyle::PAS_Left);
227 IO.enumCase(Value, "false", FormatStyle::PAS_Right);
228 }
229};
230
231template <>
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000232struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
Manuel Klimeka8eb9142013-05-13 12:51:40 +0000233 static void enumeration(IO &IO,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000234 FormatStyle::SpaceBeforeParensOptions &Value) {
235 IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000236 IO.enumCase(Value, "ControlStatements",
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000237 FormatStyle::SBPO_ControlStatements);
238 IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000239
240 // For backward compatibility.
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000241 IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
242 IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000243 }
244};
245
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000246template <> struct MappingTraits<FormatStyle> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000247 static void mapping(IO &IO, FormatStyle &Style) {
248 // When reading, read the language first, we need it for getPredefinedStyle.
249 IO.mapOptional("Language", Style.Language);
250
Alexander Kornienko49149672013-05-10 11:56:10 +0000251 if (IO.outputting()) {
Jacques Pienaarfc275112015-02-18 23:48:37 +0000252 StringRef StylesArray[] = {"LLVM", "Google", "Chromium",
253 "Mozilla", "WebKit", "GNU"};
Alexander Kornienko49149672013-05-10 11:56:10 +0000254 ArrayRef<StringRef> Styles(StylesArray);
255 for (size_t i = 0, e = Styles.size(); i < e; ++i) {
256 StringRef StyleName(Styles[i]);
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000257 FormatStyle PredefinedStyle;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000258 if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000259 Style == PredefinedStyle) {
Alexander Kornienko49149672013-05-10 11:56:10 +0000260 IO.mapOptional("# BasedOnStyle", StyleName);
261 break;
262 }
263 }
264 } else {
Alexander Kornienkod6538332013-05-07 15:32:14 +0000265 StringRef BasedOnStyle;
266 IO.mapOptional("BasedOnStyle", BasedOnStyle);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000267 if (!BasedOnStyle.empty()) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000268 FormatStyle::LanguageKind OldLanguage = Style.Language;
269 FormatStyle::LanguageKind Language =
270 ((FormatStyle *)IO.getContext())->Language;
271 if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000272 IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
273 return;
274 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000275 Style.Language = OldLanguage;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000276 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000277 }
278
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000279 // For backward compatibility.
280 if (!IO.outputting()) {
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000281 IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
Birunthan Mohanathas50a6f912015-06-28 14:52:34 +0000282 IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
283 IO.mapOptional("IndentFunctionDeclarationAfterType",
284 Style.IndentWrappedFunctionNames);
285 IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
286 IO.mapOptional("SpaceAfterControlStatementKeyword",
287 Style.SpaceBeforeParens);
288 }
289
Alexander Kornienkod6538332013-05-07 15:32:14 +0000290 IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
Daniel Jasper3aa9a6a2014-11-18 23:55:27 +0000291 IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000292 IO.mapOptional("AlignConsecutiveAssignments",
293 Style.AlignConsecutiveAssignments);
Daniel Jaspere12597c2015-10-01 10:06:54 +0000294 IO.mapOptional("AlignConsecutiveDeclarations",
295 Style.AlignConsecutiveDeclarations);
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000296 IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
Daniel Jasper3219e432014-12-02 13:24:51 +0000297 IO.mapOptional("AlignOperands", Style.AlignOperands);
Daniel Jasper552f4a72013-07-31 23:55:15 +0000298 IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000299 IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
300 Style.AllowAllParametersOfDeclarationOnNextLine);
Daniel Jasper17605d32014-05-14 09:33:35 +0000301 IO.mapOptional("AllowShortBlocksOnASingleLine",
302 Style.AllowShortBlocksOnASingleLine);
Daniel Jasperb87899b2014-09-10 13:11:45 +0000303 IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
304 Style.AllowShortCaseLabelsOnASingleLine);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000305 IO.mapOptional("AllowShortFunctionsOnASingleLine",
306 Style.AllowShortFunctionsOnASingleLine);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000307 IO.mapOptional("AllowShortIfStatementsOnASingleLine",
308 Style.AllowShortIfStatementsOnASingleLine);
Daniel Jasper3a685df2013-05-16 12:12:21 +0000309 IO.mapOptional("AllowShortLoopsOnASingleLine",
310 Style.AllowShortLoopsOnASingleLine);
Daniel Jasperca4ea1c2014-08-05 12:16:31 +0000311 IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
312 Style.AlwaysBreakAfterDefinitionReturnType);
Zachary Turner448592e2015-12-18 22:20:15 +0000313 IO.mapOptional("AlwaysBreakAfterReturnType",
314 Style.AlwaysBreakAfterReturnType);
315 // If AlwaysBreakAfterDefinitionReturnType was specified but
316 // AlwaysBreakAfterReturnType was not, initialize the latter from the
317 // former for backwards compatibility.
318 if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
319 Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
320 if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
321 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
322 else if (Style.AlwaysBreakAfterDefinitionReturnType ==
323 FormatStyle::DRTBS_TopLevel)
324 Style.AlwaysBreakAfterReturnType =
325 FormatStyle::RTBS_TopLevelDefinitions;
326 }
327
Alexander Kornienko58611712013-07-04 12:02:44 +0000328 IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
329 Style.AlwaysBreakBeforeMultilineStrings);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000330 IO.mapOptional("AlwaysBreakTemplateDeclarations",
331 Style.AlwaysBreakTemplateDeclarations);
332 IO.mapOptional("BinPackArguments", Style.BinPackArguments);
333 IO.mapOptional("BinPackParameters", Style.BinPackParameters);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000334 IO.mapOptional("BraceWrapping", Style.BraceWrapping);
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000335 IO.mapOptional("BreakBeforeBinaryOperators",
336 Style.BreakBeforeBinaryOperators);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000337 IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
Francois Ferrande56a8292017-06-14 12:29:47 +0000338 IO.mapOptional("BreakBeforeInheritanceComma",
339 Style.BreakBeforeInheritanceComma);
Daniel Jasper165b29e2013-11-08 00:57:11 +0000340 IO.mapOptional("BreakBeforeTernaryOperators",
341 Style.BreakBeforeTernaryOperators);
Francois Ferranda6b6d512017-05-24 11:36:58 +0000342
343 bool BreakConstructorInitializersBeforeComma = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000344 IO.mapOptional("BreakConstructorInitializersBeforeComma",
Francois Ferranda6b6d512017-05-24 11:36:58 +0000345 BreakConstructorInitializersBeforeComma);
346 IO.mapOptional("BreakConstructorInitializers",
347 Style.BreakConstructorInitializers);
348 // If BreakConstructorInitializersBeforeComma was specified but
349 // BreakConstructorInitializers was not, initialize the latter from the
350 // former for backwards compatibility.
351 if (BreakConstructorInitializersBeforeComma &&
352 Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
353 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
354
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000355 IO.mapOptional("BreakAfterJavaFieldAnnotations",
356 Style.BreakAfterJavaFieldAnnotations);
357 IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000358 IO.mapOptional("ColumnLimit", Style.ColumnLimit);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000359 IO.mapOptional("CommentPragmas", Style.CommentPragmas);
Francois Ferrande56a8292017-06-14 12:29:47 +0000360 IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000361 IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
362 Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000363 IO.mapOptional("ConstructorInitializerIndentWidth",
364 Style.ConstructorInitializerIndentWidth);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000365 IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
366 IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
Daniel Jasper553d4872014-06-17 12:40:34 +0000367 IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000368 IO.mapOptional("DisableFormat", Style.DisableFormat);
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000369 IO.mapOptional("ExperimentalAutoDetectBinPacking",
370 Style.ExperimentalAutoDetectBinPacking);
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000371 IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000372 IO.mapOptional("ForEachMacros", Style.ForEachMacros);
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000373 IO.mapOptional("IncludeBlocks", Style.IncludeBlocks);
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000374 IO.mapOptional("IncludeCategories", Style.IncludeCategories);
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000375 IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000376 IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
Krasimir Georgievad47c902017-08-30 14:34:57 +0000377 IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000378 IO.mapOptional("IndentWidth", Style.IndentWidth);
379 IO.mapOptional("IndentWrappedFunctionNames",
380 Style.IndentWrappedFunctionNames);
Martin Probst0cd74ee2016-06-13 16:39:50 +0000381 IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
382 IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000383 IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
384 Style.KeepEmptyLinesAtTheStartOfBlocks);
Birunthan Mohanathasb001a0b2015-07-03 17:25:16 +0000385 IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
386 IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000387 IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
Daniel Jasper65ee3472013-07-31 23:16:02 +0000388 IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000389 IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
Daniel Jasper50d634b2014-10-28 16:53:38 +0000390 IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
Daniel Jaspere9beea22014-01-28 15:20:33 +0000391 IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000392 IO.mapOptional("ObjCSpaceBeforeProtocolList",
393 Style.ObjCSpaceBeforeProtocolList);
Manuel Klimek89628f62017-09-20 09:51:03 +0000394 IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
Daniel Jasper33b909c2013-10-25 14:29:37 +0000395 IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
396 Style.PenaltyBreakBeforeFirstCallParameter);
Alexander Kornienkodd7ece52013-06-07 16:02:52 +0000397 IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000398 IO.mapOptional("PenaltyBreakFirstLessLess",
399 Style.PenaltyBreakFirstLessLess);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000400 IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000401 IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
402 IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
403 Style.PenaltyReturnTypeOnItsOwnLine);
Daniel Jasper553d4872014-06-17 12:40:34 +0000404 IO.mapOptional("PointerAlignment", Style.PointerAlignment);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000405 IO.mapOptional("RawStringFormats", Style.RawStringFormats);
Daniel Jaspera0a50392015-12-01 13:28:53 +0000406 IO.mapOptional("ReflowComments", Style.ReflowComments);
407 IO.mapOptional("SortIncludes", Style.SortIncludes);
Krasimir Georgievac16a202017-06-23 11:46:03 +0000408 IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000409 IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
Manuel Klimek89628f62017-09-20 09:51:03 +0000410 IO.mapOptional("SpaceAfterTemplateKeyword",
411 Style.SpaceAfterTemplateKeyword);
Daniel Jasperd94bff32013-09-25 15:15:02 +0000412 IO.mapOptional("SpaceBeforeAssignmentOperators",
413 Style.SpaceBeforeAssignmentOperators);
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000414 IO.mapOptional("SpaceBeforeCtorInitializerColon",
415 Style.SpaceBeforeCtorInitializerColon);
416 IO.mapOptional("SpaceBeforeInheritanceColon",
417 Style.SpaceBeforeInheritanceColon);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000418 IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000419 IO.mapOptional("SpaceBeforeRangeBasedForLoopColon",
420 Style.SpaceBeforeRangeBasedForLoopColon);
Birunthan Mohanathas35cfbd72015-06-28 14:51:17 +0000421 IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
422 IO.mapOptional("SpacesBeforeTrailingComments",
423 Style.SpacesBeforeTrailingComments);
424 IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
425 IO.mapOptional("SpacesInContainerLiterals",
426 Style.SpacesInContainerLiterals);
427 IO.mapOptional("SpacesInCStyleCastParentheses",
428 Style.SpacesInCStyleCastParentheses);
429 IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
430 IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
431 IO.mapOptional("Standard", Style.Standard);
432 IO.mapOptional("TabWidth", Style.TabWidth);
433 IO.mapOptional("UseTab", Style.UseTab);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000434 }
435};
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000436
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000437template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
438 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
439 IO.mapOptional("AfterClass", Wrapping.AfterClass);
440 IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
441 IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
442 IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
443 IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
444 IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
445 IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
446 IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000447 IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000448 IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
449 IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
450 IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
Francois Ferrandad722562017-06-30 20:25:55 +0000451 IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
452 IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
453 IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000454 }
455};
456
Daniel Jasper8ce1b8d2015-10-06 11:54:18 +0000457template <> struct MappingTraits<FormatStyle::IncludeCategory> {
458 static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
459 IO.mapOptional("Regex", Category.Regex);
460 IO.mapOptional("Priority", Category.Priority);
461 }
462};
463
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000464template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> {
465 static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
466 IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve);
467 IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge);
468 IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup);
469 }
470};
471
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000472template <> struct MappingTraits<FormatStyle::RawStringFormat> {
473 static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000474 IO.mapOptional("Language", Format.Language);
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000475 IO.mapOptional("Delimiters", Format.Delimiters);
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000476 IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000477 IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +0000478 IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
479 }
480};
481
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000482// Allows to read vector<FormatStyle> while keeping default values.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000483// IO.getContext() should contain a pointer to the FormatStyle structure, that
484// will be used to get default values for missing keys.
485// If the first element has no Language specified, it will be treated as the
486// default one for the following elements.
Jacques Pienaarfc275112015-02-18 23:48:37 +0000487template <> struct DocumentListTraits<std::vector<FormatStyle>> {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000488 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
489 return Seq.size();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000490 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000491 static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000492 size_t Index) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000493 if (Index >= Seq.size()) {
494 assert(Index == Seq.size());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000495 FormatStyle Template;
Krasimir Georgiev1696bb62017-11-09 15:12:17 +0000496 if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000497 Template = Seq[0];
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000498 } else {
Daniel Jasperb05a81d2014-05-09 13:11:16 +0000499 Template = *((const FormatStyle *)IO.getContext());
Alexander Kornienko6d2c88e2013-12-10 10:30:34 +0000500 Template.Language = FormatStyle::LK_None;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000501 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000502 Seq.resize(Index + 1, Template);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000503 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000504 return Seq[Index];
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000505 }
506};
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000507} // namespace yaml
508} // namespace llvm
Alexander Kornienkod6538332013-05-07 15:32:14 +0000509
Daniel Jasperf7935112012-12-03 18:12:45 +0000510namespace clang {
511namespace format {
512
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000513const std::error_category &getParseCategory() {
Benjamin Kramerf76861c2018-03-20 21:52:19 +0000514 static const ParseErrorCategory C{};
Rafael Espindolad0136702014-06-12 02:50:04 +0000515 return C;
516}
517std::error_code make_error_code(ParseError e) {
Rafael Espindola6d0d89b2014-06-12 03:31:26 +0000518 return std::error_code(static_cast<int>(e), getParseCategory());
Rafael Espindolad0136702014-06-12 02:50:04 +0000519}
520
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +0000521inline llvm::Error make_string_error(const llvm::Twine &Message) {
522 return llvm::make_error<llvm::StringError>(Message,
523 llvm::inconvertibleErrorCode());
524}
525
Reid Kleckner6432d452016-10-19 23:39:55 +0000526const char *ParseErrorCategory::name() const noexcept {
Rafael Espindolad0136702014-06-12 02:50:04 +0000527 return "clang-format.parse_error";
528}
529
530std::string ParseErrorCategory::message(int EV) const {
531 switch (static_cast<ParseError>(EV)) {
532 case ParseError::Success:
533 return "Success";
534 case ParseError::Error:
535 return "Invalid argument";
536 case ParseError::Unsuitable:
537 return "Unsuitable";
538 }
Saleem Abdulrasoolfbfbaf62014-06-12 19:33:26 +0000539 llvm_unreachable("unexpected parse error");
Rafael Espindolad0136702014-06-12 02:50:04 +0000540}
541
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000542static FormatStyle expandPresets(const FormatStyle &Style) {
Daniel Jasper55bbe662015-10-07 04:06:10 +0000543 if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
544 return Style;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000545 FormatStyle Expanded = Style;
Manuel Klimek89628f62017-09-20 09:51:03 +0000546 Expanded.BraceWrapping = {false, false, false, false, false,
547 false, false, false, false, false,
548 false, false, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000549 switch (Style.BreakBeforeBraces) {
550 case FormatStyle::BS_Linux:
551 Expanded.BraceWrapping.AfterClass = true;
552 Expanded.BraceWrapping.AfterFunction = true;
553 Expanded.BraceWrapping.AfterNamespace = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000554 break;
555 case FormatStyle::BS_Mozilla:
556 Expanded.BraceWrapping.AfterClass = true;
557 Expanded.BraceWrapping.AfterEnum = true;
558 Expanded.BraceWrapping.AfterFunction = true;
559 Expanded.BraceWrapping.AfterStruct = true;
560 Expanded.BraceWrapping.AfterUnion = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000561 Expanded.BraceWrapping.AfterExternBlock = true;
Sylvestre Ledru82c9a0e2017-09-13 20:03:29 +0000562 Expanded.BraceWrapping.SplitEmptyFunction = true;
Francois Ferrandad722562017-06-30 20:25:55 +0000563 Expanded.BraceWrapping.SplitEmptyRecord = false;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000564 break;
565 case FormatStyle::BS_Stroustrup:
566 Expanded.BraceWrapping.AfterFunction = true;
567 Expanded.BraceWrapping.BeforeCatch = true;
568 Expanded.BraceWrapping.BeforeElse = true;
569 break;
570 case FormatStyle::BS_Allman:
571 Expanded.BraceWrapping.AfterClass = true;
572 Expanded.BraceWrapping.AfterControlStatement = true;
573 Expanded.BraceWrapping.AfterEnum = true;
574 Expanded.BraceWrapping.AfterFunction = true;
575 Expanded.BraceWrapping.AfterNamespace = true;
576 Expanded.BraceWrapping.AfterObjCDeclaration = true;
577 Expanded.BraceWrapping.AfterStruct = true;
Krasimir Georgievd6ce9372017-09-15 11:23:50 +0000578 Expanded.BraceWrapping.AfterExternBlock = true;
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000579 Expanded.BraceWrapping.BeforeCatch = true;
580 Expanded.BraceWrapping.BeforeElse = true;
581 break;
582 case FormatStyle::BS_GNU:
Manuel Klimek89628f62017-09-20 09:51:03 +0000583 Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
584 true, true, true, true, true, true, true};
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000585 break;
586 case FormatStyle::BS_WebKit:
587 Expanded.BraceWrapping.AfterFunction = true;
588 break;
589 default:
590 break;
591 }
592 return Expanded;
593}
594
Daniel Jasperf7935112012-12-03 18:12:45 +0000595FormatStyle getLLVMStyle() {
596 FormatStyle LLVMStyle;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000597 LLVMStyle.Language = FormatStyle::LK_Cpp;
Daniel Jasperf7935112012-12-03 18:12:45 +0000598 LLVMStyle.AccessModifierOffset = -2;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000599 LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000600 LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
Daniel Jasper3219e432014-12-02 13:24:51 +0000601 LLVMStyle.AlignOperands = true;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000602 LLVMStyle.AlignTrailingComments = true;
Daniel Jaspera44991332015-04-29 13:06:49 +0000603 LLVMStyle.AlignConsecutiveAssignments = false;
Daniel Jaspere12597c2015-10-01 10:06:54 +0000604 LLVMStyle.AlignConsecutiveDeclarations = false;
Daniel Jasperf7db4332013-01-29 16:03:49 +0000605 LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
Daniel Jasperd74cf402014-04-08 12:46:38 +0000606 LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Daniel Jasper17605d32014-05-14 09:33:35 +0000607 LLVMStyle.AllowShortBlocksOnASingleLine = false;
Daniel Jasperb87899b2014-09-10 13:11:45 +0000608 LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000609 LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper3a685df2013-05-16 12:12:21 +0000610 LLVMStyle.AllowShortLoopsOnASingleLine = false;
Zachary Turner448592e2015-12-18 22:20:15 +0000611 LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000612 LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Alexander Kornienko58611712013-07-04 12:02:44 +0000613 LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000614 LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Daniel Jasper18210d72014-10-09 09:52:05 +0000615 LLVMStyle.BinPackArguments = true;
Francois Ferrande56a8292017-06-14 12:29:47 +0000616 LLVMStyle.BinPackParameters = true;
Daniel Jasperac043c92014-09-15 11:11:00 +0000617 LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Daniel Jasper165b29e2013-11-08 00:57:11 +0000618 LLVMStyle.BreakBeforeTernaryOperators = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000619 LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
Manuel Klimek89628f62017-09-20 09:51:03 +0000620 LLVMStyle.BraceWrapping = {false, false, false, false, false,
621 false, false, false, false, false,
622 false, false, true, true, true};
Nico Weber2cd92f12015-10-15 16:03:01 +0000623 LLVMStyle.BreakAfterJavaFieldAnnotations = false;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000624 LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000625 LLVMStyle.BreakBeforeInheritanceComma = false;
Daniel Jaspere1a7b762016-02-01 11:21:02 +0000626 LLVMStyle.BreakStringLiterals = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000627 LLVMStyle.ColumnLimit = 80;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000628 LLVMStyle.CommentPragmas = "^ IWYU pragma:";
Francois Ferrande56a8292017-06-14 12:29:47 +0000629 LLVMStyle.CompactNamespaces = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000630 LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
Daniel Jaspercdaffa42013-08-13 10:58:30 +0000631 LLVMStyle.ConstructorInitializerIndentWidth = 4;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000632 LLVMStyle.ContinuationIndentWidth = 4;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000633 LLVMStyle.Cpp11BracedListStyle = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000634 LLVMStyle.DerivePointerAlignment = false;
Daniel Jasperb10cbc42013-07-10 14:02:49 +0000635 LLVMStyle.ExperimentalAutoDetectBinPacking = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000636 LLVMStyle.FixNamespaceComments = true;
Daniel Jaspere1e43192014-04-01 12:55:11 +0000637 LLVMStyle.ForEachMacros.push_back("foreach");
638 LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
639 LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
Daniel Jasper85c472d2015-09-29 07:53:08 +0000640 LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
Chandler Carruthd676ab12017-06-29 23:20:54 +0000641 {"^(<|\"(gtest|gmock|isl|json)/)", 3},
Daniel Jasper85c472d2015-09-29 07:53:08 +0000642 {".*", 1}};
Chandler Carruthd676ab12017-06-29 23:20:54 +0000643 LLVMStyle.IncludeIsMainRegex = "(Test)?$";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +0000644 LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000645 LLVMStyle.IndentCaseLabels = false;
Krasimir Georgievad47c902017-08-30 14:34:57 +0000646 LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
Daniel Jasperc75e1ef2014-07-09 08:42:42 +0000647 LLVMStyle.IndentWrappedFunctionNames = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000648 LLVMStyle.IndentWidth = 2;
Martin Probstfb2342d2016-06-13 17:50:10 +0000649 LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
650 LLVMStyle.JavaScriptWrapImports = true;
Alexander Kornienkoebb43ca2013-09-05 14:08:34 +0000651 LLVMStyle.TabWidth = 8;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000652 LLVMStyle.MaxEmptyLinesToKeep = 1;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000653 LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000654 LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
Ben Hamilton4dc658c2018-02-02 20:15:14 +0000655 LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000656 LLVMStyle.ObjCBlockIndentWidth = 2;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000657 LLVMStyle.ObjCSpaceAfterProperty = false;
Nico Webera6087752013-01-10 20:12:55 +0000658 LLVMStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000659 LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000660 LLVMStyle.SpacesBeforeTrailingComments = 1;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000661 LLVMStyle.Standard = FormatStyle::LS_Cpp11;
Alexander Kornienko3c3d09c2013-09-27 16:14:22 +0000662 LLVMStyle.UseTab = FormatStyle::UT_Never;
Daniel Jaspera0a50392015-12-01 13:28:53 +0000663 LLVMStyle.ReflowComments = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000664 LLVMStyle.SpacesInParentheses = false;
Daniel Jasperad981f82014-08-26 11:41:14 +0000665 LLVMStyle.SpacesInSquareBrackets = false;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000666 LLVMStyle.SpaceInEmptyParentheses = false;
Daniel Jasperb2e10a52014-01-15 15:09:08 +0000667 LLVMStyle.SpacesInContainerLiterals = true;
Daniel Jasperb55acad2013-08-20 12:36:34 +0000668 LLVMStyle.SpacesInCStyleCastParentheses = false;
Daniel Jasperdb986eb2014-09-03 07:37:29 +0000669 LLVMStyle.SpaceAfterCStyleCast = false;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000670 LLVMStyle.SpaceAfterTemplateKeyword = true;
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000671 LLVMStyle.SpaceBeforeCtorInitializerColon = true;
672 LLVMStyle.SpaceBeforeInheritanceColon = true;
Alexander Kornienkofdca83d2013-12-10 10:18:34 +0000673 LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
Francois Ferrand2a9ea782018-03-01 10:09:13 +0000674 LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
Daniel Jasperd94bff32013-09-25 15:15:02 +0000675 LLVMStyle.SpaceBeforeAssignmentOperators = true;
Daniel Jasperdd978ae2013-10-29 14:52:02 +0000676 LLVMStyle.SpacesInAngles = false;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000677
Francois Ferrand9976efa2017-05-22 08:28:17 +0000678 LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
Daniel Jasper19a541e2013-12-19 16:45:34 +0000679 LLVMStyle.PenaltyBreakComment = 300;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000680 LLVMStyle.PenaltyBreakFirstLessLess = 120;
681 LLVMStyle.PenaltyBreakString = 1000;
682 LLVMStyle.PenaltyExcessCharacter = 1000000;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000683 LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000684 LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000685
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000686 LLVMStyle.DisableFormat = false;
Daniel Jasperda446772015-11-16 12:38:56 +0000687 LLVMStyle.SortIncludes = true;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000688 LLVMStyle.SortUsingDeclarations = true;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000689
Daniel Jasperf7935112012-12-03 18:12:45 +0000690 return LLVMStyle;
691}
692
Nico Weber514ecc82014-02-02 20:50:45 +0000693FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000694 if (Language == FormatStyle::LK_TextProto) {
695 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
696 GoogleStyle.Language = FormatStyle::LK_TextProto;
Krasimir Georgieveda222e2018-01-24 11:18:39 +0000697
Krasimir Georgiev26b144c2017-07-03 15:05:14 +0000698 return GoogleStyle;
699 }
700
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000701 FormatStyle GoogleStyle = getLLVMStyle();
Nico Weber514ecc82014-02-02 20:50:45 +0000702 GoogleStyle.Language = Language;
703
Daniel Jasperf7935112012-12-03 18:12:45 +0000704 GoogleStyle.AccessModifierOffset = -1;
Daniel Jasper7fdbb3f2017-05-08 15:08:00 +0000705 GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
Daniel Jasper085a2ed2013-04-24 13:46:00 +0000706 GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
Daniel Jasper5bd0b9e2013-05-23 18:05:18 +0000707 GoogleStyle.AllowShortLoopsOnASingleLine = true;
Alexander Kornienko58611712013-07-04 12:02:44 +0000708 GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000709 GoogleStyle.AlwaysBreakTemplateDeclarations = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000710 GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000711 GoogleStyle.DerivePointerAlignment = true;
Krasimir Georgieva84e7872017-09-26 14:58:29 +0000712 GoogleStyle.IncludeCategories = {
713 {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
Daniel Jasper9c8ff352016-03-21 14:11:27 +0000714 GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000715 GoogleStyle.IndentCaseLabels = true;
Daniel Jaspera26fc5c2014-03-21 13:43:14 +0000716 GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
Ben Hamilton3a47fdd2018-02-08 01:49:10 +0000717 GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000718 GoogleStyle.ObjCSpaceAfterProperty = false;
Ben Hamiltonf84f1182018-01-18 18:37:16 +0000719 GoogleStyle.ObjCSpaceBeforeProtocolList = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000720 GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000721 GoogleStyle.RawStringFormats = {{
722 FormatStyle::LK_TextProto,
723 /*Delimiters=*/
724 {
725 "pb",
726 "PB",
Krasimir Georgiev2fac8d92018-02-16 12:10:06 +0000727 "proto",
728 "PROTO",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000729 },
Krasimir Georgiev2537e222018-01-17 16:17:26 +0000730 /*EnclosingFunctionNames=*/
Krasimir Georgieva83d3c52018-01-29 19:28:05 +0000731 {},
Krasimir Georgiev412ed092018-01-19 16:18:47 +0000732 /*CanonicalDelimiter=*/"",
Krasimir Georgiev4527f132018-01-17 12:24:59 +0000733 /*BasedOnStyle=*/"google",
734 }};
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000735 GoogleStyle.SpacesBeforeTrailingComments = 2;
736 GoogleStyle.Standard = FormatStyle::LS_Auto;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000737
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000738 GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper33b909c2013-10-25 14:29:37 +0000739 GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
Daniel Jasper4e9678f2013-07-11 20:41:21 +0000740
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000741 if (Language == FormatStyle::LK_Java) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000742 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000743 GoogleStyle.AlignOperands = false;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000744 GoogleStyle.AlignTrailingComments = false;
Daniel Jasper9e709352014-11-26 10:43:58 +0000745 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000746 GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
Daniel Jasper1cd3c712015-01-14 12:24:59 +0000747 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000748 GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
749 GoogleStyle.ColumnLimit = 100;
750 GoogleStyle.SpaceAfterCStyleCast = true;
Daniel Jasper61d81972014-11-14 08:22:46 +0000751 GoogleStyle.SpacesBeforeTrailingComments = 1;
Daniel Jasperc58c70e2014-09-15 11:21:46 +0000752 } else if (Language == FormatStyle::LK_JavaScript) {
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000753 GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
Daniel Jasper41a2bf72015-12-21 13:52:19 +0000754 GoogleStyle.AlignOperands = false;
Daniel Jasper28d8a5a2016-09-07 23:01:13 +0000755 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000756 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jaspere551bb72014-11-05 17:22:31 +0000757 GoogleStyle.BreakBeforeTernaryOperators = false;
Martin Probst2083f312017-05-09 12:45:48 +0000758 // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
759 // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
760 GoogleStyle.CommentPragmas =
761 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
Daniel Jasper8f83a902014-05-09 10:28:58 +0000762 GoogleStyle.MaxEmptyLinesToKeep = 3;
Martin Probstece8c0c2016-06-13 16:41:28 +0000763 GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
Nico Weber514ecc82014-02-02 20:50:45 +0000764 GoogleStyle.SpacesInContainerLiterals = false;
Daniel Jasperabd1f572016-03-02 22:44:03 +0000765 GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
Martin Probst0cd74ee2016-06-13 16:39:50 +0000766 GoogleStyle.JavaScriptWrapImports = false;
Nico Weber514ecc82014-02-02 20:50:45 +0000767 } else if (Language == FormatStyle::LK_Proto) {
Daniel Jasperd74cf402014-04-08 12:46:38 +0000768 GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
Daniel Jasper9c95dfe2018-03-12 10:32:18 +0000769 GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
Daniel Jasper783bac62014-04-15 09:54:30 +0000770 GoogleStyle.SpacesInContainerLiterals = false;
Krasimir Georgievc2091802018-01-31 10:14:10 +0000771 GoogleStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev374e6de2018-02-08 10:47:12 +0000772 // This affects protocol buffer options specifications and text protos.
773 // Text protos are currently mostly formatted inside C++ raw string literals
774 // and often the current breaking behavior of string literals is not
775 // beneficial there. Investigate turning this on once proper string reflow
776 // has been implemented.
777 GoogleStyle.BreakStringLiterals = false;
Daniel Jasper03a04fe2016-12-12 12:42:29 +0000778 } else if (Language == FormatStyle::LK_ObjC) {
779 GoogleStyle.ColumnLimit = 100;
Nico Weber514ecc82014-02-02 20:50:45 +0000780 }
781
Daniel Jasperf7935112012-12-03 18:12:45 +0000782 return GoogleStyle;
783}
784
Nico Weber514ecc82014-02-02 20:50:45 +0000785FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
786 FormatStyle ChromiumStyle = getGoogleStyle(Language);
Nico Weber450425c2014-11-26 16:43:18 +0000787 if (Language == FormatStyle::LK_Java) {
Daniel Jasperfd4ed182015-01-04 20:40:45 +0000788 ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
Nico Weber2cd92f12015-10-15 16:03:01 +0000789 ChromiumStyle.BreakAfterJavaFieldAnnotations = true;
Nico Weber450425c2014-11-26 16:43:18 +0000790 ChromiumStyle.ContinuationIndentWidth = 8;
Nico Weber2cd92f12015-10-15 16:03:01 +0000791 ChromiumStyle.IndentWidth = 4;
Nico Weberea649692017-01-04 02:33:36 +0000792 } else if (Language == FormatStyle::LK_JavaScript) {
793 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
794 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
Nico Weber450425c2014-11-26 16:43:18 +0000795 } else {
796 ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
797 ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
798 ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
799 ChromiumStyle.AllowShortLoopsOnASingleLine = false;
800 ChromiumStyle.BinPackParameters = false;
801 ChromiumStyle.DerivePointerAlignment = false;
Nico Weber9e2bc302017-01-31 18:42:05 +0000802 if (Language == FormatStyle::LK_ObjC)
803 ChromiumStyle.ColumnLimit = 80;
Nico Weber450425c2014-11-26 16:43:18 +0000804 }
Daniel Jasper1b750ed2013-01-14 16:24:39 +0000805 return ChromiumStyle;
806}
807
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000808FormatStyle getMozillaStyle() {
809 FormatStyle MozillaStyle = getLLVMStyle();
810 MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000811 MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Manuel Klimek89628f62017-09-20 09:51:03 +0000812 MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000813 MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
814 FormatStyle::DRTBS_TopLevel;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000815 MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Sylvestre Ledrudcb038d2016-12-14 16:09:29 +0000816 MozillaStyle.BinPackParameters = false;
817 MozillaStyle.BinPackArguments = false;
Birunthan Mohanathas305fa9c2015-07-12 03:13:54 +0000818 MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000819 MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Andi-Bogdan Postelnicu0ef8ee12017-03-10 15:10:37 +0000820 MozillaStyle.BreakBeforeInheritanceComma = true;
Birunthan Mohanathasa0810022015-06-29 15:18:58 +0000821 MozillaStyle.ConstructorInitializerIndentWidth = 2;
822 MozillaStyle.ContinuationIndentWidth = 2;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000823 MozillaStyle.Cpp11BracedListStyle = false;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000824 MozillaStyle.FixNamespaceComments = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000825 MozillaStyle.IndentCaseLabels = true;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000826 MozillaStyle.ObjCSpaceAfterProperty = true;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000827 MozillaStyle.ObjCSpaceBeforeProtocolList = false;
828 MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
Daniel Jasper553d4872014-06-17 12:40:34 +0000829 MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
Sylvestre Ledru83bbd572016-08-09 14:24:40 +0000830 MozillaStyle.SpaceAfterTemplateKeyword = false;
Alexander Kornienkoc8602662013-05-06 14:11:27 +0000831 return MozillaStyle;
832}
833
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000834FormatStyle getWebKitStyle() {
835 FormatStyle Style = getLLVMStyle();
Daniel Jasper65ee3472013-07-31 23:16:02 +0000836 Style.AccessModifierOffset = -4;
Daniel Jasper6501f7e2015-10-27 12:38:37 +0000837 Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Daniel Jasper3219e432014-12-02 13:24:51 +0000838 Style.AlignOperands = false;
Daniel Jasper552f4a72013-07-31 23:55:15 +0000839 Style.AlignTrailingComments = false;
Daniel Jasperac043c92014-09-15 11:11:00 +0000840 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Roman Kashitsyn291f64f2015-08-10 13:43:19 +0000841 Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Francois Ferranda6b6d512017-05-24 11:36:58 +0000842 Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000843 Style.Cpp11BracedListStyle = false;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000844 Style.ColumnLimit = 0;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000845 Style.FixNamespaceComments = false;
Daniel Jaspere33d4af2013-07-26 16:56:36 +0000846 Style.IndentWidth = 4;
Daniel Jasper65ee3472013-07-31 23:16:02 +0000847 Style.NamespaceIndentation = FormatStyle::NI_Inner;
Daniel Jasper50d634b2014-10-28 16:53:38 +0000848 Style.ObjCBlockIndentWidth = 4;
Daniel Jaspere9beea22014-01-28 15:20:33 +0000849 Style.ObjCSpaceAfterProperty = true;
Daniel Jasper553d4872014-06-17 12:40:34 +0000850 Style.PointerAlignment = FormatStyle::PAS_Left;
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000851 return Style;
852}
853
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000854FormatStyle getGNUStyle() {
855 FormatStyle Style = getLLVMStyle();
Birunthan Mohanathasa0388a82015-06-29 15:30:42 +0000856 Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Zachary Turner448592e2015-12-18 22:20:15 +0000857 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Daniel Jasperac043c92014-09-15 11:11:00 +0000858 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Alexander Kornienko3a33f022013-12-12 09:49:52 +0000859 Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000860 Style.BreakBeforeTernaryOperators = true;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000861 Style.Cpp11BracedListStyle = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000862 Style.ColumnLimit = 79;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +0000863 Style.FixNamespaceComments = false;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000864 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Chandler Carruthf8b72662014-03-02 12:37:31 +0000865 Style.Standard = FormatStyle::LS_Cpp03;
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000866 return Style;
867}
868
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000869FormatStyle getNoStyle() {
870 FormatStyle NoStyle = getLLVMStyle();
871 NoStyle.DisableFormat = true;
Daniel Jasperda446772015-11-16 12:38:56 +0000872 NoStyle.SortIncludes = false;
Krasimir Georgievac16a202017-06-23 11:46:03 +0000873 NoStyle.SortUsingDeclarations = false;
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000874 return NoStyle;
875}
876
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000877bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
878 FormatStyle *Style) {
879 if (Name.equals_lower("llvm")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000880 *Style = getLLVMStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000881 } else if (Name.equals_lower("chromium")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000882 *Style = getChromiumStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000883 } else if (Name.equals_lower("mozilla")) {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000884 *Style = getMozillaStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000885 } else if (Name.equals_lower("google")) {
Nico Weber514ecc82014-02-02 20:50:45 +0000886 *Style = getGoogleStyle(Language);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000887 } else if (Name.equals_lower("webkit")) {
Daniel Jasperffefb3d2013-07-24 13:10:59 +0000888 *Style = getWebKitStyle();
Alexander Kornienkofe7a57f2013-12-10 15:42:15 +0000889 } else if (Name.equals_lower("gnu")) {
890 *Style = getGNUStyle();
Daniel Jasperc64b09a2014-05-22 15:12:22 +0000891 } else if (Name.equals_lower("none")) {
892 *Style = getNoStyle();
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000893 } else {
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000894 return false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000895 }
Alexander Kornienkod6538332013-05-07 15:32:14 +0000896
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000897 Style->Language = Language;
Alexander Kornienko006b5c82013-05-19 00:53:30 +0000898 return true;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000899}
900
Rafael Espindolac0809172014-06-12 14:02:15 +0000901std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000902 assert(Style);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000903 FormatStyle::LanguageKind Language = Style->Language;
904 assert(Language != FormatStyle::LK_None);
Alexander Kornienko06e00332013-05-20 15:18:01 +0000905 if (Text.trim().empty())
Rafael Espindolad0136702014-06-12 02:50:04 +0000906 return make_error_code(ParseError::Error);
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000907 Style->StyleSet.Clear();
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000908 std::vector<FormatStyle> Styles;
Alexander Kornienkod6538332013-05-07 15:32:14 +0000909 llvm::yaml::Input Input(Text);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000910 // DocumentListTraits<vector<FormatStyle>> uses the context to get default
911 // values for the fields, keys for which are missing from the configuration.
912 // Mapping also uses the context to get the language to find the correct
913 // base style.
914 Input.setContext(Style);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000915 Input >> Styles;
916 if (Input.error())
917 return Input.error();
918
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000919 for (unsigned i = 0; i < Styles.size(); ++i) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000920 // Ensures that only the first configuration can skip the Language option.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000921 if (Styles[i].Language == FormatStyle::LK_None && i != 0)
Rafael Espindolad0136702014-06-12 02:50:04 +0000922 return make_error_code(ParseError::Error);
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000923 // Ensure that each language is configured at most once.
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000924 for (unsigned j = 0; j < i; ++j) {
925 if (Styles[i].Language == Styles[j].Language) {
926 DEBUG(llvm::dbgs()
927 << "Duplicate languages in the config file on positions " << j
928 << " and " << i << "\n");
Rafael Espindolad0136702014-06-12 02:50:04 +0000929 return make_error_code(ParseError::Error);
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000930 }
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000931 }
932 }
933 // Look for a suitable configuration starting from the end, so we can
934 // find the configuration for the specific language first, and the default
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000935 // configuration (which can only be at slot 0) after it.
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000936 FormatStyle::FormatStyleSet StyleSet;
937 bool LanguageFound = false;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +0000938 for (int i = Styles.size() - 1; i >= 0; --i) {
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000939 if (Styles[i].Language != FormatStyle::LK_None)
940 StyleSet.Add(Styles[i]);
941 if (Styles[i].Language == Language)
942 LanguageFound = true;
Alexander Kornienkocabdd732013-11-29 15:19:43 +0000943 }
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000944 if (!LanguageFound) {
945 if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
946 return make_error_code(ParseError::Unsuitable);
947 FormatStyle DefaultStyle = Styles[0];
948 DefaultStyle.Language = Language;
949 StyleSet.Add(std::move(DefaultStyle));
950 }
951 *Style = *StyleSet.Get(Language);
952 return make_error_code(ParseError::Success);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000953}
954
955std::string configurationAsText(const FormatStyle &Style) {
956 std::string Text;
957 llvm::raw_string_ostream Stream(Text);
958 llvm::yaml::Output Output(Stream);
959 // We use the same mapping method for input and output, so we need a non-const
960 // reference here.
Daniel Jasperc1bc38e2015-09-29 14:57:55 +0000961 FormatStyle NonConstStyle = expandPresets(Style);
Alexander Kornienkod6538332013-05-07 15:32:14 +0000962 Output << NonConstStyle;
Alexander Kornienko9a38ec22013-05-13 12:56:35 +0000963 return Stream.str();
Alexander Kornienkod6538332013-05-07 15:32:14 +0000964}
965
Krasimir Georgiev54076fe2018-01-15 12:06:16 +0000966llvm::Optional<FormatStyle>
967FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
968 if (!Styles)
969 return None;
970 auto It = Styles->find(Language);
971 if (It == Styles->end())
972 return None;
973 FormatStyle Style = It->second;
974 Style.StyleSet = *this;
975 return Style;
976}
977
978void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
979 assert(Style.Language != LK_None &&
980 "Cannot add a style for LK_None to a StyleSet");
981 assert(
982 !Style.StyleSet.Styles &&
983 "Cannot add a style associated with an existing StyleSet to a StyleSet");
984 if (!Styles)
985 Styles = std::make_shared<MapType>();
986 (*Styles)[Style.Language] = std::move(Style);
987}
988
989void FormatStyle::FormatStyleSet::Clear() {
990 Styles.reset();
991}
992
993llvm::Optional<FormatStyle>
994FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
995 return StyleSet.Get(Language);
996}
997
Craig Topperaf35e852013-06-30 22:29:28 +0000998namespace {
999
Daniel Jasper496c1992016-09-07 22:48:53 +00001000class JavaScriptRequoter : public TokenAnalyzer {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001001public:
Daniel Jasper496c1992016-09-07 22:48:53 +00001002 JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
1003 : TokenAnalyzer(Env, Style) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001004
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001005 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001006 analyze(TokenAnnotator &Annotator,
1007 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001008 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001009 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1010 AnnotatedLines.end());
Daniel Jasper496c1992016-09-07 22:48:53 +00001011 tooling::Replacements Result;
1012 requoteJSStringLiteral(AnnotatedLines, Result);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001013 return {Result, 0};
Alexander Kornienko62b85b92013-03-13 14:41:29 +00001014 }
1015
1016private:
Daniel Jasper496c1992016-09-07 22:48:53 +00001017 // Replaces double/single-quoted string literal as appropriate, re-escaping
1018 // the contents in the process.
Daniel Jasper97439922016-03-17 13:03:41 +00001019 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
Eric Liu4cfb88a2016-04-25 15:09:22 +00001020 tooling::Replacements &Result) {
Daniel Jasper97439922016-03-17 13:03:41 +00001021 for (AnnotatedLine *Line : Lines) {
1022 requoteJSStringLiteral(Line->Children, Result);
1023 if (!Line->Affected)
1024 continue;
1025 for (FormatToken *FormatTok = Line->First; FormatTok;
1026 FormatTok = FormatTok->Next) {
1027 StringRef Input = FormatTok->TokenText;
Martin Probsta1669792016-05-12 11:20:32 +00001028 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
Daniel Jasper97439922016-03-17 13:03:41 +00001029 // NB: testing for not starting with a double quote to avoid
Daniel Jasper496c1992016-09-07 22:48:53 +00001030 // breaking `template strings`.
Eric Liu635423e2016-04-28 07:52:03 +00001031 (Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
Daniel Jasper97439922016-03-17 13:03:41 +00001032 !Input.startswith("\"")) ||
Eric Liu635423e2016-04-28 07:52:03 +00001033 (Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
Daniel Jasper97439922016-03-17 13:03:41 +00001034 !Input.startswith("\'")))
1035 continue;
1036
1037 // Change start and end quote.
Eric Liu635423e2016-04-28 07:52:03 +00001038 bool IsSingle = Style.JavaScriptQuotes == FormatStyle::JSQS_Single;
Daniel Jasper97439922016-03-17 13:03:41 +00001039 SourceLocation Start = FormatTok->Tok.getLocation();
1040 auto Replace = [&](SourceLocation Start, unsigned Length,
1041 StringRef ReplacementText) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001042 auto Err = Result.add(tooling::Replacement(
1043 Env.getSourceManager(), Start, Length, ReplacementText));
1044 // FIXME: handle error. For now, print error message and skip the
1045 // replacement for release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001046 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001047 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001048 assert(false);
1049 }
Daniel Jasper97439922016-03-17 13:03:41 +00001050 };
1051 Replace(Start, 1, IsSingle ? "'" : "\"");
1052 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
1053 IsSingle ? "'" : "\"");
1054
1055 // Escape internal quotes.
Daniel Jasper97439922016-03-17 13:03:41 +00001056 bool Escaped = false;
1057 for (size_t i = 1; i < Input.size() - 1; i++) {
1058 switch (Input[i]) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001059 case '\\':
1060 if (!Escaped && i + 1 < Input.size() &&
1061 ((IsSingle && Input[i + 1] == '"') ||
1062 (!IsSingle && Input[i + 1] == '\''))) {
1063 // Remove this \, it's escaping a " or ' that no longer needs
1064 // escaping
Eric Liu4cfb88a2016-04-25 15:09:22 +00001065 Replace(Start.getLocWithOffset(i), 1, "");
1066 continue;
1067 }
1068 Escaped = !Escaped;
1069 break;
1070 case '\"':
1071 case '\'':
1072 if (!Escaped && IsSingle == (Input[i] == '\'')) {
1073 // Escape the quote.
1074 Replace(Start.getLocWithOffset(i), 0, "\\");
Eric Liu4cfb88a2016-04-25 15:09:22 +00001075 }
1076 Escaped = false;
1077 break;
1078 default:
1079 Escaped = false;
1080 break;
Daniel Jasper97439922016-03-17 13:03:41 +00001081 }
1082 }
Daniel Jasper97439922016-03-17 13:03:41 +00001083 }
1084 }
1085 }
Daniel Jasper496c1992016-09-07 22:48:53 +00001086};
1087
1088class Formatter : public TokenAnalyzer {
1089public:
1090 Formatter(const Environment &Env, const FormatStyle &Style,
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001091 FormattingAttemptStatus *Status)
1092 : TokenAnalyzer(Env, Style), Status(Status) {}
Daniel Jasper496c1992016-09-07 22:48:53 +00001093
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001094 std::pair<tooling::Replacements, unsigned>
Daniel Jasper496c1992016-09-07 22:48:53 +00001095 analyze(TokenAnnotator &Annotator,
1096 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1097 FormatTokenLexer &Tokens) override {
1098 tooling::Replacements Result;
1099 deriveLocalStyle(AnnotatedLines);
1100 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1101 AnnotatedLines.end());
1102 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1103 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1104 }
1105 Annotator.setCommentLineLevels(AnnotatedLines);
1106
1107 WhitespaceManager Whitespaces(
1108 Env.getSourceManager(), Style,
1109 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
1110 ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
1111 Env.getSourceManager(), Whitespaces, Encoding,
1112 BinPackInconclusiveFunctions);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001113 unsigned Penalty =
1114 UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
1115 Tokens.getKeywords(), Env.getSourceManager(),
1116 Status)
1117 .format(AnnotatedLines, /*DryRun=*/false,
1118 /*AdditionalIndent=*/0,
1119 /*FixBadIndentation=*/false,
1120 /*FirstStartColumn=*/Env.getFirstStartColumn(),
1121 /*NextStartColumn=*/Env.getNextStartColumn(),
1122 /*LastStartColumn=*/Env.getLastStartColumn());
Daniel Jasper496c1992016-09-07 22:48:53 +00001123 for (const auto &R : Whitespaces.generateReplacements())
1124 if (Result.add(R))
Krasimir Georgieve56e9a42017-10-30 14:30:14 +00001125 return std::make_pair(Result, 0);
1126 return std::make_pair(Result, Penalty);
Daniel Jasper496c1992016-09-07 22:48:53 +00001127 }
1128
1129private:
Alexander Kornienko9e649af2013-09-11 12:25:57 +00001130 static bool inputUsesCRLF(StringRef Text) {
1131 return Text.count('\r') * 2 > Text.count('\n');
1132 }
1133
Daniel Jasper352f0df2015-07-18 16:35:30 +00001134 bool
1135 hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001136 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001137 if (hasCpp03IncompatibleFormat(Line->Children))
1138 return true;
1139 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1140 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1141 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1142 return true;
1143 if (Tok->is(TT_TemplateCloser) &&
1144 Tok->Previous->is(TT_TemplateCloser))
1145 return true;
1146 }
1147 }
1148 }
1149 return false;
1150 }
1151
1152 int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) {
1153 int AlignmentDiff = 0;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001154 for (const AnnotatedLine *Line : Lines) {
Daniel Jasper352f0df2015-07-18 16:35:30 +00001155 AlignmentDiff += countVariableAlignments(Line->Children);
1156 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1157 if (!Tok->is(TT_PointerOrReference))
1158 continue;
1159 bool SpaceBefore =
1160 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1161 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1162 Tok->Next->WhitespaceRange.getEnd();
1163 if (SpaceBefore && !SpaceAfter)
1164 ++AlignmentDiff;
1165 if (!SpaceBefore && SpaceAfter)
1166 --AlignmentDiff;
1167 }
1168 }
1169 return AlignmentDiff;
1170 }
1171
Manuel Klimek71814b42013-10-11 21:25:45 +00001172 void
1173 deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001174 bool HasBinPackedFunction = false;
1175 bool HasOnePerLineFunction = false;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001176 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001177 if (!AnnotatedLines[i]->First->Next)
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001178 continue;
Daniel Jasper9fe0e8d2013-09-05 09:29:45 +00001179 FormatToken *Tok = AnnotatedLines[i]->First->Next;
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001180 while (Tok->Next) {
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001181 if (Tok->PackingKind == PPK_BinPacked)
1182 HasBinPackedFunction = true;
1183 if (Tok->PackingKind == PPK_OnePerLine)
1184 HasOnePerLineFunction = true;
1185
Manuel Klimek6e6310e2013-05-29 14:47:47 +00001186 Tok = Tok->Next;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001187 }
1188 }
Eric Liu635423e2016-04-28 07:52:03 +00001189 if (Style.DerivePointerAlignment)
1190 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1191 ? FormatStyle::PAS_Left
1192 : FormatStyle::PAS_Right;
1193 if (Style.Standard == FormatStyle::LS_Auto)
1194 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1195 ? FormatStyle::LS_Cpp11
1196 : FormatStyle::LS_Cpp03;
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001197 BinPackInconclusiveFunctions =
1198 HasBinPackedFunction || !HasOnePerLineFunction;
Daniel Jasper7fce3ab2013-02-06 14:22:40 +00001199 }
1200
Daniel Jasperb10cbc42013-07-10 14:02:49 +00001201 bool BinPackInconclusiveFunctions;
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00001202 FormattingAttemptStatus *Status;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001203};
1204
1205// This class clean up the erroneous/redundant code around the given ranges in
1206// file.
1207class Cleaner : public TokenAnalyzer {
1208public:
Eric Liu635423e2016-04-28 07:52:03 +00001209 Cleaner(const Environment &Env, const FormatStyle &Style)
1210 : TokenAnalyzer(Env, Style),
Eric Liu4cfb88a2016-04-25 15:09:22 +00001211 DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
1212
1213 // FIXME: eliminate unused parameters.
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001214 std::pair<tooling::Replacements, unsigned>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001215 analyze(TokenAnnotator &Annotator,
1216 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Martin Probsta9855af2016-09-02 14:29:48 +00001217 FormatTokenLexer &Tokens) override {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001218 // FIXME: in the current implementation the granularity of affected range
1219 // is an annotated line. However, this is not sufficient. Furthermore,
1220 // redundant code introduced by replacements does not necessarily
1221 // intercept with ranges of replacements that result in the redundancy.
1222 // To determine if some redundant code is actually introduced by
1223 // replacements(e.g. deletions), we need to come up with a more
1224 // sophisticated way of computing affected ranges.
1225 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1226 AnnotatedLines.end());
1227
1228 checkEmptyNamespace(AnnotatedLines);
1229
Eric Liuce5e4bc2016-05-18 08:02:56 +00001230 for (auto &Line : AnnotatedLines) {
1231 if (Line->Affected) {
1232 cleanupRight(Line->First, tok::comma, tok::comma);
1233 cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
Eric Liu2574d152016-09-13 15:02:43 +00001234 cleanupRight(Line->First, tok::l_paren, tok::comma);
1235 cleanupLeft(Line->First, tok::comma, tok::r_paren);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001236 cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
1237 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
Malcolm Parsons5d8cdb82016-10-20 14:58:45 +00001238 cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001239 }
1240 }
1241
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00001242 return {generateFixes(), 0};
Eric Liu4cfb88a2016-04-25 15:09:22 +00001243 }
1244
1245private:
1246 bool containsOnlyComments(const AnnotatedLine &Line) {
1247 for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
1248 if (Tok->isNot(tok::comment))
1249 return false;
1250 }
1251 return true;
1252 }
1253
1254 // Iterate through all lines and remove any empty (nested) namespaces.
1255 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
Eric Liu7956c402016-10-05 15:49:01 +00001256 std::set<unsigned> DeletedLines;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001257 for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1258 auto &Line = *AnnotatedLines[i];
1259 if (Line.startsWith(tok::kw_namespace) ||
1260 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001261 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001262 }
1263 }
1264
1265 for (auto Line : DeletedLines) {
1266 FormatToken *Tok = AnnotatedLines[Line]->First;
1267 while (Tok) {
1268 deleteToken(Tok);
1269 Tok = Tok->Next;
1270 }
1271 }
1272 }
1273
1274 // The function checks if the namespace, which starts from \p CurrentLine, and
1275 // its nested namespaces are empty and delete them if they are empty. It also
1276 // sets \p NewLine to the last line checked.
1277 // Returns true if the current namespace is empty.
1278 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
Eric Liu7956c402016-10-05 15:49:01 +00001279 unsigned CurrentLine, unsigned &NewLine,
1280 std::set<unsigned> &DeletedLines) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001281 unsigned InitLine = CurrentLine, End = AnnotatedLines.size();
Eric Liu635423e2016-04-28 07:52:03 +00001282 if (Style.BraceWrapping.AfterNamespace) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001283 // If the left brace is in a new line, we should consume it first so that
1284 // it does not make the namespace non-empty.
1285 // FIXME: error handling if there is no left brace.
1286 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1287 NewLine = CurrentLine;
1288 return false;
1289 }
1290 } else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1291 return false;
1292 }
1293 while (++CurrentLine < End) {
1294 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1295 break;
1296
1297 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1298 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1299 tok::kw_namespace)) {
Eric Liu7956c402016-10-05 15:49:01 +00001300 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1301 DeletedLines))
Eric Liu4cfb88a2016-04-25 15:09:22 +00001302 return false;
1303 CurrentLine = NewLine;
1304 continue;
1305 }
1306
1307 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1308 continue;
1309
1310 // If there is anything other than comments or nested namespaces in the
1311 // current namespace, the namespace cannot be empty.
1312 NewLine = CurrentLine;
1313 return false;
1314 }
1315
1316 NewLine = CurrentLine;
1317 if (CurrentLine >= End)
1318 return false;
1319
1320 // Check if the empty namespace is actually affected by changed ranges.
1321 if (!AffectedRangeMgr.affectsCharSourceRange(CharSourceRange::getCharRange(
1322 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1323 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1324 return false;
1325
1326 for (unsigned i = InitLine; i <= CurrentLine; ++i) {
1327 DeletedLines.insert(i);
1328 }
1329
1330 return true;
1331 }
1332
Eric Liuce5e4bc2016-05-18 08:02:56 +00001333 // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
1334 // of the token in the pair if the left token has \p LK token kind and the
1335 // right token has \p RK token kind. If \p DeleteLeft is true, the left token
1336 // is deleted on match; otherwise, the right token is deleted.
1337 template <typename LeftKind, typename RightKind>
1338 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1339 bool DeleteLeft) {
1340 auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
1341 for (auto *Res = Tok.Next; Res; Res = Res->Next)
1342 if (!Res->is(tok::comment) &&
1343 DeletedTokens.find(Res) == DeletedTokens.end())
1344 return Res;
1345 return nullptr;
1346 };
1347 for (auto *Left = Start; Left;) {
1348 auto *Right = NextNotDeleted(*Left);
1349 if (!Right)
1350 break;
1351 if (Left->is(LK) && Right->is(RK)) {
1352 deleteToken(DeleteLeft ? Left : Right);
Eric Liu01426ff2016-09-09 17:50:49 +00001353 for (auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1354 deleteToken(Tok);
Eric Liuce5e4bc2016-05-18 08:02:56 +00001355 // If the right token is deleted, we should keep the left token
1356 // unchanged and pair it with the new right token.
1357 if (!DeleteLeft)
1358 continue;
1359 }
1360 Left = Right;
1361 }
1362 }
1363
1364 template <typename LeftKind, typename RightKind>
1365 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1366 cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
1367 }
1368
1369 template <typename LeftKind, typename RightKind>
1370 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1371 cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
1372 }
1373
Eric Liu4cfb88a2016-04-25 15:09:22 +00001374 // Delete the given token.
1375 inline void deleteToken(FormatToken *Tok) {
1376 if (Tok)
1377 DeletedTokens.insert(Tok);
1378 }
1379
1380 tooling::Replacements generateFixes() {
1381 tooling::Replacements Fixes;
1382 std::vector<FormatToken *> Tokens;
1383 std::copy(DeletedTokens.begin(), DeletedTokens.end(),
1384 std::back_inserter(Tokens));
1385
1386 // Merge multiple continuous token deletions into one big deletion so that
1387 // the number of replacements can be reduced. This makes computing affected
1388 // ranges more efficient when we run reformat on the changed code.
1389 unsigned Idx = 0;
1390 while (Idx < Tokens.size()) {
1391 unsigned St = Idx, End = Idx;
1392 while ((End + 1) < Tokens.size() &&
1393 Tokens[End]->Next == Tokens[End + 1]) {
1394 End++;
1395 }
1396 auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
1397 Tokens[End]->Tok.getEndLoc());
Eric Liu40ef2fb2016-08-01 10:16:37 +00001398 auto Err =
1399 Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
1400 // FIXME: better error handling. for now just print error message and skip
1401 // for the release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001402 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001403 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001404 assert(false && "Fixes must not conflict!");
1405 }
Eric Liu4cfb88a2016-04-25 15:09:22 +00001406 Idx = End + 1;
1407 }
1408
1409 return Fixes;
1410 }
1411
1412 // Class for less-than inequality comparason for the set `RedundantTokens`.
1413 // We store tokens in the order they appear in the translation unit so that
1414 // we do not need to sort them in `generateFixes()`.
1415 struct FormatTokenLess {
Eric Liu635423e2016-04-28 07:52:03 +00001416 FormatTokenLess(const SourceManager &SM) : SM(SM) {}
Eric Liu4cfb88a2016-04-25 15:09:22 +00001417
Eric Liu2874ac32016-05-18 08:14:49 +00001418 bool operator()(const FormatToken *LHS, const FormatToken *RHS) const {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001419 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1420 RHS->Tok.getLocation());
1421 }
Eric Liu635423e2016-04-28 07:52:03 +00001422 const SourceManager &SM;
Eric Liu4cfb88a2016-04-25 15:09:22 +00001423 };
1424
1425 // Tokens to be deleted.
1426 std::set<FormatToken *, FormatTokenLess> DeletedTokens;
Daniel Jasperf7935112012-12-03 18:12:45 +00001427};
1428
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001429class ObjCHeaderStyleGuesser : public TokenAnalyzer {
1430public:
1431 ObjCHeaderStyleGuesser(const Environment &Env, const FormatStyle &Style)
1432 : TokenAnalyzer(Env, Style), IsObjC(false) {}
1433
1434 std::pair<tooling::Replacements, unsigned>
1435 analyze(TokenAnnotator &Annotator,
1436 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1437 FormatTokenLexer &Tokens) override {
1438 assert(Style.Language == FormatStyle::LK_Cpp);
1439 IsObjC = guessIsObjC(AnnotatedLines, Tokens.getKeywords());
1440 tooling::Replacements Result;
1441 return {Result, 0};
1442 }
1443
1444 bool isObjC() { return IsObjC; }
1445
1446private:
1447 static bool guessIsObjC(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1448 const AdditionalKeywords &Keywords) {
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001449 // Keep this array sorted, since we are binary searching over it.
1450 static constexpr llvm::StringLiteral FoundationIdentifiers[] = {
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001451 "CGFloat",
Ben Hamilton19c782d2018-03-22 03:25:22 +00001452 "CGPoint",
1453 "CGPointMake",
1454 "CGPointZero",
1455 "CGRect",
1456 "CGRectEdge",
1457 "CGRectInfinite",
1458 "CGRectMake",
1459 "CGRectNull",
1460 "CGRectZero",
1461 "CGSize",
1462 "CGSizeMake",
1463 "CGVector",
1464 "CGVectorMake",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001465 "NSAffineTransform",
1466 "NSArray",
1467 "NSAttributedString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001468 "NSBundle",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001469 "NSCache",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001470 "NSCalendar",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001471 "NSCharacterSet",
1472 "NSCountedSet",
1473 "NSData",
1474 "NSDataDetector",
1475 "NSDecimal",
1476 "NSDecimalNumber",
1477 "NSDictionary",
1478 "NSEdgeInsets",
1479 "NSHashTable",
1480 "NSIndexPath",
1481 "NSIndexSet",
1482 "NSInteger",
1483 "NSLocale",
1484 "NSMapTable",
1485 "NSMutableArray",
1486 "NSMutableAttributedString",
1487 "NSMutableCharacterSet",
1488 "NSMutableData",
1489 "NSMutableDictionary",
1490 "NSMutableIndexSet",
1491 "NSMutableOrderedSet",
1492 "NSMutableSet",
1493 "NSMutableString",
1494 "NSNumber",
1495 "NSNumberFormatter",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001496 "NSObject",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001497 "NSOrderedSet",
1498 "NSPoint",
1499 "NSPointerArray",
1500 "NSRange",
1501 "NSRect",
1502 "NSRegularExpression",
1503 "NSSet",
1504 "NSSize",
1505 "NSString",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001506 "NSTimeZone",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001507 "NSUInteger",
1508 "NSURL",
1509 "NSURLComponents",
1510 "NSURLQueryItem",
1511 "NSUUID",
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001512 "NSValue",
Ben Hamilton19c782d2018-03-22 03:25:22 +00001513 "UIImage",
1514 "UIView",
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001515 };
1516
Ben Hamilton6432afe2018-03-22 17:37:19 +00001517 auto LineContainsObjCCode = [&Keywords](const AnnotatedLine &Line) {
1518 for (const FormatToken *FormatTok = Line.First; FormatTok;
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001519 FormatTok = FormatTok->Next) {
Jacek Olesiakce4f0af2018-02-15 08:47:56 +00001520 if ((FormatTok->Previous && FormatTok->Previous->is(tok::at) &&
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001521 (FormatTok->isObjCAtKeyword(tok::objc_interface) ||
1522 FormatTok->isObjCAtKeyword(tok::objc_implementation) ||
1523 FormatTok->isObjCAtKeyword(tok::objc_protocol) ||
1524 FormatTok->isObjCAtKeyword(tok::objc_end) ||
1525 FormatTok->isOneOf(tok::numeric_constant, tok::l_square,
1526 tok::l_brace))) ||
1527 (FormatTok->Tok.isAnyIdentifier() &&
Krasimir Georgiev8e216782018-01-17 20:01:02 +00001528 std::binary_search(std::begin(FoundationIdentifiers),
1529 std::end(FoundationIdentifiers),
1530 FormatTok->TokenText)) ||
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001531 FormatTok->is(TT_ObjCStringLiteral) ||
1532 FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1533 TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
1534 TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
1535 TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
1536 return true;
1537 }
1538 }
Ben Hamilton6432afe2018-03-22 17:37:19 +00001539 return false;
1540 };
1541 for (auto Line : AnnotatedLines) {
1542 if (LineContainsObjCCode(*Line))
1543 return true;
1544 for (auto ChildLine : Line->Children) {
1545 if (LineContainsObjCCode(*ChildLine))
1546 return true;
1547 }
Ben Hamiltone2e3e672018-01-17 17:33:08 +00001548 }
1549 return false;
1550 }
1551
1552 bool IsObjC;
1553};
1554
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001555struct IncludeDirective {
1556 StringRef Filename;
1557 StringRef Text;
1558 unsigned Offset;
Daniel Jasperd2629dc2015-12-16 10:10:16 +00001559 int Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001560};
1561
Craig Topperaf35e852013-06-30 22:29:28 +00001562} // end anonymous namespace
1563
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001564// Determines whether 'Ranges' intersects with ('Start', 'End').
1565static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
1566 unsigned End) {
1567 for (auto Range : Ranges) {
1568 if (Range.getOffset() < End &&
1569 Range.getOffset() + Range.getLength() > Start)
1570 return true;
1571 }
1572 return false;
1573}
1574
Eric Liua992afe2016-08-10 09:32:23 +00001575// Returns a pair (Index, OffsetToEOL) describing the position of the cursor
1576// before sorting/deduplicating. Index is the index of the include under the
1577// cursor in the original set of includes. If this include has duplicates, it is
1578// the index of the first of the duplicates as the others are going to be
1579// removed. OffsetToEOL describes the cursor's position relative to the end of
1580// its current line.
1581// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
1582static std::pair<unsigned, unsigned>
1583FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
1584 const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
1585 unsigned CursorIndex = UINT_MAX;
1586 unsigned OffsetToEOL = 0;
1587 for (int i = 0, e = Includes.size(); i != e; ++i) {
1588 unsigned Start = Includes[Indices[i]].Offset;
1589 unsigned End = Start + Includes[Indices[i]].Text.size();
1590 if (!(Cursor >= Start && Cursor < End))
1591 continue;
1592 CursorIndex = Indices[i];
1593 OffsetToEOL = End - Cursor;
1594 // Put the cursor on the only remaining #include among the duplicate
1595 // #includes.
1596 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1597 CursorIndex = i;
1598 break;
1599 }
1600 return std::make_pair(CursorIndex, OffsetToEOL);
1601}
1602
1603// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
1604// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
1605// source order.
1606// #include directives with the same text will be deduplicated, and only the
1607// first #include in the duplicate #includes remains. If the `Cursor` is
1608// provided and put on a deleted #include, it will be moved to the remaining
1609// #include in the duplicate #includes.
Martin Probstc4a0dd42016-05-20 11:24:24 +00001610static void sortCppIncludes(const FormatStyle &Style,
Eric Liua992afe2016-08-10 09:32:23 +00001611 const SmallVectorImpl<IncludeDirective> &Includes,
1612 ArrayRef<tooling::Range> Ranges, StringRef FileName,
1613 tooling::Replacements &Replaces, unsigned *Cursor) {
1614 unsigned IncludesBeginOffset = Includes.front().Offset;
Daniel Jasperd6a00782016-08-30 21:33:41 +00001615 unsigned IncludesEndOffset =
1616 Includes.back().Offset + Includes.back().Text.size();
1617 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1618 if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001619 return;
1620 SmallVector<unsigned, 16> Indices;
1621 for (unsigned i = 0, e = Includes.size(); i != e; ++i)
1622 Indices.push_back(i);
Daniel Jasper94a96fc2016-03-03 17:34:14 +00001623 std::stable_sort(
1624 Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
1625 return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
1626 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1627 });
Eric Liua992afe2016-08-10 09:32:23 +00001628 // The index of the include on which the cursor will be put after
1629 // sorting/deduplicating.
1630 unsigned CursorIndex;
1631 // The offset from cursor to the end of line.
1632 unsigned CursorToEOLOffset;
1633 if (Cursor)
1634 std::tie(CursorIndex, CursorToEOLOffset) =
1635 FindCursorIndex(Includes, Indices, *Cursor);
1636
1637 // Deduplicate #includes.
1638 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1639 [&](unsigned LHSI, unsigned RHSI) {
1640 return Includes[LHSI].Text == Includes[RHSI].Text;
1641 }),
1642 Indices.end());
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001643
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001644 int CurrentCategory = Includes.front().Category;
1645
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001646 // If the #includes are out of order, we generate a single replacement fixing
1647 // the entire block. Otherwise, no replacement is generated.
Eric Liua992afe2016-08-10 09:32:23 +00001648 if (Indices.size() == Includes.size() &&
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001649 std::is_sorted(Indices.begin(), Indices.end()) &&
1650 Style.IncludeBlocks == FormatStyle::IBS_Preserve)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001651 return;
1652
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001653 std::string result;
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001654 for (unsigned Index : Indices) {
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001655 if (!result.empty()) {
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001656 result += "\n";
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001657 if (Style.IncludeBlocks == FormatStyle::IBS_Regroup &&
1658 CurrentCategory != Includes[Index].Category)
1659 result += "\n";
1660 }
Daniel Jasperb68aabf2015-11-23 08:36:35 +00001661 result += Includes[Index].Text;
Eric Liua992afe2016-08-10 09:32:23 +00001662 if (Cursor && CursorIndex == Index)
1663 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001664 CurrentCategory = Includes[Index].Category;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001665 }
1666
Eric Liu40ef2fb2016-08-01 10:16:37 +00001667 auto Err = Replaces.add(tooling::Replacement(
Eric Liua992afe2016-08-10 09:32:23 +00001668 FileName, Includes.front().Offset, IncludesBlockSize, result));
Eric Liu40ef2fb2016-08-01 10:16:37 +00001669 // FIXME: better error handling. For now, just skip the replacement for the
1670 // release version.
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001671 if (Err) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00001672 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
Piotr Padlewski1ec383c2016-12-23 11:40:44 +00001673 assert(false);
1674 }
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001675}
1676
Eric Liu659afd52016-05-31 13:34:20 +00001677namespace {
1678
1679// This class manages priorities of #include categories and calculates
1680// priorities for headers.
1681class IncludeCategoryManager {
1682public:
1683 IncludeCategoryManager(const FormatStyle &Style, StringRef FileName)
1684 : Style(Style), FileName(FileName) {
1685 FileStem = llvm::sys::path::stem(FileName);
1686 for (const auto &Category : Style.IncludeCategories)
Chandler Carruthd676ab12017-06-29 23:20:54 +00001687 CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001688 IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
1689 FileName.endswith(".cpp") || FileName.endswith(".c++") ||
1690 FileName.endswith(".cxx") || FileName.endswith(".m") ||
1691 FileName.endswith(".mm");
1692 }
1693
1694 // Returns the priority of the category which \p IncludeName belongs to.
1695 // If \p CheckMainHeader is true and \p IncludeName is a main header, returns
1696 // 0. Otherwise, returns the priority of the matching category or INT_MAX.
1697 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) {
1698 int Ret = INT_MAX;
1699 for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
1700 if (CategoryRegexs[i].match(IncludeName)) {
1701 Ret = Style.IncludeCategories[i].Priority;
1702 break;
1703 }
1704 if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1705 Ret = 0;
1706 return Ret;
1707 }
1708
1709private:
1710 bool isMainHeader(StringRef IncludeName) const {
1711 if (!IncludeName.startswith("\""))
1712 return false;
1713 StringRef HeaderStem =
1714 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
Chandler Carruthd676ab12017-06-29 23:20:54 +00001715 if (FileStem.startswith(HeaderStem) ||
1716 FileStem.startswith_lower(HeaderStem)) {
Eric Liu659afd52016-05-31 13:34:20 +00001717 llvm::Regex MainIncludeRegex(
Chandler Carruthd676ab12017-06-29 23:20:54 +00001718 (HeaderStem + Style.IncludeIsMainRegex).str(),
1719 llvm::Regex::IgnoreCase);
Eric Liu659afd52016-05-31 13:34:20 +00001720 if (MainIncludeRegex.match(FileStem))
1721 return true;
1722 }
1723 return false;
1724 }
1725
1726 const FormatStyle &Style;
1727 bool IsMainFile;
1728 StringRef FileName;
1729 StringRef FileStem;
1730 SmallVector<llvm::Regex, 4> CategoryRegexs;
1731};
1732
1733const char IncludeRegexPattern[] =
1734 R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1735
1736} // anonymous namespace
1737
Martin Probstc4a0dd42016-05-20 11:24:24 +00001738tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1739 ArrayRef<tooling::Range> Ranges,
1740 StringRef FileName,
1741 tooling::Replacements &Replaces,
1742 unsigned *Cursor) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001743 unsigned Prev = 0;
1744 unsigned SearchFrom = 0;
Eric Liu659afd52016-05-31 13:34:20 +00001745 llvm::Regex IncludeRegex(IncludeRegexPattern);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001746 SmallVector<StringRef, 4> Matches;
1747 SmallVector<IncludeDirective, 16> IncludesInBlock;
Daniel Jasper85c472d2015-09-29 07:53:08 +00001748
1749 // In compiled files, consider the first #include to be the main #include of
1750 // the file if it is not a system #include. This ensures that the header
1751 // doesn't have hidden dependencies
1752 // (http://llvm.org/docs/CodingStandards.html#include-style).
1753 //
1754 // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
1755 // cases where the first #include is unlikely to be the main header.
Eric Liu659afd52016-05-31 13:34:20 +00001756 IncludeCategoryManager Categories(Style, FileName);
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001757 bool FirstIncludeBlock = true;
Daniel Jaspera252f5d2015-12-21 17:28:24 +00001758 bool MainIncludeFound = false;
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001759 bool FormattingOff = false;
1760
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001761 for (;;) {
1762 auto Pos = Code.find('\n', SearchFrom);
1763 StringRef Line =
1764 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001765
1766 StringRef Trimmed = Line.trim();
1767 if (Trimmed == "// clang-format off")
1768 FormattingOff = true;
1769 else if (Trimmed == "// clang-format on")
1770 FormattingOff = false;
1771
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001772 const bool EmptyLineSkipped =
1773 Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge ||
1774 Style.IncludeBlocks == FormatStyle::IBS_Regroup);
1775
Daniel Jasper9b8c7c72015-11-21 09:17:08 +00001776 if (!FormattingOff && !Line.endswith("\\")) {
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001777 if (IncludeRegex.match(Line, &Matches)) {
Nico Weberff063702015-10-21 17:13:45 +00001778 StringRef IncludeName = Matches[2];
Eric Liu659afd52016-05-31 13:34:20 +00001779 int Category = Categories.getIncludePriority(
1780 IncludeName,
1781 /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
1782 if (Category == 0)
1783 MainIncludeFound = true;
Nico Weberff063702015-10-21 17:13:45 +00001784 IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
Krasimir Georgiev4c2c9c32017-11-27 13:23:45 +00001785 } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
Martin Probstc4a0dd42016-05-20 11:24:24 +00001786 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1787 Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001788 IncludesInBlock.clear();
Daniel Jasper32d75fa2015-12-21 13:40:49 +00001789 FirstIncludeBlock = false;
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001790 }
1791 Prev = Pos + 1;
1792 }
1793 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1794 break;
1795 SearchFrom = Pos + 1;
1796 }
1797 if (!IncludesInBlock.empty())
Martin Probstc4a0dd42016-05-20 11:24:24 +00001798 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1799 return Replaces;
1800}
1801
Martin Probstfa37b182017-01-27 09:09:11 +00001802bool isMpegTS(StringRef Code) {
1803 // MPEG transport streams use the ".ts" file extension. clang-format should
1804 // not attempt to format those. MPEG TS' frame format starts with 0x47 every
1805 // 189 bytes - detect that and return.
1806 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1807}
1808
Manuel Klimek89628f62017-09-20 09:51:03 +00001809bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
Krasimir Georgieva2e7d0d2017-08-29 13:51:38 +00001810
Martin Probstc4a0dd42016-05-20 11:24:24 +00001811tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
1812 ArrayRef<tooling::Range> Ranges,
1813 StringRef FileName, unsigned *Cursor) {
1814 tooling::Replacements Replaces;
1815 if (!Style.SortIncludes)
1816 return Replaces;
Krasimir Georgiev86873032017-08-29 13:57:31 +00001817 if (isLikelyXml(Code))
1818 return Replaces;
1819 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
1820 isMpegTS(Code))
Martin Probstfa37b182017-01-27 09:09:11 +00001821 return Replaces;
Martin Probstc4a0dd42016-05-20 11:24:24 +00001822 if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
1823 return sortJavaScriptImports(Style, Code, Ranges, FileName);
1824 sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001825 return Replaces;
1826}
1827
Eric Liu4cfb88a2016-04-25 15:09:22 +00001828template <typename T>
Eric Liu4f8d9942016-07-11 13:53:12 +00001829static llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00001830processReplacements(T ProcessFunc, StringRef Code,
1831 const tooling::Replacements &Replaces,
1832 const FormatStyle &Style) {
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001833 if (Replaces.empty())
1834 return tooling::Replacements();
1835
Eric Liu4f8d9942016-07-11 13:53:12 +00001836 auto NewCode = applyAllReplacements(Code, Replaces);
1837 if (!NewCode)
1838 return NewCode.takeError();
Eric Liu40ef2fb2016-08-01 10:16:37 +00001839 std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001840 StringRef FileName = Replaces.begin()->getFilePath();
Eric Liu4cfb88a2016-04-25 15:09:22 +00001841
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001842 tooling::Replacements FormatReplaces =
Eric Liu4f8d9942016-07-11 13:53:12 +00001843 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001844
Eric Liu40ef2fb2016-08-01 10:16:37 +00001845 return Replaces.merge(FormatReplaces);
Manuel Klimekb12e5a52016-03-01 12:37:30 +00001846}
1847
Eric Liu4f8d9942016-07-11 13:53:12 +00001848llvm::Expected<tooling::Replacements>
1849formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
1850 const FormatStyle &Style) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00001851 // We need to use lambda function here since there are two versions of
Eric Liubaf58c22016-05-18 13:43:48 +00001852 // `sortIncludes`.
1853 auto SortIncludes = [](const FormatStyle &Style, StringRef Code,
1854 std::vector<tooling::Range> Ranges,
1855 StringRef FileName) -> tooling::Replacements {
1856 return sortIncludes(Style, Code, Ranges, FileName);
1857 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001858 auto SortedReplaces =
Eric Liubaf58c22016-05-18 13:43:48 +00001859 processReplacements(SortIncludes, Code, Replaces, Style);
Eric Liu4f8d9942016-07-11 13:53:12 +00001860 if (!SortedReplaces)
1861 return SortedReplaces.takeError();
Eric Liubaf58c22016-05-18 13:43:48 +00001862
1863 // We need to use lambda function here since there are two versions of
Eric Liu4cfb88a2016-04-25 15:09:22 +00001864 // `reformat`.
1865 auto Reformat = [](const FormatStyle &Style, StringRef Code,
1866 std::vector<tooling::Range> Ranges,
1867 StringRef FileName) -> tooling::Replacements {
1868 return reformat(Style, Code, Ranges, FileName);
1869 };
Eric Liu4f8d9942016-07-11 13:53:12 +00001870 return processReplacements(Reformat, Code, *SortedReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00001871}
1872
Eric Liu659afd52016-05-31 13:34:20 +00001873namespace {
1874
1875inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
Eric Liuc0d3a802016-09-23 15:10:56 +00001876 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
Eric Liu659afd52016-05-31 13:34:20 +00001877 llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText());
1878}
1879
Eric Liuc0d3a802016-09-23 15:10:56 +00001880inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
1881 return Replace.getOffset() == UINT_MAX && Replace.getLength() == 1;
1882}
1883
Eric Liu964782a2016-12-02 11:01:43 +00001884// Returns the offset after skipping a sequence of tokens, matched by \p
1885// GetOffsetAfterSequence, from the start of the code.
1886// \p GetOffsetAfterSequence should be a function that matches a sequence of
1887// tokens and returns an offset after the sequence.
1888unsigned getOffsetAfterTokenSequence(
1889 StringRef FileName, StringRef Code, const FormatStyle &Style,
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001890 llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
1891 GetOffsetAfterSequence) {
Eric Liu964782a2016-12-02 11:01:43 +00001892 std::unique_ptr<Environment> Env =
1893 Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
1894 const SourceManager &SourceMgr = Env->getSourceManager();
1895 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1896 getFormattingLangOpts(Style));
1897 Token Tok;
1898 // Get the first token.
1899 Lex.LexFromRawLexer(Tok);
Krasimir Georgiev317c5392017-03-08 09:13:25 +00001900 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
Eric Liu35288322016-06-06 11:00:13 +00001901}
1902
1903// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
1904// \p Tok will be the token after this directive; otherwise, it can be any token
1905// after the given \p Tok (including \p Tok).
1906bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
1907 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1908 Tok.is(tok::raw_identifier) &&
1909 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
Eric Liu93459d32016-12-19 10:41:05 +00001910 Tok.is(tok::raw_identifier);
Eric Liu35288322016-06-06 11:00:13 +00001911 if (Matched)
1912 Lex.LexFromRawLexer(Tok);
1913 return Matched;
1914}
1915
Eric Liu964782a2016-12-02 11:01:43 +00001916void skipComments(Lexer &Lex, Token &Tok) {
1917 while (Tok.is(tok::comment))
1918 if (Lex.LexFromRawLexer(Tok))
1919 return;
1920}
1921
1922// Returns the offset after header guard directives and any comments
1923// before/after header guards. If no header guard presents in the code, this
1924// will returns the offset after skipping all comments from the start of the
1925// code.
Eric Liu35288322016-06-06 11:00:13 +00001926unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1927 StringRef Code,
Eric Liu43d67b62016-06-11 11:45:08 +00001928 const FormatStyle &Style) {
Eric Liu964782a2016-12-02 11:01:43 +00001929 return getOffsetAfterTokenSequence(
1930 FileName, Code, Style,
1931 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1932 skipComments(Lex, Tok);
1933 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1934 if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
1935 skipComments(Lex, Tok);
1936 if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
1937 return SM.getFileOffset(Tok.getLocation());
1938 }
1939 return InitialOffset;
1940 });
1941}
1942
1943// Check if a sequence of tokens is like
1944// "#include ("header.h" | <header.h>)".
1945// If it is, \p Tok will be the token after this directive; otherwise, it can be
1946// any token after the given \p Tok (including \p Tok).
1947bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
1948 auto Matched = [&]() {
1949 Lex.LexFromRawLexer(Tok);
1950 return true;
1951 };
1952 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1953 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
1954 if (Lex.LexFromRawLexer(Tok))
1955 return false;
1956 if (Tok.is(tok::string_literal))
1957 return Matched();
1958 if (Tok.is(tok::less)) {
1959 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1960 }
1961 if (Tok.is(tok::greater))
1962 return Matched();
1963 }
Eric Liu35288322016-06-06 11:00:13 +00001964 }
Eric Liu964782a2016-12-02 11:01:43 +00001965 return false;
1966}
1967
1968// Returns the offset of the last #include directive after which a new
1969// #include can be inserted. This ignores #include's after the #include block(s)
1970// in the beginning of a file to avoid inserting headers into code sections
1971// where new #include's should not be added by default.
1972// These code sections include:
1973// - raw string literals (containing #include).
1974// - #if blocks.
1975// - Special #include's among declarations (e.g. functions).
1976//
1977// If no #include after which a new #include can be inserted, this returns the
1978// offset after skipping all comments from the start of the code.
1979// Inserting after an #include is not allowed if it comes after code that is not
1980// #include (e.g. pre-processing directive that is not #include, declarations).
1981unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1982 const FormatStyle &Style) {
1983 return getOffsetAfterTokenSequence(
1984 FileName, Code, Style,
1985 [](const SourceManager &SM, Lexer &Lex, Token Tok) {
1986 skipComments(Lex, Tok);
1987 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1988 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1989 MaxOffset = SM.getFileOffset(Tok.getLocation());
1990 return MaxOffset;
1991 });
Eric Liu35288322016-06-06 11:00:13 +00001992}
1993
Eric Liuc0d3a802016-09-23 15:10:56 +00001994bool isDeletedHeader(llvm::StringRef HeaderName,
Benjamin Kramerebac56e2016-11-24 15:42:29 +00001995 const std::set<llvm::StringRef> &HeadersToDelete) {
1996 return HeadersToDelete.count(HeaderName) ||
1997 HeadersToDelete.count(HeaderName.trim("\"<>"));
Eric Liuc0d3a802016-09-23 15:10:56 +00001998}
1999
Eric Liu659afd52016-05-31 13:34:20 +00002000// FIXME: insert empty lines between newly created blocks.
2001tooling::Replacements
2002fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
2003 const FormatStyle &Style) {
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002004 if (!Style.isCpp())
Eric Liu659afd52016-05-31 13:34:20 +00002005 return Replaces;
2006
2007 tooling::Replacements HeaderInsertions;
Eric Liuc0d3a802016-09-23 15:10:56 +00002008 std::set<llvm::StringRef> HeadersToDelete;
Eric Liu40ef2fb2016-08-01 10:16:37 +00002009 tooling::Replacements Result;
Eric Liu659afd52016-05-31 13:34:20 +00002010 for (const auto &R : Replaces) {
Eric Liu40ef2fb2016-08-01 10:16:37 +00002011 if (isHeaderInsertion(R)) {
2012 // Replacements from \p Replaces must be conflict-free already, so we can
2013 // simply consume the error.
2014 llvm::consumeError(HeaderInsertions.add(R));
Eric Liuc0d3a802016-09-23 15:10:56 +00002015 } else if (isHeaderDeletion(R)) {
2016 HeadersToDelete.insert(R.getReplacementText());
Eric Liu40ef2fb2016-08-01 10:16:37 +00002017 } else if (R.getOffset() == UINT_MAX) {
Eric Liu659afd52016-05-31 13:34:20 +00002018 llvm::errs() << "Insertions other than header #include insertion are "
2019 "not supported! "
2020 << R.getReplacementText() << "\n";
Eric Liu40ef2fb2016-08-01 10:16:37 +00002021 } else {
2022 llvm::consumeError(Result.add(R));
2023 }
Eric Liu659afd52016-05-31 13:34:20 +00002024 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002025 if (HeaderInsertions.empty() && HeadersToDelete.empty())
Eric Liu659afd52016-05-31 13:34:20 +00002026 return Replaces;
Eric Liu659afd52016-05-31 13:34:20 +00002027
2028 llvm::Regex IncludeRegex(IncludeRegexPattern);
2029 llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
2030 SmallVector<StringRef, 4> Matches;
2031
2032 StringRef FileName = Replaces.begin()->getFilePath();
2033 IncludeCategoryManager Categories(Style, FileName);
2034
2035 // Record the offset of the end of the last include in each category.
2036 std::map<int, int> CategoryEndOffsets;
2037 // All possible priorities.
2038 // Add 0 for main header and INT_MAX for headers that are not in any category.
2039 std::set<int> Priorities = {0, INT_MAX};
2040 for (const auto &Category : Style.IncludeCategories)
2041 Priorities.insert(Category.Priority);
2042 int FirstIncludeOffset = -1;
Eric Liu35288322016-06-06 11:00:13 +00002043 // All new headers should be inserted after this offset.
2044 unsigned MinInsertOffset =
2045 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
Eric Liu303baf52016-06-03 12:52:59 +00002046 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
Eric Liu21d10322016-12-09 11:45:50 +00002047 // Max insertion offset in the original code.
Eric Liu964782a2016-12-02 11:01:43 +00002048 unsigned MaxInsertOffset =
Eric Liu21d10322016-12-09 11:45:50 +00002049 MinInsertOffset +
Eric Liu964782a2016-12-02 11:01:43 +00002050 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
Eric Liu659afd52016-05-31 13:34:20 +00002051 SmallVector<StringRef, 32> Lines;
Eric Liu303baf52016-06-03 12:52:59 +00002052 TrimmedCode.split(Lines, '\n');
Eric Liu35288322016-06-06 11:00:13 +00002053 unsigned Offset = MinInsertOffset;
2054 unsigned NextLineOffset;
Eric Liu3753f912016-06-14 14:09:21 +00002055 std::set<StringRef> ExistingIncludes;
Eric Liu659afd52016-05-31 13:34:20 +00002056 for (auto Line : Lines) {
Eric Liu35288322016-06-06 11:00:13 +00002057 NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
Eric Liu659afd52016-05-31 13:34:20 +00002058 if (IncludeRegex.match(Line, &Matches)) {
Eric Liuc0d3a802016-09-23 15:10:56 +00002059 // The header name with quotes or angle brackets.
Eric Liu659afd52016-05-31 13:34:20 +00002060 StringRef IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002061 ExistingIncludes.insert(IncludeName);
Eric Liu964782a2016-12-02 11:01:43 +00002062 // Only record the offset of current #include if we can insert after it.
2063 if (Offset <= MaxInsertOffset) {
2064 int Category = Categories.getIncludePriority(
2065 IncludeName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
2066 CategoryEndOffsets[Category] = NextLineOffset;
2067 if (FirstIncludeOffset < 0)
2068 FirstIncludeOffset = Offset;
2069 }
Eric Liuc0d3a802016-09-23 15:10:56 +00002070 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
2071 // If this is the last line without trailing newline, we need to make
2072 // sure we don't delete across the file boundary.
2073 unsigned Length = std::min(Line.size() + 1, Code.size() - Offset);
2074 llvm::Error Err =
2075 Result.add(tooling::Replacement(FileName, Offset, Length, ""));
2076 if (Err) {
2077 // Ignore the deletion on conflict.
2078 llvm::errs() << "Failed to add header deletion replacement for "
2079 << IncludeName << ": " << llvm::toString(std::move(Err))
2080 << "\n";
2081 }
2082 }
Eric Liu659afd52016-05-31 13:34:20 +00002083 }
Eric Liu35288322016-06-06 11:00:13 +00002084 Offset = NextLineOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002085 }
2086
2087 // Populate CategoryEndOfssets:
2088 // - Ensure that CategoryEndOffset[Highest] is always populated.
2089 // - If CategoryEndOffset[Priority] isn't set, use the next higher value that
2090 // is set, up to CategoryEndOffset[Highest].
Eric Liu659afd52016-05-31 13:34:20 +00002091 auto Highest = Priorities.begin();
2092 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
2093 if (FirstIncludeOffset >= 0)
2094 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
2095 else
Eric Liu303baf52016-06-03 12:52:59 +00002096 CategoryEndOffsets[*Highest] = MinInsertOffset;
Eric Liu659afd52016-05-31 13:34:20 +00002097 }
2098 // By this point, CategoryEndOffset[Highest] is always set appropriately:
2099 // - to an appropriate location before/after existing #includes, or
2100 // - to right after the header guard, or
2101 // - to the beginning of the file.
2102 for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
2103 if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
2104 CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
2105
Eric Liu11a42372016-10-05 15:42:19 +00002106 bool NeedNewLineAtEnd = !Code.empty() && Code.back() != '\n';
Eric Liu659afd52016-05-31 13:34:20 +00002107 for (const auto &R : HeaderInsertions) {
2108 auto IncludeDirective = R.getReplacementText();
2109 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
2110 assert(Matched && "Header insertion replacement must have replacement text "
2111 "'#include ...'");
Benjamin Kramer1cb7ee12016-05-31 14:14:42 +00002112 (void)Matched;
Eric Liu659afd52016-05-31 13:34:20 +00002113 auto IncludeName = Matches[2];
Eric Liu3753f912016-06-14 14:09:21 +00002114 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
2115 DEBUG(llvm::dbgs() << "Skip adding existing include : " << IncludeName
2116 << "\n");
2117 continue;
2118 }
Eric Liu659afd52016-05-31 13:34:20 +00002119 int Category =
2120 Categories.getIncludePriority(IncludeName, /*CheckMainHeader=*/true);
2121 Offset = CategoryEndOffsets[Category];
2122 std::string NewInclude = !IncludeDirective.endswith("\n")
2123 ? (IncludeDirective + "\n").str()
2124 : IncludeDirective.str();
Eric Liu11a42372016-10-05 15:42:19 +00002125 // When inserting headers at end of the code, also append '\n' to the code
2126 // if it does not end with '\n'.
2127 if (NeedNewLineAtEnd && Offset == Code.size()) {
2128 NewInclude = "\n" + NewInclude;
2129 NeedNewLineAtEnd = false;
2130 }
Eric Liu40ef2fb2016-08-01 10:16:37 +00002131 auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
2132 auto Err = Result.add(NewReplace);
2133 if (Err) {
2134 llvm::consumeError(std::move(Err));
Eric Liu11a42372016-10-05 15:42:19 +00002135 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
2136 NewReplace = tooling::Replacement(FileName, NewOffset, 0, NewInclude);
Eric Liu40ef2fb2016-08-01 10:16:37 +00002137 Result = Result.merge(tooling::Replacements(NewReplace));
2138 }
Eric Liu659afd52016-05-31 13:34:20 +00002139 }
2140 return Result;
2141}
2142
2143} // anonymous namespace
2144
Eric Liu4f8d9942016-07-11 13:53:12 +00002145llvm::Expected<tooling::Replacements>
Eric Liu4cfb88a2016-04-25 15:09:22 +00002146cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
2147 const FormatStyle &Style) {
2148 // We need to use lambda function here since there are two versions of
2149 // `cleanup`.
2150 auto Cleanup = [](const FormatStyle &Style, StringRef Code,
2151 std::vector<tooling::Range> Ranges,
2152 StringRef FileName) -> tooling::Replacements {
2153 return cleanup(Style, Code, Ranges, FileName);
2154 };
Eric Liu659afd52016-05-31 13:34:20 +00002155 // Make header insertion replacements insert new headers into correct blocks.
2156 tooling::Replacements NewReplaces =
2157 fixCppIncludeInsertions(Code, Replaces, Style);
2158 return processReplacements(Cleanup, Code, NewReplaces, Style);
Eric Liu4cfb88a2016-04-25 15:09:22 +00002159}
2160
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002161namespace internal {
2162std::pair<tooling::Replacements, unsigned>
2163reformat(const FormatStyle &Style, StringRef Code,
2164 ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
2165 unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
2166 FormattingAttemptStatus *Status) {
Eric Liu4cfb88a2016-04-25 15:09:22 +00002167 FormatStyle Expanded = expandPresets(Style);
2168 if (Expanded.DisableFormat)
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002169 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002170 if (isLikelyXml(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002171 return {tooling::Replacements(), 0};
Krasimir Georgiev86873032017-08-29 13:57:31 +00002172 if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002173 return {tooling::Replacements(), 0};
Daniel Jasper496c1992016-09-07 22:48:53 +00002174
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002175 typedef std::function<std::pair<tooling::Replacements, unsigned>(
2176 const Environment &)>
Krasimir Georgievac16a202017-06-23 11:46:03 +00002177 AnalyzerPass;
2178 SmallVector<AnalyzerPass, 4> Passes;
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002179
Krasimir Georgievac16a202017-06-23 11:46:03 +00002180 if (Style.Language == FormatStyle::LK_Cpp) {
2181 if (Style.FixNamespaceComments)
2182 Passes.emplace_back([&](const Environment &Env) {
2183 return NamespaceEndCommentsFixer(Env, Expanded).process();
2184 });
2185
2186 if (Style.SortUsingDeclarations)
2187 Passes.emplace_back([&](const Environment &Env) {
2188 return UsingDeclarationsSorter(Env, Expanded).process();
2189 });
Krasimir Georgiev32eaa862017-03-01 15:35:39 +00002190 }
2191
2192 if (Style.Language == FormatStyle::LK_JavaScript &&
Krasimir Georgievac16a202017-06-23 11:46:03 +00002193 Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
2194 Passes.emplace_back([&](const Environment &Env) {
2195 return JavaScriptRequoter(Env, Expanded).process();
2196 });
2197
2198 Passes.emplace_back([&](const Environment &Env) {
2199 return Formatter(Env, Expanded, Status).process();
2200 });
2201
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002202 std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
2203 Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
2204 LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002205 llvm::Optional<std::string> CurrentCode = None;
2206 tooling::Replacements Fixes;
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002207 unsigned Penalty = 0;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002208 for (size_t I = 0, E = Passes.size(); I < E; ++I) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002209 std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002210 auto NewCode = applyAllReplacements(
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002211 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002212 if (NewCode) {
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002213 Fixes = Fixes.merge(PassFixes.first);
2214 Penalty += PassFixes.second;
Krasimir Georgievac16a202017-06-23 11:46:03 +00002215 if (I + 1 < E) {
2216 CurrentCode = std::move(*NewCode);
2217 Env = Environment::CreateVirtualEnvironment(
2218 *CurrentCode, FileName,
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002219 tooling::calculateRangesAfterReplacements(Fixes, Ranges),
2220 FirstStartColumn, NextStartColumn, LastStartColumn);
Krasimir Georgievac16a202017-06-23 11:46:03 +00002221 }
2222 }
Daniel Jasper496c1992016-09-07 22:48:53 +00002223 }
2224
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002225 return {Fixes, Penalty};
2226}
2227} // namespace internal
2228
2229tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2230 ArrayRef<tooling::Range> Ranges,
2231 StringRef FileName,
2232 FormattingAttemptStatus *Status) {
2233 return internal::reformat(Style, Code, Ranges,
2234 /*FirstStartColumn=*/0,
2235 /*NextStartColumn=*/0,
2236 /*LastStartColumn=*/0, FileName, Status)
2237 .first;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002238}
2239
Eric Liu4cfb88a2016-04-25 15:09:22 +00002240tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
2241 ArrayRef<tooling::Range> Ranges,
2242 StringRef FileName) {
Martin Probst816a9662017-05-29 08:41:11 +00002243 // cleanups only apply to C++ (they mostly concern ctor commas etc.)
2244 if (Style.Language != FormatStyle::LK_Cpp)
2245 return tooling::Replacements();
Eric Liu4cfb88a2016-04-25 15:09:22 +00002246 std::unique_ptr<Environment> Env =
Eric Liu635423e2016-04-28 07:52:03 +00002247 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2248 Cleaner Clean(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002249 return Clean.process().first;
Daniel Jasperec04c0d2013-05-16 10:40:07 +00002250}
2251
Krasimir Georgievbcda54b2017-04-21 14:35:20 +00002252tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
2253 ArrayRef<tooling::Range> Ranges,
2254 StringRef FileName, bool *IncompleteFormat) {
2255 FormattingAttemptStatus Status;
2256 auto Result = reformat(Style, Code, Ranges, FileName, &Status);
2257 if (!Status.FormatComplete)
2258 *IncompleteFormat = true;
2259 return Result;
2260}
2261
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002262tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
2263 StringRef Code,
2264 ArrayRef<tooling::Range> Ranges,
2265 StringRef FileName) {
2266 std::unique_ptr<Environment> Env =
2267 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2268 NamespaceEndCommentsFixer Fix(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002269 return Fix.process().first;
Krasimir Georgiev7cb267a2017-02-27 13:28:36 +00002270}
2271
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002272tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
2273 StringRef Code,
2274 ArrayRef<tooling::Range> Ranges,
2275 StringRef FileName) {
2276 std::unique_ptr<Environment> Env =
2277 Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
2278 UsingDeclarationsSorter Sorter(*Env, Style);
Krasimir Georgiev9ad83fe2017-10-30 14:01:50 +00002279 return Sorter.process().first;
Krasimir Georgievb03877a2017-06-21 12:03:12 +00002280}
2281
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002282LangOptions getFormattingLangOpts(const FormatStyle &Style) {
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002283 LangOptions LangOpts;
2284 LangOpts.CPlusPlus = 1;
Daniel Jasper4db69bd2014-09-04 18:23:42 +00002285 LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
2286 LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Aaron Ballmanc351fba2017-12-04 20:27:34 +00002287 LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Richard Smithc70f1d62017-12-14 15:16:18 +00002288 LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
Daniel Jasper55213652013-03-22 10:01:29 +00002289 LangOpts.LineComment = 1;
Daniel Jasper1dbc2102017-03-31 13:30:24 +00002290 bool AlternativeOperators = Style.isCpp();
Daniel Jasper30a24062014-11-14 09:02:28 +00002291 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002292 LangOpts.Bool = 1;
2293 LangOpts.ObjC1 = 1;
2294 LangOpts.ObjC2 = 1;
Eric Liu4cfb88a2016-04-25 15:09:22 +00002295 LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Saleem Abdulrasoold170c4b2015-10-04 17:51:05 +00002296 LangOpts.DeclSpecKeyword = 1; // To get __declspec.
Daniel Jasperc1fa2812013-01-10 13:08:12 +00002297 return LangOpts;
2298}
2299
Edwin Vaned544aa72013-09-30 13:31:48 +00002300const char *StyleOptionHelpDescription =
2301 "Coding style, currently supports:\n"
2302 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2303 "Use -style=file to load style configuration from\n"
2304 ".clang-format file located in one of the parent\n"
2305 "directories of the source file (or current\n"
2306 "directory for stdin).\n"
2307 "Use -style=\"{key: value, ...}\" to set specific\n"
2308 "parameters, e.g.:\n"
2309 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2310
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002311static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
Daniel Jasper498f5582015-12-25 08:53:31 +00002312 if (FileName.endswith(".java"))
Daniel Jasperc58c70e2014-09-15 11:21:46 +00002313 return FormatStyle::LK_Java;
Daniel Jasper498f5582015-12-25 08:53:31 +00002314 if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
2315 return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002316 if (FileName.endswith(".m") || FileName.endswith(".mm"))
2317 return FormatStyle::LK_ObjC;
Daniel Jasper498f5582015-12-25 08:53:31 +00002318 if (FileName.endswith_lower(".proto") ||
2319 FileName.endswith_lower(".protodevel"))
Daniel Jasper7052ce62014-01-19 09:04:08 +00002320 return FormatStyle::LK_Proto;
Krasimir Georgiev66496652017-11-17 15:10:49 +00002321 if (FileName.endswith_lower(".textpb") ||
2322 FileName.endswith_lower(".pb.txt") ||
2323 FileName.endswith_lower(".textproto") ||
2324 FileName.endswith_lower(".asciipb"))
2325 return FormatStyle::LK_TextProto;
Daniel Jasper498f5582015-12-25 08:53:31 +00002326 if (FileName.endswith_lower(".td"))
2327 return FormatStyle::LK_TableGen;
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002328 return FormatStyle::LK_Cpp;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002329}
2330
Ben Hamilton3b345c32018-02-21 15:54:31 +00002331FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
Ben Hamilton6e066352018-02-27 15:56:40 +00002332 const auto GuessedLanguage = getLanguageByFileName(FileName);
2333 if (GuessedLanguage == FormatStyle::LK_Cpp) {
Ben Hamilton07e58362018-02-21 21:27:27 +00002334 auto Extension = llvm::sys::path::extension(FileName);
Ben Hamilton3b345c32018-02-21 15:54:31 +00002335 // If there's no file extension (or it's .h), we need to check the contents
2336 // of the code to see if it contains Objective-C.
Ben Hamilton07e58362018-02-21 21:27:27 +00002337 if (Extension.empty() || Extension == ".h") {
2338 auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002339 std::unique_ptr<Environment> Env =
Ben Hamilton07e58362018-02-21 21:27:27 +00002340 Environment::CreateVirtualEnvironment(Code, NonEmptyFileName, /*Ranges=*/{});
Ben Hamilton3b345c32018-02-21 15:54:31 +00002341 ObjCHeaderStyleGuesser Guesser(*Env, getLLVMStyle());
2342 Guesser.process();
Ben Hamilton6e066352018-02-27 15:56:40 +00002343 if (Guesser.isObjC())
2344 return FormatStyle::LK_ObjC;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002345 }
2346 }
Ben Hamilton6e066352018-02-27 15:56:40 +00002347 return GuessedLanguage;
Ben Hamilton3b345c32018-02-21 15:54:31 +00002348}
2349
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002350llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002351 StringRef FallbackStyleName,
2352 StringRef Code, vfs::FileSystem *FS) {
Eric Liu547d8792016-03-24 13:22:42 +00002353 if (!FS) {
2354 FS = vfs::getRealFileSystem().get();
2355 }
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002356 FormatStyle Style = getLLVMStyle();
Ben Hamilton3b345c32018-02-21 15:54:31 +00002357 Style.Language = guessLanguage(FileName, Code);
Daniel Jasper03a04fe2016-12-12 12:42:29 +00002358
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002359 FormatStyle FallbackStyle = getNoStyle();
2360 if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
2361 return make_string_error("Invalid fallback style \"" + FallbackStyleName);
Edwin Vaned544aa72013-09-30 13:31:48 +00002362
2363 if (StyleName.startswith("{")) {
2364 // Parse YAML/JSON style from the command line.
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002365 if (std::error_code ec = parseConfiguration(StyleName, &Style))
2366 return make_string_error("Error parsing -style: " + ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002367 return Style;
2368 }
2369
2370 if (!StyleName.equals_lower("file")) {
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002371 if (!getPredefinedStyle(StyleName, Style.Language, &Style))
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002372 return make_string_error("Invalid value for -style");
Edwin Vaned544aa72013-09-30 13:31:48 +00002373 return Style;
2374 }
2375
Alexander Kornienkoc1637f12013-12-10 11:28:13 +00002376 // Look for .clang-format/_clang-format file in the file's parent directories.
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002377 SmallString<128> UnsuitableConfigFiles;
Edwin Vaned544aa72013-09-30 13:31:48 +00002378 SmallString<128> Path(FileName);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002379 if (std::error_code EC = FS->makeAbsolute(Path))
2380 return make_string_error(EC.message());
Antonio Maiorano34c03762016-12-22 05:10:07 +00002381
Alexander Kornienkoe2e03872013-10-14 00:46:35 +00002382 for (StringRef Directory = Path; !Directory.empty();
Edwin Vaned544aa72013-09-30 13:31:48 +00002383 Directory = llvm::sys::path::parent_path(Directory)) {
Eric Liu547d8792016-03-24 13:22:42 +00002384
2385 auto Status = FS->status(Directory);
2386 if (!Status ||
2387 Status->getType() != llvm::sys::fs::file_type::directory_file) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002388 continue;
Eric Liu547d8792016-03-24 13:22:42 +00002389 }
2390
Edwin Vaned544aa72013-09-30 13:31:48 +00002391 SmallString<128> ConfigFile(Directory);
2392
2393 llvm::sys::path::append(ConfigFile, ".clang-format");
2394 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liud4758322016-03-24 13:22:37 +00002395
Eric Liu547d8792016-03-24 13:22:42 +00002396 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002397 bool FoundConfigFile =
Eric Liu547d8792016-03-24 13:22:42 +00002398 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002399 if (!FoundConfigFile) {
Edwin Vaned544aa72013-09-30 13:31:48 +00002400 // Try _clang-format too, since dotfiles are not commonly used on Windows.
2401 ConfigFile = Directory;
2402 llvm::sys::path::append(ConfigFile, "_clang-format");
2403 DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Eric Liu547d8792016-03-24 13:22:42 +00002404 Status = FS->status(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002405 FoundConfigFile = Status && (Status->getType() ==
2406 llvm::sys::fs::file_type::regular_file);
Edwin Vaned544aa72013-09-30 13:31:48 +00002407 }
2408
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002409 if (FoundConfigFile) {
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002410 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
Eric Liu547d8792016-03-24 13:22:42 +00002411 FS->getBufferForFile(ConfigFile.str());
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002412 if (std::error_code EC = Text.getError())
2413 return make_string_error(EC.message());
Rafael Espindola2d2b4202014-07-06 17:43:24 +00002414 if (std::error_code ec =
2415 parseConfiguration(Text.get()->getBuffer(), &Style)) {
Rafael Espindolad0136702014-06-12 02:50:04 +00002416 if (ec == ParseError::Unsuitable) {
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002417 if (!UnsuitableConfigFiles.empty())
2418 UnsuitableConfigFiles.append(", ");
2419 UnsuitableConfigFiles.append(ConfigFile);
Alexander Kornienkobc4ae442013-12-02 15:21:38 +00002420 continue;
Alexander Kornienkocabdd732013-11-29 15:19:43 +00002421 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002422 return make_string_error("Error reading " + ConfigFile + ": " +
2423 ec.message());
Edwin Vaned544aa72013-09-30 13:31:48 +00002424 }
2425 DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
2426 return Style;
2427 }
2428 }
Antonio Maiorano3adfb6a2017-01-17 00:12:27 +00002429 if (!UnsuitableConfigFiles.empty())
2430 return make_string_error("Configuration file(s) do(es) not support " +
2431 getLanguageName(Style.Language) + ": " +
2432 UnsuitableConfigFiles);
Antonio Maiorano7eb75072017-01-20 01:22:42 +00002433 return FallbackStyle;
Edwin Vaned544aa72013-09-30 13:31:48 +00002434}
2435
Daniel Jasper8d1832e2013-01-07 13:26:07 +00002436} // namespace format
2437} // namespace clang