31 #include "llvm/ADT/STLExtras.h"
32 #include "llvm/Support/Allocator.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/Path.h"
35 #include "llvm/Support/Regex.h"
36 #include "llvm/Support/YAMLTraits.h"
42 #define DEBUG_TYPE "format-formatter"
46 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
47 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::
FormatStyle::IncludeCategory)
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,
"Proto", FormatStyle::LK_Proto);
57 IO.enumCase(Value,
"TableGen", FormatStyle::LK_TableGen);
61 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageStandard> {
63 IO.enumCase(Value,
"Cpp03", FormatStyle::LS_Cpp03);
64 IO.enumCase(Value,
"C++03", FormatStyle::LS_Cpp03);
65 IO.enumCase(Value,
"Cpp11", FormatStyle::LS_Cpp11);
66 IO.enumCase(Value,
"C++11", FormatStyle::LS_Cpp11);
67 IO.enumCase(Value,
"Auto", FormatStyle::LS_Auto);
71 template <>
struct ScalarEnumerationTraits<
FormatStyle::UseTabStyle> {
73 IO.enumCase(Value,
"Never", FormatStyle::UT_Never);
74 IO.enumCase(Value,
"false", FormatStyle::UT_Never);
75 IO.enumCase(Value,
"Always", FormatStyle::UT_Always);
76 IO.enumCase(Value,
"true", FormatStyle::UT_Always);
77 IO.enumCase(Value,
"ForIndentation", FormatStyle::UT_ForIndentation);
78 IO.enumCase(Value,
"ForContinuationAndIndentation",
79 FormatStyle::UT_ForContinuationAndIndentation);
83 template <>
struct ScalarEnumerationTraits<
FormatStyle::JavaScriptQuoteStyle> {
85 IO.enumCase(Value,
"Leave", FormatStyle::JSQS_Leave);
86 IO.enumCase(Value,
"Single", FormatStyle::JSQS_Single);
87 IO.enumCase(Value,
"Double", FormatStyle::JSQS_Double);
91 template <>
struct ScalarEnumerationTraits<
FormatStyle::ShortFunctionStyle> {
93 IO.enumCase(Value,
"None", FormatStyle::SFS_None);
94 IO.enumCase(Value,
"false", FormatStyle::SFS_None);
95 IO.enumCase(Value,
"All", FormatStyle::SFS_All);
96 IO.enumCase(Value,
"true", FormatStyle::SFS_All);
97 IO.enumCase(Value,
"Inline", FormatStyle::SFS_Inline);
98 IO.enumCase(Value,
"Empty", FormatStyle::SFS_Empty);
102 template <>
struct ScalarEnumerationTraits<
FormatStyle::BinaryOperatorStyle> {
104 IO.enumCase(Value,
"All", FormatStyle::BOS_All);
105 IO.enumCase(Value,
"true", FormatStyle::BOS_All);
106 IO.enumCase(Value,
"None", FormatStyle::BOS_None);
107 IO.enumCase(Value,
"false", FormatStyle::BOS_None);
108 IO.enumCase(Value,
"NonAssignment", FormatStyle::BOS_NonAssignment);
112 template <>
struct ScalarEnumerationTraits<
FormatStyle::BraceBreakingStyle> {
114 IO.enumCase(Value,
"Attach", FormatStyle::BS_Attach);
115 IO.enumCase(Value,
"Linux", FormatStyle::BS_Linux);
116 IO.enumCase(Value,
"Mozilla", FormatStyle::BS_Mozilla);
117 IO.enumCase(Value,
"Stroustrup", FormatStyle::BS_Stroustrup);
118 IO.enumCase(Value,
"Allman", FormatStyle::BS_Allman);
119 IO.enumCase(Value,
"GNU", FormatStyle::BS_GNU);
120 IO.enumCase(Value,
"WebKit", FormatStyle::BS_WebKit);
121 IO.enumCase(Value,
"Custom", FormatStyle::BS_Custom);
126 struct ScalarEnumerationTraits<
FormatStyle::ReturnTypeBreakingStyle> {
128 IO.enumCase(Value,
"None", FormatStyle::RTBS_None);
129 IO.enumCase(Value,
"All", FormatStyle::RTBS_All);
130 IO.enumCase(Value,
"TopLevel", FormatStyle::RTBS_TopLevel);
131 IO.enumCase(Value,
"TopLevelDefinitions",
132 FormatStyle::RTBS_TopLevelDefinitions);
133 IO.enumCase(Value,
"AllDefinitions", FormatStyle::RTBS_AllDefinitions);
138 struct ScalarEnumerationTraits<
FormatStyle::DefinitionReturnTypeBreakingStyle> {
141 IO.enumCase(Value,
"None", FormatStyle::DRTBS_None);
142 IO.enumCase(Value,
"All", FormatStyle::DRTBS_All);
143 IO.enumCase(Value,
"TopLevel", FormatStyle::DRTBS_TopLevel);
146 IO.enumCase(Value,
"false", FormatStyle::DRTBS_None);
147 IO.enumCase(Value,
"true", FormatStyle::DRTBS_All);
152 struct ScalarEnumerationTraits<
FormatStyle::NamespaceIndentationKind> {
154 FormatStyle::NamespaceIndentationKind &
Value) {
155 IO.enumCase(Value,
"None", FormatStyle::NI_None);
156 IO.enumCase(Value,
"Inner", FormatStyle::NI_Inner);
157 IO.enumCase(Value,
"All", FormatStyle::NI_All);
161 template <>
struct ScalarEnumerationTraits<
FormatStyle::BracketAlignmentStyle> {
163 IO.enumCase(Value,
"Align", FormatStyle::BAS_Align);
164 IO.enumCase(Value,
"DontAlign", FormatStyle::BAS_DontAlign);
165 IO.enumCase(Value,
"AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
168 IO.enumCase(Value,
"true", FormatStyle::BAS_Align);
169 IO.enumCase(Value,
"false", FormatStyle::BAS_DontAlign);
173 template <>
struct ScalarEnumerationTraits<
FormatStyle::PointerAlignmentStyle> {
175 IO.enumCase(Value,
"Middle", FormatStyle::PAS_Middle);
176 IO.enumCase(Value,
"Left", FormatStyle::PAS_Left);
177 IO.enumCase(Value,
"Right", FormatStyle::PAS_Right);
180 IO.enumCase(Value,
"true", FormatStyle::PAS_Left);
181 IO.enumCase(Value,
"false", FormatStyle::PAS_Right);
186 struct ScalarEnumerationTraits<
FormatStyle::SpaceBeforeParensOptions> {
188 FormatStyle::SpaceBeforeParensOptions &
Value) {
189 IO.enumCase(Value,
"Never", FormatStyle::SBPO_Never);
190 IO.enumCase(Value,
"ControlStatements",
191 FormatStyle::SBPO_ControlStatements);
192 IO.enumCase(Value,
"Always", FormatStyle::SBPO_Always);
195 IO.enumCase(Value,
"false", FormatStyle::SBPO_Never);
196 IO.enumCase(Value,
"true", FormatStyle::SBPO_ControlStatements);
203 IO.mapOptional(
"Language", Style.
Language);
205 if (IO.outputting()) {
206 StringRef StylesArray[] = {
"LLVM",
"Google",
"Chromium",
207 "Mozilla",
"WebKit",
"GNU"};
209 for (
size_t i = 0, e = Styles.size(); i < e; ++i) {
210 StringRef StyleName(Styles[i]);
213 Style == PredefinedStyle) {
214 IO.mapOptional(
"# BasedOnStyle", StyleName);
219 StringRef BasedOnStyle;
220 IO.mapOptional(
"BasedOnStyle", BasedOnStyle);
221 if (!BasedOnStyle.empty()) {
222 FormatStyle::LanguageKind OldLanguage = Style.
Language;
223 FormatStyle::LanguageKind Language =
226 IO.setError(Twine(
"Unknown value for BasedOnStyle: ", BasedOnStyle));
234 if (!IO.outputting()) {
236 IO.mapOptional(
"IndentFunctionDeclarationAfterType",
239 IO.mapOptional(
"SpaceAfterControlStatementKeyword",
245 IO.mapOptional(
"AlignConsecutiveAssignments",
247 IO.mapOptional(
"AlignConsecutiveDeclarations",
252 IO.mapOptional(
"AllowAllParametersOfDeclarationOnNextLine",
254 IO.mapOptional(
"AllowShortBlocksOnASingleLine",
256 IO.mapOptional(
"AllowShortCaseLabelsOnASingleLine",
258 IO.mapOptional(
"AllowShortFunctionsOnASingleLine",
260 IO.mapOptional(
"AllowShortIfStatementsOnASingleLine",
262 IO.mapOptional(
"AllowShortLoopsOnASingleLine",
264 IO.mapOptional(
"AlwaysBreakAfterDefinitionReturnType",
266 IO.mapOptional(
"AlwaysBreakAfterReturnType",
276 FormatStyle::DRTBS_TopLevel)
278 FormatStyle::RTBS_TopLevelDefinitions;
281 IO.mapOptional(
"AlwaysBreakBeforeMultilineStrings",
283 IO.mapOptional(
"AlwaysBreakTemplateDeclarations",
288 IO.mapOptional(
"BreakBeforeBinaryOperators",
291 IO.mapOptional(
"BreakBeforeTernaryOperators",
293 IO.mapOptional(
"BreakConstructorInitializersBeforeComma",
295 IO.mapOptional(
"BreakAfterJavaFieldAnnotations",
300 IO.mapOptional(
"ConstructorInitializerAllOnOneLineOrOnePerLine",
302 IO.mapOptional(
"ConstructorInitializerIndentWidth",
308 IO.mapOptional(
"ExperimentalAutoDetectBinPacking",
315 IO.mapOptional(
"IndentWrappedFunctionNames",
319 IO.mapOptional(
"KeepEmptyLinesAtTheStartOfBlocks",
327 IO.mapOptional(
"ObjCSpaceBeforeProtocolList",
329 IO.mapOptional(
"PenaltyBreakBeforeFirstCallParameter",
332 IO.mapOptional(
"PenaltyBreakFirstLessLess",
336 IO.mapOptional(
"PenaltyReturnTypeOnItsOwnLine",
342 IO.mapOptional(
"SpaceBeforeAssignmentOperators",
346 IO.mapOptional(
"SpacesBeforeTrailingComments",
349 IO.mapOptional(
"SpacesInContainerLiterals",
351 IO.mapOptional(
"SpacesInCStyleCastParentheses",
355 IO.mapOptional(
"Standard", Style.
Standard);
356 IO.mapOptional(
"TabWidth", Style.
TabWidth);
357 IO.mapOptional(
"UseTab", Style.
UseTab);
361 template <>
struct MappingTraits<
FormatStyle::BraceWrappingFlags> {
362 static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
363 IO.mapOptional(
"AfterClass", Wrapping.AfterClass);
364 IO.mapOptional(
"AfterControlStatement", Wrapping.AfterControlStatement);
365 IO.mapOptional(
"AfterEnum", Wrapping.AfterEnum);
366 IO.mapOptional(
"AfterFunction", Wrapping.AfterFunction);
367 IO.mapOptional(
"AfterNamespace", Wrapping.AfterNamespace);
368 IO.mapOptional(
"AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
369 IO.mapOptional(
"AfterStruct", Wrapping.AfterStruct);
370 IO.mapOptional(
"AfterUnion", Wrapping.AfterUnion);
371 IO.mapOptional(
"BeforeCatch", Wrapping.BeforeCatch);
372 IO.mapOptional(
"BeforeElse", Wrapping.BeforeElse);
373 IO.mapOptional(
"IndentBraces", Wrapping.IndentBraces);
379 IO.mapOptional(
"Regex", Category.Regex);
380 IO.mapOptional(
"Priority", Category.Priority);
389 template <>
struct DocumentListTraits<std::vector<FormatStyle>> {
390 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
395 if (Index >= Seq.size()) {
396 assert(Index == Seq.size());
398 if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
401 Template = *((
const FormatStyle *)IO.getContext());
402 Template.
Language = FormatStyle::LK_None;
404 Seq.resize(Index + 1, Template);
424 return "clang-format.parse_error";
428 switch (static_cast<ParseError>(EV)) {
432 return "Invalid argument";
436 llvm_unreachable(
"unexpected parse error");
443 Expanded.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
444 false,
false,
false,
false,
false};
475 Expanded.
BraceWrapping = {
true,
true,
true,
true,
true,
true,
476 true,
true,
true,
true,
true};
512 LLVMStyle.
BraceWrapping = {
false,
false,
false,
false,
false,
false,
513 false,
false,
false,
false,
false};
529 {
"^(<|\"(gtest|isl|json)/)", 3},
615 GoogleStyle.
CommentPragmas =
"@(export|requirecss|return|see|visibility) ";
645 return ChromiumStyle;
713 if (Name.equals_lower(
"llvm")) {
715 }
else if (Name.equals_lower(
"chromium")) {
717 }
else if (Name.equals_lower(
"mozilla")) {
719 }
else if (Name.equals_lower(
"google")) {
721 }
else if (Name.equals_lower(
"webkit")) {
723 }
else if (Name.equals_lower(
"gnu")) {
725 }
else if (Name.equals_lower(
"none")) {
739 if (Text.trim().empty())
742 std::vector<FormatStyle> Styles;
748 Input.setContext(Style);
751 return Input.error();
753 for (
unsigned i = 0; i < Styles.size(); ++i) {
758 for (
unsigned j = 0; j < i; ++j) {
759 if (Styles[i].Language == Styles[j].Language) {
761 <<
"Duplicate languages in the config file on positions " << j
762 <<
" and " << i <<
"\n");
770 for (
int i = Styles.size() - 1; i >= 0; --i) {
771 if (Styles[i].Language == Language ||
783 llvm::raw_string_ostream Stream(Text);
784 llvm::yaml::Output Output(Stream);
788 Output << NonConstStyle;
794 class Formatter :
public TokenAnalyzer {
798 : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {}
801 analyze(TokenAnnotator &Annotator,
802 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
804 deriveLocalStyle(AnnotatedLines);
805 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
806 AnnotatedLines.end());
810 requoteJSStringLiteral(AnnotatedLines, Result);
812 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
813 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
816 Annotator.setCommentLineLevels(AnnotatedLines);
819 Env.getSourceManager(),
Style,
820 inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
826 .format(AnnotatedLines);
834 void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
836 for (AnnotatedLine *
Line : Lines) {
837 requoteJSStringLiteral(
Line->Children, Result);
840 for (FormatToken *FormatTok =
Line->First; FormatTok;
841 FormatTok = FormatTok->Next) {
842 StringRef
Input = FormatTok->TokenText;
843 if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
848 !Input.startswith(
"\"")) ||
850 !Input.startswith(
"\'")))
855 SourceLocation Start = FormatTok->Tok.getLocation();
856 auto Replace = [&](SourceLocation Start,
unsigned Length,
857 StringRef ReplacementText) {
859 Length, ReplacementText));
861 Replace(Start, 1, IsSingle ?
"'" :
"\"");
862 Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
863 IsSingle ?
"'" :
"\"");
866 size_t ColumnWidth = FormatTok->TokenText.size();
867 bool Escaped =
false;
868 for (
size_t i = 1; i < Input.size() - 1; i++) {
871 if (!Escaped && i + 1 < Input.size() &&
872 ((IsSingle && Input[i + 1] ==
'"') ||
873 (!IsSingle && Input[i + 1] ==
'\''))) {
877 Replace(Start.getLocWithOffset(i), 1,
"");
884 if (!Escaped && IsSingle == (Input[i] ==
'\'')) {
886 Replace(Start.getLocWithOffset(i), 0,
"\\");
902 FormatTok->ColumnWidth = ColumnWidth;
907 static bool inputUsesCRLF(StringRef
Text) {
908 return Text.count(
'\r') * 2 > Text.count(
'\n');
912 hasCpp03IncompatibleFormat(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
913 for (
const AnnotatedLine *
Line : Lines) {
914 if (hasCpp03IncompatibleFormat(
Line->Children))
916 for (FormatToken *Tok =
Line->First->Next; Tok; Tok = Tok->Next) {
917 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
918 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
920 if (Tok->is(TT_TemplateCloser) &&
921 Tok->Previous->is(TT_TemplateCloser))
929 int countVariableAlignments(
const SmallVectorImpl<AnnotatedLine *> &Lines) {
930 int AlignmentDiff = 0;
931 for (
const AnnotatedLine *
Line : Lines) {
932 AlignmentDiff += countVariableAlignments(
Line->Children);
933 for (FormatToken *Tok =
Line->First; Tok && Tok->Next; Tok = Tok->Next) {
934 if (!Tok->is(TT_PointerOrReference))
937 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
938 bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
939 Tok->Next->WhitespaceRange.getEnd();
940 if (SpaceBefore && !SpaceAfter)
942 if (!SpaceBefore && SpaceAfter)
946 return AlignmentDiff;
950 deriveLocalStyle(
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
951 bool HasBinPackedFunction =
false;
952 bool HasOnePerLineFunction =
false;
953 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
954 if (!AnnotatedLines[i]->First->Next)
956 FormatToken *Tok = AnnotatedLines[i]->First->Next;
959 HasBinPackedFunction =
true;
961 HasOnePerLineFunction =
true;
975 HasBinPackedFunction || !HasOnePerLineFunction;
984 class Cleaner :
public TokenAnalyzer {
987 : TokenAnalyzer(Env, Style),
992 analyze(TokenAnnotator &Annotator,
993 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1002 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1003 AnnotatedLines.end());
1005 checkEmptyNamespace(AnnotatedLines);
1007 for (
auto &
Line : AnnotatedLines) {
1008 if (
Line->Affected) {
1009 cleanupRight(
Line->First, tok::comma, tok::comma);
1010 cleanupRight(
Line->First, TT_CtorInitializerColon, tok::comma);
1011 cleanupLeft(
Line->First, TT_CtorInitializerComma, tok::l_brace);
1012 cleanupLeft(
Line->First, TT_CtorInitializerColon, tok::l_brace);
1016 return generateFixes();
1020 bool containsOnlyComments(
const AnnotatedLine &
Line) {
1021 for (FormatToken *Tok = Line.First; Tok !=
nullptr; Tok = Tok->Next) {
1022 if (Tok->isNot(tok::comment))
1029 void checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1030 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1031 auto &Line = *AnnotatedLines[i];
1032 if (Line.startsWith(tok::kw_namespace) ||
1033 Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
1034 checkEmptyNamespace(AnnotatedLines, i, i);
1039 FormatToken *Tok = AnnotatedLines[
Line]->First;
1051 bool checkEmptyNamespace(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1052 unsigned CurrentLine,
unsigned &
NewLine) {
1053 unsigned InitLine = CurrentLine,
End = AnnotatedLines.size();
1058 if (!AnnotatedLines[++CurrentLine]->startsWith(tok::l_brace)) {
1059 NewLine = CurrentLine;
1062 }
else if (!AnnotatedLines[CurrentLine]->endsWith(tok::l_brace)) {
1065 while (++CurrentLine < End) {
1066 if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
1069 if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
1070 AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
1071 tok::kw_namespace)) {
1072 if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine))
1078 if (containsOnlyComments(*AnnotatedLines[CurrentLine]))
1083 NewLine = CurrentLine;
1087 NewLine = CurrentLine;
1088 if (CurrentLine >= End)
1093 AnnotatedLines[InitLine]->First->Tok.getLocation(),
1094 AnnotatedLines[CurrentLine]->Last->Tok.getEndLoc())))
1097 for (
unsigned i = InitLine; i <= CurrentLine; ++i) {
1098 DeletedLines.insert(i);
1108 template <
typename LeftKind,
typename RightKind>
1109 void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
1111 auto NextNotDeleted = [
this](
const FormatToken &Tok) -> FormatToken * {
1112 for (
auto *Res = Tok.Next; Res; Res = Res->Next)
1113 if (!Res->is(tok::comment) &&
1118 for (
auto *Left = Start; Left;) {
1119 auto *Right = NextNotDeleted(*Left);
1122 if (Left->is(LK) && Right->is(RK)) {
1123 deleteToken(DeleteLeft ? Left : Right);
1133 template <
typename LeftKind,
typename RightKind>
1134 void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
1135 cleanupPair(Start, LK, RK,
true);
1138 template <
typename LeftKind,
typename RightKind>
1139 void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
1140 cleanupPair(Start, LK, RK,
false);
1144 inline void deleteToken(FormatToken *Tok) {
1151 std::vector<FormatToken *>
Tokens;
1153 std::back_inserter(Tokens));
1159 while (Idx < Tokens.size()) {
1160 unsigned St = Idx, End = Idx;
1161 while ((End + 1) < Tokens.size() &&
1162 Tokens[
End]->Next == Tokens[End + 1]) {
1166 Tokens[
End]->Tok.getEndLoc());
1177 struct FormatTokenLess {
1178 FormatTokenLess(
const SourceManager &
SM) : SM(SM) {}
1180 bool operator()(
const FormatToken *LHS,
const FormatToken *RHS)
const {
1181 return SM.isBeforeInTranslationUnit(LHS->Tok.getLocation(),
1182 RHS->Tok.getLocation());
1193 struct IncludeDirective {
1205 for (
auto Range : Ranges) {
1206 if (Range.getOffset() < End &&
1207 Range.getOffset() + Range.getLength() > Start)
1221 Includes.back().Offset + Includes.back().Text.size()))
1224 for (
unsigned i = 0, e = Includes.size(); i != e; ++i)
1225 Indices.push_back(i);
1227 Indices.begin(), Indices.end(), [&](
unsigned LHSI,
unsigned RHSI) {
1229 std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
1234 if (std::is_sorted(Indices.begin(), Indices.end()))
1238 bool CursorMoved =
false;
1239 for (
unsigned Index : Indices) {
1240 if (!result.empty())
1242 result += Includes[Index].Text;
1244 if (Cursor && !CursorMoved) {
1245 unsigned Start = Includes[Index].Offset;
1246 unsigned End = Start + Includes[Index].Text.size();
1247 if (*Cursor >= Start && *Cursor < End) {
1248 *Cursor = Includes.front().Offset + result.size() + *Cursor -
End;
1256 assert(result.size() ==
1257 Includes.back().Offset + Includes.back().Text.size() -
1258 Includes.front().Offset);
1261 result.size(), result));
1268 class IncludeCategoryManager {
1271 : Style(Style), FileName(FileName) {
1272 FileStem = llvm::sys::path::stem(FileName);
1275 IsMainFile = FileName.endswith(
".c") || FileName.endswith(
".cc") ||
1276 FileName.endswith(
".cpp") || FileName.endswith(
".c++") ||
1277 FileName.endswith(
".cxx") || FileName.endswith(
".m") ||
1278 FileName.endswith(
".mm");
1284 int getIncludePriority(StringRef IncludeName,
bool CheckMainHeader) {
1291 if (CheckMainHeader &&
IsMainFile && Ret > 0 && isMainHeader(IncludeName))
1297 bool isMainHeader(StringRef IncludeName)
const {
1298 if (!IncludeName.startswith(
"\""))
1300 StringRef HeaderStem =
1301 llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
1302 if (
FileStem.startswith(HeaderStem)) {
1303 llvm::Regex MainIncludeRegex(
1305 if (MainIncludeRegex.match(
FileStem))
1318 const char IncludeRegexPattern[] =
1319 R
"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
1329 unsigned SearchFrom = 0;
1330 llvm::Regex IncludeRegex(IncludeRegexPattern);
1341 IncludeCategoryManager Categories(Style, FileName);
1342 bool FirstIncludeBlock =
true;
1343 bool MainIncludeFound =
false;
1344 bool FormattingOff =
false;
1347 auto Pos = Code.find(
'\n', SearchFrom);
1349 Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
1351 StringRef Trimmed = Line.trim();
1352 if (Trimmed ==
"// clang-format off")
1353 FormattingOff =
true;
1354 else if (Trimmed ==
"// clang-format on")
1355 FormattingOff =
false;
1357 if (!FormattingOff && !Line.endswith(
"\\")) {
1358 if (IncludeRegex.match(Line, &Matches)) {
1359 StringRef IncludeName = Matches[2];
1360 int Category = Categories.getIncludePriority(
1362 !MainIncludeFound && FirstIncludeBlock);
1364 MainIncludeFound =
true;
1365 IncludesInBlock.push_back({IncludeName,
Line, Prev, Category});
1366 }
else if (!IncludesInBlock.empty()) {
1369 IncludesInBlock.clear();
1370 FirstIncludeBlock =
false;
1374 if (Pos == StringRef::npos || Pos + 1 == Code.size())
1376 SearchFrom = Pos + 1;
1378 if (!IncludesInBlock.empty())
1379 sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
1385 StringRef FileName,
unsigned *
Cursor) {
1389 if (Style.
Language == FormatStyle::LanguageKind::LK_JavaScript)
1395 template <
typename T>
1396 static llvm::Expected<tooling::Replacements>
1400 if (Replaces.empty())
1405 return NewCode.takeError();
1406 std::vector<tooling::Range> ChangedRanges =
1408 StringRef FileName = Replaces.begin()->getFilePath();
1411 ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
1416 llvm::Expected<tooling::Replacements>
1422 std::vector<tooling::Range> Ranges,
1426 auto SortedReplaces =
1428 if (!SortedReplaces)
1429 return SortedReplaces.takeError();
1434 std::vector<tooling::Range> Ranges,
1436 return reformat(Style, Code, Ranges, FileName);
1448 void skipComments(Lexer &Lex,
Token &Tok) {
1449 while (Tok.is(tok::comment))
1450 if (Lex.LexFromRawLexer(Tok))
1457 bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef
Name,
Token &Tok) {
1458 bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
1459 Tok.is(tok::raw_identifier) &&
1460 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
1461 Tok.is(tok::raw_identifier);
1463 Lex.LexFromRawLexer(Tok);
1467 unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
1470 std::unique_ptr<Environment> Env =
1472 const SourceManager &SourceMgr = Env->getSourceManager();
1473 Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr,
1477 Lex.LexFromRawLexer(Tok);
1478 skipComments(Lex, Tok);
1479 unsigned AfterComments = SourceMgr.getFileOffset(Tok.getLocation());
1480 if (checkAndConsumeDirectiveWithName(Lex,
"ifndef", Tok)) {
1481 skipComments(Lex, Tok);
1482 if (checkAndConsumeDirectiveWithName(Lex,
"define", Tok))
1483 return SourceMgr.getFileOffset(Tok.getLocation());
1485 return AfterComments;
1497 if (Style.
Language != FormatStyle::LanguageKind::LK_Cpp)
1501 for (
const auto &R : Replaces) {
1502 if (isHeaderInsertion(R))
1503 HeaderInsertions.insert(R);
1504 else if (R.getOffset() ==
UINT_MAX)
1505 llvm::errs() <<
"Insertions other than header #include insertion are "
1507 << R.getReplacementText() <<
"\n";
1509 if (HeaderInsertions.empty())
1512 std::set_difference(Replaces.begin(), Replaces.end(),
1513 HeaderInsertions.begin(), HeaderInsertions.end(),
1514 std::inserter(Result, Result.begin()));
1516 llvm::Regex IncludeRegex(IncludeRegexPattern);
1517 llvm::Regex DefineRegex(R
"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
1518 SmallVector<StringRef, 4> Matches;
1520 StringRef FileName = Replaces.begin()->getFilePath();
1521 IncludeCategoryManager Categories(Style, FileName);
1524 std::map<int, int> CategoryEndOffsets;
1527 std::set<int> Priorities = {0,
INT_MAX};
1529 Priorities.insert(
Category.Priority);
1530 int FirstIncludeOffset = -1;
1532 unsigned MinInsertOffset =
1533 getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style);
1534 StringRef TrimmedCode = Code.drop_front(MinInsertOffset);
1535 SmallVector<StringRef, 32> Lines;
1536 TrimmedCode.split(Lines,
'\n');
1537 unsigned Offset = MinInsertOffset;
1538 unsigned NextLineOffset;
1539 std::set<StringRef> ExistingIncludes;
1540 for (
auto Line : Lines) {
1541 NextLineOffset =
std::min(Code.size(), Offset + Line.size() + 1);
1542 if (IncludeRegex.match(Line, &Matches)) {
1543 StringRef IncludeName = Matches[2];
1544 ExistingIncludes.insert(IncludeName);
1545 int Category = Categories.getIncludePriority(
1546 IncludeName, FirstIncludeOffset < 0);
1547 CategoryEndOffsets[
Category] = NextLineOffset;
1548 if (FirstIncludeOffset < 0)
1549 FirstIncludeOffset =
Offset;
1551 Offset = NextLineOffset;
1558 auto Highest = Priorities.begin();
1559 if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
1560 if (FirstIncludeOffset >= 0)
1561 CategoryEndOffsets[*Highest] = FirstIncludeOffset;
1563 CategoryEndOffsets[*Highest] = MinInsertOffset;
1569 for (
auto I = ++Priorities.begin(),
E = Priorities.end();
I !=
E; ++
I)
1570 if (CategoryEndOffsets.find(*
I) == CategoryEndOffsets.end())
1571 CategoryEndOffsets[*
I] = CategoryEndOffsets[*std::prev(
I)];
1573 for (
const auto &R : HeaderInsertions) {
1574 auto IncludeDirective = R.getReplacementText();
1575 bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
1576 assert(Matched &&
"Header insertion replacement must have replacement text "
1579 auto IncludeName = Matches[2];
1580 if (ExistingIncludes.find(IncludeName) != ExistingIncludes.end()) {
1581 DEBUG(llvm::dbgs() <<
"Skip adding existing include : " << IncludeName
1586 Categories.getIncludePriority(IncludeName,
true);
1587 Offset = CategoryEndOffsets[
Category];
1588 std::string NewInclude = !IncludeDirective.endswith(
"\n")
1589 ? (IncludeDirective +
"\n").str()
1590 : IncludeDirective.str();
1598 llvm::Expected<tooling::Replacements>
1604 std::vector<tooling::Range> Ranges,
1606 return cleanup(Style, Code, Ranges, FileName);
1610 fixCppIncludeInsertions(Code, Replaces, Style);
1622 Formatter Format(Env, Expanded, IncompleteFormat);
1623 return Format.process();
1633 std::unique_ptr<Environment> Env =
1635 Formatter Format(*Env, Expanded, IncompleteFormat);
1636 return Format.process();
1642 Cleaner Clean(Env, Style);
1643 return Clean.process();
1648 StringRef FileName) {
1649 std::unique_ptr<Environment> Env =
1651 Cleaner Clean(*Env, Style);
1652 return Clean.process();
1657 LangOpts.CPlusPlus = 1;
1660 LangOpts.LineComment = 1;
1662 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
1666 LangOpts.MicrosoftExt = 1;
1667 LangOpts.DeclSpecKeyword = 1;
1672 "Coding style, currently supports:\n"
1673 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
1674 "Use -style=file to load style configuration from\n"
1675 ".clang-format file located in one of the parent\n"
1676 "directories of the source file (or current\n"
1677 "directory for stdin).\n"
1678 "Use -style=\"{key: value, ...}\" to set specific\n"
1679 "parameters, e.g.:\n"
1680 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
1683 if (FileName.endswith(
".java"))
1685 if (FileName.endswith_lower(
".js") || FileName.endswith_lower(
".ts"))
1687 if (FileName.endswith_lower(
".proto") ||
1688 FileName.endswith_lower(
".protodevel"))
1690 if (FileName.endswith_lower(
".td"))
1703 llvm::errs() <<
"Invalid fallback style \"" << FallbackStyle
1704 <<
"\" using LLVM style\n";
1708 if (StyleName.startswith(
"{")) {
1711 llvm::errs() <<
"Error parsing -style: " << ec.message() <<
", using "
1712 << FallbackStyle <<
" style\n";
1717 if (!StyleName.equals_lower(
"file")) {
1719 llvm::errs() <<
"Invalid value for -style, using " << FallbackStyle
1727 llvm::sys::fs::make_absolute(Path);
1728 for (StringRef Directory = Path; !Directory.empty();
1729 Directory = llvm::sys::path::parent_path(Directory)) {
1731 auto Status = FS->
status(Directory);
1733 Status->getType() != llvm::sys::fs::file_type::directory_file) {
1739 llvm::sys::path::append(ConfigFile,
".clang-format");
1740 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
1742 Status = FS->
status(ConfigFile.str());
1744 Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
1747 ConfigFile = Directory;
1748 llvm::sys::path::append(ConfigFile,
"_clang-format");
1749 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
1750 Status = FS->
status(ConfigFile.str());
1752 (Status->getType() == llvm::sys::fs::file_type::regular_file);
1756 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
1758 if (std::error_code EC = Text.getError()) {
1759 llvm::errs() << EC.message() <<
"\n";
1762 if (std::error_code ec =
1765 if (!UnsuitableConfigFiles.empty())
1766 UnsuitableConfigFiles.append(
", ");
1767 UnsuitableConfigFiles.append(ConfigFile);
1770 llvm::errs() <<
"Error reading " << ConfigFile <<
": " << ec.message()
1774 DEBUG(llvm::dbgs() <<
"Using configuration file " << ConfigFile <<
"\n");
1778 if (!UnsuitableConfigFiles.empty()) {
1779 llvm::errs() <<
"Configuration file(s) do(es) not support "
1781 << UnsuitableConfigFiles <<
"\n";
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.
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
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.
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...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
This file implements a sorter for JavaScript ES6 imports.
Defines the virtual file system interface vfs::FileSystem.
detail::InMemoryDirectory::const_iterator E
Defines the Diagnostic-related interfaces.
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 class handles loading and caching of source files into memory.