Formatter: Get bit tests in ifs right.

It's generally not possible to know if 'a' '*' 'b' is a multiplication
expression or a variable declaration with a purely lexer-based approach. The
formatter currently uses a heuristic that classifies this token sequence as a
multiplication in rhs contexts (after '=' or 'return') and as a declaration
else.

Because of this, it gets bit tests in ifs, such as "if (a & b)" wrong. However,
declarations in ifs always have to be followed by '=', so this patch changes
the formatter to classify '&' as an operator if it's at the start of an if
statement.

Before:
  if (a& b)
  if (int* b = f())

Now:
  if (a & b)
  if (int* b = f())

llvm-svn: 172731
This commit is contained in:
Nico Weber 2013-01-17 17:17:19 +00:00
parent 149d952e86
commit 80a82761bd
2 changed files with 32 additions and 1 deletions

View File

@ -771,13 +771,28 @@ public:
return false;
}
bool parseParens() {
bool parseParens(bool LookForDecls = false) {
if (CurrentToken == NULL)
return false;
AnnotatedToken *Left = CurrentToken->Parent;
if (CurrentToken->is(tok::caret))
Left->Type = TT_ObjCBlockLParen;
while (CurrentToken != NULL) {
// LookForDecls is set when "if (" has been seen. Check for
// 'identifier' '*' 'identifier' followed by not '=' -- this
// '*' has to be a binary operator but determineStarAmpUsage() will
// categorize it as an unary operator, so set the right type here.
if (LookForDecls && !CurrentToken->Children.empty()) {
AnnotatedToken &Prev = *CurrentToken->Parent;
AnnotatedToken &Next = CurrentToken->Children[0];
if (Prev.Parent->is(tok::identifier) &&
(Prev.is(tok::star) || Prev.is(tok::amp)) &&
CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
Prev.Type = TT_BinaryOperator;
LookForDecls = false;
}
}
if (CurrentToken->is(tok::r_paren)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@ -896,6 +911,14 @@ public:
if (ColonIsObjCMethodExpr)
Tok->Type = TT_ObjCMethodExpr;
break;
case tok::kw_if:
case tok::kw_while:
if (CurrentToken->is(tok::l_paren)) {
next();
if (!parseParens(/*LookForDecls=*/true))
return false;
}
break;
case tok::l_paren: {
if (!parseParens())
return false;

View File

@ -1235,6 +1235,14 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
" *A, // Operator detection might be confused by the '{'\n"
" *BB // Operator detection might be confused by previous comment\n"
"};");
verifyFormat("if (int *a = &b)");
verifyFormat("if (int &a = *b)");
verifyFormat("if (a & b[i])");
verifyFormat("if (a::b::c::d & b[i])");
verifyFormat("if (*b[i])");
verifyFormat("if (int *a = (&b))");
verifyFormat("while (int *a = &b)");
}
TEST_F(FormatTest, FormatsCasts) {