17#include "llvm/Support/Debug.h"
18#define DEBUG_TYPE "definition-block-separator"
28 separateBlocks(AnnotatedLines,
Result, Tokens);
32void DefinitionBlockSeparator::separateBlocks(
35 const bool IsNeverStyle =
38 auto GetBracketLevelChange = [](
const FormatToken *Tok) {
39 if (Tok->isOneOf(tok::l_brace, tok::l_paren, tok::l_square))
41 if (Tok->isOneOf(tok::r_brace, tok::r_paren, tok::r_square))
45 auto LikelyDefinition = [&](
const AnnotatedLine *
Line,
46 bool ExcludeEnum =
false) {
47 if ((
Line->MightBeFunctionDecl &&
Line->mightBeFunctionDefinition()) ||
48 Line->startsWithNamespace()) {
52 for (
const FormatToken *CurrentToken =
Line->First; CurrentToken;
53 CurrentToken = CurrentToken->Next) {
54 if (BracketLevel == 0) {
55 if (CurrentToken->isOneOf(tok::kw_class, tok::kw_struct,
61 if (!ExcludeEnum && CurrentToken->is(tok::kw_enum))
64 BracketLevel += GetBracketLevelChange(CurrentToken);
68 unsigned NewlineCount =
70 WhitespaceManager Whitespaces(
77 for (
unsigned I = 0; I < Lines.size(); ++I) {
78 const auto &CurrentLine = Lines[I];
79 if (CurrentLine->InPPDirective)
81 FormatToken *TargetToken =
nullptr;
82 AnnotatedLine *TargetLine;
83 auto OpeningLineIndex = CurrentLine->MatchingOpeningBlockLineIndex;
84 AnnotatedLine *OpeningLine =
nullptr;
85 const auto IsAccessSpecifierToken = [](
const FormatToken *Token) {
86 return Token->isAccessSpecifier() || Token->isObjCAccessSpecifier();
88 const auto InsertReplacement = [&](
const int NewlineToInsert) {
93 if (TargetToken->is(tok::eof))
95 if (IsAccessSpecifierToken(TargetToken) ||
96 (OpeningLineIndex > 0 &&
97 IsAccessSpecifierToken(Lines[OpeningLineIndex - 1]->
First))) {
100 if (!TargetLine->Affected)
102 Whitespaces.replaceWhitespace(*TargetToken, NewlineToInsert,
103 TargetToken->OriginalColumn,
104 TargetToken->OriginalColumn);
106 const auto IsPPConditional = [&](
const size_t LineIndex) {
107 const auto &
Line = Lines[LineIndex];
108 return Line->First->is(tok::hash) &&
Line->First->Next &&
109 Line->First->Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_else,
110 tok::pp_ifndef, tok::pp_elifndef,
111 tok::pp_elifdef, tok::pp_elif,
114 const auto FollowingOtherOpening = [&]() {
115 return OpeningLineIndex == 0 ||
116 Lines[OpeningLineIndex - 1]->Last->opensScope() ||
117 IsPPConditional(OpeningLineIndex - 1);
119 const auto HasEnumOnLine = [&]() {
120 bool FoundEnumKeyword =
false;
121 int BracketLevel = 0;
122 for (
const FormatToken *CurrentToken = CurrentLine->First; CurrentToken;
123 CurrentToken = CurrentToken->Next) {
124 if (BracketLevel == 0) {
125 if (CurrentToken->is(tok::kw_enum))
126 FoundEnumKeyword =
true;
127 else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace))
130 BracketLevel += GetBracketLevelChange(CurrentToken);
132 return FoundEnumKeyword && I + 1 < Lines.size() &&
133 Lines[I + 1]->First->is(tok::l_brace);
136 bool IsDefBlock =
false;
137 const auto MayPrecedeDefinition = [&](
const int Direction = -1) {
138 assert(Direction >= -1);
139 assert(Direction <= 1);
140 const size_t OperateIndex = OpeningLineIndex + Direction;
141 assert(OperateIndex < Lines.size());
142 const auto &OperateLine = Lines[OperateIndex];
143 if (LikelyDefinition(OperateLine))
146 if (
const auto *Tok = OperateLine->First;
152 if (OperateLine->First->is(tok::identifier) &&
153 OperateLine->First == OperateLine->Last &&
154 OperateIndex + 1 < Lines.size()) {
160 AnnotatedLine *NextLine = Lines[OperateIndex + 1];
161 if (NextLine->MightBeFunctionDecl &&
162 NextLine->mightBeFunctionDefinition() &&
163 NextLine->First->NewlinesBefore == 1 &&
164 OperateLine->First->is(TT_FunctionLikeOrFreestandingMacro)) {
169 if (
Style.
isCSharp() && OperateLine->First->is(TT_AttributeSquare))
174 if (HasEnumOnLine() &&
175 !LikelyDefinition(CurrentLine,
true)) {
178 OpeningLineIndex = I;
179 while (OpeningLineIndex > 0 && MayPrecedeDefinition())
181 OpeningLine = Lines[OpeningLineIndex];
182 TargetLine = OpeningLine;
183 TargetToken = TargetLine->First;
184 if (!FollowingOtherOpening())
185 InsertReplacement(NewlineCount);
186 else if (IsNeverStyle)
187 InsertReplacement(OpeningLineIndex != 0);
188 TargetLine = CurrentLine;
189 TargetToken = TargetLine->First;
190 while (TargetToken && TargetToken->isNot(tok::r_brace))
191 TargetToken = TargetToken->Next;
193 while (I < Lines.size() && Lines[I]->First->isNot(tok::r_brace))
195 }
else if (CurrentLine->First->closesScope()) {
196 if (OpeningLineIndex > Lines.size())
201 if (OpeningLineIndex > 0 &&
202 Lines[OpeningLineIndex]->
First->is(tok::l_brace) &&
203 Lines[OpeningLineIndex - 1]->Last->isNot(tok::l_brace)) {
206 OpeningLine = Lines[OpeningLineIndex];
208 if (LikelyDefinition(OpeningLine)) {
210 while (OpeningLineIndex > 0 && MayPrecedeDefinition())
212 OpeningLine = Lines[OpeningLineIndex];
213 TargetLine = OpeningLine;
214 TargetToken = TargetLine->First;
215 if (!FollowingOtherOpening()) {
217 if (TargetToken->isNot(tok::l_brace))
218 InsertReplacement(NewlineCount);
219 }
else if (IsNeverStyle) {
220 InsertReplacement(OpeningLineIndex != 0);
226 if (IsDefBlock && I + 1 < Lines.size()) {
227 OpeningLineIndex = I + 1;
228 TargetLine = Lines[OpeningLineIndex];
229 TargetToken = TargetLine->First;
234 if (!TargetToken->closesScope() && !IsPPConditional(OpeningLineIndex)) {
236 while (OpeningLineIndex + 1 < Lines.size() &&
237 MayPrecedeDefinition(0)) {
240 TargetLine = Lines[OpeningLineIndex];
241 if (!LikelyDefinition(TargetLine)) {
242 OpeningLineIndex = I + 1;
243 TargetLine = Lines[I + 1];
244 TargetToken = TargetLine->First;
245 InsertReplacement(NewlineCount);
247 }
else if (IsNeverStyle) {
248 InsertReplacement(1);
252 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.