aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-09-16 01:51:54 +0000
committerDouglas Gregor <dgregor@apple.com>2010-09-16 01:51:54 +0000
commit9497a73ad0d54859edbf48beb93ebb19a7ae50c9 (patch)
treec71789bbb2dda9a909fb3655f088085e2f286d10 /lib/Parse
parentb36cd3e1757fb4fcd9509f35558c847b04bef35f (diff)
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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114057 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParseDecl.cpp15
-rw-r--r--lib/Parse/ParseExpr.cpp58
-rw-r--r--lib/Parse/ParseObjc.cpp29
-rw-r--r--lib/Parse/ParseTentative.cpp3
4 files changed, 102 insertions, 3 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 45487e0fd1..ef495e33d8 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2304,7 +2304,10 @@ bool Parser::isTypeSpecifierQualifier() {
/// 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 @@ bool Parser::isDeclarationSpecifier() {
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
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 33c7d67ce1..be468d537d 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -677,6 +677,35 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
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 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
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 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
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();
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 46870d9528..a9cab9ec18 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1862,6 +1862,35 @@ bool Parser::isSimpleObjCMessageExpression() {
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 ']'
///
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index c22d99fa9d..085edb1281 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -821,6 +821,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (NextToken().is(tok::l_paren))
return TPResult::Ambiguous();
+ if (isStartOfObjCClassMessageMissingOpenBracket())
+ return TPResult::False();
+
return TPResult::True();
// GNU typeof support.