1 //===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements a token annotator, i.e. creates
11 /// \c AnnotatedTokens out of \c FormatTokens with required extra information.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
16 #define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
18 #include "UnwrappedLineParser.h"
19 #include "clang/Format/Format.h"
27 LT_ObjCDecl
, // An @interface, @implementation, or @protocol line.
29 LT_ObjCProperty
, // An @property line.
31 LT_PreprocessorDirective
,
32 LT_VirtualFunctionDecl
,
33 LT_ArrayOfStructInitializer
,
34 LT_CommentAbovePPDirective
,
38 // Contained in class declaration/definition.
40 // Contained within function definition.
42 // Contained within other scope block (loop, if/else, etc).
48 AnnotatedLine(const UnwrappedLine
&Line
)
49 : First(Line
.Tokens
.front().Tok
), Level(Line
.Level
),
50 PPLevel(Line
.PPLevel
),
51 MatchingOpeningBlockLineIndex(Line
.MatchingOpeningBlockLineIndex
),
52 MatchingClosingBlockLineIndex(Line
.MatchingClosingBlockLineIndex
),
53 InPPDirective(Line
.InPPDirective
),
54 InPragmaDirective(Line
.InPragmaDirective
),
55 InMacroBody(Line
.InMacroBody
),
56 MustBeDeclaration(Line
.MustBeDeclaration
), MightBeFunctionDecl(false),
57 IsMultiVariableDeclStmt(false), Affected(false),
58 LeadingEmptyLinesAffected(false), ChildrenAffected(false),
59 ReturnTypeWrapped(false), IsContinuation(Line
.IsContinuation
),
60 FirstStartColumn(Line
.FirstStartColumn
) {
61 assert(!Line
.Tokens
.empty());
63 // Calculate Next and Previous for all tokens. Note that we must overwrite
64 // Next and Previous for every token, as previous formatting runs might have
65 // left them in a different state.
66 First
->Previous
= nullptr;
67 FormatToken
*Current
= First
;
68 addChildren(Line
.Tokens
.front(), Current
);
69 for (const UnwrappedLineNode
&Node
: llvm::drop_begin(Line
.Tokens
)) {
70 if (Node
.Tok
->MacroParent
)
71 ContainsMacroCall
= true;
72 Current
->Next
= Node
.Tok
;
73 Node
.Tok
->Previous
= Current
;
74 Current
= Current
->Next
;
75 addChildren(Node
, Current
);
76 // FIXME: if we add children, previous will point to the token before
77 // the children; changing this requires significant changes across
84 void addChildren(const UnwrappedLineNode
&Node
, FormatToken
*Current
) {
85 Current
->Children
.clear();
86 for (const auto &Child
: Node
.Children
) {
87 Children
.push_back(new AnnotatedLine(Child
));
88 if (Children
.back()->ContainsMacroCall
)
89 ContainsMacroCall
= true;
90 Current
->Children
.push_back(Children
.back());
95 for (AnnotatedLine
*Child
: Children
)
97 FormatToken
*Current
= First
;
99 Current
->Children
.clear();
100 Current
->Role
.reset();
101 Current
= Current
->Next
;
105 bool isComment() const {
106 return First
&& First
->is(tok::comment
) && !First
->getNextNonComment();
109 /// \c true if this line starts with the given tokens in order, ignoring
111 template <typename
... Ts
> bool startsWith(Ts
... Tokens
) const {
112 return First
&& First
->startsSequence(Tokens
...);
115 /// \c true if this line ends with the given tokens in reversed order,
116 /// ignoring comments.
117 /// For example, given tokens [T1, T2, T3, ...], the function returns true if
118 /// this line is like "... T3 T2 T1".
119 template <typename
... Ts
> bool endsWith(Ts
... Tokens
) const {
120 return Last
&& Last
->endsSequence(Tokens
...);
123 /// \c true if this line looks like a function definition instead of a
124 /// function declaration. Asserts MightBeFunctionDecl.
125 bool mightBeFunctionDefinition() const {
126 assert(MightBeFunctionDecl
);
127 // Try to determine if the end of a stream of tokens is either the
128 // Definition or the Declaration for a function. It does this by looking for
129 // the ';' in foo(); and using that it ends with a ; to know this is the
130 // Definition, however the line could end with
131 // foo(); /* comment */
136 // endsWith() ignores the comment.
137 return !endsWith(tok::semi
);
140 /// \c true if this line starts a namespace definition.
141 bool startsWithNamespace() const {
142 return startsWith(tok::kw_namespace
) || startsWith(TT_NamespaceMacro
) ||
143 startsWith(tok::kw_inline
, tok::kw_namespace
) ||
144 startsWith(tok::kw_export
, tok::kw_namespace
);
150 SmallVector
<AnnotatedLine
*, 0> Children
;
155 size_t MatchingOpeningBlockLineIndex
;
156 size_t MatchingClosingBlockLineIndex
;
158 bool InPragmaDirective
;
160 bool MustBeDeclaration
;
161 bool MightBeFunctionDecl
;
162 bool IsMultiVariableDeclStmt
;
164 /// \c True if this line contains a macro call for which an expansion exists.
165 bool ContainsMacroCall
= false;
167 /// \c True if this line should be formatted, i.e. intersects directly or
168 /// indirectly with one of the input ranges.
171 /// \c True if the leading empty lines of this line intersect with one of the
173 bool LeadingEmptyLinesAffected
;
175 /// \c True if one of this line's children intersects with an input range.
176 bool ChildrenAffected
;
178 /// \c True if breaking after last attribute group in function return type.
179 bool ReturnTypeWrapped
;
181 /// \c True if this line should be indented by ContinuationIndent in addition
182 /// to the normal indention level.
185 unsigned FirstStartColumn
;
189 AnnotatedLine(const AnnotatedLine
&) = delete;
190 void operator=(const AnnotatedLine
&) = delete;
193 /// Determines extra information about the tokens comprising an
194 /// \c UnwrappedLine.
195 class TokenAnnotator
{
197 TokenAnnotator(const FormatStyle
&Style
, const AdditionalKeywords
&Keywords
)
198 : Style(Style
), Keywords(Keywords
) {}
200 /// Adapts the indent levels of comment lines to the indent of the
202 // FIXME: Can/should this be done in the UnwrappedLineParser?
203 void setCommentLineLevels(SmallVectorImpl
<AnnotatedLine
*> &Lines
) const;
205 void annotate(AnnotatedLine
&Line
);
206 void calculateFormattingInformation(AnnotatedLine
&Line
) const;
209 /// Calculate the penalty for splitting before \c Tok.
210 unsigned splitPenalty(const AnnotatedLine
&Line
, const FormatToken
&Tok
,
211 bool InFunctionDecl
) const;
213 bool spaceRequiredBeforeParens(const FormatToken
&Right
) const;
215 bool spaceRequiredBetween(const AnnotatedLine
&Line
, const FormatToken
&Left
,
216 const FormatToken
&Right
) const;
218 bool spaceRequiredBefore(const AnnotatedLine
&Line
,
219 const FormatToken
&Right
) const;
221 bool mustBreakBefore(const AnnotatedLine
&Line
,
222 const FormatToken
&Right
) const;
224 bool canBreakBefore(const AnnotatedLine
&Line
,
225 const FormatToken
&Right
) const;
227 bool mustBreakForReturnType(const AnnotatedLine
&Line
) const;
229 void printDebugInfo(const AnnotatedLine
&Line
) const;
231 void calculateUnbreakableTailLengths(AnnotatedLine
&Line
) const;
233 void calculateArrayInitializerColumnList(AnnotatedLine
&Line
) const;
235 FormatToken
*calculateInitializerColumnList(AnnotatedLine
&Line
,
236 FormatToken
*CurrentToken
,
237 unsigned Depth
) const;
238 FormatStyle::PointerAlignmentStyle
239 getTokenReferenceAlignment(const FormatToken
&PointerOrReference
) const;
241 FormatStyle::PointerAlignmentStyle
getTokenPointerOrReferenceAlignment(
242 const FormatToken
&PointerOrReference
) const;
244 const FormatStyle
&Style
;
246 const AdditionalKeywords
&Keywords
;
248 SmallVector
<ScopeType
> Scopes
;
251 } // end namespace format
252 } // end namespace clang