unsigned ParenLevel = State.Indent.size() - 1;
if (Newline) {
+ unsigned WhitespaceStartColumn = State.Column;
if (Current.Tok.is(tok::string_literal) &&
Previous.Tok.is(tok::string_literal)) {
State.Column = State.Column - Previous.Tok.getLength();
State.LineContainsContinuedForLoopSection =
Previous.Tok.isNot(tok::semi);
- if (!DryRun)
- replaceWhitespace(Current, 1, State.Column);
+ if (!DryRun) {
+ if (!Line.InPPDirective)
+ replaceWhitespace(Current, 1, State.Column);
+ else
+ replacePPWhitespace(Current, 1, State.Column, WhitespaceStartColumn);
+ }
State.LastSpace[ParenLevel] = State.Indent[ParenLevel];
if (Current.Tok.is(tok::colon) &&
addTokenToState(NewLine, true, State);
// Exceeding column limit is bad.
- if (State.Column > Style.ColumnLimit)
+ if (State.Column > Style.ColumnLimit - (Line.InPPDirective ? 1 : 0))
return UINT_MAX;
if (StopAt <= CurrentPenalty)
/// each \c FormatToken.
void replaceWhitespace(const FormatToken &Tok, unsigned NewLines,
unsigned Spaces) {
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, Tok.WhiteSpaceStart, Tok.WhiteSpaceLength,
+ std::string(NewLines, '\n') + std::string(Spaces, ' ')));
+ }
+
+ /// \brief Like \c replaceWhitespace, but additionally adds right-aligned
+ /// backslashes to escape newlines inside a preprocessor directive.
+ ///
+ /// This function and \c replaceWhitespace have the same behavior if
+ /// \c Newlines == 0.
+ void replacePPWhitespace(const FormatToken &Tok, unsigned NewLines,
+ unsigned Spaces, unsigned WhitespaceStartColumn) {
std::string NewLineText;
- if (!Line.InPPDirective) {
- NewLineText = std::string(NewLines, '\n');
- } else if (NewLines > 0) {
+ if (NewLines > 0) {
unsigned Offset =
- SourceMgr.getSpellingColumnNumber(Tok.WhiteSpaceStart) - 1;
+ std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn);
for (unsigned i = 0; i < NewLines; ++i) {
NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
NewLineText += "\\\n";
Token.Tok.is(tok::kw_private)) &&
static_cast<int>(Indent) + Style.AccessModifierOffset >= 0)
Indent += Style.AccessModifierOffset;
- replaceWhitespace(Token, Newlines, Indent);
+ if (!Line.InPPDirective || Token.HasUnescapedNewline)
+ replaceWhitespace(Token, Newlines, Indent);
+ else
+ // FIXME: Figure out how to get the previous end-of-line column.
+ replacePPWhitespace(Token, Newlines, Indent, 0);
return Indent;
}
return MessedUp;
}
- void verifyFormat(llvm::StringRef Code) {
- EXPECT_EQ(Code.str(), format(messUp(Code)));
+ FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ void verifyFormat(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ EXPECT_EQ(Code.str(), format(messUp(Code), Style));
}
void verifyGoogleFormat(llvm::StringRef Code) {
- EXPECT_EQ(Code.str(), format(messUp(Code), getGoogleStyle()));
+ verifyFormat(Code, getGoogleStyle());
}
};
EXPECT_EQ("#define A B", format("# \\\n define \\\n A \\\n B"));
}
+TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {
+ // If the macro fits in one line, we have the full width.
+ verifyFormat("#define A(B)", getLLVMStyleWithColumns(12));
+
+ verifyFormat("#define A(\\\n B)", getLLVMStyleWithColumns(11));
+ verifyFormat("#define AA(\\\n B)", getLLVMStyleWithColumns(11));
+ verifyFormat("#define A( \\\n A, B)", getLLVMStyleWithColumns(12));
+}
+
+TEST_F(FormatTest, HandlePreprocessorDirectiveContext) {
+ verifyFormat(
+ "// some comment\n"
+ "\n"
+ "#include \"a.h\"\n"
+ "#define A(A,\\\n"
+ " B)\n"
+ "#include \"b.h\"\n"
+ "\n"
+ "// some comment\n", getLLVMStyleWithColumns(13));
+}
+
TEST_F(FormatTest, MixingPreprocessorDirectivesAndNormalCode) {
verifyFormat("#define ALooooooooooooooooooooooooooooooooooooooongMacro("
" \\\n"