1 //===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief This file implements a token annotator, i.e. creates 12 /// \c AnnotatedTokens out of \c FormatTokens with required extra information. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H 17 #define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H 18 19 #include "UnwrappedLineParser.h" 20 #include "clang/Format/Format.h" 21 #include <string> 22 23 namespace clang { 24 class SourceManager; 25 26 namespace format { 27 28 enum LineType { 29 LT_Invalid, 30 LT_ImportStatement, 31 LT_ObjCDecl, // An @interface, @implementation, or @protocol line. 32 LT_ObjCMethodDecl, 33 LT_ObjCProperty, // An @property line. 34 LT_Other, 35 LT_PreprocessorDirective, 36 LT_VirtualFunctionDecl 37 }; 38 39 class AnnotatedLine { 40 public: 41 AnnotatedLine(const UnwrappedLine &Line) 42 : First(Line.Tokens.front().Tok), Level(Line.Level), 43 InPPDirective(Line.InPPDirective), 44 MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), 45 IsMultiVariableDeclStmt(false), Affected(false), 46 LeadingEmptyLinesAffected(false), ChildrenAffected(false) { 47 assert(!Line.Tokens.empty()); 48 49 // Calculate Next and Previous for all tokens. Note that we must overwrite 50 // Next and Previous for every token, as previous formatting runs might have 51 // left them in a different state. 52 First->Previous = nullptr; 53 FormatToken *Current = First; 54 for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(), 55 E = Line.Tokens.end(); 56 I != E; ++I) { 57 const UnwrappedLineNode &Node = *I; 58 Current->Next = I->Tok; 59 I->Tok->Previous = Current; 60 Current = Current->Next; 61 Current->Children.clear(); 62 for (const auto &Child : Node.Children) { 63 Children.push_back(new AnnotatedLine(Child)); 64 Current->Children.push_back(Children.back()); 65 } 66 } 67 Last = Current; 68 Last->Next = nullptr; 69 } 70 71 ~AnnotatedLine() { 72 for (unsigned i = 0, e = Children.size(); i != e; ++i) { 73 delete Children[i]; 74 } 75 FormatToken *Current = First; 76 while (Current) { 77 Current->Children.clear(); 78 Current->Role.reset(); 79 Current = Current->Next; 80 } 81 } 82 83 /// \c true if this line starts with the given tokens in order, ignoring 84 /// comments. 85 template <typename... Ts> bool startsWith(Ts... Tokens) const { 86 return startsWithInternal(First, Tokens...); 87 } 88 89 /// \c true if this line ends with the given tokens in reversed order, 90 /// ignoring comments. 91 /// For example, given tokens [T1, T2, T3, ...], the function returns true if 92 /// this line is like "... T3 T2 T1". 93 template <typename... Ts> bool endsWith(Ts... Tokens) const { 94 return endsWithInternal(Last, Tokens...); 95 } 96 97 /// \c true if this line looks like a function definition instead of a 98 /// function declaration. Asserts MightBeFunctionDecl. 99 bool mightBeFunctionDefinition() const { 100 assert(MightBeFunctionDecl); 101 // FIXME: Line.Last points to other characters than tok::semi 102 // and tok::lbrace. 103 return !Last->isOneOf(tok::semi, tok::comment); 104 } 105 106 FormatToken *First; 107 FormatToken *Last; 108 109 SmallVector<AnnotatedLine *, 0> Children; 110 111 LineType Type; 112 unsigned Level; 113 bool InPPDirective; 114 bool MustBeDeclaration; 115 bool MightBeFunctionDecl; 116 bool IsMultiVariableDeclStmt; 117 118 /// \c True if this line should be formatted, i.e. intersects directly or 119 /// indirectly with one of the input ranges. 120 bool Affected; 121 122 /// \c True if the leading empty lines of this line intersect with one of the 123 /// input ranges. 124 bool LeadingEmptyLinesAffected; 125 126 /// \c True if a one of this line's children intersects with an input range. 127 bool ChildrenAffected; 128 129 private: 130 // Disallow copying. 131 AnnotatedLine(const AnnotatedLine &) = delete; 132 void operator=(const AnnotatedLine &) = delete; 133 134 template <typename A, typename... Ts> 135 bool startsWithInternal(const FormatToken *Tok, A K1) const { 136 // Even though we skip comments in the outer `startWithInternal` function, 137 // this loop is still necessary if it is invoked by the public interface 138 // `startsWith`. 139 while (Tok && Tok->is(tok::comment)) 140 Tok = Tok->Next; 141 return Tok && Tok->is(K1); 142 } 143 144 template <typename A, typename... Ts> 145 bool startsWithInternal(const FormatToken *Tok, A K1, Ts... Tokens) const { 146 // Skip comments before calling `startsWithInternal(Tok, K1)` so that the 147 // second call to `startsWithInternal` takes the correct `Tok->Next`, which 148 // should be the next token of the token checked in the first call. 149 while (Tok && Tok->is(tok::comment)) 150 Tok = Tok->Next; 151 return Tok && startsWithInternal(Tok, K1) && 152 startsWithInternal(Tok->Next, Tokens...); 153 } 154 155 template <typename A, typename... Ts> 156 bool endsWithInternal(const FormatToken *Tok, A K1) const { 157 // See the comments above in `startsWithInternal(Tok, K1)`. 158 while (Tok && Tok->is(tok::comment)) 159 Tok = Tok->Previous; 160 return Tok && Tok->is(K1); 161 } 162 163 template <typename A, typename... Ts> 164 bool endsWithInternal(const FormatToken *Tok, A K1, Ts... Tokens) const { 165 // See the comments above in `startsWithInternal(Tok, K1, Tokens)`. 166 while (Tok && Tok->is(tok::comment)) 167 Tok = Tok->Previous; 168 return Tok && endsWithInternal(Tok, K1) && 169 endsWithInternal(Tok->Previous, Tokens...); 170 } 171 }; 172 173 /// \brief Determines extra information about the tokens comprising an 174 /// \c UnwrappedLine. 175 class TokenAnnotator { 176 public: 177 TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords) 178 : Style(Style), Keywords(Keywords) {} 179 180 /// \brief Adapts the indent levels of comment lines to the indent of the 181 /// subsequent line. 182 // FIXME: Can/should this be done in the UnwrappedLineParser? 183 void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines); 184 185 void annotate(AnnotatedLine &Line); 186 void calculateFormattingInformation(AnnotatedLine &Line); 187 188 private: 189 /// \brief Calculate the penalty for splitting before \c Tok. 190 unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok, 191 bool InFunctionDecl); 192 193 bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, 194 const FormatToken &Right); 195 196 bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Tok); 197 198 bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right); 199 200 bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right); 201 202 bool mustBreakForReturnType(const AnnotatedLine &Line) const; 203 204 void printDebugInfo(const AnnotatedLine &Line); 205 206 void calculateUnbreakableTailLengths(AnnotatedLine &Line); 207 208 const FormatStyle &Style; 209 210 const AdditionalKeywords &Keywords; 211 }; 212 213 } // end namespace format 214 } // end namespace clang 215 216 #endif 217