33 #include "llvm/ADT/STLExtras.h"
34 #include "llvm/Support/Allocator.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Support/Path.h"
37 #include "llvm/Support/Regex.h"
38 #include "llvm/Support/YAMLTraits.h"
43 #define DEBUG_TYPE "format-formatter"
51 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageKind> {
53 IO.enumCase(Value,
"Cpp", FormatStyle::LK_Cpp);
54 IO.enumCase(Value,
"Java", FormatStyle::LK_Java);
55 IO.enumCase(Value,
"JavaScript", FormatStyle::LK_JavaScript);
56 IO.enumCase(Value,
"ObjC", FormatStyle::LK_ObjC);
57 IO.enumCase(Value,
"Proto", FormatStyle::LK_Proto);
58 IO.enumCase(Value,
"TableGen", FormatStyle::LK_TableGen);
59 IO.enumCase(Value,
"TextProto", FormatStyle::LK_TextProto);
63 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageStandard> {
65 IO.enumCase(Value,
"Cpp03", FormatStyle::LS_Cpp03);
66 IO.enumCase(Value,
"C++03", FormatStyle::LS_Cpp03);
67 IO.enumCase(Value,
"Cpp11", FormatStyle::LS_Cpp11);
68 IO.enumCase(Value,
"C++11", FormatStyle::LS_Cpp11);
69 IO.enumCase(Value,
"Auto", FormatStyle::LS_Auto);
73 template <>
struct ScalarEnumerationTraits<
FormatStyle::UseTabStyle> {
75 IO.enumCase(Value,
"Never", FormatStyle::UT_Never);
76 IO.enumCase(Value,
"false", FormatStyle::UT_Never);
77 IO.enumCase(Value,
"Always", FormatStyle::UT_Always);
78 IO.enumCase(Value,
"true", FormatStyle::UT_Always);
79 IO.enumCase(Value,
"ForIndentation", FormatStyle::UT_ForIndentation);
80 IO.enumCase(Value,
"ForContinuationAndIndentation",
81 FormatStyle::UT_ForContinuationAndIndentation);
85 template <>
struct ScalarEnumerationTraits<
FormatStyle::JavaScriptQuoteStyle> {
87 IO.enumCase(Value,
"Leave", FormatStyle::JSQS_Leave);
88 IO.enumCase(Value,
"Single", FormatStyle::JSQS_Single);
89 IO.enumCase(Value,
"Double", FormatStyle::JSQS_Double);
93 template <>
struct ScalarEnumerationTraits<
FormatStyle::ShortFunctionStyle> {
95 IO.enumCase(Value,
"None", FormatStyle::SFS_None);
96 IO.enumCase(Value,
"false", FormatStyle::SFS_None);
97 IO.enumCase(Value,
"All", FormatStyle::SFS_All);
98 IO.enumCase(Value,
"true", FormatStyle::SFS_All);
99 IO.enumCase(Value,
"Inline", FormatStyle::SFS_Inline);
100 IO.enumCase(Value,
"InlineOnly", FormatStyle::SFS_InlineOnly);
101 IO.enumCase(Value,
"Empty", FormatStyle::SFS_Empty);
105 template <>
struct ScalarEnumerationTraits<
FormatStyle::BinaryOperatorStyle> {
107 IO.enumCase(Value,
"All", FormatStyle::BOS_All);
108 IO.enumCase(Value,
"true", FormatStyle::BOS_All);
109 IO.enumCase(Value,
"None", FormatStyle::BOS_None);
110 IO.enumCase(Value,
"false", FormatStyle::BOS_None);
111 IO.enumCase(Value,
"NonAssignment", FormatStyle::BOS_NonAssignment);
115 template <>
struct ScalarEnumerationTraits<
FormatStyle::BraceBreakingStyle> {
117 IO.enumCase(Value,
"Attach", FormatStyle::BS_Attach);
118 IO.enumCase(Value,
"Linux", FormatStyle::BS_Linux);
119 IO.enumCase(Value,
"Mozilla", FormatStyle::BS_Mozilla);
120 IO.enumCase(Value,
"Stroustrup", FormatStyle::BS_Stroustrup);
121 IO.enumCase(Value,
"Allman", FormatStyle::BS_Allman);
122 IO.enumCase(Value,
"GNU", FormatStyle::BS_GNU);
123 IO.enumCase(Value,
"WebKit", FormatStyle::BS_WebKit);
124 IO.enumCase(Value,
"Custom", FormatStyle::BS_Custom);
128 template <>
struct ScalarEnumerationTraits<
FormatStyle::BreakConstructorInitializersStyle> {
130 IO.enumCase(Value,
"BeforeColon", FormatStyle::BCIS_BeforeColon);
131 IO.enumCase(Value,
"BeforeComma", FormatStyle::BCIS_BeforeComma);
132 IO.enumCase(Value,
"AfterColon", FormatStyle::BCIS_AfterColon);
137 struct ScalarEnumerationTraits<
FormatStyle::ReturnTypeBreakingStyle> {
139 IO.enumCase(Value,
"None", FormatStyle::RTBS_None);
140 IO.enumCase(Value,
"All", FormatStyle::RTBS_All);
141 IO.enumCase(Value,
"TopLevel", FormatStyle::RTBS_TopLevel);
142 IO.enumCase(Value,
"TopLevelDefinitions",
143 FormatStyle::RTBS_TopLevelDefinitions);
144 IO.enumCase(Value,
"AllDefinitions", FormatStyle::RTBS_AllDefinitions);
149 struct ScalarEnumerationTraits<
FormatStyle::DefinitionReturnTypeBreakingStyle> {
152 IO.enumCase(Value,
"None", FormatStyle::DRTBS_None);
153 IO.enumCase(Value,
"All", FormatStyle::DRTBS_All);
154 IO.enumCase(Value,
"TopLevel", FormatStyle::DRTBS_TopLevel);
157 IO.enumCase(Value,
"false", FormatStyle::DRTBS_None);
158 IO.enumCase(Value,
"true", FormatStyle::DRTBS_All);
163 struct ScalarEnumerationTraits<
FormatStyle::NamespaceIndentationKind> {
165 FormatStyle::NamespaceIndentationKind &
Value) {
166 IO.enumCase(Value,
"None", FormatStyle::NI_None);
167 IO.enumCase(Value,
"Inner", FormatStyle::NI_Inner);
168 IO.enumCase(Value,
"All", FormatStyle::NI_All);
172 template <>
struct ScalarEnumerationTraits<
FormatStyle::BracketAlignmentStyle> {
174 IO.enumCase(Value,
"Align", FormatStyle::BAS_Align);
175 IO.enumCase(Value,
"DontAlign", FormatStyle::BAS_DontAlign);
176 IO.enumCase(Value,
"AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
179 IO.enumCase(Value,
"true", FormatStyle::BAS_Align);
180 IO.enumCase(Value,
"false", FormatStyle::BAS_DontAlign);
184 template <>
struct ScalarEnumerationTraits<
FormatStyle::EscapedNewlineAlignmentStyle> {
186 IO.enumCase(Value,
"DontAlign", FormatStyle::ENAS_DontAlign);
187 IO.enumCase(Value,
"Left", FormatStyle::ENAS_Left);
188 IO.enumCase(Value,
"Right", FormatStyle::ENAS_Right);
191 IO.enumCase(Value,
"true", FormatStyle::ENAS_Left);
192 IO.enumCase(Value,
"false", FormatStyle::ENAS_Right);
196 template <>
struct ScalarEnumerationTraits<
FormatStyle::PointerAlignmentStyle> {
198 IO.enumCase(Value,
"Middle", FormatStyle::PAS_Middle);
199 IO.enumCase(Value,
"Left", FormatStyle::PAS_Left);
200 IO.enumCase(Value,
"Right", FormatStyle::PAS_Right);
203 IO.enumCase(Value,
"true", FormatStyle::PAS_Left);
204 IO.enumCase(Value,
"false", FormatStyle::PAS_Right);
209 struct ScalarEnumerationTraits<
FormatStyle::SpaceBeforeParensOptions> {
211 FormatStyle::SpaceBeforeParensOptions &
Value) {
212 IO.enumCase(Value,
"Never", FormatStyle::SBPO_Never);
213 IO.enumCase(Value,
"ControlStatements",
214 FormatStyle::SBPO_ControlStatements);
215 IO.enumCase(Value,
"Always", FormatStyle::SBPO_Always);
218 IO.enumCase(Value,
"false", FormatStyle::SBPO_Never);
219 IO.enumCase(Value,
"true", FormatStyle::SBPO_ControlStatements);
226 IO.mapOptional(
"Language", Style.
Language);
228 if (IO.outputting()) {
229 StringRef StylesArray[] = {
"LLVM",
"Google",
"Chromium",
230 "Mozilla",
"WebKit",
"GNU"};
232 for (
size_t i = 0, e = Styles.size(); i < e; ++i) {
233 StringRef StyleName(Styles[i]);
236 Style == PredefinedStyle) {
237 IO.mapOptional(
"# BasedOnStyle", StyleName);
242 StringRef BasedOnStyle;
243 IO.mapOptional(
"BasedOnStyle", BasedOnStyle);
244 if (!BasedOnStyle.empty()) {
245 FormatStyle::LanguageKind OldLanguage = Style.
Language;
246 FormatStyle::LanguageKind Language =
249 IO.setError(Twine(
"Unknown value for BasedOnStyle: ", BasedOnStyle));
257 if (!IO.outputting()) {
260 IO.mapOptional(
"IndentFunctionDeclarationAfterType",
263 IO.mapOptional(
"SpaceAfterControlStatementKeyword",
269 IO.mapOptional(
"AlignConsecutiveAssignments",
271 IO.mapOptional(
"AlignConsecutiveDeclarations",
276 IO.mapOptional(
"AllowAllParametersOfDeclarationOnNextLine",
278 IO.mapOptional(
"AllowShortBlocksOnASingleLine",
280 IO.mapOptional(
"AllowShortCaseLabelsOnASingleLine",
282 IO.mapOptional(
"AllowShortFunctionsOnASingleLine",
284 IO.mapOptional(
"AllowShortIfStatementsOnASingleLine",
286 IO.mapOptional(
"AllowShortLoopsOnASingleLine",
288 IO.mapOptional(
"AlwaysBreakAfterDefinitionReturnType",
290 IO.mapOptional(
"AlwaysBreakAfterReturnType",
300 FormatStyle::DRTBS_TopLevel)
302 FormatStyle::RTBS_TopLevelDefinitions;
305 IO.mapOptional(
"AlwaysBreakBeforeMultilineStrings",
307 IO.mapOptional(
"AlwaysBreakTemplateDeclarations",
312 IO.mapOptional(
"BreakBeforeBinaryOperators",
315 IO.mapOptional(
"BreakBeforeInheritanceComma",
317 IO.mapOptional(
"BreakBeforeTernaryOperators",
320 bool BreakConstructorInitializersBeforeComma =
false;
321 IO.mapOptional(
"BreakConstructorInitializersBeforeComma",
322 BreakConstructorInitializersBeforeComma);
323 IO.mapOptional(
"BreakConstructorInitializers",
328 if (BreakConstructorInitializersBeforeComma &&
332 IO.mapOptional(
"BreakAfterJavaFieldAnnotations",
338 IO.mapOptional(
"ConstructorInitializerAllOnOneLineOrOnePerLine",
340 IO.mapOptional(
"ConstructorInitializerIndentWidth",
346 IO.mapOptional(
"ExperimentalAutoDetectBinPacking",
354 IO.mapOptional(
"IndentWrappedFunctionNames",
358 IO.mapOptional(
"KeepEmptyLinesAtTheStartOfBlocks",
366 IO.mapOptional(
"ObjCSpaceBeforeProtocolList",
368 IO.mapOptional(
"PenaltyBreakAssignment",
370 IO.mapOptional(
"PenaltyBreakBeforeFirstCallParameter",
373 IO.mapOptional(
"PenaltyBreakFirstLessLess",
377 IO.mapOptional(
"PenaltyReturnTypeOnItsOwnLine",
385 IO.mapOptional(
"SpaceBeforeAssignmentOperators",
389 IO.mapOptional(
"SpacesBeforeTrailingComments",
392 IO.mapOptional(
"SpacesInContainerLiterals",
394 IO.mapOptional(
"SpacesInCStyleCastParentheses",
398 IO.mapOptional(
"Standard", Style.
Standard);
399 IO.mapOptional(
"TabWidth", Style.
TabWidth);
400 IO.mapOptional(
"UseTab", Style.
UseTab);
404 template <>
struct MappingTraits<
FormatStyle::BraceWrappingFlags> {
405 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
406 IO.mapOptional(
"AfterClass", Wrapping.AfterClass);
407 IO.mapOptional(
"AfterControlStatement", Wrapping.AfterControlStatement);
408 IO.mapOptional(
"AfterEnum", Wrapping.AfterEnum);
409 IO.mapOptional(
"AfterFunction", Wrapping.AfterFunction);
410 IO.mapOptional(
"AfterNamespace", Wrapping.AfterNamespace);
411 IO.mapOptional(
"AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
412 IO.mapOptional(
"AfterStruct", Wrapping.AfterStruct);
413 IO.mapOptional(
"AfterUnion", Wrapping.AfterUnion);
414 IO.mapOptional(
"BeforeCatch", Wrapping.BeforeCatch);
415 IO.mapOptional(
"BeforeElse", Wrapping.BeforeElse);
416 IO.mapOptional(
"IndentBraces", Wrapping.IndentBraces);
417 IO.mapOptional(
"SplitEmptyFunction", Wrapping.SplitEmptyFunction);
418 IO.mapOptional(
"SplitEmptyRecord", Wrapping.SplitEmptyRecord);
419 IO.mapOptional(
"SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
425 IO.mapOptional(
"Regex", Category.Regex);
426 IO.mapOptional(
"Priority", Category.Priority);
435 template <>
struct DocumentListTraits<std::vector<FormatStyle>> {
436 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
441 if (Index >= Seq.size()) {
442 assert(Index == Seq.size());
444 if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
447 Template = *((
const FormatStyle *)IO.getContext());
448 Template.
Language = FormatStyle::LK_None;
450 Seq.resize(Index + 1, Template);
470 return llvm::make_error<llvm::StringError>(Message,
471 llvm::inconvertibleErrorCode());
475 return "clang-format.parse_error";
479 switch (static_cast<ParseError>(EV)) {
483 return "Invalid argument";
487 llvm_unreachable(
"unexpected parse error");
494 Expanded.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
495 false,
false,
false,
false,
false,
true,
529 Expanded.
BraceWrapping = {
true,
true,
true,
true,
true,
true,
530 true,
true,
true,
true,
true,
true,
567 LLVMStyle.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
568 false,
false,
false,
false,
false,
true,
588 {
"^(<|\"(gtest|gmock|isl|json)/)", 3},
685 "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
721 return ChromiumStyle;
796 if (Name.equals_lower(
"llvm")) {
798 }
else if (Name.equals_lower(
"chromium")) {
800 }
else if (Name.equals_lower(
"mozilla")) {
802 }
else if (Name.equals_lower(
"google")) {
804 }
else if (Name.equals_lower(
"webkit")) {
806 }
else if (Name.equals_lower(
"gnu")) {
808 }
else if (Name.equals_lower(
"none")) {
822 if (Text.trim().empty())
825 std::vector<FormatStyle> Styles;
831 Input.setContext(Style);
834 return Input.error();
836 for (
unsigned i = 0; i < Styles.size(); ++i) {
841 for (
unsigned j = 0; j < i; ++j) {
842 if (Styles[i].Language == Styles[j].Language) {
844 <<
"Duplicate languages in the config file on positions " << j
845 <<
" and " << i <<
"\n");
853 for (
int i = Styles.size() - 1; i >= 0; --i) {
854 if (Styles[i].Language == Language ||
866 llvm::raw_string_ostream Stream(Text);
867 llvm::yaml::Output Output(Stream);
871 Output << NonConstStyle;
877 class JavaScriptRequoter :
public TokenAnalyzer {
880 : TokenAnalyzer(Env, Style) {}
882 tooling::Replacements
883 analyze(TokenAnnotator &Annotator,
885 FormatTokenLexer &
Tokens)
override {
886 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
887 AnnotatedLines.end());
888 tooling::Replacements
Result;
889 requoteJSStringLiteral(AnnotatedLines, Result);
896 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
897 tooling::Replacements &Result) {
898 for (AnnotatedLine *
Line : Lines) {
899 requoteJSStringLiteral(
Line->Children, Result);
902 for (FormatToken *FormatTok =
Line->First; FormatTok;
903 FormatTok = FormatTok->Next) {
904 StringRef
Input = FormatTok->TokenText;
905 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
909 !Input.startswith(
"\"")) ||
911 !Input.startswith(
"\'")))
916 SourceLocation Start = FormatTok->Tok.getLocation();
917 auto Replace = [&](SourceLocation Start,
unsigned Length,
918 StringRef ReplacementText) {
920 Env.getSourceManager(), Start,
Length, ReplacementText));
928 Replace(Start, 1, IsSingle ?
"'" :
"\"");
929 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
930 IsSingle ?
"'" :
"\"");
933 bool Escaped =
false;
934 for (
size_t i = 1; i < Input.size() - 1; i++) {
937 if (!Escaped && i + 1 < Input.size() &&
938 ((IsSingle && Input[i + 1] ==
'"') ||
939 (!IsSingle && Input[i + 1] ==
'\''))) {
942 Replace(Start.getLocWithOffset(i), 1,
"");
949 if (!Escaped && IsSingle == (Input[i] ==
'\'')) {
951 Replace(Start.getLocWithOffset(i), 0,
"\\");
965 class Formatter :
public TokenAnalyzer {
968 FormattingAttemptStatus *
Status)
969 : TokenAnalyzer(Env, Style), Status(Status) {}
971 tooling::Replacements
972 analyze(TokenAnnotator &Annotator,
973 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
974 FormatTokenLexer &Tokens)
override {
975 tooling::Replacements Result;
976 deriveLocalStyle(AnnotatedLines);
977 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
978 AnnotatedLines.end());
979 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
980 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
982 Annotator.setCommentLineLevels(AnnotatedLines);
985 Env.getSourceManager(),
Style,
986 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
991 Env.getSourceManager(),
Status)
992 .format(AnnotatedLines);
993 for (
const auto &R :
Whitespaces.generateReplacements())
1001 static bool inputUsesCRLF(StringRef
Text) {
1002 return Text.count(
'\r') * 2 > Text.count(
'\n');
1006 hasCpp03IncompatibleFormat(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
1007 for (
const AnnotatedLine *
Line : Lines) {
1008 if (hasCpp03IncompatibleFormat(
Line->Children))
1010 for (FormatToken *Tok =
Line->First->Next; Tok; Tok = Tok->Next) {
1011 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1012 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1014 if (Tok->is(TT_TemplateCloser) &&
1015 Tok->Previous->is(TT_TemplateCloser))
1023 int countVariableAlignments(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
1024 int AlignmentDiff = 0;
1025 for (
const AnnotatedLine *
Line : Lines) {
1026 AlignmentDiff += countVariableAlignments(
Line->Children);
1027 for (FormatToken *Tok =
Line->First; Tok && Tok->Next; Tok = Tok->Next) {
1028 if (!Tok->is(TT_PointerOrReference))
1031 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1032 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
1033 Tok->Next->WhitespaceRange.getEnd();
1034 if (SpaceBefore && !SpaceAfter)
1036 if (!SpaceBefore && SpaceAfter)
1040 return AlignmentDiff;
1044 deriveLocalStyle(
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1045 bool HasBinPackedFunction =
false;
1046 bool HasOnePerLineFunction =
false;
1047 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1048 if (!AnnotatedLines[i]->First->Next)
1050 FormatToken *Tok = AnnotatedLines[i]->First->Next;
1053 HasBinPackedFunction =
true;
1055 HasOnePerLineFunction =
true;
1060 if (
Style.DerivePointerAlignment)
1061 Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
1065 Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
1069 HasBinPackedFunction || !HasOnePerLineFunction;
1078 class Cleaner :
public TokenAnalyzer {
1081 : TokenAnalyzer(Env, Style),
1085 tooling::Replacements
1086 analyze(TokenAnnotator &Annotator,
1087 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1088 FormatTokenLexer &Tokens)
override {
1096 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1097 AnnotatedLines.end());
1099 checkEmptyNamespace(AnnotatedLines);
1101 for (
auto &
Line : AnnotatedLines) {
1102 if (
Line->Affected) {
1103 cleanupRight(
Line->First, tok::comma, tok::comma);
1104 cleanupRight(
Line->First, TT_CtorInitializerColon, tok::comma);
1105 cleanupRight(
Line->First, tok::l_paren, tok::comma);
1106 cleanupLeft(
Line->First, tok::comma, tok::r_paren);
1107 cleanupLeft(
Line->First, TT_CtorInitializerComma, tok::l_brace);
1108 cleanupLeft(
Line->First, TT_CtorInitializerColon, tok::l_brace);
1109 cleanupLeft(
Line->First, TT_CtorInitializerColon, tok::equal);
1113 return generateFixes();
1117 bool containsOnlyComments(
const AnnotatedLine &
Line) {
1118 for (FormatToken *Tok = Line.First; Tok !=
nullptr; Tok = Tok->Next) {
1119 if (Tok->isNot(tok::comment))
1126 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1127 std::set<unsigned> DeletedLines;
1128 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1129 auto &Line = *AnnotatedLines[i];
1130 if (Line.startsWith(tok::kw_namespace) ||
1131 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
1132 checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
1136 for (
auto Line : DeletedLines) {
1137 FormatToken *Tok = AnnotatedLines[
Line]->First;
1149 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1150 unsigned CurrentLine,
unsigned &
NewLine,
1151 std::set<unsigned> &DeletedLines) {
1152 unsigned InitLine = CurrentLine,
End = AnnotatedLines.size();
1157 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1158 NewLine = CurrentLine;
1161 }
else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1164 while (++CurrentLine < End) {
1165 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1168 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1169 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1170 tok::kw_namespace)) {
1171 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
1178 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1183 NewLine = CurrentLine;
1187 NewLine = CurrentLine;
1188 if (CurrentLine >= End)
1193 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1194 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1197 for (
unsigned i = InitLine; i <= CurrentLine; ++i) {
1198 DeletedLines.insert(i);
1208 template <
typename LeftKind,
typename RightKind>
1209 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1211 auto NextNotDeleted = [
this](
const FormatToken &Tok) -> FormatToken * {
1212 for (
auto *Res = Tok.Next; Res; Res = Res->Next)
1213 if (!Res->is(tok::comment) &&
1218 for (
auto *Left = Start; Left;) {
1219 auto *Right = NextNotDeleted(*Left);
1222 if (Left->is(LK) && Right->is(RK)) {
1223 deleteToken(DeleteLeft ? Left : Right);
1224 for (
auto *Tok = Left->Next; Tok && Tok != Right; Tok = Tok->Next)
1235 template <
typename LeftKind,
typename RightKind>
1236 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1237 cleanupPair(Start, LK, RK,
true);
1240 template <
typename LeftKind,
typename RightKind>
1241 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1242 cleanupPair(Start, LK, RK,
false);
1246 inline void deleteToken(FormatToken *Tok) {
1251 tooling::Replacements generateFixes() {
1252 tooling::Replacements Fixes;
1253 std::vector<FormatToken *>
Tokens;
1255 std::back_inserter(Tokens));
1261 while (Idx < Tokens.size()) {
1262 unsigned St = Idx, End = Idx;
1263 while ((End + 1) < Tokens.size() &&
1264 Tokens[
End]->Next == Tokens[End + 1]) {
1268 Tokens[
End]->Tok.getEndLoc());
1275 assert(
false &&
"Fixes must not conflict!");
1286 struct FormatTokenLess {
1287 FormatTokenLess(
const SourceManager &
SM) : SM(SM) {}
1289 bool operator()(
const FormatToken *LHS,
const FormatToken *RHS)
const {
1290 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1291 RHS->Tok.getLocation());
1300 struct IncludeDirective {
1312 for (
auto Range : Ranges) {
1313 if (Range.getOffset() < End &&
1314 Range.getOffset() + Range.getLength() > Start)
1327 static std::pair<unsigned, unsigned>
1331 unsigned OffsetToEOL = 0;
1332 for (
int i = 0, e = Includes.size(); i != e; ++i) {
1333 unsigned Start = Includes[Indices[i]].Offset;
1334 unsigned End = Start + Includes[Indices[i]].Text.size();
1335 if (!(Cursor >= Start && Cursor < End))
1337 CursorIndex = Indices[i];
1338 OffsetToEOL = End -
Cursor;
1341 while (--i >= 0 && Includes[CursorIndex].Text == Includes[Indices[i]].Text)
1345 return std::make_pair(CursorIndex, OffsetToEOL);
1359 unsigned IncludesBeginOffset = Includes.front().Offset;
1360 unsigned IncludesEndOffset =
1361 Includes.back().Offset + Includes.back().Text.size();
1362 unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset;
1363 if (!
affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
1366 for (
unsigned i = 0, e = Includes.size(); i != e; ++i)
1367 Indices.push_back(i);
1369 Indices.begin(), Indices.end(), [&](
unsigned LHSI,
unsigned RHSI) {
1371 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1375 unsigned CursorIndex;
1377 unsigned CursorToEOLOffset;
1379 std::tie(CursorIndex, CursorToEOLOffset) =
1383 Indices.erase(std::unique(Indices.begin(), Indices.end(),
1384 [&](
unsigned LHSI,
unsigned RHSI) {
1385 return Includes[LHSI].Text == Includes[RHSI].Text;
1391 if (Indices.size() == Includes.size() &&
1392 std::is_sorted(Indices.begin(), Indices.end()))
1396 for (
unsigned Index : Indices) {
1397 if (!result.empty())
1399 result += Includes[Index].Text;
1400 if (Cursor && CursorIndex == Index)
1401 *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
1405 FileName, Includes.front().Offset, IncludesBlockSize, result));
1418 class IncludeCategoryManager {
1421 : Style(Style), FileName(FileName) {
1422 FileStem = llvm::sys::path::stem(FileName);
1425 IsMainFile = FileName.endswith(
".c") || FileName.endswith(
".cc") ||
1426 FileName.endswith(
".cpp") || FileName.endswith(
".c++") ||
1427 FileName.endswith(
".cxx") || FileName.endswith(
".m") ||
1428 FileName.endswith(
".mm");
1434 int getIncludePriority(StringRef IncludeName,
bool CheckMainHeader) {
1441 if (CheckMainHeader &&
IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1447 bool isMainHeader(StringRef IncludeName)
const {
1448 if (!IncludeName.startswith(
"\""))
1450 StringRef HeaderStem =
1451 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
1452 if (
FileStem.startswith(HeaderStem) ||
1453 FileStem.startswith_lower(HeaderStem)) {
1454 llvm::Regex MainIncludeRegex(
1456 llvm::Regex::IgnoreCase);
1457 if (MainIncludeRegex.match(
FileStem))
1470 const char IncludeRegexPattern[] =
1471 R
"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1481 unsigned SearchFrom = 0;
1482 llvm::Regex IncludeRegex(IncludeRegexPattern);
1493 IncludeCategoryManager Categories(Style, FileName);
1494 bool FirstIncludeBlock =
true;
1495 bool MainIncludeFound =
false;
1496 bool FormattingOff =
false;
1499 auto Pos = Code.find(
'\n', SearchFrom);
1501 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
1503 StringRef Trimmed = Line.trim();
1504 if (Trimmed ==
"// clang-format off")
1505 FormattingOff =
true;
1506 else if (Trimmed ==
"// clang-format on")
1507 FormattingOff =
false;
1509 if (!FormattingOff && !Line.endswith(
"\\")) {
1510 if (IncludeRegex.match(Line, &Matches)) {
1511 StringRef IncludeName = Matches[2];
1512 int Category = Categories.getIncludePriority(
1514 !MainIncludeFound && FirstIncludeBlock);
1516 MainIncludeFound =
true;
1517 IncludesInBlock.push_back({IncludeName,
Line, Prev, Category});
1518 }
else if (!IncludesInBlock.empty()) {
1521 IncludesInBlock.clear();
1522 FirstIncludeBlock =
false;
1526 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1528 SearchFrom = Pos + 1;
1530 if (!IncludesInBlock.empty())
1531 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1539 return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
1544 StringRef FileName,
unsigned *
Cursor) {
1548 if (Style.
Language == FormatStyle::LanguageKind::LK_JavaScript &&
1551 if (Style.
Language == FormatStyle::LanguageKind::LK_JavaScript)
1557 template <
typename T>
1562 if (Replaces.
empty())
1567 return NewCode.takeError();
1569 StringRef FileName = Replaces.
begin()->getFilePath();
1572 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
1574 return Replaces.
merge(FormatReplaces);
1583 std::vector<tooling::Range> Ranges,
1587 auto SortedReplaces =
1589 if (!SortedReplaces)
1590 return SortedReplaces.takeError();
1595 std::vector<tooling::Range> Ranges,
1597 return reformat(Style, Code, Ranges, FileName);
1610 return Replace.getOffset() ==
UINT_MAX && Replace.getLength() == 1;
1617 unsigned getOffsetAfterTokenSequence(
1618 StringRef FileName, StringRef Code,
const FormatStyle &Style,
1619 llvm::function_ref<
unsigned(
const SourceManager &, Lexer &,
Token &)>
1620 GetOffsetAfterSequence) {
1621 std::unique_ptr<Environment> Env =
1623 const SourceManager &
SourceMgr = Env->getSourceManager();
1624 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1628 Lex.LexFromRawLexer(Tok);
1629 return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
1635 bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef
Name,
Token &Tok) {
1636 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1637 Tok.is(tok::raw_identifier) &&
1638 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
1639 Tok.is(tok::raw_identifier);
1641 Lex.LexFromRawLexer(Tok);
1645 void skipComments(Lexer &Lex,
Token &Tok) {
1646 while (Tok.is(tok::comment))
1647 if (Lex.LexFromRawLexer(Tok))
1655 unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1658 return getOffsetAfterTokenSequence(
1659 FileName, Code, Style,
1660 [](
const SourceManager &
SM, Lexer &Lex,
Token Tok) {
1661 skipComments(Lex, Tok);
1662 unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
1663 if (checkAndConsumeDirectiveWithName(Lex,
"ifndef", Tok)) {
1664 skipComments(Lex, Tok);
1665 if (checkAndConsumeDirectiveWithName(Lex,
"define", Tok))
1666 return SM.getFileOffset(Tok.getLocation());
1668 return InitialOffset;
1676 bool checkAndConsumeInclusiveDirective(Lexer &Lex,
Token &Tok) {
1677 auto Matched = [&]() {
1678 Lex.LexFromRawLexer(Tok);
1681 if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1682 Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() ==
"include") {
1683 if (Lex.LexFromRawLexer(Tok))
1685 if (Tok.is(tok::string_literal))
1687 if (Tok.is(tok::less)) {
1688 while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
1690 if (Tok.is(tok::greater))
1710 unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
1712 return getOffsetAfterTokenSequence(
1713 FileName, Code, Style,
1714 [](
const SourceManager &SM, Lexer &Lex,
Token Tok) {
1715 skipComments(Lex, Tok);
1716 unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
1717 while (checkAndConsumeInclusiveDirective(Lex, Tok))
1718 MaxOffset = SM.getFileOffset(Tok.getLocation());
1723 bool isDeletedHeader(llvm::StringRef HeaderName,
1724 const std::set<llvm::StringRef> &HeadersToDelete) {
1725 return HeadersToDelete.count(HeaderName) ||
1726 HeadersToDelete.count(HeaderName.trim(
"\"<>"));
1730 tooling::Replacements
1731 fixCppIncludeInsertions(StringRef Code,
const tooling::Replacements &Replaces,
1736 tooling::Replacements HeaderInsertions;
1737 std::set<llvm::StringRef> HeadersToDelete;
1738 tooling::Replacements Result;
1739 for (
const auto &R : Replaces) {
1740 if (isHeaderInsertion(R)) {
1743 llvm::consumeError(HeaderInsertions.add(R));
1744 }
else if (isHeaderDeletion(R)) {
1745 HeadersToDelete.insert(R.getReplacementText());
1746 }
else if (R.getOffset() ==
UINT_MAX) {
1747 llvm::errs() <<
"Insertions other than header #include insertion are "
1749 << R.getReplacementText() <<
"\n";
1751 llvm::consumeError(Result.add(R));
1754 if (HeaderInsertions.empty() && HeadersToDelete.empty())
1757 llvm::Regex IncludeRegex(IncludeRegexPattern);
1758 llvm::Regex DefineRegex(R
"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1759 SmallVector<StringRef, 4> Matches;
1761 StringRef FileName = Replaces.begin()->getFilePath();
1762 IncludeCategoryManager Categories(Style, FileName);
1765 std::map<int, int> CategoryEndOffsets;
1768 std::set<int> Priorities = {0,
INT_MAX};
1770 Priorities.insert(
Category.Priority);
1771 int FirstIncludeOffset = -1;
1773 unsigned MinInsertOffset =
1774 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
1775 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
1777 unsigned MaxInsertOffset =
1779 getMaxHeaderInsertionOffset(FileName, TrimmedCode, Style);
1780 SmallVector<StringRef, 32> Lines;
1781 TrimmedCode.split(Lines,
'\n');
1782 unsigned Offset = MinInsertOffset;
1783 unsigned NextLineOffset;
1784 std::set<StringRef> ExistingIncludes;
1785 for (
auto Line : Lines) {
1786 NextLineOffset =
std::min(Code.size(), Offset + Line.size() + 1);
1787 if (IncludeRegex.match(Line, &Matches)) {
1789 StringRef IncludeName = Matches[2];
1790 ExistingIncludes.insert(IncludeName);
1792 if (Offset <= MaxInsertOffset) {
1793 int Category = Categories.getIncludePriority(
1794 IncludeName, FirstIncludeOffset < 0);
1795 CategoryEndOffsets[
Category] = NextLineOffset;
1796 if (FirstIncludeOffset < 0)
1797 FirstIncludeOffset =
Offset;
1799 if (isDeletedHeader(IncludeName, HeadersToDelete)) {
1802 unsigned Length =
std::min(Line.size() + 1, Code.size() -
Offset);
1807 llvm::errs() <<
"Failed to add header deletion replacement for "
1813 Offset = NextLineOffset;
1820 auto Highest = Priorities.begin();
1821 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
1822 if (FirstIncludeOffset >= 0)
1823 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
1825 CategoryEndOffsets[*Highest] = MinInsertOffset;
1831 for (
auto I = ++Priorities.begin(),
E = Priorities.end();
I !=
E; ++
I)
1832 if (CategoryEndOffsets.find(*
I) == CategoryEndOffsets.end())
1833 CategoryEndOffsets[*
I] = CategoryEndOffsets[*std::prev(
I)];
1835 bool NeedNewLineAtEnd = !Code.empty() && Code.back() !=
'\n';
1836 for (
const auto &R : HeaderInsertions) {
1837 auto IncludeDirective = R.getReplacementText();
1838 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
1839 assert(Matched &&
"Header insertion replacement must have replacement text "
1842 auto IncludeName = Matches[2];
1843 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
1844 DEBUG(llvm::dbgs() <<
"Skip adding existing include : " << IncludeName
1849 Categories.getIncludePriority(IncludeName,
true);
1850 Offset = CategoryEndOffsets[
Category];
1851 std::string NewInclude = !IncludeDirective.endswith(
"\n")
1852 ? (IncludeDirective +
"\n").str()
1853 : IncludeDirective.str();
1856 if (NeedNewLineAtEnd && Offset == Code.size()) {
1857 NewInclude =
"\n" + NewInclude;
1858 NeedNewLineAtEnd =
false;
1861 auto Err = Result.add(NewReplace);
1863 llvm::consumeError(std::move(Err));
1864 unsigned NewOffset = Result.getShiftedCodePosition(Offset);
1866 Result = Result.merge(tooling::Replacements(NewReplace));
1880 std::vector<tooling::Range> Ranges,
1882 return cleanup(Style, Code, Ranges, FileName);
1886 fixCppIncludeInsertions(Code, Replaces, Style);
1900 typedef std::function<tooling::Replacements(const Environment &)>
1919 return JavaScriptRequoter(Env, Expanded).process();
1923 return Formatter(Env, Expanded, Status).process();
1926 std::unique_ptr<Environment> Env =
1930 for (
size_t I = 0,
E = Passes.size();
I <
E; ++
I) {
1933 CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes);
1935 Fixes = Fixes.
merge(PassFixes);
1937 CurrentCode = std::move(*NewCode);
1939 *CurrentCode, FileName,
1950 StringRef FileName) {
1954 std::unique_ptr<Environment> Env =
1956 Cleaner Clean(*Env, Style);
1957 return Clean.process();
1962 StringRef FileName,
bool *IncompleteFormat) {
1964 auto Result =
reformat(Style, Code, Ranges, FileName, &Status);
1966 *IncompleteFormat =
true;
1973 StringRef FileName) {
1974 std::unique_ptr<Environment> Env =
1983 StringRef FileName) {
1984 std::unique_ptr<Environment> Env =
1992 LangOpts.CPlusPlus = 1;
1996 LangOpts.LineComment = 1;
1997 bool AlternativeOperators = Style.
isCpp();
1998 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
2002 LangOpts.MicrosoftExt = 1;
2003 LangOpts.DeclSpecKeyword = 1;
2008 "Coding style, currently supports:\n"
2009 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
2010 "Use -style=file to load style configuration from\n"
2011 ".clang-format file located in one of the parent\n"
2012 "directories of the source file (or current\n"
2013 "directory for stdin).\n"
2014 "Use -style=\"{key: value, ...}\" to set specific\n"
2015 "parameters, e.g.:\n"
2016 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
2019 if (FileName.endswith(
".java"))
2021 if (FileName.endswith_lower(
".js") || FileName.endswith_lower(
".ts"))
2023 if (FileName.endswith(
".m") || FileName.endswith(
".mm"))
2025 if (FileName.endswith_lower(
".proto") ||
2026 FileName.endswith_lower(
".protodevel"))
2028 if (FileName.endswith_lower(
".td"))
2034 StringRef FallbackStyleName,
2046 (Code.contains(
"\n- (") || Code.contains(
"\n+ (")))
2053 if (StyleName.startswith(
"{")) {
2060 if (!StyleName.equals_lower(
"file")) {
2072 for (StringRef Directory = Path; !Directory.empty();
2073 Directory = llvm::sys::path::parent_path(Directory)) {
2077 Status->getType() != llvm::sys::fs::file_type::directory_file) {
2083 llvm::sys::path::append(ConfigFile,
".clang-format");
2084 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
2087 bool FoundConfigFile =
2088 Status && (
Status->getType() == llvm::sys::fs::file_type::regular_file);
2089 if (!FoundConfigFile) {
2091 ConfigFile = Directory;
2092 llvm::sys::path::append(ConfigFile,
"_clang-format");
2093 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
2096 llvm::sys::fs::file_type::regular_file);
2099 if (FoundConfigFile) {
2100 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
2102 if (std::error_code EC = Text.getError())
2104 if (std::error_code ec =
2107 if (!UnsuitableConfigFiles.empty())
2108 UnsuitableConfigFiles.append(
", ");
2109 UnsuitableConfigFiles.append(ConfigFile);
2115 DEBUG(llvm::dbgs() <<
"Using configuration file " << ConfigFile <<
"\n");
2119 if (!UnsuitableConfigFiles.empty())
2122 UnsuitableConfigFiles);
2123 return FallbackStyle;
Defines the SourceManager interface.
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
AffectedRangeManager class manages affected ranges in the code.
The virtual file system interface.
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...
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
Defines the Diagnostic-related interfaces.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
detail::InMemoryDirectory::const_iterator I
WhitespaceManager class manages whitespace around tokens and their replacements.
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
static CharSourceRange getCharRange(SourceRange R)
ArrayRef< FormatToken * > Tokens
This file contains the declaration of the UnwrappedLineParser, which turns a stream of tokens into Un...
This file implements a sorter for JavaScript ES6 imports.
Defines the virtual file system interface vfs::FileSystem.
detail::InMemoryDirectory::const_iterator E
std::string toString(const til::SExpr *E)
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
This is a convenience method that opens a file, gets its content and then closes the file...
This file declares an abstract TokenAnalyzer, and associated helper classes.
This file implements an indenter that manages the indentation of continuations.
This file declares UsingDeclarationsSorter, a TokenAnalyzer that sorts consecutive using declarations...
std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.