blob: dcc67d875fe42f4882310da350f25495a0eaeb38 [file] [log] [blame]
Daniel Jasper0df50932014-12-10 19:00:42 +00001//===--- UnwrappedLineFormatter.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 Implements a combinartorial exploration of all the different
12/// linebreaks unwrapped lines can be formatted in.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
17#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
18
19#include "ContinuationIndenter.h"
20#include "clang/Format/Format.h"
21#include <map>
22#include <queue>
23#include <string>
24
25namespace clang {
26namespace format {
27
28class ContinuationIndenter;
29class WhitespaceManager;
30
31class UnwrappedLineFormatter {
32public:
33 UnwrappedLineFormatter(ContinuationIndenter *Indenter,
34 WhitespaceManager *Whitespaces,
Nico Weberfac23712015-02-04 15:26:27 +000035 const FormatStyle &Style,
Manuel Klimekec5c3db2015-05-07 12:26:30 +000036 const AdditionalKeywords &Keywords,
37 bool *IncompleteFormat)
Nico Weberfac23712015-02-04 15:26:27 +000038 : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
Manuel Klimekec5c3db2015-05-07 12:26:30 +000039 Keywords(Keywords), IncompleteFormat(IncompleteFormat) {}
Daniel Jasper0df50932014-12-10 19:00:42 +000040
41 unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
42 int AdditionalIndent = 0, bool FixBadIndentation = false);
43
Daniel Jasper289afc02015-04-23 09:23:17 +000044
45 /// \brief If the \p State's next token is an r_brace closing a nested block,
46 /// format the nested block before it.
47 ///
48 /// Returns \c true if all children could be placed successfully and adapts
49 /// \p Penalty as well as \p State. If \p DryRun is false, also directly
50 /// creates changes using \c Whitespaces.
51 ///
52 /// The crucial idea here is that children always get formatted upon
53 /// encountering the closing brace right after the nested block. Now, if we
54 /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
55 /// \c false), the entire block has to be kept on the same line (which is only
56 /// possible if it fits on the line, only contains a single statement, etc.
57 ///
58 /// If \p NewLine is true, we format the nested block on separate lines, i.e.
59 /// break after the "{", format all lines with correct indentation and the put
60 /// the closing "}" on yet another new line.
61 ///
62 /// This enables us to keep the simple structure of the
63 /// \c UnwrappedLineFormatter, where we only have two options for each token:
64 /// break or don't break.
65 bool formatChildren(LineState &State, bool NewLine, bool DryRun,
66 unsigned &Penalty);
67
Daniel Jasper0df50932014-12-10 19:00:42 +000068private:
69 /// \brief Formats an \c AnnotatedLine and returns the penalty.
70 ///
71 /// If \p DryRun is \c false, directly applies the changes.
72 unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
73 bool DryRun);
74
75 /// \brief An edge in the solution space from \c Previous->State to \c State,
76 /// inserting a newline dependent on the \c NewLine.
77 struct StateNode {
78 StateNode(const LineState &State, bool NewLine, StateNode *Previous)
79 : State(State), NewLine(NewLine), Previous(Previous) {}
80 LineState State;
81 bool NewLine;
82 StateNode *Previous;
83 };
84
85 /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
86 ///
87 /// In case of equal penalties, we want to prefer states that were inserted
88 /// first. During state generation we make sure that we insert states first
89 /// that break the line as late as possible.
90 typedef std::pair<unsigned, unsigned> OrderedPenalty;
91
92 /// \brief An item in the prioritized BFS search queue. The \c StateNode's
93 /// \c State has the given \c OrderedPenalty.
94 typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
95
96 /// \brief The BFS queue type.
97 typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
98 std::greater<QueueItem> > QueueType;
99
100 /// \brief Get the offset of the line relatively to the level.
101 ///
102 /// For example, 'public:' labels in classes are offset by 1 or 2
103 /// characters to the left from their level.
104 int getIndentOffset(const FormatToken &RootToken) {
Daniel Jasper83709082015-02-18 17:14:05 +0000105 if (Style.Language == FormatStyle::LK_Java ||
106 Style.Language == FormatStyle::LK_JavaScript)
Daniel Jasper0df50932014-12-10 19:00:42 +0000107 return 0;
Daniel Jasper53395402015-04-07 15:04:40 +0000108 if (RootToken.isAccessSpecifier(false) ||
Daniel Jasper03618142015-05-06 19:21:23 +0000109 RootToken.isObjCAccessSpecifier() ||
110 (RootToken.is(Keywords.kw_signals) && RootToken.Next &&
111 RootToken.Next->is(tok::colon)))
Daniel Jasper0df50932014-12-10 19:00:42 +0000112 return Style.AccessModifierOffset;
113 return 0;
114 }
115
116 /// \brief Add a new line and the required indent before the first Token
117 /// of the \c UnwrappedLine if there was no structural parsing error.
118 void formatFirstToken(FormatToken &RootToken,
119 const AnnotatedLine *PreviousLine, unsigned IndentLevel,
120 unsigned Indent, bool InPPDirective);
121
122 /// \brief Get the indent of \p Level from \p IndentForLevel.
123 ///
124 /// \p IndentForLevel must contain the indent for the level \c l
125 /// at \p IndentForLevel[l], or a value < 0 if the indent for
126 /// that level is unknown.
127 unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level);
128
129 void join(AnnotatedLine &A, const AnnotatedLine &B);
130
131 unsigned getColumnLimit(bool InPPDirective) const {
132 // In preprocessor directives reserve two chars for trailing " \"
133 return Style.ColumnLimit - (InPPDirective ? 2 : 0);
134 }
135
136 struct CompareLineStatePointers {
137 bool operator()(LineState *obj1, LineState *obj2) const {
138 return *obj1 < *obj2;
139 }
140 };
141
142 /// \brief Analyze the entire solution space starting from \p InitialState.
143 ///
144 /// This implements a variant of Dijkstra's algorithm on the graph that spans
145 /// the solution space (\c LineStates are the nodes). The algorithm tries to
146 /// find the shortest path (the one with lowest penalty) from \p InitialState
147 /// to a state where all tokens are placed. Returns the penalty.
148 ///
149 /// If \p DryRun is \c false, directly applies the changes.
150 unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false);
151
152 void reconstructPath(LineState &State, StateNode *Current);
153
154 /// \brief Add the following state to the analysis queue \c Queue.
155 ///
156 /// Assume the current state is \p PreviousNode and has been reached with a
157 /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
158 void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
159 bool NewLine, unsigned *Count, QueueType *Queue);
160
Daniel Jasper0df50932014-12-10 19:00:42 +0000161 ContinuationIndenter *Indenter;
162 WhitespaceManager *Whitespaces;
163 FormatStyle Style;
Nico Weberfac23712015-02-04 15:26:27 +0000164 const AdditionalKeywords &Keywords;
Daniel Jasper0df50932014-12-10 19:00:42 +0000165
166 llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
167
168 // Cache to store the penalty of formatting a vector of AnnotatedLines
169 // starting from a specific additional offset. Improves performance if there
170 // are many nested blocks.
171 std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
172 unsigned> PenaltyCache;
Manuel Klimekec5c3db2015-05-07 12:26:30 +0000173
174 bool *IncompleteFormat;
Daniel Jasper0df50932014-12-10 19:00:42 +0000175};
176} // end namespace format
177} // end namespace clang
178
179#endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H