26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/Support/Allocator.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/Regex.h"
31 #include "llvm/Support/YAMLTraits.h"
35 #define DEBUG_TYPE "format-formatter"
39 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
40 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::
FormatStyle::IncludeCategory)
44 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageKind> {
46 IO.enumCase(Value,
"Cpp", FormatStyle::LK_Cpp);
47 IO.enumCase(Value,
"Java", FormatStyle::LK_Java);
48 IO.enumCase(Value,
"JavaScript", FormatStyle::LK_JavaScript);
49 IO.enumCase(Value,
"Proto", FormatStyle::LK_Proto);
50 IO.enumCase(Value,
"TableGen", FormatStyle::LK_TableGen);
54 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageStandard> {
56 IO.enumCase(Value,
"Cpp03", FormatStyle::LS_Cpp03);
57 IO.enumCase(Value,
"C++03", FormatStyle::LS_Cpp03);
58 IO.enumCase(Value,
"Cpp11", FormatStyle::LS_Cpp11);
59 IO.enumCase(Value,
"C++11", FormatStyle::LS_Cpp11);
60 IO.enumCase(Value,
"Auto", FormatStyle::LS_Auto);
64 template <>
struct ScalarEnumerationTraits<
FormatStyle::UseTabStyle> {
66 IO.enumCase(Value,
"Never", FormatStyle::UT_Never);
67 IO.enumCase(Value,
"false", FormatStyle::UT_Never);
68 IO.enumCase(Value,
"Always", FormatStyle::UT_Always);
69 IO.enumCase(Value,
"true", FormatStyle::UT_Always);
70 IO.enumCase(Value,
"ForIndentation", FormatStyle::UT_ForIndentation);
74 template <>
struct ScalarEnumerationTraits<
FormatStyle::ShortFunctionStyle> {
76 IO.enumCase(Value,
"None", FormatStyle::SFS_None);
77 IO.enumCase(Value,
"false", FormatStyle::SFS_None);
78 IO.enumCase(Value,
"All", FormatStyle::SFS_All);
79 IO.enumCase(Value,
"true", FormatStyle::SFS_All);
80 IO.enumCase(Value,
"Inline", FormatStyle::SFS_Inline);
81 IO.enumCase(Value,
"Empty", FormatStyle::SFS_Empty);
85 template <>
struct ScalarEnumerationTraits<
FormatStyle::BinaryOperatorStyle> {
87 IO.enumCase(Value,
"All", FormatStyle::BOS_All);
88 IO.enumCase(Value,
"true", FormatStyle::BOS_All);
89 IO.enumCase(Value,
"None", FormatStyle::BOS_None);
90 IO.enumCase(Value,
"false", FormatStyle::BOS_None);
91 IO.enumCase(Value,
"NonAssignment", FormatStyle::BOS_NonAssignment);
95 template <>
struct ScalarEnumerationTraits<
FormatStyle::BraceBreakingStyle> {
97 IO.enumCase(Value,
"Attach", FormatStyle::BS_Attach);
98 IO.enumCase(Value,
"Linux", FormatStyle::BS_Linux);
99 IO.enumCase(Value,
"Mozilla", FormatStyle::BS_Mozilla);
100 IO.enumCase(Value,
"Stroustrup", FormatStyle::BS_Stroustrup);
101 IO.enumCase(Value,
"Allman", FormatStyle::BS_Allman);
102 IO.enumCase(Value,
"GNU", FormatStyle::BS_GNU);
103 IO.enumCase(Value,
"WebKit", FormatStyle::BS_WebKit);
104 IO.enumCase(Value,
"Custom", FormatStyle::BS_Custom);
109 struct ScalarEnumerationTraits<
FormatStyle::ReturnTypeBreakingStyle> {
111 IO.enumCase(Value,
"None", FormatStyle::RTBS_None);
112 IO.enumCase(Value,
"All", FormatStyle::RTBS_All);
113 IO.enumCase(Value,
"TopLevel", FormatStyle::RTBS_TopLevel);
114 IO.enumCase(Value,
"TopLevelDefinitions",
115 FormatStyle::RTBS_TopLevelDefinitions);
116 IO.enumCase(Value,
"AllDefinitions", FormatStyle::RTBS_AllDefinitions);
121 struct ScalarEnumerationTraits<
FormatStyle::DefinitionReturnTypeBreakingStyle> {
124 IO.enumCase(Value,
"None", FormatStyle::DRTBS_None);
125 IO.enumCase(Value,
"All", FormatStyle::DRTBS_All);
126 IO.enumCase(Value,
"TopLevel", FormatStyle::DRTBS_TopLevel);
129 IO.enumCase(Value,
"false", FormatStyle::DRTBS_None);
130 IO.enumCase(Value,
"true", FormatStyle::DRTBS_All);
135 struct ScalarEnumerationTraits<
FormatStyle::NamespaceIndentationKind> {
137 FormatStyle::NamespaceIndentationKind &
Value) {
138 IO.enumCase(Value,
"None", FormatStyle::NI_None);
139 IO.enumCase(Value,
"Inner", FormatStyle::NI_Inner);
140 IO.enumCase(Value,
"All", FormatStyle::NI_All);
144 template <>
struct ScalarEnumerationTraits<
FormatStyle::BracketAlignmentStyle> {
146 IO.enumCase(Value,
"Align", FormatStyle::BAS_Align);
147 IO.enumCase(Value,
"DontAlign", FormatStyle::BAS_DontAlign);
148 IO.enumCase(Value,
"AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
151 IO.enumCase(Value,
"true", FormatStyle::BAS_Align);
152 IO.enumCase(Value,
"false", FormatStyle::BAS_DontAlign);
156 template <>
struct ScalarEnumerationTraits<
FormatStyle::PointerAlignmentStyle> {
158 IO.enumCase(Value,
"Middle", FormatStyle::PAS_Middle);
159 IO.enumCase(Value,
"Left", FormatStyle::PAS_Left);
160 IO.enumCase(Value,
"Right", FormatStyle::PAS_Right);
163 IO.enumCase(Value,
"true", FormatStyle::PAS_Left);
164 IO.enumCase(Value,
"false", FormatStyle::PAS_Right);
169 struct ScalarEnumerationTraits<
FormatStyle::SpaceBeforeParensOptions> {
171 FormatStyle::SpaceBeforeParensOptions &
Value) {
172 IO.enumCase(Value,
"Never", FormatStyle::SBPO_Never);
173 IO.enumCase(Value,
"ControlStatements",
174 FormatStyle::SBPO_ControlStatements);
175 IO.enumCase(Value,
"Always", FormatStyle::SBPO_Always);
178 IO.enumCase(Value,
"false", FormatStyle::SBPO_Never);
179 IO.enumCase(Value,
"true", FormatStyle::SBPO_ControlStatements);
186 IO.mapOptional(
"Language", Style.
Language);
188 if (IO.outputting()) {
189 StringRef StylesArray[] = {
"LLVM",
"Google",
"Chromium",
190 "Mozilla",
"WebKit",
"GNU"};
192 for (
size_t i = 0, e = Styles.size(); i < e; ++i) {
193 StringRef StyleName(Styles[i]);
196 Style == PredefinedStyle) {
197 IO.mapOptional(
"# BasedOnStyle", StyleName);
202 StringRef BasedOnStyle;
203 IO.mapOptional(
"BasedOnStyle", BasedOnStyle);
204 if (!BasedOnStyle.empty()) {
205 FormatStyle::LanguageKind OldLanguage = Style.
Language;
206 FormatStyle::LanguageKind Language =
209 IO.setError(Twine(
"Unknown value for BasedOnStyle: ", BasedOnStyle));
217 if (!IO.outputting()) {
219 IO.mapOptional(
"IndentFunctionDeclarationAfterType",
222 IO.mapOptional(
"SpaceAfterControlStatementKeyword",
228 IO.mapOptional(
"AlignConsecutiveAssignments",
230 IO.mapOptional(
"AlignConsecutiveDeclarations",
235 IO.mapOptional(
"AllowAllParametersOfDeclarationOnNextLine",
237 IO.mapOptional(
"AllowShortBlocksOnASingleLine",
239 IO.mapOptional(
"AllowShortCaseLabelsOnASingleLine",
241 IO.mapOptional(
"AllowShortFunctionsOnASingleLine",
243 IO.mapOptional(
"AllowShortIfStatementsOnASingleLine",
245 IO.mapOptional(
"AllowShortLoopsOnASingleLine",
247 IO.mapOptional(
"AlwaysBreakAfterDefinitionReturnType",
249 IO.mapOptional(
"AlwaysBreakAfterReturnType",
259 FormatStyle::DRTBS_TopLevel)
261 FormatStyle::RTBS_TopLevelDefinitions;
264 IO.mapOptional(
"AlwaysBreakBeforeMultilineStrings",
266 IO.mapOptional(
"AlwaysBreakTemplateDeclarations",
271 IO.mapOptional(
"BreakBeforeBinaryOperators",
274 IO.mapOptional(
"BreakBeforeTernaryOperators",
276 IO.mapOptional(
"BreakConstructorInitializersBeforeComma",
280 IO.mapOptional(
"ConstructorInitializerAllOnOneLineOrOnePerLine",
282 IO.mapOptional(
"ConstructorInitializerIndentWidth",
288 IO.mapOptional(
"ExperimentalAutoDetectBinPacking",
294 IO.mapOptional(
"IndentWrappedFunctionNames",
296 IO.mapOptional(
"KeepEmptyLinesAtTheStartOfBlocks",
304 IO.mapOptional(
"ObjCSpaceBeforeProtocolList",
306 IO.mapOptional(
"PenaltyBreakBeforeFirstCallParameter",
309 IO.mapOptional(
"PenaltyBreakFirstLessLess",
313 IO.mapOptional(
"PenaltyReturnTypeOnItsOwnLine",
319 IO.mapOptional(
"SpaceBeforeAssignmentOperators",
323 IO.mapOptional(
"SpacesBeforeTrailingComments",
326 IO.mapOptional(
"SpacesInContainerLiterals",
328 IO.mapOptional(
"SpacesInCStyleCastParentheses",
332 IO.mapOptional(
"Standard", Style.
Standard);
333 IO.mapOptional(
"TabWidth", Style.
TabWidth);
334 IO.mapOptional(
"UseTab", Style.
UseTab);
338 template <>
struct MappingTraits<
FormatStyle::BraceWrappingFlags> {
339 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
340 IO.mapOptional(
"AfterClass", Wrapping.AfterClass);
341 IO.mapOptional(
"AfterControlStatement", Wrapping.AfterControlStatement);
342 IO.mapOptional(
"AfterEnum", Wrapping.AfterEnum);
343 IO.mapOptional(
"AfterFunction", Wrapping.AfterFunction);
344 IO.mapOptional(
"AfterNamespace", Wrapping.AfterNamespace);
345 IO.mapOptional(
"AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
346 IO.mapOptional(
"AfterStruct", Wrapping.AfterStruct);
347 IO.mapOptional(
"AfterUnion", Wrapping.AfterUnion);
348 IO.mapOptional(
"BeforeCatch", Wrapping.BeforeCatch);
349 IO.mapOptional(
"BeforeElse", Wrapping.BeforeElse);
350 IO.mapOptional(
"IndentBraces", Wrapping.IndentBraces);
356 IO.mapOptional(
"Regex", Category.Regex);
357 IO.mapOptional(
"Priority", Category.Priority);
366 template <>
struct DocumentListTraits<std::vector<FormatStyle>> {
367 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
372 if (Index >= Seq.size()) {
373 assert(Index == Seq.size());
375 if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
378 Template = *((
const FormatStyle *)IO.getContext());
379 Template.
Language = FormatStyle::LK_None;
381 Seq.resize(Index + 1, Template);
401 return "clang-format.parse_error";
405 switch (static_cast<ParseError>(EV)) {
409 return "Invalid argument";
413 llvm_unreachable(
"unexpected parse error");
420 Expanded.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
421 false,
false,
false,
false,
false};
452 Expanded.
BraceWrapping = {
true,
true,
true,
true,
true,
true,
453 true,
true,
true,
true,
true};
489 LLVMStyle.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
490 false,
false,
false,
false,
false};
505 {
"^(<|\"(gtest|isl|json)/)", 3},
613 return ChromiumStyle;
681 if (Name.equals_lower(
"llvm")) {
683 }
else if (Name.equals_lower(
"chromium")) {
685 }
else if (Name.equals_lower(
"mozilla")) {
687 }
else if (Name.equals_lower(
"google")) {
689 }
else if (Name.equals_lower(
"webkit")) {
691 }
else if (Name.equals_lower(
"gnu")) {
693 }
else if (Name.equals_lower(
"none")) {
707 if (Text.trim().empty())
710 std::vector<FormatStyle> Styles;
716 Input.setContext(Style);
719 return Input.error();
721 for (
unsigned i = 0; i < Styles.size(); ++i) {
726 for (
unsigned j = 0; j < i; ++j) {
727 if (Styles[i].Language == Styles[j].Language) {
729 <<
"Duplicate languages in the config file on positions " << j
730 <<
" and " << i <<
"\n");
738 for (
int i = Styles.size() - 1; i >= 0; --i) {
739 if (Styles[i].Language == Language ||
751 llvm::raw_string_ostream Stream(Text);
752 llvm::yaml::Output Output(Stream);
756 Output << NonConstStyle;
762 class FormatTokenLexer {
768 SourceMgr(SourceMgr), ID(ID), Style(Style),
775 Lex->SetKeepWhitespaceMode(
true);
782 ArrayRef<FormatToken *> lex() {
786 Tokens.push_back(getNextToken());
788 tryParseJSRegexLiteral();
789 tryMergePreviousTokens();
790 if (
Tokens.back()->NewlinesBefore > 0 ||
Tokens.back()->IsMultiline)
796 const AdditionalKeywords &getKeywords() {
return Keywords; }
799 void tryMergePreviousTokens() {
800 if (tryMerge_TMacro())
802 if (tryMergeConflictMarkers())
804 if (tryMergeLessLess())
808 if (tryMergeTemplateString())
811 static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
814 static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
816 static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
818 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
820 if (tryMergeTokens(JSNotIdentity, TT_BinaryOperator))
822 if (tryMergeTokens(JSShiftEqual, TT_BinaryOperator))
824 if (tryMergeTokens(JSRightArrow, TT_JsFatArrow))
829 bool tryMergeLessLess() {
834 bool FourthTokenIsLess =
false;
836 FourthTokenIsLess = (
Tokens.end() - 4)[0]->is(tok::less);
838 auto First =
Tokens.end() - 3;
839 if (First[2]->is(tok::less) || First[1]->isNot(tok::less) ||
840 First[0]->isNot(tok::less) || FourthTokenIsLess)
844 if (First[1]->WhitespaceRange.getBegin() !=
845 First[1]->WhitespaceRange.getEnd())
848 First[0]->Tok.setKind(tok::lessless);
849 First[0]->TokenText =
"<<";
850 First[0]->ColumnWidth += 1;
855 bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
TokenType NewType) {
856 if (
Tokens.size() < Kinds.size())
859 SmallVectorImpl<FormatToken *>::const_iterator First =
860 Tokens.end() - Kinds.size();
861 if (!First[0]->is(Kinds[0]))
863 unsigned AddLength = 0;
864 for (
unsigned i = 1; i < Kinds.size(); ++i) {
865 if (!First[i]->is(Kinds[i]) ||
866 First[i]->WhitespaceRange.getBegin() !=
867 First[i]->WhitespaceRange.getEnd())
869 AddLength += First[i]->TokenText.size();
872 First[0]->TokenText = StringRef(First[0]->TokenText.data(),
873 First[0]->TokenText.size() + AddLength);
874 First[0]->ColumnWidth += AddLength;
875 First[0]->Type = NewType;
880 bool precedesOperand(FormatToken *Tok) {
884 return Tok->isOneOf(tok::period, tok::l_paren, tok::comma, tok::l_brace,
885 tok::r_brace, tok::l_square, tok::semi, tok::exclaim,
886 tok::colon, tok::question, tok::tilde) ||
887 Tok->isOneOf(tok::kw_return, tok::kw_do, tok::kw_case, tok::kw_throw,
888 tok::kw_else, tok::kw_new, tok::kw_delete, tok::kw_void,
889 tok::kw_typeof,
Keywords.kw_instanceof,
891 Tok->isBinaryOperator();
894 bool canPrecedeRegexLiteral(FormatToken *Prev) {
902 if (Prev->isOneOf(tok::plusplus, tok::minusminus))
907 if (!precedesOperand(Prev))
917 void tryParseJSRegexLiteral() {
918 FormatToken *RegexToken =
Tokens.back();
919 if (!RegexToken->isOneOf(tok::slash, tok::slashequal))
922 FormatToken *Prev =
nullptr;
926 if ((*I)->isNot(tok::comment)) {
932 if (!canPrecedeRegexLiteral(Prev))
936 const char *
Offset =
Lex->getBufferLocation();
937 const char *RegexBegin = Offset - RegexToken->TokenText.size();
939 bool InCharacterClass =
false;
940 bool HaveClosingSlash =
false;
941 for (; !HaveClosingSlash && Offset != Buffer.end(); ++
Offset) {
951 InCharacterClass =
true;
954 InCharacterClass =
false;
957 if (!InCharacterClass)
958 HaveClosingSlash =
true;
963 RegexToken->Type = TT_RegexLiteral;
965 RegexToken->Tok.setKind(tok::string_literal);
966 RegexToken->TokenText = StringRef(RegexBegin, Offset - RegexBegin);
967 RegexToken->ColumnWidth = RegexToken->TokenText.size();
972 bool tryMergeTemplateString() {
976 FormatToken *EndBacktick =
Tokens.back();
980 if (!EndBacktick->isOneOf(tok::comment, tok::string_literal,
981 tok::char_constant, tok::unknown))
983 size_t CommentBacktickPos = EndBacktick->TokenText.find(
'`');
986 if (CommentBacktickPos == StringRef::npos)
989 unsigned TokenCount = 0;
990 bool IsMultiline =
false;
991 unsigned EndColumnInFirstLine =
992 EndBacktick->OriginalColumn + EndBacktick->ColumnWidth;
995 if (
I[0]->IsMultiline)
1000 if (
I[0]->is(TT_TemplateString))
1003 if (
I[0]->isNot(tok::unknown) ||
I[0]->TokenText !=
"`") {
1007 if (
I[0]->IsMultiline)
1008 EndColumnInFirstLine =
I[0]->OriginalColumn +
I[0]->ColumnWidth;
1011 if (
I[0]->NewlinesBefore > 0 && (
I + 1 !=
E)) {
1012 EndColumnInFirstLine =
I[1]->OriginalColumn +
I[1]->ColumnWidth;
1019 Tokens.back()->Type = TT_TemplateString;
1020 const char *EndOffset =
1021 EndBacktick->TokenText.data() + 1 + CommentBacktickPos;
1022 if (CommentBacktickPos != 0) {
1025 SourceLocation Loc = EndBacktick->Tok.getLocation();
1026 resetLexer(SourceMgr.
getFileOffset(Loc) + CommentBacktickPos + 1);
1028 Tokens.back()->TokenText =
1029 StringRef(
Tokens.back()->TokenText.data(),
1030 EndOffset -
Tokens.back()->TokenText.data());
1032 unsigned EndOriginalColumn = EndBacktick->OriginalColumn;
1033 if (EndOriginalColumn == 0) {
1034 SourceLocation Loc = EndBacktick->Tok.getLocation();
1038 EndOriginalColumn += CommentBacktickPos;
1045 Tokens.back()->ColumnWidth =
1046 EndColumnInFirstLine -
Tokens.back()->OriginalColumn;
1048 Tokens.back()->LastLineColumnWidth = EndOriginalColumn + 1;
1049 Tokens.back()->IsMultiline =
true;
1052 Tokens.back()->ColumnWidth =
1053 EndOriginalColumn -
Tokens.back()->OriginalColumn + 1;
1060 bool tryMerge_TMacro() {
1064 if (!Last->is(tok::r_paren))
1068 if (!String->is(tok::string_literal) || String->IsMultiline)
1075 if (Macro->TokenText !=
"_T")
1078 const char *Start = Macro->TokenText.data();
1079 const char *
End = Last->TokenText.data() + Last->TokenText.size();
1080 String->TokenText = StringRef(Start, End - Start);
1081 String->IsFirst = Macro->IsFirst;
1082 String->LastNewlineOffset = Macro->LastNewlineOffset;
1083 String->WhitespaceRange = Macro->WhitespaceRange;
1084 String->OriginalColumn = Macro->OriginalColumn;
1086 String->TokenText, String->OriginalColumn, Style.
TabWidth, Encoding);
1087 String->NewlinesBefore = Macro->NewlinesBefore;
1088 String->HasUnescapedNewline = Macro->HasUnescapedNewline;
1097 bool tryMergeConflictMarkers() {
1112 unsigned FirstInLineOffset;
1115 StringRef Buffer = SourceMgr.
getBuffer(ID)->getBuffer();
1117 auto LineOffset = Buffer.rfind(
'\n', FirstInLineOffset);
1118 if (LineOffset == StringRef::npos) {
1124 auto FirstSpace = Buffer.find_first_of(
" \n", LineOffset);
1125 StringRef LineStart;
1126 if (FirstSpace == StringRef::npos) {
1127 LineStart = Buffer.substr(LineOffset);
1129 LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
1133 if (LineStart ==
"<<<<<<<" || LineStart ==
">>>>") {
1134 Type = TT_ConflictStart;
1135 }
else if (LineStart ==
"|||||||" || LineStart ==
"=======" ||
1136 LineStart ==
"====") {
1137 Type = TT_ConflictAlternative;
1138 }
else if (LineStart ==
">>>>>>>" || LineStart ==
"<<<<") {
1139 Type = TT_ConflictEnd;
1142 if (Type != TT_Unknown) {
1149 Tokens.back()->Type = Type;
1150 Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
1159 FormatToken *getStashedToken() {
1162 StringRef TokenText =
FormatTok->TokenText;
1164 unsigned OriginalColumn =
FormatTok->OriginalColumn;
1167 SourceLocation TokLocation =
1168 FormatTok->Tok.getLocation().getLocWithOffset(Tok.getLength() - 1);
1169 FormatTok->Tok.setLocation(TokLocation);
1170 FormatTok->WhitespaceRange = SourceRange(TokLocation, TokLocation);
1173 FormatTok->OriginalColumn = OriginalColumn + 1;
1178 FormatToken *getNextToken() {
1181 return getStashedToken();
1185 return getStashedToken();
1190 SourceLocation WhitespaceStart =
1197 while (
FormatTok->Tok.is(tok::unknown)) {
1199 auto EscapesNewline = [&](
int pos) {
1201 if (pos >= 0 && Text[pos] ==
'\r')
1205 for (; pos >= 0; --pos, ++count)
1206 if (Text[pos] !=
'\\')
1212 for (
int i = 0, e = Text.size(); i != e; ++i) {
1216 FormatTok->HasUnescapedNewline = !EscapesNewline(i - 1);
1217 FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
1221 FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
1235 if (i + 1 == e || (Text[i + 1] !=
'\r' && Text[i + 1] !=
'\n'))
1236 FormatTok->Type = TT_ImplicitStringLiteral;
1239 FormatTok->Type = TT_ImplicitStringLiteral;
1242 if (
FormatTok->Type == TT_ImplicitStringLiteral)
1246 if (
FormatTok->is(TT_ImplicitStringLiteral))
1248 WhitespaceLength +=
FormatTok->Tok.getLength();
1260 WhitespaceLength += 2;
1266 FormatTok->WhitespaceRange = SourceRange(
1267 WhitespaceStart, WhitespaceStart.getLocWithOffset(WhitespaceLength));
1274 StringRef UntrimmedText =
FormatTok->TokenText;
1277 }
else if (
FormatTok->Tok.is(tok::raw_identifier)) {
1279 FormatTok->Tok.setIdentifierInfo(&Info);
1280 FormatTok->Tok.setKind(Info.getTokenID());
1282 FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete,
1283 tok::kw_operator)) {
1284 FormatTok->Tok.setKind(tok::identifier);
1285 FormatTok->Tok.setIdentifierInfo(
nullptr);
1287 FormatTok->isOneOf(tok::kw_struct, tok::kw_union,
1288 tok::kw_operator)) {
1289 FormatTok->Tok.setKind(tok::identifier);
1290 FormatTok->Tok.setIdentifierInfo(
nullptr);
1292 }
else if (
FormatTok->Tok.is(tok::greatergreater)) {
1296 }
else if (
FormatTok->Tok.is(tok::lessless)) {
1305 size_t FirstNewlinePos = Text.find(
'\n');
1306 if (FirstNewlinePos == StringRef::npos) {
1322 Text.substr(Text.find_last_of(
'\n') + 1), 0, Style.
TabWidth,
1328 if (!(
Tokens.size() > 0 &&
Tokens.back()->Tok.getIdentifierInfo() &&
1329 Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
1334 }
else if (
FormatTok->is(tok::identifier)) {
1369 void readRawToken(FormatToken &Tok) {
1370 Lex->LexFromRawLexer(Tok.Tok);
1371 Tok.TokenText = StringRef(SourceMgr.
getCharacterData(Tok.Tok.getLocation()),
1372 Tok.Tok.getLength());
1375 if (Tok.is(tok::unknown)) {
1376 if (!Tok.TokenText.empty() && Tok.TokenText[0] ==
'"') {
1377 Tok.Tok.setKind(tok::string_literal);
1378 Tok.IsUnterminatedLiteral =
true;
1380 Tok.TokenText ==
"''") {
1381 Tok.Tok.setKind(tok::char_constant);
1385 if (Tok.is(tok::comment) && (Tok.TokenText ==
"// clang-format on" ||
1386 Tok.TokenText ==
"/* clang-format on */")) {
1392 if (Tok.is(tok::comment) && (Tok.TokenText ==
"// clang-format off" ||
1393 Tok.TokenText ==
"/* clang-format off */")) {
1398 void resetLexer(
unsigned Offset) {
1402 Buffer.begin() +
Offset, Buffer.end()));
1403 Lex->SetKeepWhitespaceMode(
true);
1415 return "JavaScript";
1423 class Formatter :
public UnwrappedLineConsumer {
1425 Formatter(
const FormatStyle &Style, SourceManager &SourceMgr, FileID ID,
1426 ArrayRef<CharSourceRange>
Ranges)
1427 : Style(Style), ID(ID), SourceMgr(SourceMgr),
1429 inputUsesCRLF(SourceMgr.getBufferData(ID))),
1431 Encoding(encoding::
detectEncoding(SourceMgr.getBufferData(ID))) {
1432 DEBUG(llvm::dbgs() <<
"File encoding: "
1436 DEBUG(llvm::dbgs() <<
"Language: " << getLanguageName(Style.
Language)
1442 FormatTokenLexer
Tokens(SourceMgr, ID, Style, Encoding);
1444 UnwrappedLineParser Parser(Style,
Tokens.getKeywords(),
Tokens.lex(),
1448 for (
unsigned Run = 0, RunE =
UnwrappedLines.size(); Run + 1 != RunE;
1450 DEBUG(llvm::dbgs() <<
"Run " << Run <<
"...\n");
1451 SmallVector<AnnotatedLine *, 16> AnnotatedLines;
1452 for (
unsigned i = 0, e =
UnwrappedLines[Run].size(); i != e; ++i) {
1453 AnnotatedLines.push_back(
new AnnotatedLine(
UnwrappedLines[Run][i]));
1456 format(AnnotatedLines,
Tokens, IncompleteFormat);
1458 llvm::dbgs() <<
"Replacements for run " << Run <<
":\n";
1460 E = RunResult.end();
1462 llvm::dbgs() <<
I->toString() <<
"\n";
1465 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1466 delete AnnotatedLines[i];
1468 Result.insert(RunResult.begin(), RunResult.end());
1475 FormatTokenLexer &
Tokens,
1476 bool *IncompleteFormat) {
1477 TokenAnnotator Annotator(Style, Tokens.getKeywords());
1478 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1479 Annotator.annotate(*AnnotatedLines[i]);
1481 deriveLocalStyle(AnnotatedLines);
1482 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1483 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1485 computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
1487 Annotator.setCommentLineLevels(AnnotatedLines);
1491 UnwrappedLineFormatter(&
Indenter, &Whitespaces, Style, Tokens.getKeywords(),
1493 .format(AnnotatedLines);
1494 return Whitespaces.generateReplacements();
1503 bool SomeLineAffected =
false;
1504 const AnnotatedLine *PreviousLine =
nullptr;
1506 AnnotatedLine *
Line = *
I;
1507 Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
1511 if (Line->InPPDirective) {
1512 FormatToken *Last = Line->Last;
1514 while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
1515 Last = (*PPEnd)->Last;
1519 if (affectsTokenRange(*Line->First, *Last,
1521 SomeLineAffected =
true;
1522 markAllAsAffected(I, PPEnd);
1528 if (nonPPLineAffected(Line, PreviousLine))
1529 SomeLineAffected =
true;
1531 PreviousLine =
Line;
1534 return SomeLineAffected;
1539 bool nonPPLineAffected(AnnotatedLine *Line,
1540 const AnnotatedLine *PreviousLine) {
1541 bool SomeLineAffected =
false;
1542 Line->ChildrenAffected =
1543 computeAffectedLines(Line->Children.begin(), Line->Children.end());
1544 if (Line->ChildrenAffected)
1545 SomeLineAffected =
true;
1548 bool SomeTokenAffected =
false;
1551 bool IncludeLeadingNewlines =
false;
1555 bool SomeFirstChildAffected =
false;
1557 for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
1559 if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
1560 SomeTokenAffected =
true;
1563 if (!Tok->Children.empty() && Tok->Children.front()->Affected)
1564 SomeFirstChildAffected =
true;
1566 IncludeLeadingNewlines = Tok->Children.empty();
1571 bool LineMoved = PreviousLine && PreviousLine->Affected &&
1572 Line->First->NewlinesBefore == 0;
1574 bool IsContinuedComment =
1575 Line->First->is(tok::comment) && Line->First->Next ==
nullptr &&
1576 Line->First->NewlinesBefore < 2 && PreviousLine &&
1577 PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
1579 if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
1580 IsContinuedComment) {
1581 Line->Affected =
true;
1582 SomeLineAffected =
true;
1584 return SomeLineAffected;
1591 (*I)->Affected =
true;
1592 markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
1599 bool affectsTokenRange(
const FormatToken &First,
const FormatToken &Last,
1600 bool IncludeLeadingNewlines) {
1601 SourceLocation Start = First.WhitespaceRange.getBegin();
1602 if (!IncludeLeadingNewlines)
1603 Start = Start.getLocWithOffset(First.LastNewlineOffset);
1604 SourceLocation End = Last.getStartOfNonWhitespace();
1605 End = End.getLocWithOffset(Last.TokenText.size());
1607 return affectsCharSourceRange(Range);
1612 bool affectsLeadingEmptyLines(
const FormatToken &Tok) {
1614 Tok.WhitespaceRange.getBegin(),
1615 Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
1616 return affectsCharSourceRange(EmptyLineRange);
1620 bool affectsCharSourceRange(
const CharSourceRange &Range) {
1621 for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
1624 if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
1625 !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
1631 static bool inputUsesCRLF(StringRef Text) {
1632 return Text.count(
'\r') * 2 > Text.count(
'\n');
1636 hasCpp03IncompatibleFormat(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
1637 for (
const AnnotatedLine* Line : Lines) {
1638 if (hasCpp03IncompatibleFormat(Line->Children))
1640 for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
1641 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1642 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1644 if (Tok->is(TT_TemplateCloser) &&
1645 Tok->Previous->is(TT_TemplateCloser))
1653 int countVariableAlignments(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
1654 int AlignmentDiff = 0;
1655 for (
const AnnotatedLine* Line : Lines) {
1656 AlignmentDiff += countVariableAlignments(Line->Children);
1657 for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1658 if (!Tok->is(TT_PointerOrReference))
1661 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1662 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1663 Tok->Next->WhitespaceRange.getEnd();
1664 if (SpaceBefore && !SpaceAfter)
1666 if (!SpaceBefore && SpaceAfter)
1670 return AlignmentDiff;
1674 deriveLocalStyle(
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1675 bool HasBinPackedFunction =
false;
1676 bool HasOnePerLineFunction =
false;
1677 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1678 if (!AnnotatedLines[i]->First->Next)
1680 FormatToken *Tok = AnnotatedLines[i]->First->Next;
1683 HasBinPackedFunction =
true;
1685 HasOnePerLineFunction =
true;
1695 Style.
Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1699 HasBinPackedFunction || !HasOnePerLineFunction;
1702 void consumeUnwrappedLine(
const UnwrappedLine &TheLine)
override {
1707 void finishRun()
override {
1722 struct IncludeDirective {
1734 for (
auto Range : Ranges) {
1735 if (Range.getOffset() < End &&
1736 Range.getOffset() + Range.getLength() > Start)
1750 Includes.back().Offset + Includes.back().Text.size()))
1753 for (
unsigned i = 0, e = Includes.size(); i != e; ++i)
1754 Indices.push_back(i);
1755 std::sort(Indices.begin(), Indices.end(), [&](
unsigned LHSI,
unsigned RHSI) {
1757 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1762 bool OutOfOrder =
false;
1763 for (
unsigned i = 1, e = Indices.size(); i != e; ++i) {
1764 if (Indices[i] != i) {
1773 bool CursorMoved =
false;
1774 for (
unsigned Index : Indices) {
1775 if (!result.empty())
1777 result += Includes[Index].Text;
1779 if (Cursor && !CursorMoved) {
1780 unsigned Start = Includes[Index].Offset;
1781 unsigned End = Start + Includes[Index].Text.size();
1782 if (*Cursor >= Start && *Cursor < End) {
1783 *Cursor = Includes.front().Offset + result.size() + *Cursor -
End;
1791 assert(result.size() ==
1792 Includes.back().Offset + Includes.back().Text.size() -
1793 Includes.front().Offset);
1796 result.size(), result));
1801 StringRef FileName,
unsigned *
Cursor) {
1807 unsigned SearchFrom = 0;
1808 llvm::Regex IncludeRegex(
1809 R
"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))");
1820 bool IsSource = FileName.endswith(
".c") || FileName.endswith(
".cc") ||
1821 FileName.endswith(
".cpp") || FileName.endswith(
".c++") ||
1822 FileName.endswith(
".cxx") || FileName.endswith(
".m") ||
1823 FileName.endswith(
".mm");
1824 StringRef FileStem = llvm::sys::path::stem(FileName);
1825 bool FirstIncludeBlock =
true;
1826 bool MainIncludeFound =
false;
1831 CategoryRegexs.emplace_back(
Category.Regex);
1833 bool FormattingOff =
false;
1836 auto Pos = Code.find(
'\n', SearchFrom);
1838 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
1840 StringRef Trimmed = Line.trim();
1841 if (Trimmed ==
"// clang-format off")
1842 FormattingOff =
true;
1843 else if (Trimmed ==
"// clang-format on")
1844 FormattingOff =
false;
1846 if (!FormattingOff && !Line.endswith(
"\\")) {
1847 if (IncludeRegex.match(Line, &Matches)) {
1848 StringRef IncludeName = Matches[2];
1850 for (
unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) {
1851 if (CategoryRegexs[i].
match(IncludeName)) {
1856 if (IsSource && !MainIncludeFound && Category > 0 &&
1857 FirstIncludeBlock && IncludeName.startswith(
"\"")) {
1858 StringRef HeaderStem =
1859 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
1860 if (FileStem.startswith(HeaderStem)) {
1862 MainIncludeFound =
true;
1865 IncludesInBlock.push_back({IncludeName,
Line, Prev, Category});
1866 }
else if (!IncludesInBlock.empty()) {
1867 sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
1869 IncludesInBlock.clear();
1870 FirstIncludeBlock =
false;
1874 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1876 SearchFrom = Pos + 1;
1878 if (!IncludesInBlock.empty())
1879 sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1886 bool *IncompleteFormat) {
1890 Formatter formatter(Expanded, SourceMgr, ID, Ranges);
1891 return formatter.format(IncompleteFormat);
1896 StringRef FileName,
bool *IncompleteFormat) {
1907 InMemoryFileSystem->addFile(
1908 FileName, 0, llvm::MemoryBuffer::getMemBuffer(
1909 Code, FileName,
false));
1913 std::vector<CharSourceRange> CharRanges;
1919 return reformat(Style, SourceMgr, ID, CharRanges, IncompleteFormat);
1924 LangOpts.CPlusPlus = 1;
1927 LangOpts.LineComment = 1;
1929 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
1933 LangOpts.MicrosoftExt = 1;
1934 LangOpts.DeclSpecKeyword = 1;
1939 "Coding style, currently supports:\n"
1940 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
1941 "Use -style=file to load style configuration from\n"
1942 ".clang-format file located in one of the parent\n"
1943 "directories of the source file (or current\n"
1944 "directory for stdin).\n"
1945 "Use -style=\"{key: value, ...}\" to set specific\n"
1946 "parameters, e.g.:\n"
1947 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
1950 if (FileName.endswith(
".java"))
1952 if (FileName.endswith_lower(
".js") || FileName.endswith_lower(
".ts"))
1954 if (FileName.endswith_lower(
".proto") ||
1955 FileName.endswith_lower(
".protodevel"))
1957 if (FileName.endswith_lower(
".td"))
1963 StringRef FallbackStyle) {
1967 llvm::errs() <<
"Invalid fallback style \"" << FallbackStyle
1968 <<
"\" using LLVM style\n";
1972 if (StyleName.startswith(
"{")) {
1975 llvm::errs() <<
"Error parsing -style: " << ec.message() <<
", using "
1976 << FallbackStyle <<
" style\n";
1981 if (!StyleName.equals_lower(
"file")) {
1983 llvm::errs() <<
"Invalid value for -style, using " << FallbackStyle
1991 llvm::sys::fs::make_absolute(Path);
1992 for (StringRef Directory = Path; !Directory.empty();
1993 Directory = llvm::sys::path::parent_path(Directory)) {
1994 if (!llvm::sys::fs::is_directory(Directory))
1998 llvm::sys::path::append(ConfigFile,
".clang-format");
1999 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
2000 bool IsFile =
false;
2003 llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
2007 ConfigFile = Directory;
2008 llvm::sys::path::append(ConfigFile,
"_clang-format");
2009 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
2010 llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
2014 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
2015 llvm::MemoryBuffer::getFile(ConfigFile.c_str());
2016 if (std::error_code EC = Text.getError()) {
2017 llvm::errs() << EC.message() <<
"\n";
2020 if (std::error_code ec =
2023 if (!UnsuitableConfigFiles.empty())
2024 UnsuitableConfigFiles.append(
", ");
2025 UnsuitableConfigFiles.append(ConfigFile);
2028 llvm::errs() <<
"Error reading " << ConfigFile <<
": " << ec.message()
2032 DEBUG(llvm::dbgs() <<
"Using configuration file " << ConfigFile <<
"\n");
2036 if (!UnsuitableConfigFiles.empty()) {
2037 llvm::errs() <<
"Configuration file(s) do(es) not support "
2038 << getLanguageName(Style.
Language) <<
": "
2039 << UnsuitableConfigFiles <<
"\n";
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
Implements support for file system lookup, file system caching, and directory search management...
Defines the SourceManager interface.
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
std::unique_ptr< llvm::MemoryBuffer > Buffer
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
This file implements a token annotator, i.e.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
An in-memory file system.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Concrete class used by the front-end to report problems and issues.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
detail::InMemoryDirectory::const_iterator I
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
WhitespaceManager class manages whitespace around tokens and their replacements.
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, unsigned LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
The result type of a method or function.
static CharSourceRange getCharRange(SourceRange R)
The l-value was considered opaque, so the alignment was determined from a type.
Encodes a location in the source.
const TemplateArgument * iterator
Options for controlling the compiler diagnostics engine.
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
This file contains the declaration of the UnwrappedLineParser, which turns a stream of tokens into Un...
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Used for handling and querying diagnostic IDs.
detail::InMemoryDirectory::const_iterator E
Defines the Diagnostic-related interfaces.
Keeps track of options that affect how file operations are performed.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
This file implements an indenter that manages the indentation of continuations.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
This class handles loading and caching of source files into memory.