clang 20.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
158 assert(First);
159 return First->is(tok::comment) ? First->getNextNonComment() : First;
160 }
161
163 assert(Last);
164 return Last->is(tok::comment) ? Last->getPreviousNonComment() : Last;
165 }
166
169
171
173 unsigned Level;
174 unsigned PPLevel;
183
184 /// \c True if this line contains a macro call for which an expansion exists.
185 bool ContainsMacroCall = false;
186
187 /// \c True if calculateFormattingInformation() has been called on this line.
188 bool Computed = false;
189
190 /// \c True if this line should be formatted, i.e. intersects directly or
191 /// indirectly with one of the input ranges.
193
194 /// \c True if the leading empty lines of this line intersect with one of the
195 /// input ranges.
197
198 /// \c True if one of this line's children intersects with an input range.
200
201 /// \c True if breaking after last attribute group in function return type.
203
204 /// \c True if this line should be indented by ContinuationIndent in addition
205 /// to the normal indention level.
207
209
210private:
211 // Disallow copying.
212 AnnotatedLine(const AnnotatedLine &) = delete;
213 void operator=(const AnnotatedLine &) = delete;
214};
215
216/// Determines extra information about the tokens comprising an
217/// \c UnwrappedLine.
219public:
220 TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
221 : Style(Style), IsCpp(Style.isCpp()),
222 LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {
223 assert(IsCpp == LangOpts.CXXOperatorNames);
224 }
225
226 /// Adapts the indent levels of comment lines to the indent of the
227 /// subsequent line.
228 // FIXME: Can/should this be done in the UnwrappedLineParser?
230
233
234private:
235 /// Calculate the penalty for splitting before \c Tok.
236 unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
237 bool InFunctionDecl) const;
238
239 bool spaceRequiredBeforeParens(const FormatToken &Right) const;
240
241 bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
242 const FormatToken &Right) const;
243
244 bool spaceRequiredBefore(const AnnotatedLine &Line,
245 const FormatToken &Right) const;
246
247 bool mustBreakBefore(const AnnotatedLine &Line,
248 const FormatToken &Right) const;
249
250 bool canBreakBefore(const AnnotatedLine &Line,
251 const FormatToken &Right) const;
252
253 bool mustBreakForReturnType(const AnnotatedLine &Line) const;
254
255 void printDebugInfo(const AnnotatedLine &Line) const;
256
257 void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;
258
259 void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;
260
261 FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
262 FormatToken *CurrentToken,
263 unsigned Depth) const;
265 getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;
266
267 FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(
268 const FormatToken &PointerOrReference) const;
269
270 const FormatStyle &Style;
271
272 bool IsCpp;
273 LangOptions LangOpts;
274
275 const AdditionalKeywords &Keywords;
276
277 SmallVector<ScopeType> Scopes, MacroBodyScopes;
278};
279
280} // end namespace format
281} // end namespace clang
282
283#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:499
The base class of the type hierarchy.
Definition: Type.h:1828
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 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:3930
@ 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:1032
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:55
PointerAlignmentStyle
The &, && and * alignment style.
Definition: Format.h:3666
A wrapper around a Token storing information about the whitespace characters preceding it.
Definition: FormatToken.h:297
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:649
FormatToken * getNextNonComment() const
Returns the next token ignoring comments.
Definition: FormatToken.h:848
FormatToken * getPreviousNonComment() const
Returns the previous token ignoring comments.
Definition: FormatToken.h:840
FormatToken * Next
The next token in the unwrapped line.
Definition: FormatToken.h:569
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:612
FormatToken * Previous
The previous token in the unwrapped line.
Definition: FormatToken.h:566
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:660
An unwrapped line is a sequence of Token, that we would like to put on a single line if there was no ...