diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -97,7 +97,7 @@ void parsePPEndIf(); void parsePPUnknown(); void readTokenWithJavaScriptASI(); - void parseStructuralElement(); + void parseStructuralElement(bool IsTopLevel = false); bool tryToParseBracedList(); bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false, tok::TokenKind ClosingBraceKind = tok::r_brace); diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -431,7 +431,7 @@ } LLVM_FALLTHROUGH; default: - parseStructuralElement(); + parseStructuralElement(/*IsTopLevel=*/true); break; } } while (!eof()); @@ -994,6 +994,33 @@ Keywords.kw_import, tok::kw_export); } +// This function checks whether a token starts the first parameter declaration +// in a K&R C (aka C78) function definition, e.g.: +// int f(a, b) +// short a, b; +// { +// return a + b; +// } +static bool isC78ParameterDecl(const FormatToken *Tok) { + if (!Tok) + return false; + + if (!Tok->isOneOf(tok::kw_int, tok::kw_char, tok::kw_float, tok::kw_double, + tok::kw_struct, tok::kw_union, tok::kw_long, tok::kw_short, + tok::kw_unsigned, tok::kw_register, tok::identifier)) + return false; + + Tok = Tok->Previous; + if (!Tok || Tok->isNot(tok::r_paren)) + return false; + + Tok = Tok->Previous; + if (!Tok || Tok->isNot(tok::identifier)) + return false; + + return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma); +} + // readTokenWithJavaScriptASI reads the next token and terminates the current // line if JavaScript Automatic Semicolon Insertion must // happen between the current token and the next token. @@ -1041,7 +1068,7 @@ return addUnwrappedLine(); } -void UnwrappedLineParser::parseStructuralElement() { +void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { assert(!FormatTok->is(tok::l_brace)); if (Style.Language == FormatStyle::LK_TableGen && FormatTok->is(tok::pp_include)) { @@ -1343,6 +1370,18 @@ return; case tok::l_paren: parseParens(); + // Break the unwrapped line if a K&R C function definition has a parameter + // declaration. + if (!IsTopLevel || !Style.isCpp()) + break; + if (!Previous || Previous->isNot(tok::identifier)) + break; + if (Previous->Previous && Previous->Previous->is(tok::at)) + break; + if (isC78ParameterDecl(FormatTok)) { + addUnwrappedLine(); + return; + } break; case tok::kw_operator: nextToken(); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -8216,7 +8216,16 @@ "f(i)\n" "{\n" " return i + 1;\n" - "}\n", + "}", + Style); + verifyFormat("int f(a, b, c);\n" // No break here. + "int\n" // Break here. + "f(a, b, c)\n" // Break here. + "short a, b;\n" + "float c;\n" + "{\n" + " return a + b < c;\n" + "}", Style); Style = getGNUStyle(); @@ -9423,7 +9432,7 @@ verifyFormat("vector v;", TypeMacros); // multiplication FormatStyle CustomQualifier = getLLVMStyle(); - // Add indentifers that should not be parsed as a qualifier by default. + // Add identifiers that should not be parsed as a qualifier by default. CustomQualifier.AttributeMacros.push_back("__my_qualifier"); CustomQualifier.AttributeMacros.push_back("_My_qualifier"); CustomQualifier.AttributeMacros.push_back("my_other_qualifier");