From 76f98f8047dee94a3131f733ed99fb6fc23a0cfc Mon Sep 17 00:00:00 2001 From: Dinesh Dwivedi Date: Mon, 5 May 2014 13:14:35 +0000 Subject: [PATCH] Added some heuristics to identify c style casting Before: void f() { my_int a = (my_int) * b; } void f() { return P ? (my_int) * P : (my_int)0; } After: void f() { my_int a = (my_int)*b; } void f() { return P ? (my_int)*P : (my_int)0; } Differential Revision: http://reviews.llvm.org/D3576 llvm-svn: 207964 --- clang/lib/Format/TokenAnnotator.cpp | 44 +++++++++++++++++++++------ clang/unittests/Format/FormatTest.cpp | 19 +++++++----- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 65c0cabffc11..a6e04c54a219 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -756,6 +756,7 @@ private: else Current.Type = TT_BlockComment; } else if (Current.is(tok::r_paren)) { + // FIXME: Pull cast detection into its own function. FormatToken *LeftOfParens = NULL; if (Current.MatchingParen) LeftOfParens = Current.MatchingParen->getPreviousNonComment(); @@ -776,19 +777,42 @@ private: Contexts[Contexts.size() - 2].IsExpression) || (Current.Next && Current.Next->isBinaryOperator()))) IsCast = true; - if (Current.Next && Current.Next->isNot(tok::string_literal) && - (Current.Next->Tok.isLiteral() || - Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) + else if (Current.Next && Current.Next->isNot(tok::string_literal) && + (Current.Next->Tok.isLiteral() || + Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) IsCast = true; // If there is an identifier after the (), it is likely a cast, unless // there is also an identifier before the (). - if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL || - LeftOfParens->is(tok::kw_return)) && - LeftOfParens->Type != TT_OverloadedOperator && - LeftOfParens->isNot(tok::at) && - LeftOfParens->Type != TT_TemplateCloser && Current.Next && - Current.Next->is(tok::identifier)) - IsCast = true; + else if (LeftOfParens && + (LeftOfParens->Tok.getIdentifierInfo() == NULL || + LeftOfParens->is(tok::kw_return)) && + LeftOfParens->Type != TT_OverloadedOperator && + LeftOfParens->isNot(tok::at) && + LeftOfParens->Type != TT_TemplateCloser && Current.Next) { + if (Current.Next->isOneOf(tok::identifier, tok::numeric_constant)) { + IsCast = true; + } else { + // Use heuristics to recognize c style casting. + FormatToken *Prev = Current.Previous; + if (Prev && Prev->isOneOf(tok::amp, tok::star)) + Prev = Prev->Previous; + + if (Prev && Current.Next && Current.Next->Next) { + bool NextIsUnary = Current.Next->isUnaryOperator() || + Current.Next->isOneOf(tok::amp, tok::star); + IsCast = NextIsUnary && + Current.Next->Next->isOneOf(tok::identifier, + tok::numeric_constant); + } + + for (; Prev != Current.MatchingParen; Prev = Prev->Previous) { + if (!Prev || !Prev->isOneOf(tok::kw_const, tok::identifier)) { + IsCast = false; + break; + } + } + } + } if (IsCast && !ParensAreEmpty) Current.Type = TT_CastRParen; } else if (Current.is(tok::at) && Current.Next) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 7db87cb3ce54..d1f4c86bda86 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -4741,12 +4741,18 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("#define x ((int)-1)"); verifyFormat("#define p(q) ((int *)&q)"); - // FIXME: Without type knowledge, this can still fall apart miserably. - verifyFormat("void f() { my_int a = (my_int) * b; }"); - verifyFormat("void f() { return P ? (my_int) * P : (my_int)0; }"); - verifyFormat("my_int a = (my_int) ~0;"); - verifyFormat("my_int a = (my_int)++ a;"); - verifyFormat("my_int a = (my_int) + 2;"); + verifyFormat("void f() { my_int a = (my_int)*b; }"); + verifyFormat("void f() { return P ? (my_int)*P : (my_int)0; }"); + verifyFormat("my_int a = (my_int)~0;"); + verifyFormat("my_int a = (my_int)++a;"); + verifyFormat("my_int a = (my_int)+2;"); + verifyFormat("my_int a = (my_int)1;"); + verifyFormat("my_int a = (my_int *)1;"); + verifyFormat("my_int a = (const my_int)-1;"); + verifyFormat("my_int a = (const my_int *)-1;"); + + // FIXME: single value wrapped with paren will be treated as cast. + verifyFormat("void f(int i = (kValue)*kMask) {}"); // Don't break after a cast's verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaa =\n" @@ -4767,7 +4773,6 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("void f(SmallVector) {}"); verifyFormat("void f(SmallVector);"); verifyFormat("void f(SmallVector) = 0;"); - verifyFormat("void f(int i = (kValue) * kMask) {}"); verifyFormat("void f(int i = (kA * kB) & kMask) {}"); verifyFormat("int a = sizeof(int) * b;"); verifyFormat("int a = alignof(int) * b;", getGoogleStyle());