brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · e4b9443 Raw
287 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements a token annotator, i.e. creates11/// \c AnnotatedTokens out of \c FormatTokens with required extra information.12///13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H16#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H17 18#include "UnwrappedLineParser.h"19 20namespace clang {21namespace format {22 23enum LineType {24  LT_Invalid,25  // Contains public/private/protected followed by TT_InheritanceColon.26  LT_AccessModifier,27  LT_ImportStatement,28  LT_ObjCDecl, // An @interface, @implementation, or @protocol line.29  LT_ObjCMethodDecl,30  LT_ObjCProperty, // An @property line.31  LT_Other,32  LT_PreprocessorDirective,33  LT_VirtualFunctionDecl,34  LT_ArrayOfStructInitializer,35  LT_CommentAbovePPDirective,36  LT_RequiresExpression,37  LT_SimpleRequirement,38};39 40enum ScopeType {41  // Contained in class declaration/definition.42  ST_Class,43  // Contained in compound requirement.44  ST_CompoundRequirement,45  // Contained in other blocks (function, lambda, loop, if/else, child, etc).46  ST_Other,47};48 49class AnnotatedLine {50public:51  AnnotatedLine(const UnwrappedLine &Line)52      : First(Line.Tokens.front().Tok), Type(LT_Other), Level(Line.Level),53        PPLevel(Line.PPLevel),54        MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),55        MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),56        InPPDirective(Line.InPPDirective),57        InPragmaDirective(Line.InPragmaDirective),58        InMacroBody(Line.InMacroBody),59        MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),60        IsMultiVariableDeclStmt(false), Affected(false),61        LeadingEmptyLinesAffected(false), ChildrenAffected(false),62        ReturnTypeWrapped(false), IsContinuation(Line.IsContinuation),63        FirstStartColumn(Line.FirstStartColumn) {64    assert(!Line.Tokens.empty());65 66    // Calculate Next and Previous for all tokens. Note that we must overwrite67    // Next and Previous for every token, as previous formatting runs might have68    // left them in a different state.69    First->Previous = nullptr;70    FormatToken *Current = First;71    addChildren(Line.Tokens.front(), Current);72    for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {73      if (Node.Tok->MacroParent)74        ContainsMacroCall = true;75      Current->Next = Node.Tok;76      Node.Tok->Previous = Current;77      Current = Current->Next;78      addChildren(Node, Current);79      // FIXME: if we add children, previous will point to the token before80      // the children; changing this requires significant changes across81      // clang-format.82    }83    Last = Current;84    Last->Next = nullptr;85  }86 87  void addChildren(const UnwrappedLineNode &Node, FormatToken *Current) {88    Current->Children.clear();89    for (const auto &Child : Node.Children) {90      Children.push_back(new AnnotatedLine(Child));91      if (Children.back()->ContainsMacroCall)92        ContainsMacroCall = true;93      Current->Children.push_back(Children.back());94    }95  }96 97  size_t size() const {98    size_t Size = 1;99    for (const auto *Child : Children)100      Size += Child->size();101    return Size;102  }103 104  ~AnnotatedLine() {105    for (AnnotatedLine *Child : Children)106      delete Child;107    FormatToken *Current = First;108    while (Current) {109      Current->Children.clear();110      Current->Role.reset();111      Current = Current->Next;112    }113  }114 115  bool isComment() const {116    return First && First->is(tok::comment) && !First->getNextNonComment();117  }118 119  /// \c true if this line starts with the given tokens in order, ignoring120  /// comments.121  template <typename... Ts> bool startsWith(Ts... Tokens) const {122    return First && First->startsSequence(Tokens...);123  }124 125  /// \c true if this line ends with the given tokens in reversed order,126  /// ignoring comments.127  /// For example, given tokens [T1, T2, T3, ...], the function returns true if128  /// this line is like "... T3 T2 T1".129  template <typename... Ts> bool endsWith(Ts... Tokens) const {130    return Last && Last->endsSequence(Tokens...);131  }132 133  /// \c true if this line looks like a function definition instead of a134  /// function declaration. Asserts MightBeFunctionDecl.135  bool mightBeFunctionDefinition() const {136    assert(MightBeFunctionDecl);137    // Try to determine if the end of a stream of tokens is either the138    // Definition or the Declaration for a function. It does this by looking for139    // the ';' in foo(); and using that it ends with a ; to know this is the140    // Definition, however the line could end with141    //    foo(); /* comment */142    // or143    //    foo(); // comment144    // or145    //    foo() // comment146    // endsWith() ignores the comment.147    return !endsWith(tok::semi);148  }149 150  /// \c true if this line starts a namespace definition.151  bool startsWithNamespace() const {152    return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||153           startsWith(tok::kw_inline, tok::kw_namespace) ||154           startsWith(tok::kw_export, tok::kw_namespace);155  }156 157  /// \c true if this line starts a C++ export block.158  bool startsWithExportBlock() const {159    return startsWith(tok::kw_export, tok::l_brace);160  }161 162  FormatToken *getFirstNonComment() const {163    assert(First);164    return First->is(tok::comment) ? First->getNextNonComment() : First;165  }166 167  FormatToken *getLastNonComment() const {168    assert(Last);169    return Last->is(tok::comment) ? Last->getPreviousNonComment() : Last;170  }171 172  FormatToken *First;173  FormatToken *Last;174 175  SmallVector<AnnotatedLine *, 0> Children;176 177  LineType Type;178  unsigned Level;179  unsigned PPLevel;180  size_t MatchingOpeningBlockLineIndex;181  size_t MatchingClosingBlockLineIndex;182  bool InPPDirective;183  bool InPragmaDirective;184  bool InMacroBody;185  bool MustBeDeclaration;186  bool MightBeFunctionDecl;187  bool IsMultiVariableDeclStmt;188 189  /// \c True if this line contains a macro call for which an expansion exists.190  bool ContainsMacroCall = false;191 192  /// \c True if calculateFormattingInformation() has been called on this line.193  bool Computed = false;194 195  /// \c True if this line should be formatted, i.e. intersects directly or196  /// indirectly with one of the input ranges.197  bool Affected;198 199  /// \c True if the leading empty lines of this line intersect with one of the200  /// input ranges.201  bool LeadingEmptyLinesAffected;202 203  /// \c True if one of this line's children intersects with an input range.204  bool ChildrenAffected;205 206  /// \c True if breaking after last attribute group in function return type.207  bool ReturnTypeWrapped;208 209  /// \c True if this line should be indented by ContinuationIndent in addition210  /// to the normal indention level.211  bool IsContinuation;212 213  unsigned FirstStartColumn;214 215private:216  // Disallow copying.217  AnnotatedLine(const AnnotatedLine &) = delete;218  void operator=(const AnnotatedLine &) = delete;219};220 221/// Determines extra information about the tokens comprising an222/// \c UnwrappedLine.223class TokenAnnotator {224public:225  TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)226      : Style(Style), IsCpp(Style.isCpp()),227        LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {}228 229  /// Adapts the indent levels of comment lines to the indent of the230  /// subsequent line.231  // FIXME: Can/should this be done in the UnwrappedLineParser?232  void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) const;233 234  void annotate(AnnotatedLine &Line);235  void calculateFormattingInformation(AnnotatedLine &Line) const;236 237private:238  /// Calculate the penalty for splitting before \c Tok.239  unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,240                        bool InFunctionDecl) const;241 242  bool spaceRequiredBeforeParens(const FormatToken &Right) const;243 244  bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,245                            const FormatToken &Right) const;246 247  bool spaceRequiredBefore(const AnnotatedLine &Line,248                           const FormatToken &Right) const;249 250  bool mustBreakBefore(const AnnotatedLine &Line,251                       const FormatToken &Right) const;252 253  bool canBreakBefore(const AnnotatedLine &Line,254                      const FormatToken &Right) const;255 256  bool mustBreakForReturnType(const AnnotatedLine &Line) const;257 258  void printDebugInfo(const AnnotatedLine &Line) const;259 260  void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;261 262  void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;263 264  FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,265                                              FormatToken *CurrentToken,266                                              unsigned Depth) const;267  FormatStyle::PointerAlignmentStyle268  getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;269 270  FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(271      const FormatToken &PointerOrReference) const;272 273  const FormatStyle &Style;274 275  bool IsCpp;276  LangOptions LangOpts;277 278  const AdditionalKeywords &Keywords;279 280  SmallVector<ScopeType> Scopes, MacroBodyScopes;281};282 283} // end namespace format284} // end namespace clang285 286#endif287