diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2398,12 +2398,17 @@ if (Next->MatchingParen->Next && Next->MatchingParen->Next->is(TT_PointerOrReference)) return true; + // Treat cases where the parameter list only contains comma-separated + // identifiers as function declarations. For example: + // `SomeType funcdecl(OtherType)` or `SomeType funcdecl(Type1, Type2)` + bool CouldBeTypeList = true; for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->is(TT_TypeDeclarationParen)) return true; if (Tok->isOneOf(tok::l_paren, TT_TemplateOpener) && Tok->MatchingParen) { Tok = Tok->MatchingParen; + CouldBeTypeList = false; continue; } if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() || @@ -2412,8 +2417,14 @@ if (Tok->isOneOf(tok::l_brace, tok::string_literal, TT_ObjCMethodExpr) || Tok->Tok.isLiteral()) return false; + if (!Tok->isOneOf(tok::identifier, tok::comma)) + CouldBeTypeList = false; } - return false; + // TODO: we should not make this decision based on the indentation level, but + // rather based on the type of scope (for example namespaces/classes/etc. + // should probably parse `SomeType decl(Type1, Type2)` as a function but + // inside a function this should always be treated as a variable. + return CouldBeTypeList && Line.Level == 0; } bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const { 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 @@ -5482,12 +5482,28 @@ " aaaaaaaaaaaaaaaaaaaaaaaaa));"); verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " __attribute__((unused));"); - verifyGoogleFormat( + FormatStyle Google = getGoogleStyle(); + verifyFormat( "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " GUARDED_BY(aaaaaaaaaaaa);"); - verifyGoogleFormat( + "GUARDED_BY(aaaaaaaaaaaa);\n" // parsed as function decl + "void f() {\n" + " bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " GUARDED_BY(aaaaaaaaaaaa);\n" // parsed as variable decl + "}\n" + "class Cls {\n" + " bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " GUARDED_BY(aaaaaaaaaaaa);\n" // parsed as variable decl + "};", + Google); + verifyFormat( "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " GUARDED_BY(aaaaaaaaaaaa);"); + "GUARDED_BY(aaaaaaaaaaaa);", // parsed as function decl + Google); + Google.AttributeMacros = {"GUARDED_BY"}; + verifyFormat( + "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GUARDED_BY(\n" + " aaaaaaaaaaaa);", // parsed as variable decl + Google); verifyGoogleFormat( "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GUARDED_BY(aaaaaaaaaaaa) =\n" " aaaaaaaa::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;"); @@ -6683,10 +6699,67 @@ // All declarations and definitions should have the return type moved to its // own line. Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All; + Style.NamespaceIndentation = FormatStyle::NI_All; Style.TypenameMacros = {"LIST"}; verifyFormat("SomeType\n" "funcdecl(LIST(uint64_t));", Style); + verifyFormat("SomeType\n" + "funcdecl();\n" + "SomeType\n" + "funcdecl(SomeType paramname);\n" + "SomeType\n" + "funcdecl(_Atomic(uint64_t));\n" + "SomeType\n" + "funcdecl(SomeType param1, OtherType param2);\n" + // Also handle parameter lists declaration without names (but + // only at the top level, not inside functions + "SomeType\n" + "funcdecl(SomeType);\n" + "SomeType\n" + "funcdecl(SomeType, OtherType);\n" + // Check that any kind of expression/operator results in parsing + // it as a variable declaration and not a function + "SomeType vardecl(var + otherVar);\n" + "SomeType vardecl(func());\n" + "SomeType vardecl(someFunc(arg));\n" + "SomeType vardecl(var, var - otherVar);\n" + "SomeType x = var * funcdecl();\n" + "SomeType x = var * funcdecl(otherVar);\n" + "SomeType x = var * funcdecl(var, otherVar);\n" + "void\n" + "function_scope() {\n" + " SomeType x = var * funcdecl();\n" + " SomeType x = var * funcdecl(otherVar);\n" + " SomeType x = var * funcdecl(var, otherVar);\n" + // While clang will parse these as function declarations, at + // least for now clang-format assumes they are variables. + " SomeType *funcdecl();\n" + " SomeType *funcdecl(SomeType);\n" + " SomeType *funcdecl(SomeType, OtherType);\n" + "}\n" + "namespace namspace_scope {\n" + // TODO: Should we also parse these as a function declaration + // and not as a variable inside namespaces? + " SomeType\n" + " funcdecl();\n" + " SomeType\n" + " funcdecl(SomeType paramname);\n" + " SomeType\n" + " funcdecl(_Atomic(uint64_t));\n" + " SomeType\n" + " funcdecl(SomeType param1, OtherType param2);\n" + " SomeType decl(SomeType);\n" + " SomeType decl(SomeType, OtherType);\n" + " SomeType vardecl(var + otherVar);\n" + " SomeType vardecl(func());\n" + " SomeType vardecl(someFunc(arg));\n" + " SomeType vardecl(var, var - otherVar);\n" + " SomeType x = var * funcdecl();\n" + " SomeType x = var * funcdecl(otherVar);\n" + " SomeType x = var * funcdecl(var, otherVar);\n" + "} // namespace namspace_scope\n", + Style); verifyFormat("class E {\n" " int\n" " f() {\n" @@ -8629,12 +8702,20 @@ // Different ways of ()-initializiation. verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n" " LoooooooooooooooooooooooooooooooooooooooongVariable(1);"); - verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n" - " LoooooooooooooooooooooooooooooooooooooooongVariable(a);"); verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n" " LoooooooooooooooooooooooooooooooooooooooongVariable({});"); verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n" " LoooooooooooooooooooooooooooooooooooooongVariable([A a]);"); + // A single identifier inside parentheses is parsed as a function declaration + // in the global scope, but as a variable inside functions. + verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n" + "LoooooooooooooooooooooooooooooooooooooooongVariable(a);\n" + "void f() {\n" + " LoooooooooooooooooooooooooooooooooooooooongType\n" + " LoooooooooooooooooooooooooooooooooooooooongVariable(a);\n" + " LoooooooooooooooooooooooooooooooooooooooongType\n" + " LooooooooooooooooooooooooooooooooooongVariable2(a + 1);\n" + "}"); // Lambdas should not confuse the variable declaration heuristic. verifyFormat("LooooooooooooooooongType\n"