150
|
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 #include "clang/Format/Format.h"
|
|
20
|
|
21 namespace clang {
|
|
22 class SourceManager;
|
|
23
|
|
24 namespace format {
|
|
25
|
|
26 enum LineType {
|
|
27 LT_Invalid,
|
|
28 LT_ImportStatement,
|
|
29 LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
|
|
30 LT_ObjCMethodDecl,
|
|
31 LT_ObjCProperty, // An @property line.
|
|
32 LT_Other,
|
|
33 LT_PreprocessorDirective,
|
|
34 LT_VirtualFunctionDecl
|
|
35 };
|
|
36
|
|
37 class AnnotatedLine {
|
|
38 public:
|
|
39 AnnotatedLine(const UnwrappedLine &Line)
|
|
40 : First(Line.Tokens.front().Tok), Level(Line.Level),
|
|
41 MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),
|
|
42 MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),
|
|
43 InPPDirective(Line.InPPDirective),
|
|
44 MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
|
|
45 IsMultiVariableDeclStmt(false), Affected(false),
|
|
46 LeadingEmptyLinesAffected(false), ChildrenAffected(false),
|
|
47 FirstStartColumn(Line.FirstStartColumn) {
|
|
48 assert(!Line.Tokens.empty());
|
|
49
|
|
50 // Calculate Next and Previous for all tokens. Note that we must overwrite
|
|
51 // Next and Previous for every token, as previous formatting runs might have
|
|
52 // left them in a different state.
|
|
53 First->Previous = nullptr;
|
|
54 FormatToken *Current = First;
|
|
55 for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(),
|
|
56 E = Line.Tokens.end();
|
|
57 I != E; ++I) {
|
|
58 const UnwrappedLineNode &Node = *I;
|
|
59 Current->Next = I->Tok;
|
|
60 I->Tok->Previous = Current;
|
|
61 Current = Current->Next;
|
|
62 Current->Children.clear();
|
|
63 for (const auto &Child : Node.Children) {
|
|
64 Children.push_back(new AnnotatedLine(Child));
|
|
65 Current->Children.push_back(Children.back());
|
|
66 }
|
|
67 }
|
|
68 Last = Current;
|
|
69 Last->Next = nullptr;
|
|
70 }
|
|
71
|
|
72 ~AnnotatedLine() {
|
|
73 for (unsigned i = 0, e = Children.size(); i != e; ++i) {
|
|
74 delete Children[i];
|
|
75 }
|
|
76 FormatToken *Current = First;
|
|
77 while (Current) {
|
|
78 Current->Children.clear();
|
|
79 Current->Role.reset();
|
|
80 Current = Current->Next;
|
|
81 }
|
|
82 }
|
|
83
|
|
84 /// \c true if this line starts with the given tokens in order, ignoring
|
|
85 /// comments.
|
|
86 template <typename... Ts> bool startsWith(Ts... Tokens) const {
|
|
87 return First && First->startsSequence(Tokens...);
|
|
88 }
|
|
89
|
|
90 /// \c true if this line ends with the given tokens in reversed order,
|
|
91 /// ignoring comments.
|
|
92 /// For example, given tokens [T1, T2, T3, ...], the function returns true if
|
|
93 /// this line is like "... T3 T2 T1".
|
|
94 template <typename... Ts> bool endsWith(Ts... Tokens) const {
|
|
95 return Last && Last->endsSequence(Tokens...);
|
|
96 }
|
|
97
|
|
98 /// \c true if this line looks like a function definition instead of a
|
|
99 /// function declaration. Asserts MightBeFunctionDecl.
|
|
100 bool mightBeFunctionDefinition() const {
|
|
101 assert(MightBeFunctionDecl);
|
|
102 // Try to determine if the end of a stream of tokens is either the
|
|
103 // Definition or the Declaration for a function. It does this by looking for
|
|
104 // the ';' in foo(); and using that it ends with a ; to know this is the
|
|
105 // Definition, however the line could end with
|
|
106 // foo(); /* comment */
|
|
107 // or
|
|
108 // foo(); // comment
|
|
109 // or
|
|
110 // foo() // comment
|
|
111 // endsWith() ignores the comment.
|
|
112 return !endsWith(tok::semi);
|
|
113 }
|
|
114
|
|
115 /// \c true if this line starts a namespace definition.
|
|
116 bool startsWithNamespace() const {
|
|
117 return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||
|
|
118 startsWith(tok::kw_inline, tok::kw_namespace) ||
|
|
119 startsWith(tok::kw_export, tok::kw_namespace);
|
|
120 }
|
|
121
|
|
122 FormatToken *First;
|
|
123 FormatToken *Last;
|
|
124
|
|
125 SmallVector<AnnotatedLine *, 0> Children;
|
|
126
|
|
127 LineType Type;
|
|
128 unsigned Level;
|
|
129 size_t MatchingOpeningBlockLineIndex;
|
|
130 size_t MatchingClosingBlockLineIndex;
|
|
131 bool InPPDirective;
|
|
132 bool MustBeDeclaration;
|
|
133 bool MightBeFunctionDecl;
|
|
134 bool IsMultiVariableDeclStmt;
|
|
135
|
|
136 /// \c True if this line should be formatted, i.e. intersects directly or
|
|
137 /// indirectly with one of the input ranges.
|
|
138 bool Affected;
|
|
139
|
|
140 /// \c True if the leading empty lines of this line intersect with one of the
|
|
141 /// input ranges.
|
|
142 bool LeadingEmptyLinesAffected;
|
|
143
|
|
144 /// \c True if one of this line's children intersects with an input range.
|
|
145 bool ChildrenAffected;
|
|
146
|
|
147 unsigned FirstStartColumn;
|
|
148
|
|
149 private:
|
|
150 // Disallow copying.
|
|
151 AnnotatedLine(const AnnotatedLine &) = delete;
|
|
152 void operator=(const AnnotatedLine &) = delete;
|
|
153 };
|
|
154
|
|
155 /// Determines extra information about the tokens comprising an
|
|
156 /// \c UnwrappedLine.
|
|
157 class TokenAnnotator {
|
|
158 public:
|
|
159 TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
|
|
160 : Style(Style), Keywords(Keywords) {}
|
|
161
|
|
162 /// Adapts the indent levels of comment lines to the indent of the
|
|
163 /// subsequent line.
|
|
164 // FIXME: Can/should this be done in the UnwrappedLineParser?
|
|
165 void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines);
|
|
166
|
|
167 void annotate(AnnotatedLine &Line);
|
|
168 void calculateFormattingInformation(AnnotatedLine &Line);
|
|
169
|
|
170 private:
|
|
171 /// Calculate the penalty for splitting before \c Tok.
|
|
172 unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
|
|
173 bool InFunctionDecl);
|
|
174
|
|
175 bool spaceRequiredBeforeParens(const FormatToken &Right) const;
|
|
176
|
|
177 bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
|
|
178 const FormatToken &Right);
|
|
179
|
|
180 bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right);
|
|
181
|
|
182 bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
|
|
183
|
|
184 bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
|
|
185
|
|
186 bool mustBreakForReturnType(const AnnotatedLine &Line) const;
|
|
187
|
|
188 void printDebugInfo(const AnnotatedLine &Line);
|
|
189
|
|
190 void calculateUnbreakableTailLengths(AnnotatedLine &Line);
|
|
191
|
|
192 const FormatStyle &Style;
|
|
193
|
|
194 const AdditionalKeywords &Keywords;
|
|
195 };
|
|
196
|
|
197 } // end namespace format
|
|
198 } // end namespace clang
|
|
199
|
|
200 #endif
|