Improve clang-format's c-style cast detection.

Before:
  x[(uint8) y];
  x = (uint8) y;
  void f() { x = (uint8) y; }
  #define AA(X) sizeof(((X *) NULL)->a)

After:
  x[(uint8)y];
  x = (uint8)y;
  void f() { x = (uint8)y; }
  #define AA(X) sizeof(((X *)NULL)->a)

llvm-svn: 183014
This commit is contained in:
Daniel Jasper 2013-05-31 16:14:28 +00:00
parent 4d14144024
commit da6f225ef9
2 changed files with 44 additions and 14 deletions

View File

@ -602,19 +602,35 @@ private:
else
Current.Type = TT_BlockComment;
} else if (Current.is(tok::r_paren)) {
bool ParensNotExpr = !Current.Previous ||
FormatToken *LeftOfParens = NULL;
if (Current.MatchingParen)
LeftOfParens = Current.MatchingParen->getPreviousNoneComment();
bool IsCast = false;
bool ParensAreEmpty = Current.Previous == Current.MatchingParen;
bool ParensAreType = !Current.Previous ||
Current.Previous->Type == TT_PointerOrReference ||
Current.Previous->Type == TT_TemplateCloser;
Current.Previous->Type == TT_TemplateCloser ||
isSimpleTypeSpecifier(*Current.Previous);
bool ParensCouldEndDecl =
Current.Next &&
Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
bool IsSizeOfOrAlignOf =
Current.MatchingParen && Current.MatchingParen->Previous &&
Current.MatchingParen->Previous->isOneOf(tok::kw_sizeof,
tok::kw_alignof);
if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
LeftOfParens &&
LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
Contexts.back().IsExpression)
// FIXME: We need to get smarter and understand more cases of casts.
IsCast = true;
if (Current.Next &&
(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->Type != TT_ObjCMethodExpr && Current.Next &&
(Current.Next->is(tok::identifier)))
IsCast = true;
if (IsCast && !ParensAreEmpty)
Current.Type = TT_CastRParen;
} else if (Current.is(tok::at) && Current.Next) {
switch (Current.Next->Tok.getObjCKeywordID()) {
@ -677,7 +693,7 @@ private:
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNoneComment();
if (PrevToken == NULL)
if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@ -697,7 +713,7 @@ private:
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
TokenType determineIncrementUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNoneComment();
if (PrevToken == NULL)
if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@ -780,11 +796,11 @@ public:
int CurrentPrecedence = 0;
if (Current) {
if (Current->Type == TT_ConditionalExpr)
CurrentPrecedence = 1 + (int) prec::Conditional;
CurrentPrecedence = 1 + (int)prec::Conditional;
else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon)
CurrentPrecedence = 1;
else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
CurrentPrecedence = 1 + (int) Current->getPrecedence();
CurrentPrecedence = 1 + (int)Current->getPrecedence();
}
// At the end of the line or when an operator with higher precedence is

View File

@ -3173,10 +3173,24 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("Type *A = (Type *)P;");
verifyFormat("Type *A = (vector<Type *, int *>)P;");
verifyFormat("int a = (int)(2.0f);");
verifyFormat("int a = (int)2.0f;");
verifyFormat("x[(int32)y];");
verifyFormat("x = (int32)y;");
verifyFormat("#define AA(X) sizeof(((X *)NULL)->a)");
verifyFormat("int a = (int)*b;");
verifyFormat("int a = (int)2.0f;");
verifyFormat("int a = (int)~0;");
verifyFormat("int a = (int)++a;");
verifyFormat("int a = (int)sizeof(int);");
verifyFormat("int a = (int)+2;");
verifyFormat("my_int a = (my_int)2.0f;");
verifyFormat("my_int a = (my_int)sizeof(int);");
// FIXME: These also need to be identified.
verifyFormat("int a = (int) 2.0f;");
verifyFormat("int a = (int) * b;");
// FIXME: Without type knowledge, this can still fall apart miserably.
verifyFormat("void f() { my_int a = (my_int) * b; }");
verifyFormat("my_int a = (my_int) ~0;");
verifyFormat("my_int a = (my_int)++ a;");
verifyFormat("my_int a = (my_int) + 2;");
// These are not casts.
verifyFormat("void f(int *) {}");