//===--- UnwrappedLineFormatter.h - Format C++ code -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Implements a combinartorial exploration of all the different /// linebreaks unwrapped lines can be formatted in. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H #define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H #include "ContinuationIndenter.h" #include "clang/Format/Format.h" #include #include #include namespace clang { namespace format { class ContinuationIndenter; class WhitespaceManager; class UnwrappedLineFormatter { public: UnwrappedLineFormatter(ContinuationIndenter *Indenter, WhitespaceManager *Whitespaces, const FormatStyle &Style) : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {} unsigned format(const SmallVectorImpl &Lines, bool DryRun, int AdditionalIndent = 0, bool FixBadIndentation = false); private: /// \brief Formats an \c AnnotatedLine and returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. unsigned format(const AnnotatedLine &Line, unsigned FirstIndent, bool DryRun); /// \brief An edge in the solution space from \c Previous->State to \c State, /// inserting a newline dependent on the \c NewLine. struct StateNode { StateNode(const LineState &State, bool NewLine, StateNode *Previous) : State(State), NewLine(NewLine), Previous(Previous) {} LineState State; bool NewLine; StateNode *Previous; }; /// \brief A pair of that is used to prioritize the BFS on. /// /// In case of equal penalties, we want to prefer states that were inserted /// first. During state generation we make sure that we insert states first /// that break the line as late as possible. typedef std::pair OrderedPenalty; /// \brief An item in the prioritized BFS search queue. The \c StateNode's /// \c State has the given \c OrderedPenalty. typedef std::pair QueueItem; /// \brief The BFS queue type. typedef std::priority_queue, std::greater > QueueType; /// \brief Get the offset of the line relatively to the level. /// /// For example, 'public:' labels in classes are offset by 1 or 2 /// characters to the left from their level. int getIndentOffset(const FormatToken &RootToken) { if (Style.Language == FormatStyle::LK_Java) return 0; if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier()) return Style.AccessModifierOffset; return 0; } /// \brief Add a new line and the required indent before the first Token /// of the \c UnwrappedLine if there was no structural parsing error. void formatFirstToken(FormatToken &RootToken, const AnnotatedLine *PreviousLine, unsigned IndentLevel, unsigned Indent, bool InPPDirective); /// \brief Get the indent of \p Level from \p IndentForLevel. /// /// \p IndentForLevel must contain the indent for the level \c l /// at \p IndentForLevel[l], or a value < 0 if the indent for /// that level is unknown. unsigned getIndent(ArrayRef IndentForLevel, unsigned Level); void join(AnnotatedLine &A, const AnnotatedLine &B); unsigned getColumnLimit(bool InPPDirective) const { // In preprocessor directives reserve two chars for trailing " \" return Style.ColumnLimit - (InPPDirective ? 2 : 0); } struct CompareLineStatePointers { bool operator()(LineState *obj1, LineState *obj2) const { return *obj1 < *obj2; } }; /// \brief Analyze the entire solution space starting from \p InitialState. /// /// This implements a variant of Dijkstra's algorithm on the graph that spans /// the solution space (\c LineStates are the nodes). The algorithm tries to /// find the shortest path (the one with lowest penalty) from \p InitialState /// to a state where all tokens are placed. Returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false); void reconstructPath(LineState &State, StateNode *Current); /// \brief Add the following state to the analysis queue \c Queue. /// /// Assume the current state is \p PreviousNode and has been reached with a /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true. void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode, bool NewLine, unsigned *Count, QueueType *Queue); /// \brief If the \p State's next token is an r_brace closing a nested block, /// format the nested block before it. /// /// Returns \c true if all children could be placed successfully and adapts /// \p Penalty as well as \p State. If \p DryRun is false, also directly /// creates changes using \c Whitespaces. /// /// The crucial idea here is that children always get formatted upon /// encountering the closing brace right after the nested block. Now, if we /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is /// \c false), the entire block has to be kept on the same line (which is only /// possible if it fits on the line, only contains a single statement, etc. /// /// If \p NewLine is true, we format the nested block on separate lines, i.e. /// break after the "{", format all lines with correct indentation and the put /// the closing "}" on yet another new line. /// /// This enables us to keep the simple structure of the /// \c UnwrappedLineFormatter, where we only have two options for each token: /// break or don't break. bool formatChildren(LineState &State, bool NewLine, bool DryRun, unsigned &Penalty); ContinuationIndenter *Indenter; WhitespaceManager *Whitespaces; FormatStyle Style; llvm::SpecificBumpPtrAllocator Allocator; // Cache to store the penalty of formatting a vector of AnnotatedLines // starting from a specific additional offset. Improves performance if there // are many nested blocks. std::map *, unsigned>, unsigned> PenaltyCache; }; } // end namespace format } // end namespace clang #endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H