summaryrefslogtreecommitdiff
path: root/lib/Format/UnwrappedLineFormatter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
commit486754660bb926339aefcf012a3f848592babb8b (patch)
treeecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/Format/UnwrappedLineFormatter.cpp
parent55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff)
Notes
Diffstat (limited to 'lib/Format/UnwrappedLineFormatter.cpp')
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp119
1 files changed, 70 insertions, 49 deletions
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 60dc1a7169d12..906dae40cbee7 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "NamespaceEndCommentsFixer.h"
#include "UnwrappedLineFormatter.h"
#include "WhitespaceManager.h"
#include "llvm/Support/Debug.h"
@@ -26,7 +27,7 @@ bool startsExternCBlock(const AnnotatedLine &Line) {
NextNext && NextNext->is(tok::l_brace);
}
-/// \brief Tracks the indent level of \c AnnotatedLines across levels.
+/// Tracks the indent level of \c AnnotatedLines across levels.
///
/// \c nextLine must be called for each \c AnnotatedLine, after which \c
/// getIndent() will return the indent for the last line \c nextLine was called
@@ -45,10 +46,10 @@ public:
IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
}
- /// \brief Returns the indent for the current line.
+ /// Returns the indent for the current line.
unsigned getIndent() const { return Indent; }
- /// \brief Update the indent state given that \p Line is going to be formatted
+ /// Update the indent state given that \p Line is going to be formatted
/// next.
void nextLine(const AnnotatedLine &Line) {
Offset = getIndentOffset(*Line.First);
@@ -66,14 +67,14 @@ public:
Indent += Offset;
}
- /// \brief Update the indent state given that \p Line indent should be
+ /// Update the indent state given that \p Line indent should be
/// skipped.
void skipLine(const AnnotatedLine &Line) {
while (IndentForLevel.size() <= Line.Level)
IndentForLevel.push_back(Indent);
}
- /// \brief Update the level indent to adapt to the given \p Line.
+ /// Update the level indent to adapt to the given \p Line.
///
/// When a line is not formatted, we move the subsequent lines on the same
/// level to the same indent.
@@ -88,7 +89,7 @@ public:
}
private:
- /// \brief Get the offset of the line relatively to the level.
+ /// 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.
@@ -104,7 +105,7 @@ private:
return 0;
}
- /// \brief Get the indent of \p Level from \p IndentForLevel.
+ /// 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
@@ -121,16 +122,16 @@ private:
const AdditionalKeywords &Keywords;
const unsigned AdditionalIndent;
- /// \brief The indent in characters for each level.
+ /// The indent in characters for each level.
std::vector<int> IndentForLevel;
- /// \brief Offset of the current line relative to the indent level.
+ /// Offset of the current line relative to the indent level.
///
/// For example, the 'public' keywords is often indented with a negative
/// offset.
int Offset = 0;
- /// \brief The current line's indent.
+ /// The current line's indent.
unsigned Indent = 0;
};
@@ -157,7 +158,7 @@ public:
: Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
AnnotatedLines(Lines) {}
- /// \brief Returns the next line, merging multiple lines into one if possible.
+ /// Returns the next line, merging multiple lines into one if possible.
const AnnotatedLine *getNextMergedLine(bool DryRun,
LevelIndentTracker &IndentTracker) {
if (Next == End)
@@ -179,7 +180,7 @@ public:
}
private:
- /// \brief Calculates how many lines can be merged into 1 starting at \p I.
+ /// Calculates how many lines can be merged into 1 starting at \p I.
unsigned
tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
@@ -251,9 +252,9 @@ private:
if (Style.CompactNamespaces) {
if (isNamespaceDeclaration(TheLine)) {
int i = 0;
- unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
+ unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) &&
- closingLine == I[i + 1]->MatchingOpeningBlockLineIndex &&
+ closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
I[i + 1]->Last->TotalLength < Limit;
i++, closingLine--) {
// No extra indent for compacted namespaces
@@ -304,9 +305,23 @@ private:
if (TheLine->First->is(tok::l_brace) && TheLine->First == TheLine->Last &&
I != AnnotatedLines.begin() &&
I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
- return Style.AllowShortBlocksOnASingleLine
- ? tryMergeSimpleBlock(I - 1, E, Limit)
- : 0;
+ unsigned MergedLines = 0;
+ if (Style.AllowShortBlocksOnASingleLine) {
+ MergedLines = tryMergeSimpleBlock(I - 1, E, Limit);
+ // If we managed to merge the block, discard the first merged line
+ // since we are merging starting from I.
+ if (MergedLines > 0)
+ --MergedLines;
+ }
+ return MergedLines;
+ }
+ // Don't merge block with left brace wrapped after ObjC special blocks
+ if (TheLine->First->is(tok::l_brace) && I != AnnotatedLines.begin() &&
+ I[-1]->First->is(tok::at) && I[-1]->First->Next) {
+ tok::ObjCKeywordKind kwId = I[-1]->First->Next->Tok.getObjCKeywordID();
+ if (kwId == clang::tok::objc_autoreleasepool ||
+ kwId == clang::tok::objc_synchronized)
+ return 0;
}
// Try to merge a block with left brace wrapped that wasn't yet covered
if (TheLine->Last->is(tok::l_brace)) {
@@ -644,14 +659,14 @@ static void markFinalized(FormatToken *Tok) {
static void printLineState(const LineState &State) {
llvm::dbgs() << "State: ";
for (const ParenState &P : State.Stack) {
- llvm::dbgs() << P.Indent << "|" << P.LastSpace << "|" << P.NestedBlockIndent
- << " ";
+ llvm::dbgs() << (P.Tok ? P.Tok->TokenText : "F") << "|" << P.Indent << "|"
+ << P.LastSpace << "|" << P.NestedBlockIndent << " ";
}
llvm::dbgs() << State.NextToken->TokenText << "\n";
}
#endif
-/// \brief Base class for classes that format one \c AnnotatedLine.
+/// Base class for classes that format one \c AnnotatedLine.
class LineFormatter {
public:
LineFormatter(ContinuationIndenter *Indenter, WhitespaceManager *Whitespaces,
@@ -661,7 +676,7 @@ public:
BlockFormatter(BlockFormatter) {}
virtual ~LineFormatter() {}
- /// \brief Formats an \c AnnotatedLine and returns the penalty.
+ /// Formats an \c AnnotatedLine and returns the penalty.
///
/// If \p DryRun is \c false, directly applies the changes.
virtual unsigned formatLine(const AnnotatedLine &Line,
@@ -670,7 +685,7 @@ public:
bool DryRun) = 0;
protected:
- /// \brief If the \p State's next token is an r_brace closing a nested block,
+ /// 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
@@ -752,7 +767,7 @@ private:
UnwrappedLineFormatter *BlockFormatter;
};
-/// \brief Formatter that keeps the existing line breaks.
+/// Formatter that keeps the existing line breaks.
class NoColumnLimitLineFormatter : public LineFormatter {
public:
NoColumnLimitLineFormatter(ContinuationIndenter *Indenter,
@@ -761,7 +776,7 @@ public:
UnwrappedLineFormatter *BlockFormatter)
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
- /// \brief Formats the line, simply keeping all of the input's line breaking
+ /// Formats the line, simply keeping all of the input's line breaking
/// decisions.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
unsigned FirstStartColumn, bool DryRun) override {
@@ -780,7 +795,7 @@ public:
}
};
-/// \brief Formatter that puts all tokens into a single line without breaks.
+/// Formatter that puts all tokens into a single line without breaks.
class NoLineBreakFormatter : public LineFormatter {
public:
NoLineBreakFormatter(ContinuationIndenter *Indenter,
@@ -788,7 +803,7 @@ public:
UnwrappedLineFormatter *BlockFormatter)
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
- /// \brief Puts all tokens into a single line.
+ /// Puts all tokens into a single line.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
unsigned FirstStartColumn, bool DryRun) override {
unsigned Penalty = 0;
@@ -803,7 +818,7 @@ public:
}
};
-/// \brief Finds the best way to break lines.
+/// Finds the best way to break lines.
class OptimizingLineFormatter : public LineFormatter {
public:
OptimizingLineFormatter(ContinuationIndenter *Indenter,
@@ -812,7 +827,7 @@ public:
UnwrappedLineFormatter *BlockFormatter)
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
- /// \brief Formats the line by finding the best line breaks with line lengths
+ /// Formats the line by finding the best line breaks with line lengths
/// below the column limit.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
unsigned FirstStartColumn, bool DryRun) override {
@@ -835,14 +850,14 @@ private:
}
};
- /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
+ /// A pair of <penalty, count> 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<unsigned, unsigned> OrderedPenalty;
- /// \brief An edge in the solution space from \c Previous->State to \c State,
+ /// 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)
@@ -852,16 +867,16 @@ private:
StateNode *Previous;
};
- /// \brief An item in the prioritized BFS search queue. The \c StateNode's
+ /// An item in the prioritized BFS search queue. The \c StateNode's
/// \c State has the given \c OrderedPenalty.
typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
- /// \brief The BFS queue type.
+ /// The BFS queue type.
typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
std::greater<QueueItem>>
QueueType;
- /// \brief Analyze the entire solution space starting from \p InitialState.
+ /// 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
@@ -890,7 +905,8 @@ private:
Penalty = Queue.top().first.first;
StateNode *Node = Queue.top().second;
if (!Node->State.NextToken) {
- DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ LLVM_DEBUG(llvm::dbgs()
+ << "\n---\nPenalty for line: " << Penalty << "\n");
break;
}
Queue.pop();
@@ -914,7 +930,7 @@ private:
if (Queue.empty()) {
// We were unable to find a solution, do nothing.
// FIXME: Add diagnostic?
- DEBUG(llvm::dbgs() << "Could not find a solution.\n");
+ LLVM_DEBUG(llvm::dbgs() << "Could not find a solution.\n");
return 0;
}
@@ -922,13 +938,14 @@ private:
if (!DryRun)
reconstructPath(InitialState, Queue.top().second);
- DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
- DEBUG(llvm::dbgs() << "---\n");
+ LLVM_DEBUG(llvm::dbgs()
+ << "Total number of analyzed states: " << Count << "\n");
+ LLVM_DEBUG(llvm::dbgs() << "---\n");
return Penalty;
}
- /// \brief Add the following state to the analysis queue \c Queue.
+ /// 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.
@@ -950,7 +967,7 @@ private:
++(*Count);
}
- /// \brief Applies the best formatting by reconstructing the path in the
+ /// Applies the best formatting by reconstructing the path in the
/// solution space that leads to \c Best.
void reconstructPath(LineState &State, StateNode *Best) {
std::deque<StateNode *> Path;
@@ -965,7 +982,7 @@ private:
formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
- DEBUG({
+ LLVM_DEBUG({
printLineState((*I)->Previous->State);
if ((*I)->NewLine) {
llvm::dbgs() << "Penalty for placing "
@@ -1018,9 +1035,12 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
// scope was added. However, we need to carefully stop doing this when we
// exit the scope of affected lines to prevent indenting a the entire
// remaining file if it currently missing a closing brace.
+ bool PreviousRBrace =
+ PreviousLine && PreviousLine->startsWith(tok::r_brace);
bool ContinueFormatting =
TheLine.Level > RangeMinLevel ||
- (TheLine.Level == RangeMinLevel && !TheLine.startsWith(tok::r_brace));
+ (TheLine.Level == RangeMinLevel && !PreviousRBrace &&
+ !TheLine.startsWith(tok::r_brace));
bool FixIndentation = (FixBadIndentation || ContinueFormatting) &&
Indent != TheLine.First->OriginalColumn;
@@ -1036,8 +1056,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
if (ShouldFormat && TheLine.Type != LT_Invalid) {
if (!DryRun) {
bool LastLine = Line->First->is(tok::eof);
- formatFirstToken(TheLine, PreviousLine,
- Indent,
+ formatFirstToken(TheLine, PreviousLine, Lines, Indent,
LastLine ? LastStartColumn : NextStartColumn + Indent);
}
@@ -1081,7 +1100,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
TheLine.LeadingEmptyLinesAffected);
// Format the first token.
if (ReformatLeadingWhitespace)
- formatFirstToken(TheLine, PreviousLine,
+ formatFirstToken(TheLine, PreviousLine, Lines,
TheLine.First->OriginalColumn,
TheLine.First->OriginalColumn);
else
@@ -1103,10 +1122,10 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
return Penalty;
}
-void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
- const AnnotatedLine *PreviousLine,
- unsigned Indent,
- unsigned NewlineIndent) {
+void UnwrappedLineFormatter::formatFirstToken(
+ const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
+ const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
+ unsigned NewlineIndent) {
FormatToken &RootToken = *Line.First;
if (RootToken.is(tok::eof)) {
unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
@@ -1120,7 +1139,9 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
// Remove empty lines before "}" where applicable.
if (RootToken.is(tok::r_brace) &&
(!RootToken.Next ||
- (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
+ (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)) &&
+ // Do not remove empty lines before namespace closing "}".
+ !getNamespaceToken(&Line, Lines))
Newlines = std::min(Newlines, 1u);
// Remove empty lines at the start of nested blocks (lambdas/arrow functions)
if (PreviousLine == nullptr && Line.Level > 0)