clang 24.0.0git
WhitespaceManager.h
Go to the documentation of this file.
1//===--- WhitespaceManager.h - Format C++ code ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// WhitespaceManager class manages whitespace around tokens and their
11/// replacements.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
16#define LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
17
18#include "TokenAnnotator.h"
20
21namespace clang {
22namespace format {
23
24/// Manages the whitespaces around tokens and their replacements.
25///
26/// This includes special handling for certain constructs, e.g. the alignment of
27/// trailing line comments.
28///
29/// To guarantee correctness of alignment operations, the \c WhitespaceManager
30/// must be informed about every token in the source file; for each token, there
31/// must be exactly one call to either \c replaceWhitespace or
32/// \c addUntouchableToken.
33///
34/// There may be multiple calls to \c breakToken for a given token.
36public:
37 WhitespaceManager(const SourceManager &SourceMgr, const FormatStyle &Style,
38 bool UseCRLF)
39 : SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {}
40
41 bool useCRLF() const { return UseCRLF; }
42
43 /// Infers whether the input is using CRLF.
44 static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF);
45
46 /// Replaces the whitespace in front of \p Tok. Only call once for
47 /// each \c AnnotatedToken.
48 ///
49 /// \p StartOfTokenColumn is the column at which the token will start after
50 /// this replacement. It is needed for determining how \p Spaces is turned
51 /// into tabs and spaces for some format styles.
52 ///
53 /// \p IndentedFromColumn is only used when the replacement starts a new
54 /// line. It should be the column that the position of the line is derived
55 /// from. It is used for determining what lines the alignment process should
56 /// move.
57 void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
58 unsigned StartOfTokenColumn,
59 const FormatToken *AlignedTo = nullptr,
60 bool InPPDirective = false,
61 unsigned IndentedFromColumn = 0,
62 bool CreateReplacement = true);
63
64 /// Adds information about an unchangeable token's whitespace.
65 ///
66 /// Needs to be called for every token for which \c replaceWhitespace
67 /// was not called.
68 void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
69
70 llvm::Error addReplacement(const tooling::Replacement &Replacement);
71
72 /// Inserts or replaces whitespace in the middle of a token.
73 ///
74 /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix
75 /// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
76 /// characters.
77 ///
78 /// Note: \p Spaces can be negative to retain information about initial
79 /// relative column offset between a line of a block comment and the start of
80 /// the comment. This negative offset may be compensated by trailing comment
81 /// alignment here. In all other cases negative \p Spaces will be truncated to
82 /// 0.
83 ///
84 /// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
85 /// used to align backslashes correctly.
86 void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
87 unsigned ReplaceChars,
88 StringRef PreviousPostfix,
89 StringRef CurrentPrefix, bool InPPDirective,
90 unsigned Newlines, int Spaces);
91
92 /// Returns all the \c Replacements created during formatting.
94
95 /// Represents a change before a token, a break inside a token,
96 /// or the layout of an unchanged token (or whitespace within).
97 struct Change {
98 /// Functor to sort changes in original source order.
100 public:
101 IsBeforeInFile(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
102 bool operator()(const Change &C1, const Change &C2) const;
103
104 private:
105 const SourceManager &SourceMgr;
106 };
107
108 /// Creates a \c Change.
109 ///
110 /// The generated \c Change will replace the characters at
111 /// \p OriginalWhitespaceRange with a concatenation of
112 /// \p PreviousLinePostfix, \p NewlinesBefore line breaks, \p Spaces spaces
113 /// and \p CurrentLinePrefix.
114 ///
115 /// \p StartOfTokenColumn and \p ContinuesPPDirective will be used to lay
116 /// out trailing comments and escaped newlines. \p IndentedFromColumn will
117 /// be used to continue aligned lines.
120 unsigned StartOfTokenColumn, unsigned IndentedFromColumn,
121 unsigned NewlinesBefore, StringRef PreviousLinePostfix,
122 StringRef CurrentLinePrefix, const FormatToken *AlignedTo,
124
125 // The kind of the token whose whitespace this change replaces, or in which
126 // this change inserts whitespace.
127 // FIXME: Currently this is not set correctly for breaks inside comments, as
128 // the \c BreakableToken is still doing its own alignment.
130
132 // Changes might be in the middle of a token, so we cannot just keep the
133 // FormatToken around to query its information.
136 // Only used when the token is at the start of a line. The column that the
137 // position of the line is derived from. The alignment procedure moves the
138 // line when it moves a token in the same unwrapped line that is to the left
139 // of said column.
143 std::string CurrentLinePrefix;
146
147 // The number of spaces in front of the token or broken part of the token.
148 // This will be adapted when aligning tokens.
149 // Can be negative to retain information about the initial relative offset
150 // of the lines in a block comment. This is used when aligning trailing
151 // comments. Uncompensated negative offset is truncated to 0.
153
154 // If this change is inside of a token but not at the start of the token or
155 // directly after a newline.
157
158 // \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
159 // \c EscapedNewlineColumn will be calculated in
160 // \c calculateLineBreakInformation.
162 unsigned TokenLength;
165
166 // These fields are used to retain correct relative line indentation in a
167 // block comment when aligning trailing comments.
168 //
169 // If this Change represents a continuation of a block comment,
170 // \c StartOfBlockComment is pointer to the first Change in the block
171 // comment. \c IndentationOffset is a relative column offset to this
172 // change, so that the correct column can be reconstructed at the end of
173 // the alignment process.
176
177 // Depth of conditionals. Computed from tracking fake parenthesis, except
178 // it does not increase the indent for "chained" conditionals.
180
181 // A combination of indent, nesting and conditionals levels, which are used
182 // in tandem to compute lexical scope, for the purposes of deciding
183 // when to stop consecutive alignment runs.
184 std::tuple<unsigned, unsigned, unsigned> indentAndNestingLevel() const {
185 return std::make_tuple(Tok->IndentLevel, Tok->NestingLevel,
187 }
188 };
189
190private:
191 struct CellDescription {
192 unsigned Index = 0;
193 unsigned Cell = 0;
194 unsigned EndIndex = 0;
195 bool HasSplit = false;
196 CellDescription *NextColumnElement = nullptr;
197
198 constexpr bool operator==(const CellDescription &Other) const {
199 return Index == Other.Index && Cell == Other.Cell &&
200 EndIndex == Other.EndIndex;
201 }
202 constexpr bool operator!=(const CellDescription &Other) const {
203 return !(*this == Other);
204 }
205 };
206
207 struct CellDescriptions {
208 SmallVector<CellDescription> Cells;
209 SmallVector<unsigned> CellCounts;
210 unsigned InitialSpaces = 0;
211
212 // Determine if every row in the array
213 // has the same number of columns.
214 bool isRectangular() const {
215 if (CellCounts.size() < 2)
216 return false;
217
218 for (auto NumberOfColumns : CellCounts)
219 if (NumberOfColumns != CellCounts[0])
220 return false;
221 return true;
222 }
223 };
224
225 /// Calculate \c IsTrailingComment, \c TokenLength for the last tokens
226 /// or token parts in a line and \c PreviousEndOfTokenColumn and
227 /// \c EscapedNewlineColumn for the first tokens or token parts in a line.
228 void calculateLineBreakInformation();
229
230 /// Align consecutive C/C++ preprocessor macros over all \c Changes.
231 void alignConsecutiveMacros();
232
233 /// Align consecutive assignments over all \c Changes.
234 void alignConsecutiveAssignments();
235
236 /// Align consecutive bitfields over all \c Changes.
237 void alignConsecutiveBitFields();
238
239 /// Align consecutive colon. For bitfields, TableGen DAGArgs and definitions.
240 void
241 alignConsecutiveColons(const FormatStyle::AlignConsecutiveStyle &AlignStyle,
243
244 /// Align consecutive declarations over all \c Changes.
245 void alignConsecutiveDeclarations();
246
247 /// Align consecutive declarations over all \c Changes.
248 void alignChainedConditionals();
249
250 /// Align consecutive short case statements over all \c Changes.
251 void alignConsecutiveShortCaseStatements(bool IsExpr);
252
253 /// Align consecutive TableGen DAGArg colon over all \c Changes.
254 void alignConsecutiveTableGenBreakingDAGArgColons();
255
256 /// Align consecutive TableGen cond operator colon over all \c Changes.
257 void alignConsecutiveTableGenCondOperatorColons();
258
259 /// Align consecutive TableGen definitions over all \c Changes.
260 void alignConsecutiveTableGenDefinitions();
261
262 /// Align trailing comments over all \c Changes.
263 void alignTrailingComments();
264
265 /// Align trailing comments from change \p Start to change \p End at
266 /// the specified \p Column.
267 void alignTrailingComments(unsigned Start, unsigned End, unsigned Column);
268
269 /// Align escaped newlines over all \c Changes.
270 void alignEscapedNewlines();
271
272 /// Align escaped newlines from change \p Start to change \p End at
273 /// the specified \p Column.
274 void alignEscapedNewlines(unsigned Start, unsigned End, unsigned Column);
275
276 /// Align Array Initializers over all \c Changes.
277 void alignArrayInitializers();
278
279 /// Align Array Initializers from change \p Start to change \p End at
280 /// the specified \p Column.
281 void alignArrayInitializers(unsigned Start, unsigned End);
282
283 /// Align Array Initializers being careful to right justify the columns
284 /// as described by \p CellDescs.
285 void alignArrayInitializersRightJustified(CellDescriptions &&CellDescs);
286
287 /// Align Array Initializers being careful to left justify the columns
288 /// as described by \p CellDescs.
289 void alignArrayInitializersLeftJustified(CellDescriptions &&CellDescs);
290
291 /// Calculate the cell width between two indexes.
292 unsigned calculateCellWidth(unsigned Start, unsigned End,
293 bool WithSpaces = false) const;
294
295 /// Get a set of fully specified CellDescriptions between \p Start and
296 /// \p End of the change list.
297 CellDescriptions getCells(unsigned Start, unsigned End);
298
299 /// Does this \p Cell contain a split element?
300 static bool isSplitCell(const CellDescription &Cell);
301
302 /// Get the width of the preceding cells from \p Start to \p End.
303 template <typename I>
304 auto getNetWidth(const I &Start, const I &End, unsigned InitialSpaces) const {
305 auto NetWidth = InitialSpaces;
306 for (auto PrevIter = Start; PrevIter != End; ++PrevIter) {
307 // If we broke the line the initial spaces are already
308 // accounted for.
309 assert(PrevIter->Index < Changes.size());
310 if (Changes[PrevIter->Index].NewlinesBefore > 0)
311 NetWidth = 0;
312 NetWidth +=
313 calculateCellWidth(PrevIter->Index, PrevIter->EndIndex, true) + 1;
314 }
315 return NetWidth;
316 }
317
318 /// Get the maximum width of a cell in a sequence of columns.
319 template <typename I>
320 unsigned getMaximumCellWidth(I CellIter, unsigned NetWidth) const {
321 unsigned CellWidth =
322 calculateCellWidth(CellIter->Index, CellIter->EndIndex, true);
323 if (Changes[CellIter->Index].NewlinesBefore == 0)
324 CellWidth += NetWidth;
325 for (const auto *Next = CellIter->NextColumnElement; Next;
326 Next = Next->NextColumnElement) {
327 auto ThisWidth = calculateCellWidth(Next->Index, Next->EndIndex, true);
328 if (Changes[Next->Index].NewlinesBefore == 0)
329 ThisWidth += NetWidth;
330 CellWidth = std::max(CellWidth, ThisWidth);
331 }
332 return CellWidth;
333 }
334
335 /// Get The maximum width of all columns to a given cell.
336 template <typename I>
337 unsigned getMaximumNetWidth(const I &CellStart, const I &CellStop,
338 unsigned InitialSpaces, unsigned CellCount,
339 unsigned MaxRowCount) const {
340 auto MaxNetWidth = getNetWidth(CellStart, CellStop, InitialSpaces);
341 auto RowCount = 1U;
342 auto Offset = std::distance(CellStart, CellStop);
343 for (const auto *Next = CellStop->NextColumnElement; Next;
344 Next = Next->NextColumnElement) {
345 if (RowCount >= MaxRowCount)
346 break;
347 auto Start = (CellStart + RowCount * CellCount);
348 auto End = Start + Offset;
349 MaxNetWidth =
350 std::max(MaxNetWidth, getNetWidth(Start, End, InitialSpaces));
351 ++RowCount;
352 }
353 return MaxNetWidth;
354 }
355
356 /// Align a split cell with a newline to the first element in the cell.
357 void alignToStartOfCell(unsigned Start, unsigned End);
358
359 /// Link the Cell pointers in the list of Cells.
360 static CellDescriptions linkCells(CellDescriptions &&CellDesc);
361
362 void setChangeSpaces(unsigned Start, unsigned Spaces);
363
364 /// Fill \c Replaces with the replacements for all effective changes.
365 void generateChanges();
366
367 /// Stores \p Text as the replacement for the whitespace in \p Range.
368 void storeReplacement(SourceRange Range, StringRef Text);
369 void appendNewlineText(std::string &Text, const Change &C);
370 void appendEscapedNewlineText(std::string &Text, unsigned Newlines,
371 unsigned PreviousEndOfTokenColumn,
372 unsigned EscapedNewlineColumn);
373 void appendIndentText(std::string &Text, unsigned IndentLevel,
374 unsigned Spaces, unsigned WhitespaceStartColumn,
375 bool IsAligned);
376 unsigned appendTabIndent(std::string &Text, unsigned Spaces,
377 unsigned Indentation);
378
379 SmallVector<Change, 16> Changes;
380 const SourceManager &SourceMgr;
381 tooling::Replacements Replaces;
382 const FormatStyle &Style;
383 bool UseCRLF;
384};
385
386} // namespace format
387} // namespace clang
388
389#endif
int Newlines
The number of newlines immediately before the Token after formatting.
Token Tok
The Token.
unsigned NewlinesBefore
The number of newlines immediately before the Token.
unsigned IndentLevel
The indent level of this token. Copied from the surrounding line.
FormatToken * Next
The next token in the unwrapped line.
Defines the SourceManager interface.
This file implements a token annotator, i.e.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
bool operator()(const Change &C1, const Change &C2) const
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, int Spaces)
Inserts or replaces whitespace in the middle of a token.
void addUntouchableToken(const FormatToken &Tok, bool InPPDirective)
Adds information about an unchangeable token's whitespace.
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, const FormatToken *AlignedTo=nullptr, bool InPPDirective=false, unsigned IndentedFromColumn=0, bool CreateReplacement=true)
Replaces the whitespace in front of Tok.
static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF)
Infers whether the input is using CRLF.
llvm::Error addReplacement(const tooling::Replacement &Replacement)
const tooling::Replacements & generateReplacements()
Returns all the Replacements created during formatting.
WhitespaceManager(const SourceManager &SourceMgr, const FormatStyle &Style, bool UseCRLF)
A text replacement.
Definition Replacement.h:83
Maintains a set of replacements that are conflict-free.
TokenType
Determines the semantic type of a syntactic token, e.g.
Top level wrappers for InstallAPI frontend operations.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition CallGraph.h:218
bool operator!=(CanQual< T > x, CanQual< U > y)
@ Other
Other implicit parameter.
Definition Decl.h:1775
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition Format.h:51
A wrapper around a Token storing information about the whitespace characters preceding it.
Represents a change before a token, a break inside a token, or the layout of an unchanged token (or w...
std::tuple< unsigned, unsigned, unsigned > indentAndNestingLevel() const
Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, unsigned IndentedFromColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, const FormatToken *AlignedTo, bool ContinuesPPDirective, bool IsInsideToken)
Creates a Change.