[cfe-commits] r114057 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseObjc.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaExprObjC.cpp test/FixIt/fixit-objc-message.m
Douglas Gregor
dgregor at apple.com
Wed Sep 15 18:51:54 PDT 2010
Author: dgregor
Date: Wed Sep 15 20:51:54 2010
New Revision: 114057
URL: http://llvm.org/viewvc/llvm-project?rev=114057&view=rev
Log:
Implement automatic bracket insertion for Objective-C class message
sends. These are far trickier than instance messages, because we
typically have something like
NSArray alloc]
where it appears to be a declaration of a variable named "alloc" up
until we see the ']' (or a ':'), and at that point we can't backtrace.
So, we use a combination of syntactic and semantic disambiguation to
treat this as a message send only when the type is an Objective-C type
and it has the syntax of a class message send (which would otherwise
be ill-formed).
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
cfe/trunk/test/FixIt/fixit-objc-message.m
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Sep 15 20:51:54 2010
@@ -1242,7 +1242,7 @@
void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback);
- bool isDeclarationSpecifier();
+ bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false);
bool isTypeSpecifierQualifier();
bool isTypeQualifier() const;
@@ -1257,7 +1257,7 @@
bool isDeclarationStatement() {
if (getLang().CPlusPlus)
return isCXXDeclarationStatement();
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(true);
}
/// isSimpleDeclaration - Disambiguates between a declaration or an
@@ -1267,9 +1267,13 @@
bool isSimpleDeclaration() {
if (getLang().CPlusPlus)
return isCXXSimpleDeclaration();
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(true);
}
+ /// \brief Determine whether we are currently at the start of an Objective-C
+ /// class message that appears to be missing the open bracket '['.
+ bool isStartOfObjCClassMessageMissingOpenBracket();
+
/// \brief Starting with a scope specifier, identifier, or
/// template-id that refers to the current class, determine whether
/// this is a constructor declarator.
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Sep 15 20:51:54 2010
@@ -2304,7 +2304,10 @@
/// isDeclarationSpecifier() - Return true if the current token is part of a
/// declaration specifier.
-bool Parser::isDeclarationSpecifier() {
+///
+/// \param DisambiguatingWithExpression True to indicate that the purpose of
+/// this check is to disambiguate between an expression and a declaration.
+bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
@@ -2322,6 +2325,16 @@
return true;
if (Tok.is(tok::identifier))
return false;
+
+ // If we're in Objective-C and we have an Objective-C class type followed
+ // by an identifier and then either ':' or ']', in a place where an
+ // expression is permitted, then this is probably a class message send
+ // missing the initial '['. In this case, we won't consider this to be
+ // the start of a declaration.
+ if (DisambiguatingWithExpression &&
+ isStartOfObjCClassMessageMissingOpenBracket())
+ return false;
+
return isDeclarationSpecifier();
case tok::coloncolon: // ::foo::bar
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Sep 15 20:51:54 2010
@@ -677,6 +677,35 @@
break;
}
+ // If we have an Objective-C class name followed by an identifier and
+ // either ':' or ']', this is an Objective-C class message send that's
+ // missing the opening '['. Recovery appropriately.
+ if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+ const Token& Next = NextToken();
+ if (Next.is(tok::colon) || Next.is(tok::r_square))
+ if (ParsedType Type = Actions.getTypeName(II, ILoc, getCurScope()))
+ if (Type.get()->isObjCObjectOrInterfaceType()) {
+ // Fake up a Declarator to use with ActOnTypeName.
+ DeclSpec DS;
+ DS.SetRangeStart(ILoc);
+ DS.SetRangeEnd(ILoc);
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+ DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Type);
+
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
+ DeclaratorInfo);
+ if (Ty.isInvalid())
+ break;
+
+ Res = ParseObjCMessageExpressionBody(SourceLocation(),
+ SourceLocation(),
+ Ty.get(), 0);
+ break;
+ }
+ }
+
// Make sure to pass down the right value for isAddressOfOperand.
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
@@ -791,6 +820,32 @@
Res = ParseCXXThis();
break;
+ case tok::annot_typename:
+ if (isStartOfObjCClassMessageMissingOpenBracket()) {
+ ParsedType Type = getTypeAnnotation(Tok);
+
+ // Fake up a Declarator to use with ActOnTypeName.
+ DeclSpec DS;
+ DS.SetRangeStart(Tok.getLocation());
+ DS.SetRangeEnd(Tok.getLastLoc());
+
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+ DS.SetTypeSpecType(TST_typename, Tok.getLocation(), PrevSpec, DiagID,
+ Type);
+
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ if (Ty.isInvalid())
+ break;
+
+ ConsumeToken();
+ Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
+ Ty.get(), 0);
+ break;
+ }
+ // Fall through
+
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char16_t:
@@ -806,8 +861,7 @@
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
- case tok::kw___vector:
- case tok::annot_typename: {
+ case tok::kw___vector: {
if (!getLang().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Sep 15 20:51:54 2010
@@ -1862,6 +1862,35 @@
GetLookAheadToken(2).is(tok::identifier);
}
+bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
+ if (!getLang().ObjC1 || !NextToken().is(tok::identifier) ||
+ InMessageExpression)
+ return false;
+
+
+ ParsedType Type;
+
+ if (Tok.is(tok::annot_typename))
+ Type = getTypeAnnotation(Tok);
+ else if (Tok.is(tok::identifier))
+ Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
+ getCurScope());
+ else
+ return false;
+
+ if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
+ const Token &AfterNext = GetLookAheadToken(2);
+ if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) {
+ if (Tok.is(tok::identifier))
+ TryAnnotateTypeOrScopeToken();
+
+ return Tok.is(tok::annot_typename);
+ }
+ }
+
+ return false;
+}
+
/// objc-message-expr:
/// '[' objc-receiver objc-message-args ']'
///
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed Sep 15 20:51:54 2010
@@ -821,6 +821,9 @@
if (NextToken().is(tok::l_paren))
return TPResult::Ambiguous();
+ if (isStartOfObjCClassMessageMissingOpenBracket())
+ return TPResult::False();
+
return TPResult::True();
// GNU typeof support.
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Sep 15 20:51:54 2010
@@ -710,7 +710,7 @@
SourceLocation RBracLoc,
MultiExprArg ArgsIn) {
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
- : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
if (LBracLoc.isInvalid()) {
Diag(Loc, diag::err_missing_open_square_message_send)
<< FixItHint::CreateInsertion(Loc, "[");
Modified: cfe/trunk/test/FixIt/fixit-objc-message.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-objc-message.m?rev=114057&r1=114056&r2=114057&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit-objc-message.m (original)
+++ cfe/trunk/test/FixIt/fixit-objc-message.m Wed Sep 15 20:51:54 2010
@@ -21,7 +21,9 @@
int array[17];
(void)array[a method1:5+2 second:+(3.14159)]];
- (A method2:5+2 second:3.14159])
+ (A method2:5+2 second:3.14159]);
+ A method2:5+2 second:3.14159]
+ if (A method2:5+2 second:3.14159]) { }
}
@interface B : A
More information about the cfe-commits
mailing list