Author: nikola
Date: Wed Mar 22 21:51:25 2017
New Revision: 298574
URL: http://llvm.org/viewvc/llvm-project?rev=298574&view=rev
Log:
Fix issues in clang-format's AlignConsecutive modes.
Patch by Ben Harper.
Modified:
cfe/trunk/lib/Format/WhitespaceManager.cpp
cfe/trunk/lib/Format/WhitespaceManager.h
cfe/trunk/unittests/Format/FormatTest.cpp
Modified: cfe/trunk/lib/Format/WhitespaceManager.cpp
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/WhitespaceManager.cpp?rev=298574&r1=298573&r2=298574&view=diff
==
--- cfe/trunk/lib/Format/WhitespaceManager.cpp (original)
+++ cfe/trunk/lib/Format/WhitespaceManager.cpp Wed Mar 22 21:51:25 2017
@@ -50,9 +50,9 @@ void WhitespaceManager::replaceWhitespac
if (Tok.Finalized)
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
- Changes.push_back(Change(Tok, /*CreateReplacement=*/true,
- Tok.WhitespaceRange, Spaces, StartOfTokenColumn,
- Newlines, "", "", InPPDirective && !Tok.IsFirst,
+ Changes.push_back(Change(Tok, /*CreateReplacement=*/true,
Tok.WhitespaceRange,
+ Spaces, StartOfTokenColumn, Newlines, "", "",
+ InPPDirective && !Tok.IsFirst,
/*IsInsideToken=*/false));
}
@@ -192,21 +192,56 @@ AlignTokenSequence(unsigned Start, unsig
SmallVector &Changes) {
bool FoundMatchOnLine = false;
int Shift = 0;
+
+ // ScopeStack keeps track of the current scope depth. It contains indices of
+ // the first token on each scope.
+ // We only run the "Matches" function on tokens from the outer-most scope.
+ // However, we do need to pay special attention to one class of tokens
+ // that are not in the outer-most scope, and that is function parameters
+ // which are split across multiple lines, as illustrated by this example:
+ // double a(int x);
+ // intb(int y,
+ // double z);
+ // In the above example, we need to take special care to ensure that
+ // 'double z' is indented along with it's owning function 'b'.
+ SmallVector ScopeStack;
+
for (unsigned i = Start; i != End; ++i) {
-if (Changes[i].NewlinesBefore > 0) {
- FoundMatchOnLine = false;
+if (ScopeStack.size() != 0 &&
+Changes[i].nestingAndIndentLevel() <
+Changes[ScopeStack.back()].nestingAndIndentLevel())
+ ScopeStack.pop_back();
+
+if (i != Start && Changes[i].nestingAndIndentLevel() >
+ Changes[i - 1].nestingAndIndentLevel())
+ ScopeStack.push_back(i);
+
+bool InsideNestedScope = ScopeStack.size() != 0;
+
+if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
Shift = 0;
+ FoundMatchOnLine = false;
}
// If this is the first matching token to be aligned, remember by how many
// spaces it has to be shifted, so the rest of the changes on the line are
// shifted by the same amount
-if (!FoundMatchOnLine && Matches(Changes[i])) {
+if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
FoundMatchOnLine = true;
Shift = Column - Changes[i].StartOfTokenColumn;
Changes[i].Spaces += Shift;
}
+// This is for function parameters that are split across multiple lines,
+// as mentioned in the ScopeStack comment.
+if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
+ unsigned ScopeStart = ScopeStack.back();
+ if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
+ (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
+Changes[i].Spaces += Shift;
+}
+
assert(Shift >= 0);
Changes[i].StartOfTokenColumn += Shift;
if (i + 1 != Changes.size())
@@ -214,15 +249,37 @@ AlignTokenSequence(unsigned Start, unsig
}
}
-// Walk through all of the changes and find sequences of matching tokens to
-// align. To do so, keep track of the lines and whether or not a matching token
-// was found on a line. If a matching token is found, extend the current
-// sequence. If the current line cannot be part of a sequence, e.g. because
-// there is an empty line before it or it contains only non-matching tokens,
-// finalize the previous sequence.
+// Walk through a subset of the changes, starting at StartAt, and find
+// sequences of matching tokens to align. To do so, keep track of the lines and
+// whether or not a matching token was found on a line. If a matching token is
+// found, extend the current sequence. If the current line cannot be part of a
+// sequence, e.g. because there is an empty line before it or it contains only
+// non-matching tokens, finalize the previous sequence.
+// The value returned is the token on which we stopped, either because we
+// exhausted all items inside Changes, or because we hit a scope level higher
+// than our ini