Support formatting of preprocessor branches.
We now correctly format:
void SomeFunction(int param1,
#ifdef X
NoTemplate param2,
#else
template <
#ifdef A
MyType<Some> >
#else
Type1, Type2>
#endif
param2,
#endif
param3) {
f();
}
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192503 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 560e65e..aaddc34 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -221,7 +221,7 @@
void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned ExtraSpaces) {
- const FormatToken &Current = *State.NextToken;
+ FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
if (Current.is(tok::equal) &&
(State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) &&
@@ -301,7 +301,7 @@
unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
bool DryRun) {
- const FormatToken &Current = *State.NextToken;
+ FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
// If we are continuing an expression, we want to indent an extra 4 spaces.
unsigned ContinuationIndent =
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index c3642d2..60e0027 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -250,7 +250,7 @@
unsigned Column;
/// \brief The token that needs to be next formatted.
- const FormatToken *NextToken;
+ FormatToken *NextToken;
/// \brief \c true if this line contains a continued for-loop section.
bool LineContainsContinuedForLoopSection;
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 7fc6616..aac9fff 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -447,14 +447,19 @@
// State already examined with lower penalty.
continue;
- addNextStateToQueue(Penalty, Node, /*NewLine=*/false);
- addNextStateToQueue(Penalty, Node, /*NewLine=*/true);
+ FormatDecision LastFormat = Node->State.NextToken->Decision;
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false);
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true);
}
- if (Queue.empty())
+ if (Queue.empty()) {
// We were unable to find a solution, do nothing.
// FIXME: Add diagnostic?
+ DEBUG(llvm::dbgs() << "Could not find a solution.\n");
return 0;
+ }
// Reconstruct the solution.
if (!DryRun)
@@ -815,29 +820,54 @@
const std::vector<CharSourceRange> &Ranges)
: Style(Style), Lex(Lex), SourceMgr(SourceMgr),
Whitespaces(SourceMgr, Style, inputUsesCRLF(Lex.getBuffer())),
- Ranges(Ranges), Encoding(encoding::detectEncoding(Lex.getBuffer())) {
+ Ranges(Ranges), UnwrappedLines(1),
+ Encoding(encoding::detectEncoding(Lex.getBuffer())) {
DEBUG(llvm::dbgs() << "File encoding: "
<< (Encoding == encoding::Encoding_UTF8 ? "UTF8"
: "unknown")
<< "\n");
}
- virtual ~Formatter() {
- for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
- delete AnnotatedLines[i];
- }
- }
-
tooling::Replacements format() {
+ tooling::Replacements Result;
FormatTokenLexer Tokens(Lex, SourceMgr, Style, Encoding);
UnwrappedLineParser Parser(Style, Tokens.lex(), *this);
bool StructuralError = Parser.parse();
+ assert(UnwrappedLines.rbegin()->empty());
+ for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE;
+ ++Run) {
+ DEBUG(llvm::dbgs() << "Run " << Run << "...\n");
+ SmallVector<AnnotatedLine *, 16> AnnotatedLines;
+ for (unsigned i = 0, e = UnwrappedLines[Run].size(); i != e; ++i) {
+ AnnotatedLines.push_back(new AnnotatedLine(UnwrappedLines[Run][i]));
+ }
+ tooling::Replacements RunResult =
+ format(AnnotatedLines, StructuralError, Tokens);
+ DEBUG({
+ llvm::dbgs() << "Replacements for run " << Run << ":\n";
+ for (tooling::Replacements::iterator I = RunResult.begin(),
+ E = RunResult.end();
+ I != E; ++I) {
+ llvm::dbgs() << I->toString() << "\n";
+ }
+ });
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ delete AnnotatedLines[i];
+ }
+ Result.insert(RunResult.begin(), RunResult.end());
+ Whitespaces.reset();
+ }
+ return Result;
+ }
+
+ tooling::Replacements format(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ bool StructuralError, FormatTokenLexer &Tokens) {
TokenAnnotator Annotator(Style, Tokens.getIdentTable().get("in"));
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.annotate(*AnnotatedLines[i]);
}
- deriveLocalStyle();
+ deriveLocalStyle(AnnotatedLines);
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
}
@@ -920,8 +950,7 @@
} else {
// Format the first token if necessary, and notify the WhitespaceManager
// about the unchanged whitespace.
- for (const FormatToken *Tok = TheLine.First; Tok != NULL;
- Tok = Tok->Next) {
+ for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
if (Tok == TheLine.First &&
(Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
unsigned LevelIndent = Tok->OriginalColumn;
@@ -947,6 +976,9 @@
// last token.
PreviousLineWasTouched = false;
}
+ for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ Tok->Finalized = true;
+ }
PreviousLine = *I;
}
return Whitespaces.generateReplacements();
@@ -957,7 +989,8 @@
return Text.count('\r') * 2 > Text.count('\n');
}
- void deriveLocalStyle() {
+ void
+ deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
unsigned CountBoundToVariable = 0;
unsigned CountBoundToType = 0;
bool HasCpp03IncompatibleFormat = false;
@@ -1229,13 +1262,18 @@
}
virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
- AnnotatedLines.push_back(new AnnotatedLine(TheLine));
+ assert(!UnwrappedLines.empty());
+ UnwrappedLines.back().push_back(TheLine);
+ }
+
+ virtual void finishRun() {
+ UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>());
}
/// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine if there was no structural parsing error.
/// Returns the indent level of the \c UnwrappedLine.
- void formatFirstToken(const FormatToken &RootToken,
+ void formatFirstToken(FormatToken &RootToken,
const AnnotatedLine *PreviousLine, unsigned Indent,
bool InPPDirective) {
unsigned Newlines =
@@ -1272,7 +1310,7 @@
SourceManager &SourceMgr;
WhitespaceManager Whitespaces;
std::vector<CharSourceRange> Ranges;
- SmallVector<AnnotatedLine *, 16> AnnotatedLines;
+ SmallVector<SmallVector<UnwrappedLine, 16>, 2> UnwrappedLines;
encoding::Encoding Encoding;
bool BinPackInconclusiveFunctions;
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index 7469216..35764ce 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -145,6 +145,7 @@
bool HasRowWithSufficientColumns = false;
unsigned Column = 0;
for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) {
+ assert(i < MustBreakBeforeItem.size());
if (MustBreakBeforeItem[i] || Column == Columns) {
++Format.LineCount;
Column = 0;
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 2541c78..1262102 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -76,6 +76,12 @@
PPK_Inconclusive
};
+enum FormatDecision {
+ FD_Unformatted,
+ FD_Continue,
+ FD_Break
+};
+
class TokenRole;
class AnnotatedLine;
@@ -93,7 +99,8 @@
LongestObjCSelectorName(0), FakeRParens(0),
StartsBinaryExpression(false), EndsBinaryExpression(false),
LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
- MatchingParen(NULL), Previous(NULL), Next(NULL) {}
+ MatchingParen(NULL), Previous(NULL), Next(NULL),
+ Decision(FD_Unformatted), Finalized(false) {}
/// \brief The \c Token.
Token Tok;
@@ -338,6 +345,14 @@
SmallVector<AnnotatedLine *, 1> Children;
+ /// \brief Stores the formatting decision for the token once it was made.
+ FormatDecision Decision;
+
+ /// \brief If \c true, this token has been fully formatted (indented and
+ /// potentially re-formatted inside), and we do not allow further formatting
+ /// changes.
+ bool Finalized;
+
private:
// Disallow copying.
FormatToken(const FormatToken &) LLVM_DELETED_FUNCTION;
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index a564d52..9d9f5ef 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -523,11 +523,17 @@
if (CurrentToken != NULL)
CurrentToken = CurrentToken->Next;
- // Reset token type in case we have already looked at it and then recovered
- // from an error (e.g. failure to find the matching >).
- if (CurrentToken != NULL && CurrentToken->Type != TT_LambdaLSquare &&
- CurrentToken->Type != TT_ImplicitStringLiteral)
- CurrentToken->Type = TT_Unknown;
+ if (CurrentToken != NULL) {
+ // Reset token type in case we have already looked at it and then
+ // recovered from an error (e.g. failure to find the matching >).
+ if (CurrentToken->Type != TT_LambdaLSquare &&
+ CurrentToken->Type != TT_ImplicitStringLiteral)
+ CurrentToken->Type = TT_Unknown;
+ if (CurrentToken->Role)
+ CurrentToken->Role.reset(NULL);
+ CurrentToken->FakeLParens.clear();
+ CurrentToken->FakeRParens = 0;
+ }
}
/// \brief A struct to hold information valid in a specific context, e.g.
@@ -1482,10 +1488,13 @@
<< " C=" << Tok->CanBreakBefore << " T=" << Tok->Type
<< " S=" << Tok->SpacesRequiredBefore
<< " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName()
- << " PPK=" << Tok->PackingKind << " FakeLParens=";
+ << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind
+ << " FakeLParens=";
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
llvm::errs() << Tok->FakeLParens[i] << "/";
llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n";
+ if (Tok->Next == NULL)
+ assert(Tok == Line.Last);
Tok = Tok->Next;
}
llvm::errs() << "----\n";
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index d8aa3f3..93840dc 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -174,6 +174,8 @@
return Tokens[Position];
}
+ void reset() { Position = -1; }
+
private:
ArrayRef<FormatToken *> Tokens;
int Position;
@@ -186,23 +188,54 @@
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(NULL),
- Callback(Callback), AllTokens(Tokens) {}
+ Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+
+void UnwrappedLineParser::reset() {
+ PPBranchLevel = -1;
+ Line.reset(new UnwrappedLine);
+ CommentsBeforeNextToken.clear();
+ FormatTok = NULL;
+ MustBreakBeforeNextToken = false;
+ PreprocessorDirectives.clear();
+ CurrentLines = &Lines;
+ DeclarationScopeStack.clear();
+ StructuralError = false;
+ PPStack.clear();
+}
bool UnwrappedLineParser::parse() {
- DEBUG(llvm::dbgs() << "----\n");
IndexedTokenSource TokenSource(AllTokens);
- Tokens = &TokenSource;
- readToken();
- parseFile();
- for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(),
- E = Lines.end();
- I != E; ++I) {
- Callback.consumeUnwrappedLine(*I);
- }
+ do {
+ DEBUG(llvm::dbgs() << "----\n");
+ reset();
+ Tokens = &TokenSource;
+ TokenSource.reset();
- // Create line with eof token.
- pushToken(FormatTok);
- Callback.consumeUnwrappedLine(*Line);
+ readToken();
+ parseFile();
+ // Create line with eof token.
+ pushToken(FormatTok);
+ addUnwrappedLine();
+
+ for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(),
+ E = Lines.end();
+ I != E; ++I) {
+ Callback.consumeUnwrappedLine(*I);
+ }
+ Callback.finishRun();
+ Lines.clear();
+ while (!PPLevelBranchIndex.empty() &&
+ PPLevelBranchIndex.back() + 1 == PPLevelBranchCount.back()) {
+ PPLevelBranchIndex.resize(PPLevelBranchIndex.size() - 1);
+ PPLevelBranchCount.resize(PPLevelBranchCount.size() - 1);
+ }
+ if (!PPLevelBranchIndex.empty()) {
+ ++PPLevelBranchIndex.back();
+ assert(PPLevelBranchIndex.size() == PPLevelBranchCount.size());
+ assert(PPLevelBranchIndex.back() <= PPLevelBranchCount.back());
+ }
+ } while (!PPLevelBranchIndex.empty());
+
return StructuralError;
}
@@ -379,11 +412,11 @@
parsePPDefine();
return;
case tok::pp_if:
- parsePPIf();
+ parsePPIf(/*IfDef=*/false);
break;
case tok::pp_ifdef:
case tok::pp_ifndef:
- parsePPIfdef();
+ parsePPIf(/*IfDef=*/true);
break;
case tok::pp_else:
parsePPElse();
@@ -407,12 +440,20 @@
PPStack.push_back(PP_Conditional);
}
-void UnwrappedLineParser::parsePPIf() {
+void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ ++PPBranchLevel;
+ assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
+ if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
+ PPLevelBranchIndex.push_back(0);
+ PPLevelBranchCount.push_back(0);
+ }
+ PPChainBranchIndex.push(0);
nextToken();
- if ((FormatTok->Tok.isLiteral() &&
- StringRef(FormatTok->Tok.getLiteralData(), FormatTok->Tok.getLength()) ==
- "0") ||
- FormatTok->Tok.is(tok::kw_false)) {
+ bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ StringRef(FormatTok->Tok.getLiteralData(),
+ FormatTok->Tok.getLength()) == "0") ||
+ FormatTok->Tok.is(tok::kw_false);
+ if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) {
PPStack.push_back(PP_Unreachable);
} else {
pushPPConditional();
@@ -420,21 +461,34 @@
parsePPUnknown();
}
-void UnwrappedLineParser::parsePPIfdef() {
- pushPPConditional();
- parsePPUnknown();
-}
-
void UnwrappedLineParser::parsePPElse() {
if (!PPStack.empty())
PPStack.pop_back();
- pushPPConditional();
+ assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
+ if (!PPChainBranchIndex.empty())
+ ++PPChainBranchIndex.top();
+ if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
+ PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) {
+ PPStack.push_back(PP_Unreachable);
+ } else {
+ pushPPConditional();
+ }
parsePPUnknown();
}
void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
void UnwrappedLineParser::parsePPEndIf() {
+ assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
+ if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
+ if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
+ assert(PPLevelBranchCount[PPBranchLevel] == 0);
+ PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
+ }
+ }
+ --PPBranchLevel;
+ if (!PPChainBranchIndex.empty())
+ PPChainBranchIndex.pop();
if (!PPStack.empty())
PPStack.pop_back();
parsePPUnknown();
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 3acdbd6..7a3993e 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -52,6 +52,7 @@
public:
virtual ~UnwrappedLineConsumer() {}
virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0;
+ virtual void finishRun() = 0;
};
class FormatTokenSource;
@@ -65,14 +66,14 @@
bool parse();
private:
+ void reset();
void parseFile();
void parseLevel(bool HasOpeningBrace);
void parseBlock(bool MustBeDeclaration, bool AddLevel = true);
void parseChildBlock();
void parsePPDirective();
void parsePPDefine();
- void parsePPIf();
- void parsePPIfdef();
+ void parsePPIf(bool IfDef);
void parsePPElIf();
void parsePPElse();
void parsePPEndIf();
@@ -161,6 +162,27 @@
// Keeps a stack of currently active preprocessor branching directives.
SmallVector<PPBranchKind, 16> PPStack;
+ // The \c UnwrappedLineParser re-parses the code for each combination
+ // of preprocessor branches that can be taken.
+ // To that end, we take the same branch (#if, #else, or one of the #elif
+ // branches) for each nesting level of preprocessor branches.
+ // \c PPBranchLevel stores the current nesting level of preprocessor
+ // branches during one pass over the code.
+ int PPBranchLevel;
+
+ // Contains the current branch (#if, #else or one of the #elif branches)
+ // for each nesting level.
+ SmallVector<int, 8> PPLevelBranchIndex;
+
+ // Contains the maximum number of branches at each nesting level.
+ SmallVector<int, 8> PPLevelBranchCount;
+
+ // Contains the number of branches per nesting level we are currently
+ // in while parsing a preprocessor branch sequence.
+ // This is used to update PPLevelBranchCount at the end of a branch
+ // sequence.
+ std::stack<int> PPChainBranchIndex;
+
friend class ScopedLineState;
};
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 16d80ea..c24ccdf 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -39,11 +39,18 @@
ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel),
Spaces(Spaces) {}
-void WhitespaceManager::replaceWhitespace(const FormatToken &Tok,
- unsigned Newlines,
+void WhitespaceManager::reset() {
+ Changes.clear();
+ Replaces.clear();
+}
+
+void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
unsigned IndentLevel, unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective) {
+ if (Tok.Finalized)
+ return;
+ Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
Changes.push_back(Change(true, Tok.WhitespaceRange, IndentLevel, Spaces,
StartOfTokenColumn, Newlines, "", "",
Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst));
@@ -51,6 +58,8 @@
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
bool InPPDirective) {
+ if (Tok.Finalized)
+ return;
Changes.push_back(Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
/*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore,
"", "", Tok.Tok.getKind(),
@@ -61,6 +70,8 @@
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
+ if (Tok.Finalized)
+ return;
Changes.push_back(Change(
true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
Tok.getStartOfNonWhitespace().getLocWithOffset(
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 93d331e..ae62023 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -41,9 +41,12 @@
bool UseCRLF)
: SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {}
+ /// \brief Prepares the \c WhitespaceManager for another run.
+ void reset();
+
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken.
- void replaceWhitespace(const FormatToken &Tok, unsigned Newlines,
+ void replaceWhitespace(FormatToken &Tok, unsigned Newlines,
unsigned IndentLevel, unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective = false);