namespace {
+bool startsExternCBlock(const AnnotatedLine &Line) {
+ const FormatToken *Next = Line.First->getNextNonComment();
+ const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
+ return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&
+ NextNext && NextNext->is(tok::l_brace);
+}
+
class NoColumnLimitFormatter {
public:
NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
Tok->SpacesRequiredBefore = 0;
Tok->CanBreakBefore = true;
return 1;
- } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace)) {
+ } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(Line)) {
// We don't merge short records.
if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
return 0;
// Remove empty lines after "{".
if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
PreviousLine->Last->is(tok::l_brace) &&
- PreviousLine->First->isNot(tok::kw_namespace))
+ PreviousLine->First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(*PreviousLine))
Newlines = 1;
// Insert extra new line before access specifiers.
"\n"
"};"));
- // Don't remove empty lines at the start of namespaces.
+ // Don't remove empty lines at the start of namespaces or extern "C" blocks.
EXPECT_EQ("namespace N {\n"
"\n"
"int i;\n"
"int i;\n"
"}",
getGoogleStyle()));
+ EXPECT_EQ("extern /**/ \"C\" /**/ {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("extern /**/ \"C\" /**/ {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+
+ // ...but do keep inlining and removing empty lines for non-block extern "C"
+ // functions.
+ verifyFormat("extern \"C\" int f() { return 42; }", getGoogleStyle());
+ EXPECT_EQ("extern \"C\" int f() {\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}",
+ format("extern \"C\" int f() {\n"
+ "\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}",
+ getGoogleStyle()));
// Remove empty lines at the beginning and end of blocks.
EXPECT_EQ("void f() {\n"