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 @@ -914,13 +914,31 @@ } break; case tok::pipe: - case tok::amp: // | and & in declarations/type expressions represent union and // intersection types, respectively. if (Style.Language == FormatStyle::LK_JavaScript && !Contexts.back().IsExpression) Tok->setType(TT_JsTypeOperator); break; + case tok::amp: + if (Style.Language == FormatStyle::LK_JavaScript && + !Contexts.back().IsExpression) { + Tok->setType(TT_JsTypeOperator); + break; + } + LLVM_FALLTHROUGH; // Handle multi-variable declarations of reference type + case tok::star: + if (Style.isCpp() && Contexts.back().FirstStartOfName && + Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt) { + // '*' or '&' after a comma is always a pointer or reference if + // we are in a context declaring multiple variables. + FormatToken *Prev = Tok->getPreviousNonComment(); + if (Prev && Prev->is(tok::comma)) { + Tok->setType(TT_PointerOrReference); + Line.IsMultiVariableDeclStmt = true; + } + } + break; case tok::kw_if: case tok::kw_while: if (Tok->is(tok::kw_if) && CurrentToken && @@ -2859,12 +2877,16 @@ if (!TokenBeforeMatchingParen || !Left.is(TT_TypeDeclarationParen)) return true; } - return (Left.Tok.isLiteral() || - (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && - (Style.PointerAlignment != FormatStyle::PAS_Left || - (Line.IsMultiVariableDeclStmt && - (Left.NestingLevel == 0 || - (Left.NestingLevel == 1 && Line.First->is(tok::kw_for))))))); + if (Left.Tok.isLiteral()) + return true; + // We group multiple '*'/'&' tokens for all pointer alignment settings. + // TODO: why is the l_paren needed? + if (Left.isOneOf(TT_PointerOrReference, tok::l_paren)) + return false; + // We always place a space after the comma in multi-variable declarations. + if (Line.IsMultiVariableDeclStmt && Left.is(tok::comma)) + return true; + return Style.PointerAlignment != FormatStyle::PAS_Left; } if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && (!Left.is(TT_PointerOrReference) || @@ -2880,9 +2902,7 @@ (Right.is(tok::l_brace) && Right.is(BK_Block)) || (!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, tok::l_paren) && - (Style.PointerAlignment != FormatStyle::PAS_Right && - !Line.IsMultiVariableDeclStmt) && - Left.Previous && + Style.PointerAlignment != FormatStyle::PAS_Right && Left.Previous && !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, tok::l_square)); // Ensure right pointer alignement with ellipsis e.g. int *...P 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 @@ -6629,14 +6629,30 @@ Style.PointerAlignment = FormatStyle::PAS_Left; Style.DerivePointerAlignment = false; verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " *aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n" - " *b = bbbbbbbbbbbbbbbbbbb;", + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n" + " * b = bbbbbbbbbbbbbbbbbbb;", Style); - verifyFormat("aaaaaaaaa *a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n" - " *b = bbbbbbbbbbbbbbbbbbb, *d = ddddddddddddddddddd;", + verifyFormat("aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, * b = bbbbbbbbbbbbbbbbbb,\n" + " * b = bbbbbbbbbbbbbbbbbbb, * d = dddddddddddddddd;", Style); verifyFormat("vector a, b;", Style); + verifyFormat("for (int* p, * q; p != q; p = p->next) {\n}", Style); + verifyFormat("char* x, * const* y = NULL;", Style); + verifyFormat("char** x, ** y = NULL;", Style); + verifyFormat("int x, * xp = &x, & xr = x, *& xpr = xp, * const& xcpr = xp;", + Style); + Style.PointerAlignment = FormatStyle::PAS_Right; verifyFormat("for (int *p, *q; p != q; p = p->next) {\n}", Style); + verifyFormat("char *x, *const *y = NULL;", Style); + verifyFormat("char **x, **y = NULL;", Style); + verifyFormat("int x, *xp = &x, &xr = x, *&xpr = xp, *const &xcpr = xp;", + Style); + Style.PointerAlignment = FormatStyle::PAS_Middle; + verifyFormat("for (int * p, * q; p != q; p = p->next) {\n}", Style); + verifyFormat("char * x, * const * y = NULL;", Style); + verifyFormat("char ** x, ** y = NULL;", Style); + verifyFormat("int x, * xp = &x, & xr = x, *& xpr = xp, * const & xcpr = xp;", + Style); } TEST_F(FormatTest, ConditionalExpressionsInBrackets) {