clang-format: better detection for multiplication operator

Kapfhammer kapf at student.ethz.ch
Fri Apr 4 09:18:28 PDT 2014


inline

On Fri, Apr 04, 2014 at 08:06:00AM +0200, Daniel Jasper wrote:
> I think this makes more sense for now. If we stumble upon bugs requiring
> the fix for the other operators, we still have your other patch.
> 
> 
> On Thu, Apr 3, 2014 at 10:58 PM, Johannes Kapfhammer <jkapfham at ethz.ch>wrote:
> 
> > 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) &&
> >
> 
> How does this change the behavior in any way?
It was relevant with the old patch.  Now it's only different in a few
special cases:

With it: template<int i = x << a *b>
Without: template<int i = x << a * b>

So I think we don't need it.

> 
> 
> > +               (!Current.Previous ||
> > +                Current.Previous->isNot(tok::kw_operator))) {
> >
> 
> I wonder whether we can just use:
> 
> } else if (Current.is(tok::lessless) && !Line.MustBeDeclaration) { ..
> 
I can't tell for sure if it does the same, but it seems so.

> 
> 
> > +      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)>");
> >
> 
> There are many tests here that don't contain a "<<". What are they testing?
> 
They are not needed anymore.  I thought they don't hurt, but you can
remove them if you want to.

> +}
> >
> +
> >  TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
> >    verifyFormat("void f() {\n"
> >                 "  x[aaaaaaaaa -\n"
> > --
> > 1.9.1
> >
> >



More information about the cfe-commits mailing list