mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-21 12:35:47 -04:00
[clang-format] [PR36294] AlwaysBreakAfterReturnType works incorrectly for some operator functions
Summary: https://bugs.llvm.org/show_bug.cgi?id=36294 Addressing bug related to returning after return type not being honoured for some operator types. ``` $ bin/clang-format --style="{BasedOnStyle: llvm, AlwaysBreakAfterReturnType: TopLevelDefinitions}" /tmp/foo.cpp class Foo { public: bool operator!() const; bool operator<(Foo const &) const; bool operator*() const; bool operator->() const; bool operator+() const; bool operator-() const; bool f() const; }; bool Foo::operator!() const { return true; } bool Foo::operator<(Foo const &) const { return true; } bool Foo::operator*() const { return true; } bool Foo::operator->() const { return true; } bool Foo::operator+() const { return true; } bool Foo::operator-() const { return true; } bool Foo::f() const { return true; } ``` Reviewers: mitchell-stellar, klimek, owenpan, sammccall, rianquinn Reviewed By: sammccall Subscribers: merge_guards_bot, cfe-commits Tags: #clang-format, #clang-tools-extra, #clang Differential Revision: https://reviews.llvm.org/D69573
This commit is contained in:
parent
874b6495b5
commit
a75f8d98d7
@ -950,9 +950,9 @@ private:
|
|||||||
if (CurrentToken->isOneOf(tok::star, tok::amp))
|
if (CurrentToken->isOneOf(tok::star, tok::amp))
|
||||||
CurrentToken->Type = TT_PointerOrReference;
|
CurrentToken->Type = TT_PointerOrReference;
|
||||||
consumeToken();
|
consumeToken();
|
||||||
if (CurrentToken &&
|
if (CurrentToken && CurrentToken->Previous->isOneOf(
|
||||||
CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator,
|
TT_BinaryOperator, TT_UnaryOperator, tok::comma,
|
||||||
tok::comma))
|
tok::star, tok::arrow, tok::amp, tok::ampamp))
|
||||||
CurrentToken->Previous->Type = TT_OverloadedOperator;
|
CurrentToken->Previous->Type = TT_OverloadedOperator;
|
||||||
}
|
}
|
||||||
if (CurrentToken) {
|
if (CurrentToken) {
|
||||||
@ -1344,8 +1344,12 @@ private:
|
|||||||
Contexts.back().IsExpression = false;
|
Contexts.back().IsExpression = false;
|
||||||
} else if (Current.is(tok::kw_new)) {
|
} else if (Current.is(tok::kw_new)) {
|
||||||
Contexts.back().CanBeExpression = false;
|
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.
|
// 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;
|
Contexts.back().IsExpression = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2155,11 +2159,22 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
|
|||||||
continue;
|
continue;
|
||||||
if (Next->isOneOf(tok::kw_new, tok::kw_delete)) {
|
if (Next->isOneOf(tok::kw_new, tok::kw_delete)) {
|
||||||
// For 'new[]' and 'delete[]'.
|
// For 'new[]' and 'delete[]'.
|
||||||
if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next &&
|
if (Next->Next &&
|
||||||
Next->Next->Next->is(tok::r_square))
|
Next->Next->startsSequence(tok::l_square, tok::r_square))
|
||||||
Next = Next->Next->Next;
|
Next = Next->Next->Next;
|
||||||
continue;
|
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->isOneOf(tok::star, tok::amp, tok::ampamp)) {
|
||||||
|
// For operator void*(), operator char*(), operator Foo*().
|
||||||
|
Next = Next->Next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2673,6 +2688,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
|||||||
tok::l_square));
|
tok::l_square));
|
||||||
if (Right.is(tok::star) && Left.is(tok::l_paren))
|
if (Right.is(tok::star) && Left.is(tok::l_paren))
|
||||||
return false;
|
return false;
|
||||||
|
if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) &&
|
||||||
|
(Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) &&
|
||||||
|
Left.Previous && Left.Previous->is(tok::kw_operator))
|
||||||
|
// Space between the type and the *
|
||||||
|
// operator void*(), operator char*(), operator Foo*() dependant
|
||||||
|
// on PointerAlignment style.
|
||||||
|
return (Style.PointerAlignment == FormatStyle::PAS_Right);
|
||||||
const auto SpaceRequiredForArrayInitializerLSquare =
|
const auto SpaceRequiredForArrayInitializerLSquare =
|
||||||
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
|
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
|
||||||
return Style.SpacesInContainerLiterals ||
|
return Style.SpacesInContainerLiterals ||
|
||||||
|
@ -6134,7 +6134,48 @@ TEST_F(FormatTest, ReturnTypeBreakingStyle) {
|
|||||||
"void\n"
|
"void\n"
|
||||||
"A::operator>>() {}\n"
|
"A::operator>>() {}\n"
|
||||||
"void\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 void &() {}\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 void &() 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);
|
Style);
|
||||||
verifyFormat("void *operator new(std::size_t s);", // No break here.
|
verifyFormat("void *operator new(std::size_t s);", // No break here.
|
||||||
Style);
|
Style);
|
||||||
@ -14755,6 +14796,53 @@ TEST_F(FormatTest, STLWhileNotDefineChed) {
|
|||||||
"#endif // while");
|
"#endif // while");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FormatTest, OperatorSpacing) {
|
||||||
|
FormatStyle Style = getLLVMStyle();
|
||||||
|
Style.PointerAlignment = FormatStyle::PAS_Right;
|
||||||
|
verifyFormat("Foo::operator*();", Style);
|
||||||
|
verifyFormat("Foo::operator void *();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void *);", Style);
|
||||||
|
verifyFormat("Foo::operator*(void *);", Style);
|
||||||
|
verifyFormat("Foo::operator*();", Style);
|
||||||
|
verifyFormat("operator*(int (*)(), class Foo);", Style);
|
||||||
|
|
||||||
|
verifyFormat("Foo::operator&();", Style);
|
||||||
|
verifyFormat("Foo::operator void &();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void &);", Style);
|
||||||
|
verifyFormat("Foo::operator&(void &);", Style);
|
||||||
|
verifyFormat("Foo::operator&();", Style);
|
||||||
|
verifyFormat("operator&(int (&)(), class Foo);", Style);
|
||||||
|
|
||||||
|
verifyFormat("Foo::operator&&();", Style);
|
||||||
|
verifyFormat("Foo::operator void &&();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void &&);", Style);
|
||||||
|
verifyFormat("Foo::operator&&(void &&);", Style);
|
||||||
|
verifyFormat("Foo::operator&&();", Style);
|
||||||
|
verifyFormat("operator&&(int(&&)(), class Foo);", Style);
|
||||||
|
|
||||||
|
Style.PointerAlignment = FormatStyle::PAS_Left;
|
||||||
|
verifyFormat("Foo::operator*();", Style);
|
||||||
|
verifyFormat("Foo::operator void*();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void*);", Style);
|
||||||
|
verifyFormat("Foo::operator*(void*);", Style);
|
||||||
|
verifyFormat("Foo::operator*();", Style);
|
||||||
|
verifyFormat("operator*(int (*)(), class Foo);", Style);
|
||||||
|
|
||||||
|
verifyFormat("Foo::operator&();", Style);
|
||||||
|
verifyFormat("Foo::operator void&();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void&);", Style);
|
||||||
|
verifyFormat("Foo::operator&(void&);", Style);
|
||||||
|
verifyFormat("Foo::operator&();", Style);
|
||||||
|
verifyFormat("operator&(int (&)(), class Foo);", Style);
|
||||||
|
|
||||||
|
verifyFormat("Foo::operator&&();", Style);
|
||||||
|
verifyFormat("Foo::operator void&&();", Style);
|
||||||
|
verifyFormat("Foo::operator()(void&&);", Style);
|
||||||
|
verifyFormat("Foo::operator&&(void&&);", Style);
|
||||||
|
verifyFormat("Foo::operator&&();", Style);
|
||||||
|
verifyFormat("operator&&(int(&&)(), class Foo);", Style);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace format
|
} // namespace format
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
Loading…
Reference in New Issue
Block a user