Author: Owen Pan Date: 2022-11-12T00:40:46-08:00 New Revision: 96e23906b5e80dc86b5d2431d30c9afc38ae4d20
URL: https://github.com/llvm/llvm-project/commit/96e23906b5e80dc86b5d2431d30c9afc38ae4d20 DIFF: https://github.com/llvm/llvm-project/commit/96e23906b5e80dc86b5d2431d30c9afc38ae4d20.diff LOG: [clang-format] Correctly annotate function names before attributes Fixes #58827. Differential Revision: https://reviews.llvm.org/D137486 Added: Modified: clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/TokenAnnotatorTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f489b2c2ddb3c..e63818cfcd9ab 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -71,6 +71,38 @@ static bool isKeywordWithCondition(const FormatToken &Tok) { tok::kw_constexpr, tok::kw_catch); } +/// Returns \c true if the token starts a C++ attribute, \c false otherwise. +static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) { + if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square)) + return false; + // The first square bracket is part of an ObjC array literal + if (Tok.Previous && Tok.Previous->is(tok::at)) + return false; + const FormatToken *AttrTok = Tok.Next->Next; + if (!AttrTok) + return false; + // C++17 '[[using ns: foo, bar(baz, blech)]]' + // We assume nobody will name an ObjC variable 'using'. + if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) + return true; + if (AttrTok->isNot(tok::identifier)) + return false; + while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) { + // ObjC message send. We assume nobody will use : in a C++11 attribute + // specifier parameter, although this is technically valid: + // [[foo(:)]]. + if (AttrTok->is(tok::colon) || + AttrTok->startsSequence(tok::identifier, tok::identifier) || + AttrTok->startsSequence(tok::r_paren, tok::identifier)) { + return false; + } + if (AttrTok->is(tok::ellipsis)) + return true; + AttrTok = AttrTok->Next; + } + return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square); +} + /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and @@ -538,34 +570,7 @@ class AnnotatingParser { } bool isCpp11AttributeSpecifier(const FormatToken &Tok) { - if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square)) - return false; - // The first square bracket is part of an ObjC array literal - if (Tok.Previous && Tok.Previous->is(tok::at)) - return false; - const FormatToken *AttrTok = Tok.Next->Next; - if (!AttrTok) - return false; - // C++17 '[[using ns: foo, bar(baz, blech)]]' - // We assume nobody will name an ObjC variable 'using'. - if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) - return true; - if (AttrTok->isNot(tok::identifier)) - return false; - while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) { - // ObjC message send. We assume nobody will use : in a C++11 attribute - // specifier parameter, although this is technically valid: - // [[foo(:)]]. - if (AttrTok->is(tok::colon) || - AttrTok->startsSequence(tok::identifier, tok::identifier) || - AttrTok->startsSequence(tok::r_paren, tok::identifier)) { - return false; - } - if (AttrTok->is(tok::ellipsis)) - return true; - AttrTok = AttrTok->Next; - } - return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square); + return isCppAttribute(Style.isCpp(), Tok); } bool parseSquare() { @@ -2844,6 +2849,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, } if (!Next->is(tok::identifier)) return false; + } else if (isCppAttribute(IsCpp, *Next)) { + Next = Next->MatchingParen; } else if (Next->is(tok::l_paren)) { break; } else { diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 65ecb12c46cd7..477e78c9c19e8 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1047,6 +1047,16 @@ TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) { EXPECT_TOKEN(Tokens[8], tok::r_paren, TT_Unknown); } +TEST_F(TokenAnnotatorTest, UnderstandsFunctionDeclarationNames) { + auto Tokens = annotate("void f [[noreturn]] ();"); + ASSERT_EQ(Tokens.size(), 11u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName); + + Tokens = annotate("void f [[noreturn]] () {}"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName); +} + TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) { auto Annotate = [this](llvm::StringRef Code) { return annotate(Code, getLLVMStyle(FormatStyle::LK_Verilog)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits