From: Daniel Jasper Date: Mon, 18 Apr 2016 11:31:21 +0000 (+0000) Subject: clang-format: Improve heuristics to detect function declarations/definitions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=510a022f1b6a1a9dcfc8b0f609581eaf8213ec5c;p=clang clang-format: Improve heuristics to detect function declarations/definitions. Specifically understand ellipses in parameter lists and treat trailing reference qualifiers and the "{" as signals. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@266599 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 2f3bb3a8c7..9c74539943 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1553,7 +1553,8 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { // This function heuristically determines whether 'Current' starts the name of a // function declaration. -static bool isFunctionDeclarationName(const FormatToken &Current) { +static bool isFunctionDeclarationName(const FormatToken &Current, + const AnnotatedLine &Line) { auto skipOperatorName = [](const FormatToken* Next) -> const FormatToken* { for (; Next; Next = Next->Next) { if (Next->is(TT_OverloadedOperatorLParen)) @@ -1573,6 +1574,7 @@ static bool isFunctionDeclarationName(const FormatToken &Current) { return nullptr; }; + // Find parentheses of parameter list. const FormatToken *Next = Current.Next; if (Current.is(tok::kw_operator)) { if (Current.Previous && Current.Previous->is(tok::coloncolon)) @@ -1602,14 +1604,22 @@ static bool isFunctionDeclarationName(const FormatToken &Current) { } } - if (!Next || !Next->is(tok::l_paren)) + // Check whether parameter list can be long to a function declaration. + if (!Next || !Next->is(tok::l_paren) || !Next->MatchingParen) return false; + // If the lines ends with "{", this is likely an function definition. + if (Line.Last->is(tok::l_brace)) + return true; if (Next->Next == Next->MatchingParen) + return true; // Empty parentheses. + // If there is an &/&& after the r_paren, this is likely a function. + if (Next->MatchingParen->Next && + Next->MatchingParen->Next->is(TT_PointerOrReference)) return true; for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() || - Tok->isOneOf(TT_PointerOrReference, TT_StartOfName)) + Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) return true; if (Tok->isOneOf(tok::l_brace, tok::string_literal, TT_ObjCMethodExpr) || Tok->Tok.isLiteral()) @@ -1655,7 +1665,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { FormatToken *Current = Line.First->Next; bool InFunctionDecl = Line.MightBeFunctionDecl; while (Current) { - if (isFunctionDeclarationName(*Current)) + if (isFunctionDeclarationName(*Current, Line)) Current->Type = TT_FunctionDeclarationName; if (Current->is(TT_LineComment)) { if (Current->Previous->BlockKind == BK_BracedInit && diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 1b0e5865b7..0a9969a9b7 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -5621,6 +5621,10 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { AlignLeft); verifyFormat("Deleted& operator=(const Deleted&) &;", AlignLeft); verifyFormat("SomeType MemberFunction(const Deleted&) &;", AlignLeft); + verifyFormat("auto Function(T t) & -> void {}", AlignLeft); + verifyFormat("auto Function(T... t) & -> void {}", AlignLeft); + verifyFormat("auto Function(T) & -> void {}", AlignLeft); + verifyFormat("auto Function(T) & -> void;", AlignLeft); FormatStyle Spaces = getLLVMStyle(); Spaces.SpacesInCStyleCastParentheses = true; @@ -6119,6 +6123,10 @@ TEST_F(FormatTest, BreaksLongDeclarations) { "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}"); verifyFormat("decltype(LoooooooooooooooooooooooooooooooooooooooongName)\n" "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}"); + verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n" + "LooooooooooooooooooooooooooongFunctionDeclaration(T... t);"); + verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n" + "LooooooooooooooooooooooooooongFunctionDeclaration(T /*t*/) {}"); FormatStyle Indented = getLLVMStyle(); Indented.IndentWrappedFunctionNames = true; verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n"