clang 22.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
25 // Contains public/private/protected followed by TT_InheritanceColon.
28 LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
30 LT_ObjCProperty, // An @property line.
38};
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
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(const AnnotatedLine &Line,
251 const FormatToken &Right) const;
252
253 bool canBreakBefore(const AnnotatedLine &Line,
254 const FormatToken &Right) const;
255
256 bool mustBreakForReturnType(const AnnotatedLine &Line) const;
257
258 void printDebugInfo(const AnnotatedLine &Line) const;
259
260 void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;
261
262 void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;
263
264 FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
265 FormatToken *CurrentToken,
266 unsigned Depth) const;
268 getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;
269
270 FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(
271 const FormatToken &PointerOrReference) const;
272
273 const FormatStyle &Style;
274
275 bool IsCpp;
276 LangOptions LangOpts;
277
278 const AdditionalKeywords &Keywords;
279
280 SmallVector<ScopeType> Scopes, MacroBodyScopes;
281};
282
283} // end namespace format
284} // end namespace clang
285
286#endif
DynTypedNode Node
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...
Definition: LangOptions.h:434
The base class of the type hierarchy.
Definition: TypeBase.h:1833
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
Determines extra information about the tokens comprising an UnwrappedLine.
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=getLLVMStyle())
Returns the LangOpts that the formatter expects you to set.
Definition: Format.cpp:4077
@ LT_CommentAbovePPDirective
@ LT_ArrayOfStructInitializer
The JSON file list parser is used to communicate input to InstallAPI.
#define false
Definition: stdbool.h:26
Encapsulates keywords that are context sensitive or for languages not properly supported by Clang's l...
Definition: FormatToken.h:1026
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:55
PointerAlignmentStyle
The &, && and * alignment style.
Definition: Format.h:3795
A wrapper around a Token storing information about the whitespace characters preceding it.
Definition: FormatToken.h:300
bool startsSequence(A K1, Ts... Tokens) const
true if this token starts a sequence with the given tokens in order, following the Next pointers,...
Definition: FormatToken.h:658
FormatToken * getNextNonComment() const
Returns the next token ignoring comments.
Definition: FormatToken.h:842
FormatToken * getPreviousNonComment() const
Returns the previous token ignoring comments.
Definition: FormatToken.h:834
FormatToken * Next
The next token in the unwrapped line.
Definition: FormatToken.h:572
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:618
FormatToken * Previous
The previous token in the unwrapped line.
Definition: FormatToken.h:569
bool endsSequence(A K1, Ts... Tokens) const
true if this token ends a sequence with the given tokens in order, following the Previous pointers,...
Definition: FormatToken.h:669
An unwrapped line is a sequence of Token, that we would like to put on a single line if there was no ...