Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -952,7 +952,7 @@ consumeToken(); if (CurrentToken && CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, - tok::comma)) + tok::comma, tok::star, tok::arrow)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { @@ -1344,8 +1344,12 @@ Contexts.back().IsExpression = false; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; - } else if (Current.isOneOf(tok::semi, tok::exclaim)) { + } else if (Current.is(tok::semi) || + (Current.is(tok::exclaim) && Current.Previous && + !Current.Previous->is(tok::kw_operator))) { // This should be the condition or increment in a for-loop. + // But not operator !() (can't use TT_OverloadedOperator here as its not + // been annotated yet). Contexts.back().IsExpression = true; } } @@ -2087,11 +2091,22 @@ continue; if (Next->isOneOf(tok::kw_new, tok::kw_delete)) { // For 'new[]' and 'delete[]'. - if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next && - Next->Next->Next->is(tok::r_square)) + if (Next->Next && + Next->Next->startsSequence(tok::l_square, tok::r_square)) Next = Next->Next->Next; continue; } + if (Next->startsSequence(tok::l_square, tok::r_square)) { + // For operator[](). + Next = Next->Next; + continue; + } + if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) && + Next->Next && Next->Next->is(tok::star)) { + // For operator void*(), operator char*(), operator Foo*(). + Next = Next->Next; + continue; + } break; } @@ -2605,6 +2620,12 @@ tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; + if (Right.is(tok::star) && + (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && + Left.Previous && Left.Previous->is(tok::kw_operator)) + // No space between the type and the * + // operator void*(), operator char*(), operator Foo*(). + return (Style.PointerAlignment == FormatStyle::PAS_Right); const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -6111,7 +6111,40 @@ "void\n" "A::operator>>() {}\n" "void\n" - "A::operator+() {}\n", + "A::operator+() {}\n" + "void\n" + "A::operator*() {}\n" + "void\n" + "A::operator->() {}\n" + "void\n" + "A::operator void *() {}\n" + "void\n" + "A::operator char *() {}\n" + "void\n" + "A::operator[]() {}\n" + "void\n" + "A::operator!() {}\n", + Style); + verifyFormat("constexpr auto\n" + "operator()() const -> reference {}\n" + "constexpr auto\n" + "operator>>() const -> reference {}\n" + "constexpr auto\n" + "operator+() const -> reference {}\n" + "constexpr auto\n" + "operator*() const -> reference {}\n" + "constexpr auto\n" + "operator->() const -> reference {}\n" + "constexpr auto\n" + "operator++() const -> reference {}\n" + "constexpr auto\n" + "operator void *() const -> reference {}\n" + "constexpr auto\n" + "operator char *() const -> reference {}\n" + "constexpr auto\n" + "operator!() const -> reference {}\n" + "constexpr auto\n" + "operator[]() const -> reference {}\n", Style); verifyFormat("void *operator new(std::size_t s);", // No break here. Style);