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 | // FIXME: Line.Last points to other characters than tok::semi |
103 | // and tok::lbrace. |
104 | return !Last->isOneOf(tok::semi, tok::comment); |
105 | } |
106 | |
107 | /// \c true if this line starts a namespace definition. |
108 | bool startsWithNamespace() const { |
109 | return startsWith(tok::kw_namespace) || |
110 | startsWith(tok::kw_inline, tok::kw_namespace) || |
111 | startsWith(tok::kw_export, tok::kw_namespace); |
112 | } |
113 | |
114 | FormatToken *First; |
115 | FormatToken *Last; |
116 | |
117 | SmallVector<AnnotatedLine *, 0> Children; |
118 | |
119 | LineType Type; |
120 | unsigned Level; |
121 | size_t MatchingOpeningBlockLineIndex; |
122 | size_t MatchingClosingBlockLineIndex; |
123 | bool InPPDirective; |
124 | bool MustBeDeclaration; |
125 | bool MightBeFunctionDecl; |
126 | bool IsMultiVariableDeclStmt; |
127 | |
128 | /// \c True if this line should be formatted, i.e. intersects directly or |
129 | /// indirectly with one of the input ranges. |
130 | bool Affected; |
131 | |
132 | /// \c True if the leading empty lines of this line intersect with one of the |
133 | /// input ranges. |
134 | bool LeadingEmptyLinesAffected; |
135 | |
136 | /// \c True if one of this line's children intersects with an input range. |
137 | bool ChildrenAffected; |
138 | |
139 | unsigned FirstStartColumn; |
140 | |
141 | private: |
142 | // Disallow copying. |
143 | AnnotatedLine(const AnnotatedLine &) = delete; |
144 | void operator=(const AnnotatedLine &) = delete; |
145 | }; |
146 | |
147 | /// Determines extra information about the tokens comprising an |
148 | /// \c UnwrappedLine. |
149 | class TokenAnnotator { |
150 | public: |
151 | TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords) |
152 | : Style(Style), Keywords(Keywords) {} |
153 | |
154 | /// Adapts the indent levels of comment lines to the indent of the |
155 | /// subsequent line. |
156 | // FIXME: Can/should this be done in the UnwrappedLineParser? |
157 | void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines); |
158 | |
159 | void annotate(AnnotatedLine &Line); |
160 | void calculateFormattingInformation(AnnotatedLine &Line); |
161 | |
162 | private: |
163 | /// Calculate the penalty for splitting before \c Tok. |
164 | unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok, |
165 | bool InFunctionDecl); |
166 | |
167 | bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, |
168 | const FormatToken &Right); |
169 | |
170 | bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right); |
171 | |
172 | bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right); |
173 | |
174 | bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right); |
175 | |
176 | bool mustBreakForReturnType(const AnnotatedLine &Line) const; |
177 | |
178 | void printDebugInfo(const AnnotatedLine &Line); |
179 | |
180 | void calculateUnbreakableTailLengths(AnnotatedLine &Line); |
181 | |
182 | const FormatStyle &Style; |
183 | |
184 | const AdditionalKeywords &Keywords; |
185 | }; |
186 | |
187 | } // end namespace format |
188 | } // end namespace clang |
189 | |
190 | #endif |
191 | |