[AMDGPU][AsmParser][NFC] Get rid of custom default operand handlers.
[llvm-project.git] / clang / lib / Format / TokenAnnotator.h
blob611e95ba11b01780e926adc21afb7c0e1d8f2884
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 //===----------------------------------------------------------------------===//
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"
21 namespace clang {
22 namespace format {
24 enum LineType {
25 LT_Invalid,
26 LT_ImportStatement,
27 LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
28 LT_ObjCMethodDecl,
29 LT_ObjCProperty, // An @property line.
30 LT_Other,
31 LT_PreprocessorDirective,
32 LT_VirtualFunctionDecl,
33 LT_ArrayOfStructInitializer,
34 LT_CommentAbovePPDirective,
37 enum ScopeType {
38 // Contained in class declaration/definition.
39 ST_Class,
40 // Contained within function definition.
41 ST_Function,
42 // Contained within other scope block (loop, if/else, etc).
43 ST_Other,
46 class AnnotatedLine {
47 public:
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
78 // clang-format.
80 Last = Current;
81 Last->Next = nullptr;
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());
94 ~AnnotatedLine() {
95 for (AnnotatedLine *Child : Children)
96 delete Child;
97 FormatToken *Current = First;
98 while (Current) {
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
110 /// comments.
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 */
132 // or
133 // foo(); // comment
134 // or
135 // 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);
147 FormatToken *First;
148 FormatToken *Last;
150 SmallVector<AnnotatedLine *, 0> Children;
152 LineType Type;
153 unsigned Level;
154 unsigned PPLevel;
155 size_t MatchingOpeningBlockLineIndex;
156 size_t MatchingClosingBlockLineIndex;
157 bool InPPDirective;
158 bool InPragmaDirective;
159 bool InMacroBody;
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.
169 bool Affected;
171 /// \c True if the leading empty lines of this line intersect with one of the
172 /// input ranges.
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.
183 bool IsContinuation;
185 unsigned FirstStartColumn;
187 private:
188 // Disallow copying.
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 {
196 public:
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
201 /// subsequent line.
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;
208 private:
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
254 #endif