MyDeveloperDay created this revision. MyDeveloperDay added reviewers: klimek, reuk, owenpan, mitchell-stellar, STL_MSFT. MyDeveloperDay added projects: clang-format, clang-tools-extra. Herald added a project: clang.
https://bugs.llvm.org/show_bug.cgi?id=43531 Fix for clang-format incorrectly handles "alternative operators" as described by https://en.cppreference.com/w/cpp/language/operator_alternative compl = ~ not = ! these are unary operators, and clang-format will remove the space between them and a numeric constant this incorrectly formats the following code int a compl 5; int a not 5; into: int a compl5; int a not5; The code adds FIXME unit tests for "alternative token" representations for {} [] and # as defined by the same link, which would require a more detailed change to the FormatTokenLexer Repository: rC Clang https://reviews.llvm.org/D68332 Files: clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -14441,6 +14441,44 @@ verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle); } +TEST_F(FormatTest, AlternativeOperators) { + // Test case for bug https://bugs.llvm.org/show_bug.cgi?id=43531 + verifyFormat("int a and b;"); + verifyFormat("int a and_eq b;"); + verifyFormat("int a bitand b;"); + verifyFormat("int a bitor b;"); + verifyFormat("int a compl b;"); + verifyFormat("int a not b;"); + verifyFormat("int a not_eq b;"); + verifyFormat("int a or b;"); + verifyFormat("int a xor b;"); + verifyFormat("int a xor_eq b;"); + verifyFormat("return this not_eq bitand other;"); + verifyFormat("bool operator not_eq(const X bitand other)"); + + verifyFormat("int a and 5;"); + verifyFormat("int a and_eq 5;"); + verifyFormat("int a bitand 5;"); + verifyFormat("int a bitor 5;"); + verifyFormat("int a compl 5;"); + verifyFormat("int a not 5;"); + verifyFormat("int a not_eq 5;"); + verifyFormat("int a or 5;"); + verifyFormat("int a xor 5;"); + verifyFormat("int a xor_eq 5;"); + + /* FIXME handle alternate tokens + * https://en.cppreference.com/w/cpp/language/operator_alternative + // alternative tokens + verifyFormat("compl foo();"); // ~foo(); + verifyFormat("foo() <%%>;"); // foo(); + verifyFormat("void foo() <%%>;"); // void foo(){} + verifyFormat("int a <:1:>;"); // int a[1];[ + verifyFormat("%:define ABC abc"); // #define ABC abc + verifyFormat("%:%:"); // ## + */ +} + } // end namespace } // end namespace format } // end namespace clang Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -2888,9 +2888,19 @@ return false; return true; } - if (Left.is(TT_UnaryOperator)) + if (Left.is(TT_UnaryOperator)) { + // Don't combine the unary operators !~ into "compl5" and "not5" + // when using alternative operators "compl" and "not" + // but allow "compl(" to not become "compl (". + if (!Right.is(tok::l_paren)) { + if (Left.is(tok::exclaim) && Left.TokenText.equals("not")) + return true; + if (Left.is(tok::tilde) && Left.TokenText.equals("compl")) + return true; + } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); + } // If the next token is a binary operator or a selector name, we have // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -14441,6 +14441,44 @@ verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle); } +TEST_F(FormatTest, AlternativeOperators) { + // Test case for bug https://bugs.llvm.org/show_bug.cgi?id=43531 + verifyFormat("int a and b;"); + verifyFormat("int a and_eq b;"); + verifyFormat("int a bitand b;"); + verifyFormat("int a bitor b;"); + verifyFormat("int a compl b;"); + verifyFormat("int a not b;"); + verifyFormat("int a not_eq b;"); + verifyFormat("int a or b;"); + verifyFormat("int a xor b;"); + verifyFormat("int a xor_eq b;"); + verifyFormat("return this not_eq bitand other;"); + verifyFormat("bool operator not_eq(const X bitand other)"); + + verifyFormat("int a and 5;"); + verifyFormat("int a and_eq 5;"); + verifyFormat("int a bitand 5;"); + verifyFormat("int a bitor 5;"); + verifyFormat("int a compl 5;"); + verifyFormat("int a not 5;"); + verifyFormat("int a not_eq 5;"); + verifyFormat("int a or 5;"); + verifyFormat("int a xor 5;"); + verifyFormat("int a xor_eq 5;"); + + /* FIXME handle alternate tokens + * https://en.cppreference.com/w/cpp/language/operator_alternative + // alternative tokens + verifyFormat("compl foo();"); // ~foo(); + verifyFormat("foo() <%%>;"); // foo(); + verifyFormat("void foo() <%%>;"); // void foo(){} + verifyFormat("int a <:1:>;"); // int a[1];[ + verifyFormat("%:define ABC abc"); // #define ABC abc + verifyFormat("%:%:"); // ## + */ +} + } // end namespace } // end namespace format } // end namespace clang Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -2888,9 +2888,19 @@ return false; return true; } - if (Left.is(TT_UnaryOperator)) + if (Left.is(TT_UnaryOperator)) { + // Don't combine the unary operators !~ into "compl5" and "not5" + // when using alternative operators "compl" and "not" + // but allow "compl(" to not become "compl (". + if (!Right.is(tok::l_paren)) { + if (Left.is(tok::exclaim) && Left.TokenText.equals("not")) + return true; + if (Left.is(tok::tilde) && Left.TokenText.equals("compl")) + return true; + } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); + } // If the next token is a binary operator or a selector name, we have // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits