clang-format: better detection for multiplication operator

Johannes Kapfhammer jkapfham at ethz.ch
Thu Apr 3 13:58:45 PDT 2014


On Sun, Mar 30, 2014 at 07:45:51PM +0200, Daniel Jasper wrote: 
> All in all, I think a much easier solution for the mentioned bug would be
> to treat "<<" similar to how we treat assignments, i.e. if we find a <<, we
> assume the RHS to be an expression (that's the very first "if" in
> determineTokenType()).
> 
Not sure if that's the right place.  The "if" branch you are talking
about will set all preceding stars (on the same level) to
TT_PointerOrReference:

Before: cout << a *a << b *b << c *c;
After:  cout << a *a << b *b << c * b;
My Fix: cout << a * a << b * b << c * c;

So we need the special care for operator<< at least in a new
"else if".  I've added a "light" version of this patch below, note
that it only handles operator<< and doesn't work with other operators.
Doing it the way I did in the last mail has the additional benefit
that it works for all operators and not just "<<" (in particular
operator+ is hard to get otherwise).  But we probably won't need this.

--

>From 16d81e7e3a0dedd5d51f963a134b26eb9c63b777 Mon Sep 17 00:00:00 2001
From: Kapfhammer <kapf at student.ethz.ch>
Date: Sun, 30 Mar 2014 12:04:17 +0200
Subject: [PATCH] Use binary operators as an indicator of for an expression and
 extend the test suite.

This solves the issue where the star was too often interpreted as a
pointer, e.g "cout<<a*b;" was formatted to "cout << a *b;" instead of
"cout << a * b;".  By marking statements more often an expression, the
function determineStarAmpUsage() is more reliable.

The test suite was extended.
---
 lib/Format/TokenAnnotator.cpp   |  5 +++++
 unittests/Format/FormatTest.cpp | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 0034235..7fbbdae 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -681,6 +681,11 @@ private:
           Previous->Type = TT_PointerOrReference;
         }
       }
+    } else if (Current.is(tok::lessless) &&
+               !Line.First->isOneOf(tok::kw_template, tok::kw_using) &&
+               (!Current.Previous ||
+                Current.Previous->isNot(tok::kw_operator))) {
+      Contexts.back().IsExpression = true;
     } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
       Contexts.back().IsExpression = true;
     } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 5395fd9..7478a23 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -4625,6 +4625,21 @@ TEST_F(FormatTest, UnderstandsRvalueReferences) {
   verifyGoogleFormat("#define WHILE(a, b, c) while (a && (b == c))");
 }
 
+TEST_F(FormatTest, FormatsMultiplicationOperator) {
+  verifyFormat("operator*(type *a)");
+  verifyFormat("operator<<(type *a)");
+  verifyFormat("{ cout << (a * b); }");
+  verifyFormat("{ cout << a * b; }");
+  verifyFormat("{ cout << a * b << c * d; }");
+  verifyFormat("type (*f)(type *a)");
+  verifyFormat("type (&f)(type *a)");
+  verifyFormat("void f(type *a)");
+  verifyFormat("using f = void (*)(a *b)");
+  verifyFormat("template <typename T = void (*)(a *b)");
+  verifyFormat("using f = void (c::*)(a *b)");
+  verifyFormat("template <typename T = void (c::*)(a *b)>");
+}
+
 TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
   verifyFormat("void f() {\n"
                "  x[aaaaaaaaa -\n"
-- 
1.9.1




More information about the cfe-commits mailing list