forked from OSchip/llvm-project
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:
parent
149d952e86
commit
80a82761bd
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue