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.
36};
37
39 // Contained in class declaration/definition.
41 // Contained within function definition.
43 // Contained within other scope block (loop, if/else, etc).
45};
46
48public:
50 : First(Line.Tokens.front().Tok), Type(LT_Other), Level(Line.Level),
62 assert(!Line.Tokens.empty());
63
64 // Calculate Next and Previous for all tokens. Note that we must overwrite
65 // Next and Previous for every token, as previous formatting runs might have
66 // left them in a different state.
67 First->Previous = nullptr;
68 FormatToken *Current = First;
69 addChildren(Line.Tokens.front(), Current);
70 for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {
71 if (Node.Tok->MacroParent)
72 ContainsMacroCall = true;
73 Current->Next = Node.Tok;
74 Node.Tok->Previous = Current;
75 Current = Current->Next;
76 addChildren(Node, Current);
77 // FIXME: if we add children, previous will point to the token before
78 // the children; changing this requires significant changes across
79 // clang-format.
80 }
81 Last = Current;
82 Last->Next = nullptr;
83 }
84
86 Current->Children.clear();
87 for (const auto &Child : Node.Children) {
88 Children.push_back(new AnnotatedLine(Child));
89 if (Children.back()->ContainsMacroCall)
90 ContainsMacroCall = true;
91 Current->Children.push_back(Children.back());
92 }
93 }
94
95 size_t size() const {
96 size_t Size = 1;
97 for (const auto *Child : Children)
98 Size += Child->size();
99 return Size;
100 }
101
103 for (AnnotatedLine *Child : Children)
104 delete Child;
105 FormatToken *Current = First;
106 while (Current) {
107 Current->Children.clear();
108 Current->Role.reset();
109 Current = Current->Next;
110 }
111 }
112
113 bool isComment() const {
114 return First && First->is(tok::comment) && !First->getNextNonComment();
115 }
116
117 /// \c true if this line starts with the given tokens in order, ignoring
118 /// comments.
119 template <typename... Ts> bool startsWith(Ts... Tokens) const {
120 return First && First->startsSequence(Tokens...);
121 }
122
123 /// \c true if this line ends with the given tokens in reversed order,
124 /// ignoring comments.
125 /// For example, given tokens [T1, T2, T3, ...], the function returns true if
126 /// this line is like "... T3 T2 T1".
127 template <typename... Ts> bool endsWith(Ts... Tokens) const {
128 return Last && Last->endsSequence(Tokens...);
129 }
130
131 /// \c true if this line looks like a function definition instead of a
132 /// function declaration. Asserts MightBeFunctionDecl.
134 assert(MightBeFunctionDecl);
135 // Try to determine if the end of a stream of tokens is either the
136 // Definition or the Declaration for a function. It does this by looking for
137 // the ';' in foo(); and using that it ends with a ; to know this is the
138 // Definition, however the line could end with
139 // foo(); /* comment */
140 // or
141 // foo(); // comment
142 // or
143 // foo() // comment
144 // endsWith() ignores the comment.
145 return !endsWith(tok::semi);
146 }
147
148 /// \c true if this line starts a namespace definition.
149 bool startsWithNamespace() const {
150 return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||
151 startsWith(tok::kw_inline, tok::kw_namespace) ||
152 startsWith(tok::kw_export, tok::kw_namespace);
153 }
154
156 assert(First);
157 return First->is(tok::comment) ? First->getNextNonComment() : First;
158 }
159
161 assert(Last);
162 return Last->is(tok::comment) ? Last->getPreviousNonComment() : Last;
163 }
164
167
169
171 unsigned Level;
172 unsigned PPLevel;
181
182 /// \c True if this line contains a macro call for which an expansion exists.
183 bool ContainsMacroCall = false;
184
185 /// \c True if this line should be formatted, i.e. intersects directly or
186 /// indirectly with one of the input ranges.
188
189 /// \c True if the leading empty lines of this line intersect with one of the
190 /// input ranges.
192
193 /// \c True if one of this line's children intersects with an input range.
195
196 /// \c True if breaking after last attribute group in function return type.
198
199 /// \c True if this line should be indented by ContinuationIndent in addition
200 /// to the normal indention level.
202
204
205private:
206 // Disallow copying.
207 AnnotatedLine(const AnnotatedLine &) = delete;
208 void operator=(const AnnotatedLine &) = delete;
209};
210
211/// Determines extra information about the tokens comprising an
212/// \c UnwrappedLine.
214public:
215 TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
216 : Style(Style), IsCpp(Style.isCpp()),
217 LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {
218 assert(IsCpp == LangOpts.CXXOperatorNames);
219 }
220
221 /// Adapts the indent levels of comment lines to the indent of the
222 /// subsequent line.
223 // FIXME: Can/should this be done in the UnwrappedLineParser?
225
228
229private:
230 /// Calculate the penalty for splitting before \c Tok.
231 unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
232 bool InFunctionDecl) const;
233
234 bool spaceRequiredBeforeParens(const FormatToken &Right) const;
235
236 bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
237 const FormatToken &Right) const;
238
239 bool spaceRequiredBefore(const AnnotatedLine &Line,
240 const FormatToken &Right) const;
241
242 bool mustBreakBefore(const AnnotatedLine &Line,
243 const FormatToken &Right) const;
244
245 bool canBreakBefore(const AnnotatedLine &Line,
246 const FormatToken &Right) const;
247
248 bool mustBreakForReturnType(const AnnotatedLine &Line) const;
249
250 void printDebugInfo(const AnnotatedLine &Line) const;
251
252 void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;
253
254 void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;
255
256 FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
257 FormatToken *CurrentToken,
258 unsigned Depth) const;
260 getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;
261
262 FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(
263 const FormatToken &PointerOrReference) const;
264
265 const FormatStyle &Style;
266
267 bool IsCpp;
268 LangOptions LangOpts;
269
270 const AdditionalKeywords &Keywords;
271
273};
274
275} // end namespace format
276} // end namespace clang
277
278#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:476
The base class of the type hierarchy.
Definition: Type.h:1829
void addChildren(const UnwrappedLineNode &Node, FormatToken *Current)
bool ReturnTypeWrapped
True if breaking after last attribute group in function return type.
FormatToken * getFirstNonComment() const
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:3873
@ 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:1024
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:55
PointerAlignmentStyle
The &, && and * alignment style.
Definition: Format.h:3622
A wrapper around a Token storing information about the whitespace characters preceding it.
Definition: FormatToken.h:292
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:641
FormatToken * getNextNonComment() const
Returns the next token ignoring comments.
Definition: FormatToken.h:840
FormatToken * getPreviousNonComment() const
Returns the previous token ignoring comments.
Definition: FormatToken.h:832
FormatToken * Next
The next token in the unwrapped line.
Definition: FormatToken.h:564
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:604
FormatToken * Previous
The previous token in the unwrapped line.
Definition: FormatToken.h:561
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:652
An unwrapped line is a sequence of Token, that we would like to put on a single line if there was no ...