]> granicus.if.org Git - clang/commitdiff
[clang-format] [PR43531] clang-format damages "alternative representations" for operators
authorPaul Hoad <mydeveloperday@gmail.com>
Fri, 4 Oct 2019 14:16:59 +0000 (14:16 +0000)
committerPaul Hoad <mydeveloperday@gmail.com>
Fri, 4 Oct 2019 14:16:59 +0000 (14:16 +0000)
Summary:
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

Reviewers: klimek, reuk, owenpan, mitchell-stellar, STL_MSFT

Reviewed By: mitchell-stellar

Subscribers: cfe-commits

Tags: #clang-format, #clang-tools-extra, #clang

Differential Revision: https://reviews.llvm.org/D68332

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373750 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTest.cpp

index 50e3d056b8385187aacb8aceb85cec7a3d1fe2a4..0c4172382130d65a9fd6c53f28dc42ff6a98fa52 100644 (file)
@@ -2900,9 +2900,19 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
       return false;
     return true;
   }
-  if (Left.is(TT_UnaryOperator))
+  if (Left.is(TT_UnaryOperator)) {
+    // The alternative operators for ~ and ! are "compl" and "not".
+    // If they are used instead, we do not want to combine them with
+    // the token to the right, unless that is a left paren.
+    if (!Right.is(tok::l_paren)) {
+      if (Left.is(tok::exclaim) && Left.TokenText == "not")
+        return true;
+      if (Left.is(tok::tilde) && Left.TokenText == "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 b770d0f26f8378df5836ff2da1c9aaa8b46effd7..14ac6f91372b1fc2b4c8147ae3d61fe4d9d70328 100644 (file)
@@ -14609,6 +14609,48 @@ TEST_F(FormatTest, AmbersandInLamda) {
   verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle);
 }
 
+TEST_F(FormatTest, AlternativeOperators) {
+  // Test case for ensuring alternate operators are not
+  // combined with their right most neighbour.
+  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;");
+
+  verifyFormat("int a compl(5);");
+  verifyFormat("int a not(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