Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -160,6 +160,14 @@ return false; } + /// Parses CPP qualified function names. + bool parse_function_qname(FormatToken *Tok) const { + while (Tok && Tok->isOneOf(tok::coloncolon, tok::identifier)) { + Tok = Tok->Next; + } + return Tok && Tok->is(tok::l_paren); + } + bool parseParens(bool LookForDecls = false) { if (!CurrentToken) return false; @@ -250,6 +258,7 @@ bool HasMultipleParametersOnALine = false; bool MightBeObjCForRangeLoop = Left->Previous && Left->Previous->is(tok::kw_for); + bool HasStarToken = false; FormatToken *PossibleObjCForInToken = nullptr; while (CurrentToken) { // LookForDecls is set when "if (" has been seen. Check for @@ -299,6 +308,55 @@ } } + // Detect cases where macros are used in function parameter lists, + // for example: + // void f(volatile ElfW(Addr)* addr = nullptr); + if (HasStarToken) { + for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) { + // Search for ') *' patterns. + if (Tok->is(tok::star) && Tok->Previous->is(tok::r_paren)) { + // Extend search to left looking for 'X(...) *' patterns. + FormatToken *LparenTok = Tok->Previous->MatchingParen; + if (LparenTok && LparenTok->is(tok::l_paren) && + LparenTok->Previous) { + FormatToken *MacroTok = LparenTok->Previous; + // Decide if 'X' is following "l_paren" of this function, + // a keyword or a comma. + if (MacroTok->is(tok::identifier) && MacroTok->Previous && + (MacroTok->Previous == Left || + MacroTok->Previous->isOneOf(tok::comma, tok::kw_const, + tok::kw_volatile))) { + Tok->Type = TT_PointerOrReference; + LparenTok->Previous->Type = TT_TypenameMacro; + } + } + } + } + } + + // Detect cases where macros are used in function return types, + // for example: + // const ElfW(Addr)* f(); + if (CurrentToken->Next && CurrentToken->Next->is(tok::star)) { + if (parse_function_qname(CurrentToken->Next->Next)) { + bool Found = true; + FormatToken *const Prev = CurrentToken->MatchingParen->Previous; + if (Prev && Prev->is(tok::identifier)) { + for (FormatToken *Tok = Prev; Tok; Tok = Tok->Previous) { + if (!Tok->is(TT_Unknown)) { + Found = false; + break; + } else if (Prev->is(tok::semi)) + break; + } + } + if (Found) { + CurrentToken->Next->Type = TT_PointerOrReference; + Prev->Type = TT_TypenameMacro; + } + } + } + if (StartsObjCMethodExpr) { CurrentToken->Type = TT_ObjCMethodExpr; if (Contexts.back().FirstObjCSelectorName) { @@ -355,6 +413,9 @@ if (CurrentToken->is(tok::comma)) Contexts.back().CanBeExpression = true; + if (CurrentToken->is(tok::star)) + HasStarToken = true; + FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -7356,6 +7356,10 @@ verifyFormat("void f(const MyFinal &final);"); verifyIndependentOfContext("bool a = f() && override.f();"); verifyIndependentOfContext("bool a = f() && final.f();"); + verifyFormat("int f(M(x) *p1 = nullptr, M(x) *p2, volatile M(x) *p3);"); + verifyFormat("M(x) *foo();"); + verifyFormat("const M(x) *foo(M(x) *a = nullptr);"); + verifyFormat("const M(x) *foo::bar(M(x) *a = nullptr);"); verifyIndependentOfContext("InvalidRegions[*R] = 0;"); @@ -7396,6 +7400,10 @@ verifyGoogleFormat("void f(Bar* a = nullptr, Bar* b);"); verifyGoogleFormat("template \n" "void f(int i = 0, SomeType** temps = NULL);"); + verifyGoogleFormat("int f(M(x)* p1 = nullptr, const M(x)* p2);"); + verifyGoogleFormat("M(x)* foo();"); + verifyGoogleFormat("const M(x)* foo(M(x)* a = nullptr);"); + verifyGoogleFormat("const M(x)* foo::bar(M(x)* a = nullptr);"); FormatStyle Left = getLLVMStyle(); Left.PointerAlignment = FormatStyle::PAS_Left; @@ -7410,6 +7418,11 @@ verifyFormat("auto x(A&&, B&&, C&&) -> D;", Left); verifyFormat("auto x = [](A&&, B&&, C&&) -> D {};", Left); verifyFormat("template X(T&&, T&&, T&&) -> X;", Left); + verifyFormat("int f(M(x)* p1 = nullptr, const M(x)* p2, volatile M(x)* p3);", + Left); + verifyFormat("M(x)* foo();", Left); + verifyFormat("const M(x)* foo(M(x)* a = nullptr);", Left); + verifyFormat("const M(x)* foo::bar(M(x)* a = nullptr);", Left); verifyIndependentOfContext("a = *(x + y);"); verifyIndependentOfContext("a = &(x + y);"); @@ -7537,6 +7550,11 @@ verifyFormat("A = new SomeType *[Length]();", PointerMiddle); verifyFormat("A = new SomeType *[Length];", PointerMiddle); verifyFormat("T ** t = new T *;", PointerMiddle); + verifyFormat("int f(M(x) * p1 = nullptr, const M(x) * p2 = nullptr);", + PointerMiddle); + verifyFormat("M(x) * foo();", PointerMiddle); + verifyFormat("const M(x) * foo(M(x) * a = nullptr);", PointerMiddle); + verifyFormat("const M(x) * foo::bar(M(x) * a = nullptr);", PointerMiddle); // Member function reference qualifiers aren't binary operators. verifyFormat("string // break\n"