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