diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp --- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp @@ -40,12 +40,32 @@ Tok = Tok->getNextNonComment(); } } else { + // Skip attributes. + if (Tok && Tok->is(tok::l_square)) { + for (int NestLevel = 1; NestLevel > 0;) { + Tok = Tok->getNextNonComment(); + if (!Tok) + break; + if (Tok->is(tok::l_square)) + ++NestLevel; + else if (Tok->is(tok::r_square)) + --NestLevel; + } + if (Tok) + Tok = Tok->getNextNonComment(); + } + + // Use the string after `namespace` as a name candidate until `{` or `::` or + // `(`. If the name is empty, use the candicate. + std::string FirstNSName; // For `namespace [[foo]] A::B::inline C {` or // `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C". - // Peek for the first '::' (or '{') and then return all tokens from one - // token before that up until the '{'. + // Peek for the first '::' (or '{' or '(')) and then return all tokens from + // one token before that up until the '{'. A '(' might be a macro with + // arguments. const FormatToken *FirstNSTok = Tok; - while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) { + while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) { + FirstNSName += FirstNSTok->TokenText; FirstNSTok = Tok; Tok = Tok->getNextNonComment(); } @@ -57,6 +77,8 @@ name += " "; Tok = Tok->getNextNonComment(); } + if (name.empty()) + name = FirstNSName; } return name; } 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 @@ -2597,10 +2597,12 @@ parseParens(); } else { while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline, - tok::l_square, tok::period) || + tok::l_square, tok::period, tok::l_paren) || (Style.isCSharp() && FormatTok->is(tok::kw_union))) if (FormatTok->is(tok::l_square)) parseSquare(); + else if (FormatTok->is(tok::l_paren)) + parseParens(); else 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 @@ -3738,6 +3738,36 @@ "void f() { f(); }\n" "}", LLVMWithNoNamespaceFix); + verifyFormat("#define M(x) x##x\n" + "namespace M(x) {\n" + "class A {};\n" + "void f() { f(); }\n" + "}", + LLVMWithNoNamespaceFix); + verifyFormat("#define M(x) x##x\n" + "namespace N::inline M(x) {\n" + "class A {};\n" + "void f() { f(); }\n" + "}", + LLVMWithNoNamespaceFix); + verifyFormat("#define M(x) x##x\n" + "namespace M(x)::inline N {\n" + "class A {};\n" + "void f() { f(); }\n" + "}", + LLVMWithNoNamespaceFix); + verifyFormat("#define M(x) x##x\n" + "namespace N::M(x) {\n" + "class A {};\n" + "void f() { f(); }\n" + "}", + LLVMWithNoNamespaceFix); + verifyFormat("#define M(x) x##x\n" + "namespace M::N(x) {\n" + "class A {};\n" + "void f() { f(); }\n" + "}", + LLVMWithNoNamespaceFix); verifyFormat("namespace N::inline D {\n" "class A {};\n" "void f() { f(); }\n" diff --git a/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp --- a/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp +++ b/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp @@ -68,6 +68,127 @@ "int i;\n" "int j;\n" "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace M(x) {\n" + "int i;\n" + "int j;\n" + "}// namespace M(x)", + fixNamespaceEndComments("#define M(x) x##x\n" + "namespace M(x) {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace A::M(x) {\n" + "int i;\n" + "int j;\n" + "}// namespace A::M(x)", + fixNamespaceEndComments("#define M(x) x##x\n" + "namespace A::M(x) {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace M(x)::A {\n" + "int i;\n" + "int j;\n" + "}// namespace M(x)::A", + fixNamespaceEndComments("#define M(x) x##x\n" + "namespace M(x)::A {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace A::inline M(x)::B {\n" + "int i;\n" + "int j;\n" + "}// namespace A::inline M(x)::B", + fixNamespaceEndComments("#define M(x) x##x\n" + "namespace A::inline M(x)::B {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n" + "int i;\n" + "int j;\n" + "}// namespace A::inline M(x)::A", + fixNamespaceEndComments( + "#define M(x) x##x\n" + "namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ( + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n" + "int i;\n" + "int j;\n" + "}// namespace A", + fixNamespaceEndComments( + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("namespace /* comment */ [[deprecated(\"foo\")]] A {\n" + "int i;\n" + "int j;\n" + "}// namespace A", + fixNamespaceEndComments( + "namespace /* comment */ [[deprecated(\"foo\")]] A {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ( + "#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ M(x) {\n" + "int i;\n" + "int j;\n" + "}// namespace M(x)", + fixNamespaceEndComments("#define M(x) x##x\n" + "namespace /* comment */ " + "[[deprecated(\"foo\")]] /* comment */ M(x) {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ " + "A::M(x) {\n" + "int i;\n" + "int j;\n" + "}// namespace A::M(x)", + fixNamespaceEndComments( + "#define M(x) x##x\n" + "namespace /* comment */ " + "[[deprecated(\"foo\")]] /* comment */ A::M(x) {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ " + "M(x) /* comment */ {\n" + "int i;\n" + "int j;\n" + "}// namespace M(x)", + fixNamespaceEndComments( + "#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment " + "*/ M(x) /* comment */ {\n" + "int i;\n" + "int j;\n" + "}")); + EXPECT_EQ("#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ " + "A::M(x) /* comment */ {\n" + "int i;\n" + "int j;\n" + "}// namespace A::M(x)", + fixNamespaceEndComments( + "#define M(x) x##x\n" + "namespace /* comment */ [[deprecated(\"foo\")]] /* comment " + "*/ A::M(x) /* comment */ {\n" + "int i;\n" + "int j;\n" + "}")); EXPECT_EQ("inline namespace A {\n" "int i;\n" "int j;\n"