From f54d42abcf82e122ed0ac4688f01c1f4da5599f2 Mon Sep 17 00:00:00 2001 From: Emilia Dreamer Date: Mon, 5 Sep 2022 12:19:31 +0200 Subject: [PATCH] [clang-format] Don't put `noexcept` on empty line following constructor With the AlwaysBreakTemplateDeclarations option, having a constructor template for a type consisting of all-uppercase letters with a noexcept specifier would put said noexcept specifier on its own blank line. This is because the all-uppercase type is understood as a macro-like attribute (such as DEPRECATED()), and noexcept is seen as the declaration. However, noexcept is a keyword and cannot be an identifier on its own. Fixes https://github.com/llvm/llvm-project/issues/56216 Differential Revision: https://reviews.llvm.org/D132189 --- clang/lib/Format/TokenAnnotator.cpp | 2 +- clang/unittests/Format/FormatTest.cpp | 12 ++++++++++++ clang/unittests/Format/TokenAnnotatorTest.cpp | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 2a64a3b..663e8ae 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1924,7 +1924,7 @@ private: !Current.Next->isBinaryOperator() && !Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace, tok::comma, tok::period, tok::arrow, - tok::coloncolon)) { + tok::coloncolon, tok::kw_noexcept)) { if (FormatToken *AfterParen = Current.MatchingParen->Next) { // Make sure this isn't the return type of an Obj-C block declaration if (AfterParen->isNot(tok::caret)) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index d330c65..ce56570 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -9607,6 +9607,15 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) { verifyFormat("template // T can be A, B or C.\n" "struct C {};", AlwaysBreak); + verifyFormat("template \n" + "C(T) noexcept;", + AlwaysBreak); + verifyFormat("template \n" + "ClassName(T) noexcept;", + AlwaysBreak); + verifyFormat("template \n" + "POOR_NAME(T) noexcept;", + AlwaysBreak); verifyFormat("template class A {\n" "public:\n" " E *f();\n" @@ -9617,6 +9626,9 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) { verifyFormat("template class C {};", NeverBreak); verifyFormat("template void f();", NeverBreak); verifyFormat("template void f() {}", NeverBreak); + verifyFormat("template C(T) noexcept;", NeverBreak); + verifyFormat("template ClassName(T) noexcept;", NeverBreak); + verifyFormat("template POOR_NAME(T) noexcept;", NeverBreak); verifyFormat("template \nvoid foo(aaaaaaaaaaaaaaaaaaaaaaaaaa " "bbbbbbbbbbbbbbbbbbbb) {}", NeverBreak); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 6a10d67..21ef5c3 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -788,6 +788,19 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) { EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); } +TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) { + auto Tokens = annotate("template \n" + "DEPRECATED(\"Use NewClass::NewFunction instead.\")\n" + "string OldFunction(const string ¶meter) {}"); + ASSERT_EQ(Tokens.size(), 20u) << Tokens; + EXPECT_TOKEN(Tokens[8], tok::r_paren, TT_FunctionAnnotationRParen); + + Tokens = annotate("template \n" + "A(T) noexcept;"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[8], tok::r_paren, TT_Unknown); +} + TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) { auto Annotate = [this](llvm::StringRef Code) { return annotate(Code, getLLVMStyle(FormatStyle::LK_Verilog)); -- 2.7.4