r355831 - clang-format: distinguish ObjC call subexpressions after r355434
Krasimir Georgiev via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 11 09:02:53 PDT 2019
Author: krasimir
Date: Mon Mar 11 09:02:52 2019
New Revision: 355831
URL: http://llvm.org/viewvc/llvm-project?rev=355831&view=rev
Log:
clang-format: distinguish ObjC call subexpressions after r355434
Summary:
The revision r355434 had the unfortunate side-effect that it started to
recognize certain ObjC expressions with a call subexpression followed by a
`a->b` subexpression as C++ lambda expressions.
This patch adds a bit of logic to handle these cases and documents them in
tests.
The commented-out test cases in the new test suite are ones that were
problematic before r355434.
Reviewers: MyDeveloperDay, gribozavr
Reviewed By: MyDeveloperDay, gribozavr
Subscribers: MyDeveloperDay, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D59210
Modified:
cfe/trunk/lib/Format/UnwrappedLineParser.cpp
cfe/trunk/unittests/Format/FormatTestObjC.cpp
Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=355831&r1=355830&r2=355831&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Mon Mar 11 09:02:52 2019
@@ -1401,6 +1401,8 @@ bool UnwrappedLineParser::tryToParseLamb
if (!tryToParseLambdaIntroducer())
return false;
+ bool SeenArrow = false;
+
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isSimpleTypeSpecifier()) {
nextToken();
@@ -1423,8 +1425,19 @@ bool UnwrappedLineParser::tryToParseLamb
case tok::coloncolon:
case tok::kw_mutable:
case tok::kw_noexcept:
+ nextToken();
+ break;
// Specialization of a template with an integer parameter can contain
// arithmetic, logical, comparison and ternary operators.
+ //
+ // FIXME: This also accepts sequences of operators that are not in the scope
+ // of a template argument list.
+ //
+ // In a C++ lambda a template type can only occur after an arrow. We use
+ // this as an heuristic to distinguish between Objective-C expressions
+ // followed by an `a->b` expression, such as:
+ // ([obj func:arg] + a->b)
+ // Otherwise the code below would parse as a lambda.
case tok::plus:
case tok::minus:
case tok::exclaim:
@@ -1444,13 +1457,17 @@ bool UnwrappedLineParser::tryToParseLamb
case tok::colon:
case tok::kw_true:
case tok::kw_false:
- nextToken();
- break;
+ if (SeenArrow) {
+ nextToken();
+ break;
+ }
+ return true;
case tok::arrow:
// This might or might not actually be a lambda arrow (this could be an
// ObjC method invocation followed by a dereferencing arrow). We might
// reset this back to TT_Unknown in TokenAnnotator.
FormatTok->Type = TT_LambdaArrow;
+ SeenArrow = true;
nextToken();
break;
default:
Modified: cfe/trunk/unittests/Format/FormatTestObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestObjC.cpp?rev=355831&r1=355830&r2=355831&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestObjC.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestObjC.cpp Mon Mar 11 09:02:52 2019
@@ -1329,6 +1329,34 @@ TEST_F(FormatTestObjC, AlwaysBreakBefore
" @\"fffff\"];");
}
+TEST_F(FormatTestObjC, DisambiguatesCallsFromCppLambdas) {
+ verifyFormat("x = ([a foo:bar] && b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + !b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + ~b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] - b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] / b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] % b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] | b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] || b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] && b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] == b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] != b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] <= b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] >= b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] << b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] ? b->c == 'd' : 'e');");
+ // FIXME: The following are wrongly classified as C++ lambda expressions.
+ // For example this code:
+ // x = ([a foo:bar] & b->c == 'd');
+ // is formatted as:
+ // x = ([a foo:bar] & b -> c == 'd');
+ // verifyFormat("x = ([a foo:bar] & b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] > b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] < b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] >> b->c == 'd');");
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
More information about the cfe-commits
mailing list