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)
43 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageKind> {
45 IO.enumCase(Value,
"Cpp", FormatStyle::LK_Cpp);
46 IO.enumCase(Value,
"Java", FormatStyle::LK_Java);
47 IO.enumCase(Value,
"JavaScript", FormatStyle::LK_JavaScript);
48 IO.enumCase(Value,
"Proto", FormatStyle::LK_Proto);
52 template <>
struct ScalarEnumerationTraits<
FormatStyle::LanguageStandard> {
54 IO.enumCase(Value,
"Cpp03", FormatStyle::LS_Cpp03);
55 IO.enumCase(Value,
"C++03", FormatStyle::LS_Cpp03);
56 IO.enumCase(Value,
"Cpp11", FormatStyle::LS_Cpp11);
57 IO.enumCase(Value,
"C++11", FormatStyle::LS_Cpp11);
58 IO.enumCase(Value,
"Auto", FormatStyle::LS_Auto);
62 template <>
struct ScalarEnumerationTraits<
FormatStyle::UseTabStyle> {
64 IO.enumCase(Value,
"Never", FormatStyle::UT_Never);
65 IO.enumCase(Value,
"false", FormatStyle::UT_Never);
66 IO.enumCase(Value,
"Always", FormatStyle::UT_Always);
67 IO.enumCase(Value,
"true", FormatStyle::UT_Always);
68 IO.enumCase(Value,
"ForIndentation", FormatStyle::UT_ForIndentation);
72 template <>
struct ScalarEnumerationTraits<
FormatStyle::ShortFunctionStyle> {
74 IO.enumCase(Value,
"None", FormatStyle::SFS_None);
75 IO.enumCase(Value,
"false", FormatStyle::SFS_None);
76 IO.enumCase(Value,
"All", FormatStyle::SFS_All);
77 IO.enumCase(Value,
"true", FormatStyle::SFS_All);
78 IO.enumCase(Value,
"Inline", FormatStyle::SFS_Inline);
79 IO.enumCase(Value,
"Empty", FormatStyle::SFS_Empty);
83 template <>
struct ScalarEnumerationTraits<
FormatStyle::BinaryOperatorStyle> {
85 IO.enumCase(Value,
"All", FormatStyle::BOS_All);
86 IO.enumCase(Value,
"true", FormatStyle::BOS_All);
87 IO.enumCase(Value,
"None", FormatStyle::BOS_None);
88 IO.enumCase(Value,
"false", FormatStyle::BOS_None);
89 IO.enumCase(Value,
"NonAssignment", FormatStyle::BOS_NonAssignment);
93 template <>
struct ScalarEnumerationTraits<
FormatStyle::BraceBreakingStyle> {
95 IO.enumCase(Value,
"Attach", FormatStyle::BS_Attach);
96 IO.enumCase(Value,
"Linux", FormatStyle::BS_Linux);
97 IO.enumCase(Value,
"Mozilla", FormatStyle::BS_Mozilla);
98 IO.enumCase(Value,
"Stroustrup", FormatStyle::BS_Stroustrup);
99 IO.enumCase(Value,
"Allman", FormatStyle::BS_Allman);
100 IO.enumCase(Value,
"GNU", FormatStyle::BS_GNU);
104 template <>
struct ScalarEnumerationTraits<
FormatStyle::DefinitionReturnTypeBreakingStyle> {
106 IO.enumCase(Value,
"None", FormatStyle::DRTBS_None);
107 IO.enumCase(Value,
"All", FormatStyle::DRTBS_All);
108 IO.enumCase(Value,
"TopLevel", FormatStyle::DRTBS_TopLevel);
111 IO.enumCase(Value,
"false", FormatStyle::DRTBS_None);
112 IO.enumCase(Value,
"true", FormatStyle::DRTBS_All);
117 struct ScalarEnumerationTraits<
FormatStyle::NamespaceIndentationKind> {
119 FormatStyle::NamespaceIndentationKind &
Value) {
120 IO.enumCase(Value,
"None", FormatStyle::NI_None);
121 IO.enumCase(Value,
"Inner", FormatStyle::NI_Inner);
122 IO.enumCase(Value,
"All", FormatStyle::NI_All);
126 template <>
struct ScalarEnumerationTraits<
FormatStyle::PointerAlignmentStyle> {
128 IO.enumCase(Value,
"Middle", FormatStyle::PAS_Middle);
129 IO.enumCase(Value,
"Left", FormatStyle::PAS_Left);
130 IO.enumCase(Value,
"Right", FormatStyle::PAS_Right);
133 IO.enumCase(Value,
"true", FormatStyle::PAS_Left);
134 IO.enumCase(Value,
"false", FormatStyle::PAS_Right);
139 struct ScalarEnumerationTraits<
FormatStyle::SpaceBeforeParensOptions> {
141 FormatStyle::SpaceBeforeParensOptions &
Value) {
142 IO.enumCase(Value,
"Never", FormatStyle::SBPO_Never);
143 IO.enumCase(Value,
"ControlStatements",
144 FormatStyle::SBPO_ControlStatements);
145 IO.enumCase(Value,
"Always", FormatStyle::SBPO_Always);
148 IO.enumCase(Value,
"false", FormatStyle::SBPO_Never);
149 IO.enumCase(Value,
"true", FormatStyle::SBPO_ControlStatements);
156 IO.mapOptional(
"Language", Style.
Language);
158 if (IO.outputting()) {
159 StringRef StylesArray[] = {
"LLVM",
"Google",
"Chromium",
160 "Mozilla",
"WebKit",
"GNU"};
162 for (
size_t i = 0, e = Styles.size(); i < e; ++i) {
163 StringRef StyleName(Styles[i]);
166 Style == PredefinedStyle) {
167 IO.mapOptional(
"# BasedOnStyle", StyleName);
172 StringRef BasedOnStyle;
173 IO.mapOptional(
"BasedOnStyle", BasedOnStyle);
174 if (!BasedOnStyle.empty()) {
175 FormatStyle::LanguageKind OldLanguage = Style.
Language;
176 FormatStyle::LanguageKind Language =
179 IO.setError(Twine(
"Unknown value for BasedOnStyle: ", BasedOnStyle));
187 if (!IO.outputting()) {
189 IO.mapOptional(
"IndentFunctionDeclarationAfterType",
192 IO.mapOptional(
"SpaceAfterControlStatementKeyword",
198 IO.mapOptional(
"AlignConsecutiveAssignments",
203 IO.mapOptional(
"AllowAllParametersOfDeclarationOnNextLine",
205 IO.mapOptional(
"AllowShortBlocksOnASingleLine",
207 IO.mapOptional(
"AllowShortCaseLabelsOnASingleLine",
209 IO.mapOptional(
"AllowShortFunctionsOnASingleLine",
211 IO.mapOptional(
"AllowShortIfStatementsOnASingleLine",
213 IO.mapOptional(
"AllowShortLoopsOnASingleLine",
215 IO.mapOptional(
"AlwaysBreakAfterDefinitionReturnType",
217 IO.mapOptional(
"AlwaysBreakBeforeMultilineStrings",
219 IO.mapOptional(
"AlwaysBreakTemplateDeclarations",
223 IO.mapOptional(
"BreakBeforeBinaryOperators",
226 IO.mapOptional(
"BreakBeforeTernaryOperators",
228 IO.mapOptional(
"BreakConstructorInitializersBeforeComma",
232 IO.mapOptional(
"ConstructorInitializerAllOnOneLineOrOnePerLine",
234 IO.mapOptional(
"ConstructorInitializerIndentWidth",
240 IO.mapOptional(
"ExperimentalAutoDetectBinPacking",
245 IO.mapOptional(
"IndentWrappedFunctionNames",
247 IO.mapOptional(
"KeepEmptyLinesAtTheStartOfBlocks",
255 IO.mapOptional(
"ObjCSpaceBeforeProtocolList",
257 IO.mapOptional(
"PenaltyBreakBeforeFirstCallParameter",
260 IO.mapOptional(
"PenaltyBreakFirstLessLess",
264 IO.mapOptional(
"PenaltyReturnTypeOnItsOwnLine",
268 IO.mapOptional(
"SpaceBeforeAssignmentOperators",
272 IO.mapOptional(
"SpacesBeforeTrailingComments",
275 IO.mapOptional(
"SpacesInContainerLiterals",
277 IO.mapOptional(
"SpacesInCStyleCastParentheses",
281 IO.mapOptional(
"Standard", Style.
Standard);
282 IO.mapOptional(
"TabWidth", Style.
TabWidth);
283 IO.mapOptional(
"UseTab", Style.
UseTab);
292 template <>
struct DocumentListTraits<std::vector<FormatStyle>> {
293 static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
298 if (Index >= Seq.size()) {
299 assert(Index == Seq.size());
301 if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
304 Template = *((
const FormatStyle *)IO.getContext());
305 Template.
Language = FormatStyle::LK_None;
307 Seq.resize(Index + 1, Template);
327 return "clang-format.parse_error";
331 switch (static_cast<ParseError>(EV)) {
335 return "Invalid argument";
339 llvm_unreachable(
"unexpected parse error");
477 return ChromiumStyle;
541 if (Name.equals_lower(
"llvm")) {
543 }
else if (Name.equals_lower(
"chromium")) {
545 }
else if (Name.equals_lower(
"mozilla")) {
547 }
else if (Name.equals_lower(
"google")) {
549 }
else if (Name.equals_lower(
"webkit")) {
551 }
else if (Name.equals_lower(
"gnu")) {
553 }
else if (Name.equals_lower(
"none")) {
567 if (Text.trim().empty())
570 std::vector<FormatStyle> Styles;
576 Input.setContext(Style);
579 return Input.error();
581 for (
unsigned i = 0; i < Styles.size(); ++i) {
586 for (
unsigned j = 0; j < i; ++j) {
587 if (Styles[i].Language == Styles[j].Language) {
589 <<
"Duplicate languages in the config file on positions " << j
590 <<
" and " << i <<
"\n");
598 for (
int i = Styles.size() - 1; i >= 0; --i) {
599 if (Styles[i].Language == Language ||
611 llvm::raw_string_ostream Stream(Text);
612 llvm::yaml::Output Output(Stream);
616 Output << NonConstStyle;
622 class FormatTokenLexer {
628 SourceMgr(SourceMgr), ID(ID), Style(Style),
635 Lex->SetKeepWhitespaceMode(
true);
642 ArrayRef<FormatToken *> lex() {
646 Tokens.push_back(getNextToken());
647 tryMergePreviousTokens();
648 if (
Tokens.back()->NewlinesBefore > 0 ||
Tokens.back()->IsMultiline)
654 const AdditionalKeywords &getKeywords() {
return Keywords; }
657 void tryMergePreviousTokens() {
658 if (tryMerge_TMacro())
660 if (tryMergeConflictMarkers())
662 if (tryMergeLessLess())
666 if (tryMergeJSRegexLiteral())
668 if (tryMergeEscapeSequence())
670 if (tryMergeTemplateString())
673 static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
676 static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
678 static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
680 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
682 if (tryMergeTokens(JSNotIdentity, TT_BinaryOperator))
684 if (tryMergeTokens(JSShiftEqual, TT_BinaryOperator))
686 if (tryMergeTokens(JSRightArrow, TT_JsFatArrow))
691 bool tryMergeLessLess() {
696 bool FourthTokenIsLess =
false;
698 FourthTokenIsLess = (
Tokens.end() - 4)[0]->is(tok::less);
700 auto First =
Tokens.end() - 3;
701 if (First[2]->is(tok::less) || First[1]->isNot(tok::less) ||
702 First[0]->isNot(tok::less) || FourthTokenIsLess)
706 if (First[1]->WhitespaceRange.getBegin() !=
707 First[1]->WhitespaceRange.getEnd())
710 First[0]->Tok.setKind(tok::lessless);
711 First[0]->TokenText =
"<<";
712 First[0]->ColumnWidth += 1;
717 bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
TokenType NewType) {
718 if (
Tokens.size() < Kinds.size())
721 SmallVectorImpl<FormatToken *>::const_iterator First =
722 Tokens.end() - Kinds.size();
723 if (!First[0]->is(Kinds[0]))
725 unsigned AddLength = 0;
726 for (
unsigned i = 1; i < Kinds.size(); ++i) {
727 if (!First[i]->is(Kinds[i]) ||
728 First[i]->WhitespaceRange.getBegin() !=
729 First[i]->WhitespaceRange.getEnd())
731 AddLength += First[i]->TokenText.size();
734 First[0]->TokenText = StringRef(First[0]->TokenText.data(),
735 First[0]->TokenText.size() + AddLength);
736 First[0]->ColumnWidth += AddLength;
737 First[0]->Type = NewType;
743 bool tryMergeEscapeSequence() {
747 if (Previous->isNot(tok::unknown) || Previous->TokenText !=
"\\")
749 ++Previous->ColumnWidth;
750 StringRef Text = Previous->TokenText;
751 Previous->TokenText = StringRef(Text.data(), Text.size() + 1);
754 Column = Previous->OriginalColumn + Previous->ColumnWidth;
763 bool tryMergeJSRegexLiteral() {
770 size_t SlashInStringPos = StringRef::npos;
771 if (
Tokens.back()->isOneOf(tok::string_literal, tok::char_constant,
775 SlashInStringPos =
Tokens.back()->TokenText.find(
'/', 1);
776 if (SlashInStringPos == StringRef::npos)
782 bool MightEndWithEscapedSlash =
783 Tokens.back()->is(tok::comment) &&
784 Tokens.back()->TokenText.startswith(
"//") &&
786 if (!MightEndWithEscapedSlash && SlashInStringPos == StringRef::npos &&
787 (
Tokens.back()->isNot(tok::slash) ||
792 unsigned TokenCount = 0;
793 for (
auto I =
Tokens.rbegin() + 1, E =
Tokens.rend(); I != E; ++I) {
796 while (Prev != E && Prev[0]->is(tok::comment))
798 if (I[0]->isOneOf(tok::slash, tok::slashequal) &&
800 ((Prev[0]->isOneOf(tok::l_paren, tok::semi, tok::l_brace,
801 tok::r_brace, tok::exclaim, tok::l_square,
802 tok::colon, tok::comma, tok::question,
804 Prev[0]->isBinaryOperator())))) {
805 unsigned LastColumn =
Tokens.back()->OriginalColumn;
806 SourceLocation Loc =
Tokens.back()->Tok.getLocation();
807 if (MightEndWithEscapedSlash) {
811 }
else if (SlashInStringPos != StringRef::npos) {
814 resetLexer(SourceMgr.
getFileOffset(Loc) + SlashInStringPos + 1);
815 LastColumn += SlashInStringPos;
818 Tokens.back()->Tok.setKind(tok::unknown);
819 Tokens.back()->Type = TT_RegexLiteral;
821 Tokens.back()->Tok.setKind(tok::string_literal);
822 Tokens.back()->ColumnWidth += LastColumn - I[0]->OriginalColumn;
827 if (I[0]->NewlinesBefore > 0)
833 bool tryMergeTemplateString() {
837 FormatToken *EndBacktick =
Tokens.back();
841 if (!EndBacktick->isOneOf(tok::comment, tok::string_literal,
842 tok::char_constant, tok::unknown))
844 size_t CommentBacktickPos = EndBacktick->TokenText.find(
'`');
847 if (CommentBacktickPos == StringRef::npos)
850 unsigned TokenCount = 0;
851 bool IsMultiline =
false;
852 unsigned EndColumnInFirstLine =
853 EndBacktick->OriginalColumn + EndBacktick->ColumnWidth;
854 for (
auto I =
Tokens.rbegin() + 1, E =
Tokens.rend(); I != E; I++) {
856 if (I[0]->IsMultiline)
861 if (I[0]->is(TT_TemplateString))
864 if (I[0]->isNot(tok::unknown) || I[0]->TokenText !=
"`") {
868 if (I[0]->IsMultiline)
869 EndColumnInFirstLine = I[0]->OriginalColumn + I[0]->ColumnWidth;
872 if (I[0]->NewlinesBefore > 0 && (I + 1 != E)) {
873 EndColumnInFirstLine = I[1]->OriginalColumn + I[1]->ColumnWidth;
880 Tokens.back()->Type = TT_TemplateString;
881 const char *EndOffset =
882 EndBacktick->TokenText.data() + 1 + CommentBacktickPos;
883 if (CommentBacktickPos != 0) {
886 SourceLocation Loc = EndBacktick->Tok.getLocation();
887 resetLexer(SourceMgr.
getFileOffset(Loc) + CommentBacktickPos + 1);
889 Tokens.back()->TokenText =
890 StringRef(
Tokens.back()->TokenText.data(),
891 EndOffset -
Tokens.back()->TokenText.data());
893 unsigned EndOriginalColumn = EndBacktick->OriginalColumn;
894 if (EndOriginalColumn == 0) {
895 SourceLocation Loc = EndBacktick->Tok.getLocation();
899 EndOriginalColumn += CommentBacktickPos;
906 Tokens.back()->ColumnWidth =
907 EndColumnInFirstLine -
Tokens.back()->OriginalColumn;
909 Tokens.back()->LastLineColumnWidth = EndOriginalColumn + 1;
910 Tokens.back()->IsMultiline =
true;
913 Tokens.back()->ColumnWidth =
914 EndOriginalColumn -
Tokens.back()->OriginalColumn + 1;
921 bool tryMerge_TMacro() {
925 if (!Last->is(tok::r_paren))
929 if (!String->is(tok::string_literal) || String->IsMultiline)
936 if (Macro->TokenText !=
"_T")
939 const char *Start = Macro->TokenText.data();
940 const char *
End = Last->TokenText.data() + Last->TokenText.size();
941 String->TokenText = StringRef(Start, End - Start);
942 String->IsFirst = Macro->IsFirst;
943 String->LastNewlineOffset = Macro->LastNewlineOffset;
944 String->WhitespaceRange = Macro->WhitespaceRange;
945 String->OriginalColumn = Macro->OriginalColumn;
947 String->TokenText, String->OriginalColumn, Style.
TabWidth, Encoding);
948 String->NewlinesBefore = Macro->NewlinesBefore;
949 String->HasUnescapedNewline = Macro->HasUnescapedNewline;
958 bool tryMergeConflictMarkers() {
973 unsigned FirstInLineOffset;
976 StringRef Buffer = SourceMgr.
getBuffer(ID)->getBuffer();
978 auto LineOffset = Buffer.rfind(
'\n', FirstInLineOffset);
979 if (LineOffset == StringRef::npos) {
985 auto FirstSpace = Buffer.find_first_of(
" \n", LineOffset);
987 if (FirstSpace == StringRef::npos) {
988 LineStart = Buffer.substr(LineOffset);
990 LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
994 if (LineStart ==
"<<<<<<<" || LineStart ==
">>>>") {
995 Type = TT_ConflictStart;
996 }
else if (LineStart ==
"|||||||" || LineStart ==
"=======" ||
997 LineStart ==
"====") {
998 Type = TT_ConflictAlternative;
999 }
else if (LineStart ==
">>>>>>>" || LineStart ==
"<<<<") {
1000 Type = TT_ConflictEnd;
1003 if (Type != TT_Unknown) {
1010 Tokens.back()->Type = Type;
1011 Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
1020 FormatToken *getStashedToken() {
1023 StringRef TokenText =
FormatTok->TokenText;
1025 unsigned OriginalColumn =
FormatTok->OriginalColumn;
1028 SourceLocation TokLocation =
1029 FormatTok->Tok.getLocation().getLocWithOffset(Tok.getLength() - 1);
1030 FormatTok->Tok.setLocation(TokLocation);
1031 FormatTok->WhitespaceRange = SourceRange(TokLocation, TokLocation);
1034 FormatTok->OriginalColumn = OriginalColumn + 1;
1039 FormatToken *getNextToken() {
1042 return getStashedToken();
1046 return getStashedToken();
1051 SourceLocation WhitespaceStart =
1058 while (
FormatTok->Tok.is(tok::unknown)) {
1060 auto EscapesNewline = [&](
int pos) {
1062 if (pos >= 0 && Text[pos] ==
'\r')
1066 for (; pos >= 0; --pos, ++count)
1067 if (Text[pos] !=
'\\')
1073 for (
int i = 0, e = Text.size(); i != e; ++i) {
1077 FormatTok->HasUnescapedNewline = !EscapesNewline(i - 1);
1078 FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
1082 FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
1096 if (i + 1 == e || (Text[i + 1] !=
'\r' && Text[i + 1] !=
'\n'))
1097 FormatTok->Type = TT_ImplicitStringLiteral;
1100 FormatTok->Type = TT_ImplicitStringLiteral;
1105 if (
FormatTok->is(TT_ImplicitStringLiteral))
1107 WhitespaceLength +=
FormatTok->Tok.getLength();
1119 WhitespaceLength += 2;
1125 FormatTok->WhitespaceRange = SourceRange(
1126 WhitespaceStart, WhitespaceStart.getLocWithOffset(WhitespaceLength));
1133 StringRef UntrimmedText =
FormatTok->TokenText;
1136 }
else if (
FormatTok->Tok.is(tok::raw_identifier)) {
1138 FormatTok->Tok.setIdentifierInfo(&Info);
1139 FormatTok->Tok.setKind(Info.getTokenID());
1141 FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete)) {
1142 FormatTok->Tok.setKind(tok::identifier);
1143 FormatTok->Tok.setIdentifierInfo(
nullptr);
1145 }
else if (
FormatTok->Tok.is(tok::greatergreater)) {
1149 }
else if (
FormatTok->Tok.is(tok::lessless)) {
1158 size_t FirstNewlinePos = Text.find(
'\n');
1159 if (FirstNewlinePos == StringRef::npos) {
1175 Text.substr(Text.find_last_of(
'\n') + 1), 0, Style.
TabWidth,
1181 if (!(
Tokens.size() > 0 &&
Tokens.back()->Tok.getIdentifierInfo() &&
1182 Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
1187 }
else if (
FormatTok->is(tok::identifier)) {
1222 void readRawToken(FormatToken &Tok) {
1223 Lex->LexFromRawLexer(Tok.Tok);
1224 Tok.TokenText = StringRef(SourceMgr.
getCharacterData(Tok.Tok.getLocation()),
1225 Tok.Tok.getLength());
1228 if (Tok.is(tok::unknown)) {
1229 if (!Tok.TokenText.empty() && Tok.TokenText[0] ==
'"') {
1230 Tok.Tok.setKind(tok::string_literal);
1231 Tok.IsUnterminatedLiteral =
true;
1233 Tok.TokenText ==
"''") {
1234 Tok.Tok.setKind(tok::char_constant);
1238 if (Tok.is(tok::comment) && (Tok.TokenText ==
"// clang-format on" ||
1239 Tok.TokenText ==
"/* clang-format on */")) {
1245 if (Tok.is(tok::comment) && (Tok.TokenText ==
"// clang-format off" ||
1246 Tok.TokenText ==
"/* clang-format off */")) {
1251 void resetLexer(
unsigned Offset) {
1255 Buffer.begin() +
Offset, Buffer.end()));
1256 Lex->SetKeepWhitespaceMode(
true);
1268 return "JavaScript";
1276 class Formatter :
public UnwrappedLineConsumer {
1278 Formatter(
const FormatStyle &Style, SourceManager &SourceMgr, FileID ID,
1279 ArrayRef<CharSourceRange>
Ranges)
1280 : Style(Style), ID(ID), SourceMgr(SourceMgr),
1282 inputUsesCRLF(SourceMgr.getBufferData(ID))),
1284 Encoding(encoding::
detectEncoding(SourceMgr.getBufferData(ID))) {
1285 DEBUG(llvm::dbgs() <<
"File encoding: "
1289 DEBUG(llvm::dbgs() <<
"Language: " << getLanguageName(Style.
Language)
1295 FormatTokenLexer
Tokens(SourceMgr, ID, Style, Encoding);
1297 UnwrappedLineParser Parser(Style,
Tokens.getKeywords(),
Tokens.lex(),
1301 for (
unsigned Run = 0, RunE =
UnwrappedLines.size(); Run + 1 != RunE;
1303 DEBUG(llvm::dbgs() <<
"Run " << Run <<
"...\n");
1304 SmallVector<AnnotatedLine *, 16> AnnotatedLines;
1305 for (
unsigned i = 0, e =
UnwrappedLines[Run].size(); i != e; ++i) {
1306 AnnotatedLines.push_back(
new AnnotatedLine(
UnwrappedLines[Run][i]));
1309 format(AnnotatedLines,
Tokens, IncompleteFormat);
1311 llvm::dbgs() <<
"Replacements for run " << Run <<
":\n";
1312 for (tooling::Replacements::iterator I = RunResult.begin(),
1313 E = RunResult.end();
1315 llvm::dbgs() << I->toString() <<
"\n";
1318 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1319 delete AnnotatedLines[i];
1321 Result.insert(RunResult.begin(), RunResult.end());
1328 FormatTokenLexer &
Tokens,
1329 bool *IncompleteFormat) {
1330 TokenAnnotator Annotator(Style, Tokens.getKeywords());
1331 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1332 Annotator.annotate(*AnnotatedLines[i]);
1334 deriveLocalStyle(AnnotatedLines);
1335 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1336 Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
1338 computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
1340 Annotator.setCommentLineLevels(AnnotatedLines);
1344 UnwrappedLineFormatter(&
Indenter, &Whitespaces, Style, Tokens.getKeywords(),
1346 .format(AnnotatedLines);
1347 return Whitespaces.generateReplacements();
1354 bool computeAffectedLines(SmallVectorImpl<AnnotatedLine *>::iterator I,
1355 SmallVectorImpl<AnnotatedLine *>::iterator E) {
1356 bool SomeLineAffected =
false;
1357 const AnnotatedLine *PreviousLine =
nullptr;
1359 AnnotatedLine *
Line = *I;
1360 Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
1364 if (Line->InPPDirective) {
1365 FormatToken *Last = Line->Last;
1366 SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
1367 while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
1368 Last = (*PPEnd)->Last;
1372 if (affectsTokenRange(*Line->First, *Last,
1374 SomeLineAffected =
true;
1375 markAllAsAffected(I, PPEnd);
1381 if (nonPPLineAffected(Line, PreviousLine))
1382 SomeLineAffected =
true;
1384 PreviousLine =
Line;
1387 return SomeLineAffected;
1392 bool nonPPLineAffected(AnnotatedLine *Line,
1393 const AnnotatedLine *PreviousLine) {
1394 bool SomeLineAffected =
false;
1395 Line->ChildrenAffected =
1396 computeAffectedLines(Line->Children.begin(), Line->Children.end());
1397 if (Line->ChildrenAffected)
1398 SomeLineAffected =
true;
1401 bool SomeTokenAffected =
false;
1404 bool IncludeLeadingNewlines =
false;
1408 bool SomeFirstChildAffected =
false;
1410 for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
1412 if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
1413 SomeTokenAffected =
true;
1416 if (!Tok->Children.empty() && Tok->Children.front()->Affected)
1417 SomeFirstChildAffected =
true;
1419 IncludeLeadingNewlines = Tok->Children.empty();
1424 bool LineMoved = PreviousLine && PreviousLine->Affected &&
1425 Line->First->NewlinesBefore == 0;
1427 bool IsContinuedComment =
1428 Line->First->is(tok::comment) && Line->First->Next ==
nullptr &&
1429 Line->First->NewlinesBefore < 2 && PreviousLine &&
1430 PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
1432 if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
1433 IsContinuedComment) {
1434 Line->Affected =
true;
1435 SomeLineAffected =
true;
1437 return SomeLineAffected;
1441 void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I,
1442 SmallVectorImpl<AnnotatedLine *>::iterator E) {
1444 (*I)->Affected =
true;
1445 markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
1452 bool affectsTokenRange(
const FormatToken &First,
const FormatToken &Last,
1453 bool IncludeLeadingNewlines) {
1454 SourceLocation Start = First.WhitespaceRange.getBegin();
1455 if (!IncludeLeadingNewlines)
1456 Start = Start.getLocWithOffset(First.LastNewlineOffset);
1457 SourceLocation End = Last.getStartOfNonWhitespace();
1458 End = End.getLocWithOffset(Last.TokenText.size());
1460 return affectsCharSourceRange(Range);
1465 bool affectsLeadingEmptyLines(
const FormatToken &Tok) {
1467 Tok.WhitespaceRange.getBegin(),
1468 Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
1469 return affectsCharSourceRange(EmptyLineRange);
1473 bool affectsCharSourceRange(
const CharSourceRange &Range) {
1474 for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
1477 if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
1478 !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
1484 static bool inputUsesCRLF(StringRef Text) {
1485 return Text.count(
'\r') * 2 > Text.count(
'\n');
1489 deriveLocalStyle(
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
1490 unsigned CountBoundToVariable = 0;
1491 unsigned CountBoundToType = 0;
1492 bool HasCpp03IncompatibleFormat =
false;
1493 bool HasBinPackedFunction =
false;
1494 bool HasOnePerLineFunction =
false;
1495 for (
unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
1496 if (!AnnotatedLines[i]->First->Next)
1498 FormatToken *Tok = AnnotatedLines[i]->First->Next;
1500 if (Tok->is(TT_PointerOrReference)) {
1502 Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
1503 bool SpacesAfter = Tok->Next->WhitespaceRange.getBegin() !=
1504 Tok->Next->WhitespaceRange.getEnd();
1505 if (SpacesBefore && !SpacesAfter)
1506 ++CountBoundToVariable;
1507 else if (!SpacesBefore && SpacesAfter)
1511 if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
1512 if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
1513 HasCpp03IncompatibleFormat =
true;
1514 if (Tok->is(TT_TemplateCloser) &&
1515 Tok->Previous->is(TT_TemplateCloser))
1516 HasCpp03IncompatibleFormat =
true;
1520 HasBinPackedFunction =
true;
1522 HasOnePerLineFunction =
true;
1528 if (CountBoundToType > CountBoundToVariable)
1530 else if (CountBoundToType < CountBoundToVariable)
1538 HasBinPackedFunction || !HasOnePerLineFunction;
1541 void consumeUnwrappedLine(
const UnwrappedLine &TheLine)
override {
1546 void finishRun()
override {
1566 bool *IncompleteFormat) {
1569 Formatter formatter(Style, SourceMgr, ID, Ranges);
1570 return formatter.format(IncompleteFormat);
1575 StringRef FileName,
bool *IncompleteFormat) {
1584 std::unique_ptr<llvm::MemoryBuffer> Buf =
1585 llvm::MemoryBuffer::getMemBuffer(Code, FileName);
1592 std::vector<CharSourceRange> CharRanges;
1598 return reformat(Style, SourceMgr, ID, CharRanges, IncompleteFormat);
1603 LangOpts.CPlusPlus = 1;
1606 LangOpts.LineComment = 1;
1608 LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
1612 LangOpts.MicrosoftExt = 1;
1617 "Coding style, currently supports:\n"
1618 " LLVM, Google, Chromium, Mozilla, WebKit.\n"
1619 "Use -style=file to load style configuration from\n"
1620 ".clang-format file located in one of the parent\n"
1621 "directories of the source file (or current\n"
1622 "directory for stdin).\n"
1623 "Use -style=\"{key: value, ...}\" to set specific\n"
1624 "parameters, e.g.:\n"
1625 " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
1628 if (FileName.endswith(
".java")) {
1630 }
else if (FileName.endswith_lower(
".js") || FileName.endswith_lower(
".ts")) {
1633 }
else if (FileName.endswith_lower(
".proto") ||
1634 FileName.endswith_lower(
".protodevel")) {
1641 StringRef FallbackStyle) {
1645 llvm::errs() <<
"Invalid fallback style \"" << FallbackStyle
1646 <<
"\" using LLVM style\n";
1650 if (StyleName.startswith(
"{")) {
1653 llvm::errs() <<
"Error parsing -style: " << ec.message() <<
", using "
1654 << FallbackStyle <<
" style\n";
1659 if (!StyleName.equals_lower(
"file")) {
1661 llvm::errs() <<
"Invalid value for -style, using " << FallbackStyle
1669 llvm::sys::fs::make_absolute(Path);
1670 for (StringRef Directory = Path; !Directory.empty();
1671 Directory = llvm::sys::path::parent_path(Directory)) {
1672 if (!llvm::sys::fs::is_directory(Directory))
1676 llvm::sys::path::append(ConfigFile,
".clang-format");
1677 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
1678 bool IsFile =
false;
1681 llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
1685 ConfigFile = Directory;
1686 llvm::sys::path::append(ConfigFile,
"_clang-format");
1687 DEBUG(llvm::dbgs() <<
"Trying " << ConfigFile <<
"...\n");
1688 llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
1692 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
1693 llvm::MemoryBuffer::getFile(ConfigFile.c_str());
1694 if (std::error_code EC = Text.getError()) {
1695 llvm::errs() << EC.message() <<
"\n";
1698 if (std::error_code ec =
1701 if (!UnsuitableConfigFiles.empty())
1702 UnsuitableConfigFiles.append(
", ");
1703 UnsuitableConfigFiles.append(ConfigFile);
1706 llvm::errs() <<
"Error reading " << ConfigFile <<
": " << ec.message()
1710 DEBUG(llvm::dbgs() <<
"Using configuration file " << ConfigFile <<
"\n");
1714 if (!UnsuitableConfigFiles.empty()) {
1715 llvm::errs() <<
"Configuration file(s) do(es) not support "
1716 << getLanguageName(Style.
Language) <<
": "
1717 << UnsuitableConfigFiles <<
"\n";
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.
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. creates AnnotatedTokens out of FormatTokens with require...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.
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)
void overrideFileContents(const FileEntry *SourceFile, llvm::MemoryBuffer *Buffer, bool DoNotFree)
Override the contents of the given source file by providing an already-allocated buffer.
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
Options for controlling the compiler diagnostics engine.
Cached information about one file (either on disk or in the virtual file system). ...
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.
const FileEntry * getVirtualFile(StringRef Filename, off_t Size, time_t ModificationTime)
Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Used for handling and querying diagnostic IDs.
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.