clang 23.0.0git
TokenAnnotator.h
Go to the documentation of this file.
1//===--- TokenAnnotator.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/// This file implements a token annotator, i.e. creates
11/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
16#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
17
18#include "UnwrappedLineParser.h"
19
20namespace clang {
21namespace format {
22
39
41 // Contained in class declaration/definition.
43 // Contained in compound requirement.
45 // Contained in other blocks (function, lambda, loop, if/else, child, etc).
47};
48
50public:
52 : First(Line.Tokens.front().Tok), Type(LT_Other), Level(Line.Level),
64 assert(!Line.Tokens.empty());
65
66 // Calculate Next and Previous for all tokens. Note that we must overwrite
67 // Next and Previous for every token, as previous formatting runs might have
68 // left them in a different state.
69 First->Previous = nullptr;
70 FormatToken *Current = First;
71 addChildren(Line.Tokens.front(), Current);
72 for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {
73 if (Node.Tok->MacroParent)
74 ContainsMacroCall = true;
75 Current->Next = Node.Tok;
76 Node.Tok->Previous = Current;
77 Current = Current->Next;
78 addChildren(Node, Current);
79 // FIXME: if we add children, previous will point to the token before
80 // the children; changing this requires significant changes across
81 // clang-format.
82 }
83 Last = Current;
84 Last->Next = nullptr;
85 }
86
87 void addChildren(const UnwrappedLineNode &Node, FormatToken *Current) {
88 Current->Children.clear();
89 for (const auto &Child : Node.Children) {
90 Children.push_back(new AnnotatedLine(Child));
91 if (Children.back()->ContainsMacroCall)
92 ContainsMacroCall = true;
93 Current->Children.push_back(Children.back());
94 }
95 }
96
97 size_t size() const {
98 size_t Size = 1;
99 for (const auto *Child : Children)
100 Size += Child->size();
101 return Size;
102 }
103
105 for (AnnotatedLine *Child : Children)
106 delete Child;
107 FormatToken *Current = First;
108 while (Current) {
109 Current->Children.clear();
110 Current->Role.reset();
111 Current = Current->Next;
112 }
113 }
114
115 bool isComment() const {
116 return First && First->is(tok::comment) && !First->getNextNonComment();
117 }
118
119 /// \c true if this line starts with the given tokens in order, ignoring
120 /// comments.
121 template <typename... Ts> bool startsWith(Ts... Tokens) const {
122 return First && First->startsSequence(Tokens...);
123 }
124
125 /// \c true if this line ends with the given tokens in reversed order,
126 /// ignoring comments.
127 /// For example, given tokens [T1, T2, T3, ...], the function returns true if
128 /// this line is like "... T3 T2 T1".
129 template <typename... Ts> bool endsWith(Ts... Tokens) const {
130 return Last && Last->endsSequence(Tokens...);
131 }
132
133 /// \c true if this line looks like a function definition instead of a
134 /// function declaration. Asserts MightBeFunctionDecl.
136 assert(MightBeFunctionDecl);
137 // Try to determine if the end of a stream of tokens is either the
138 // Definition or the Declaration for a function. It does this by looking for
139 // the ';' in foo(); and using that it ends with a ; to know this is the
140 // Definition, however the line could end with
141 // foo(); /* comment */
142 // or
143 // foo(); // comment
144 // or
145 // foo() // comment
146 // endsWith() ignores the comment.
147 return !endsWith(tok::semi);
148 }
149
150 /// \c true if this line starts a namespace definition.
151 bool startsWithNamespace() const {
152 return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||
153 startsWith(tok::kw_inline, tok::kw_namespace) ||
154 startsWith(tok::kw_export, tok::kw_namespace);
155 }
156
157 /// \c true if this line starts a C++ export block.
159 return startsWith(tok::kw_export, tok::l_brace);
160 }
161
163 assert(First);
164 return First->is(tok::comment) ? First->getNextNonComment() : First;
165 }
166
168 assert(Last);
169 return Last->is(tok::comment) ? Last->getPreviousNonComment() : Last;
170 }
171
174
176
178 unsigned Level;
179 unsigned PPLevel;
188
189 /// \c True if this line contains a macro call for which an expansion exists.
190 bool ContainsMacroCall = false;
191
192 /// \c True if calculateFormattingInformation() has been called on this line.
193 bool Computed = false;
194
195 /// \c True if this line should be formatted, i.e. intersects directly or
196 /// indirectly with one of the input ranges.
198
199 /// \c True if the leading empty lines of this line intersect with one of the
200 /// input ranges.
202
203 /// \c True if one of this line's children intersects with an input range.
205
206 /// \c True if breaking after last attribute group in function return type.
208
209 /// \c True if this line should be indented by ContinuationIndent in addition
210 /// to the normal indention level.
212
214
215private:
216 // Disallow copying.
217 AnnotatedLine(const AnnotatedLine &) = delete;
218 void operator=(const AnnotatedLine &) = delete;
219};
220
221/// Determines extra information about the tokens comprising an
222/// \c UnwrappedLine.
224public:
225 TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
226 : Style(Style), IsCpp(Style.isCpp()),
227 LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {}
228
229 /// Adapts the indent levels of comment lines to the indent of the
230 /// subsequent line.
231 // FIXME: Can/should this be done in the UnwrappedLineParser?
233
236
237private:
238 /// Calculate the penalty for splitting before \c Tok.
239 unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
240 bool InFunctionDecl) const;
241
242 bool spaceRequiredBeforeParens(const FormatToken &Right) const;
243
244 bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
245 const FormatToken &Right) const;
246
247 bool spaceRequiredBefore(const AnnotatedLine &Line,
248 const FormatToken &Right) const;
249
250 bool mustBreakBefore(AnnotatedLine &Line, const FormatToken &Right) const;
251
252 bool canBreakBefore(const AnnotatedLine &Line,
253 const FormatToken &Right) const;
254
255 bool mustBreakForReturnType(const AnnotatedLine &Line) const;
256
257 void printDebugInfo(const AnnotatedLine &Line) const;
258
259 void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;
260
261 void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;
262
263 FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
264 FormatToken *CurrentToken,
265 unsigned Depth) const;
266 FormatStyle::PointerAlignmentStyle
267 getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;
268
269 FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(
270 const FormatToken &PointerOrReference) const;
271
272 const FormatStyle &Style;
273
274 bool IsCpp;
275 LangOptions LangOpts;
276
277 const AdditionalKeywords &Keywords;
278
279 SmallVector<ScopeType> Scopes, MacroBodyScopes;
280};
281
282} // end namespace format
283} // end namespace clang
284
285#endif
Token Tok
The Token.
This file contains the declaration of the UnwrappedLineParser, which turns a stream of tokens into Un...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
void addChildren(const UnwrappedLineNode &Node, FormatToken *Current)
bool ReturnTypeWrapped
True if breaking after last attribute group in function return type.
FormatToken * getFirstNonComment() const
bool Computed
True if calculateFormattingInformation() has been called on this line.
bool LeadingEmptyLinesAffected
True if the leading empty lines of this line intersect with one of the input ranges.
bool Affected
True if this line should be formatted, i.e.
AnnotatedLine(const UnwrappedLine &Line)
bool ContainsMacroCall
True if this line contains a macro call for which an expansion exists.
bool mightBeFunctionDefinition() const
true if this line looks like a function definition instead of a function declaration.
bool ChildrenAffected
True if one of this line's children intersects with an input range.
SmallVector< AnnotatedLine *, 0 > Children
bool startsWithNamespace() const
true if this line starts a namespace definition.
bool startsWithExportBlock() const
true if this line starts a C++ export block.
bool IsContinuation
True if this line should be indented by ContinuationIndent in addition to the normal indention level.
bool endsWith(Ts... Tokens) const
true if this line ends with the given tokens in reversed order, ignoring comments.
bool startsWith(Ts... Tokens) const
true if this line starts with the given tokens in order, ignoring comments.
FormatToken * getLastNonComment() const
void calculateFormattingInformation(AnnotatedLine &Line) const
void annotate(AnnotatedLine &Line)
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
void setCommentLineLevels(SmallVectorImpl< AnnotatedLine * > &Lines) const
Adapts the indent levels of comment lines to the indent of the subsequent line.
LangOptions getFormattingLangOpts(const FormatStyle &Style)
Definition Format.cpp:4371
The JSON file list parser is used to communicate input to InstallAPI.
bool isCpp() const
Definition Format.h:3841
#define false
Definition stdbool.h:26
Encapsulates keywords that are context sensitive or for languages not properly supported by Clang's l...
A wrapper around a Token storing information about the whitespace characters preceding it.
SmallVector< AnnotatedLine *, 1 > Children
If this token starts a block, this contains all the unwrapped lines in it.
FormatToken * Next
The next token in the unwrapped line.
std::shared_ptr< TokenRole > Role
A token can have a special role that can carry extra information about the token's formatting.
SmallVector< UnwrappedLine, 0 > Children
An unwrapped line is a sequence of Token, that we would like to put on a single line if there was no ...