17#define DEBUG_TYPE "definition-block-separator"
27 separateBlocks(AnnotatedLines,
Result, Tokens);
31void DefinitionBlockSeparator::separateBlocks(
34 const bool IsNeverStyle =
37 auto GetBracketLevelChange = [](
const FormatToken *Tok) {
38 if (Tok->isOneOf(tok::l_brace, tok::l_paren, tok::l_square))
40 if (Tok->isOneOf(tok::r_brace, tok::r_paren, tok::r_square))
44 auto LikelyDefinition = [&](
const AnnotatedLine *
Line,
45 bool ExcludeEnum =
false) {
46 if ((
Line->MightBeFunctionDecl &&
Line->mightBeFunctionDefinition()) ||
47 Line->startsWithNamespace()) {
51 for (
const FormatToken *CurrentToken =
Line->First; CurrentToken;
52 CurrentToken = CurrentToken->Next) {
53 if (BracketLevel == 0) {
54 if (CurrentToken->isOneOf(tok::kw_class, tok::kw_struct,
60 if (!ExcludeEnum && CurrentToken->is(tok::kw_enum))
63 BracketLevel += GetBracketLevelChange(CurrentToken);
67 unsigned NewlineCount =
69 WhitespaceManager Whitespaces(
76 for (
unsigned I = 0; I < Lines.size(); ++I) {
77 const auto &CurrentLine = Lines[I];
78 if (CurrentLine->InPPDirective)
80 FormatToken *TargetToken =
nullptr;
81 AnnotatedLine *TargetLine;
82 auto OpeningLineIndex = CurrentLine->MatchingOpeningBlockLineIndex;
83 AnnotatedLine *OpeningLine =
nullptr;
84 const auto IsAccessSpecifierToken = [](
const FormatToken *Token) {
85 return Token->isAccessSpecifier() || Token->isObjCAccessSpecifier();
87 const auto InsertReplacement = [&](
const int NewlineToInsert) {
92 if (TargetToken->is(tok::eof))
94 if (IsAccessSpecifierToken(TargetToken) ||
95 (OpeningLineIndex > 0 &&
96 IsAccessSpecifierToken(Lines[OpeningLineIndex - 1]->
First))) {
99 if (!TargetLine->Affected)
101 Whitespaces.replaceWhitespace(*TargetToken, NewlineToInsert,
102 TargetToken->OriginalColumn,
103 TargetToken->OriginalColumn);
105 const auto IsPPConditional = [&](
const size_t LineIndex) {
106 const auto &
Line = Lines[LineIndex];
107 return Line->First->is(tok::hash) &&
Line->First->Next &&
108 Line->First->Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_else,
109 tok::pp_ifndef, tok::pp_elifndef,
110 tok::pp_elifdef, tok::pp_elif,
113 const auto FollowingOtherOpening = [&]() {
114 return OpeningLineIndex == 0 ||
115 Lines[OpeningLineIndex - 1]->Last->opensScope() ||
116 IsPPConditional(OpeningLineIndex - 1);
118 const auto HasEnumOnLine = [&]() {
119 bool FoundEnumKeyword =
false;
120 int BracketLevel = 0;
121 for (
const FormatToken *CurrentToken = CurrentLine->First; CurrentToken;
122 CurrentToken = CurrentToken->Next) {
123 if (BracketLevel == 0) {
124 if (CurrentToken->is(tok::kw_enum))
125 FoundEnumKeyword =
true;
126 else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace))
129 BracketLevel += GetBracketLevelChange(CurrentToken);
131 return FoundEnumKeyword && I + 1 < Lines.size() &&
132 Lines[I + 1]->First->is(tok::l_brace);
135 bool IsDefBlock =
false;
136 const auto MayPrecedeDefinition = [&](
const int Direction = -1) {
137 assert(Direction >= -1);
138 assert(Direction <= 1);
140 if (Lines[OpeningLineIndex]->
First->is(TT_CSharpGenericTypeConstraint))
143 const size_t OperateIndex = OpeningLineIndex +
Direction;
144 assert(OperateIndex < Lines.size());
145 const auto &OperateLine = Lines[OperateIndex];
146 if (LikelyDefinition(OperateLine))
149 if (
const auto *Tok = OperateLine->First;
155 if (OperateLine->First->is(tok::identifier) &&
156 OperateLine->First == OperateLine->Last &&
157 OperateIndex + 1 < Lines.size()) {
163 AnnotatedLine *NextLine = Lines[OperateIndex + 1];
164 if (NextLine->MightBeFunctionDecl &&
165 NextLine->mightBeFunctionDefinition() &&
166 NextLine->First->NewlinesBefore == 1 &&
167 OperateLine->First->is(TT_FunctionLikeOrFreestandingMacro)) {
172 if (
Style.
isCSharp() && OperateLine->First->is(TT_AttributeSquare))
177 if (HasEnumOnLine() &&
178 !LikelyDefinition(CurrentLine,
true)) {
181 OpeningLineIndex = I;
182 while (OpeningLineIndex > 0 && MayPrecedeDefinition())
184 OpeningLine = Lines[OpeningLineIndex];
185 TargetLine = OpeningLine;
186 TargetToken = TargetLine->First;
187 if (!FollowingOtherOpening())
188 InsertReplacement(NewlineCount);
189 else if (IsNeverStyle)
190 InsertReplacement(OpeningLineIndex != 0);
191 TargetLine = CurrentLine;
192 TargetToken = TargetLine->First;
193 while (TargetToken && TargetToken->isNot(tok::r_brace))
194 TargetToken = TargetToken->Next;
196 while (I < Lines.size() && Lines[I]->First->isNot(tok::r_brace))
198 }
else if (CurrentLine->First->closesScope()) {
199 if (OpeningLineIndex > Lines.size())
204 if (OpeningLineIndex > 0 &&
205 Lines[OpeningLineIndex]->
First->is(tok::l_brace) &&
206 Lines[OpeningLineIndex - 1]->Last->isNot(tok::l_brace)) {
209 OpeningLine = Lines[OpeningLineIndex];
211 if (LikelyDefinition(OpeningLine)) {
213 while (OpeningLineIndex > 0 && MayPrecedeDefinition())
215 OpeningLine = Lines[OpeningLineIndex];
216 TargetLine = OpeningLine;
217 TargetToken = TargetLine->First;
218 if (!FollowingOtherOpening()) {
220 if (TargetToken->isNot(tok::l_brace))
221 InsertReplacement(NewlineCount);
222 }
else if (IsNeverStyle) {
223 InsertReplacement(OpeningLineIndex != 0);
229 if (IsDefBlock && I + 1 < Lines.size()) {
230 OpeningLineIndex = I + 1;
231 TargetLine = Lines[OpeningLineIndex];
232 TargetToken = TargetLine->First;
237 if (!TargetToken->closesScope() && !IsPPConditional(OpeningLineIndex)) {
239 while (OpeningLineIndex + 1 < Lines.size() &&
240 MayPrecedeDefinition(0)) {
243 TargetLine = Lines[OpeningLineIndex];
244 if (!LikelyDefinition(TargetLine)) {
245 OpeningLineIndex = I + 1;
246 TargetLine = Lines[I + 1];
247 TargetToken = TargetLine->First;
248 InsertReplacement(NewlineCount);
250 }
else if (IsNeverStyle) {
251 InsertReplacement(1);
255 for (
const auto &R : Whitespaces.generateReplacements()) {
This file declares DefinitionBlockSeparator, a TokenAnalyzer that inserts or removes empty lines sepa...
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.