2008-01-08 03:49:32 +08:00
|
|
|
//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Objective-C portions of the Parser interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2010-09-15 22:51:05 +08:00
|
|
|
#include "RAIIObjectsForParser.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
2010-08-27 07:41:50 +08:00
|
|
|
#include "clang/Sema/PrettyDeclStackTrace.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/Scope.h"
|
2006-11-05 10:08:13 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-09-18 03:15:26 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2006-11-05 10:08:13 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2013-04-04 01:36:11 +08:00
|
|
|
/// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
|
2013-04-04 08:15:10 +08:00
|
|
|
void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
|
2013-04-04 01:36:11 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
2013-04-04 08:15:10 +08:00
|
|
|
if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
|
|
|
|
Diag(Tok, diag::err_objc_postfix_attribute_hint)
|
|
|
|
<< (Kind == tok::objc_protocol);
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_objc_postfix_attribute);
|
2013-04-04 01:36:11 +08:00
|
|
|
ParseGNUAttributes(attrs);
|
|
|
|
}
|
|
|
|
}
|
2006-11-05 10:08:13 +08:00
|
|
|
|
2008-12-09 05:53:24 +08:00
|
|
|
/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
|
2006-11-05 10:08:13 +08:00
|
|
|
/// external-declaration: [C99 6.9]
|
|
|
|
/// [OBJC] objc-class-definition
|
2007-10-30 05:39:29 +08:00
|
|
|
/// [OBJC] objc-class-declaration
|
|
|
|
/// [OBJC] objc-alias-declaration
|
|
|
|
/// [OBJC] objc-protocol-definition
|
|
|
|
/// [OBJC] objc-method-definition
|
|
|
|
/// [OBJC] '@' 'end'
|
2011-08-28 04:50:59 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
|
2006-11-05 10:08:13 +08:00
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return DeclGroupPtrTy();
|
2009-12-07 17:27:33 +08:00
|
|
|
}
|
2011-08-28 04:50:59 +08:00
|
|
|
|
|
|
|
Decl *SingleDecl = 0;
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_class:
|
|
|
|
return ParseObjCAtClassDeclaration(AtLoc);
|
2010-12-24 10:08:15 +08:00
|
|
|
case tok::objc_interface: {
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
|
|
|
|
break;
|
2010-12-24 10:08:15 +08:00
|
|
|
}
|
|
|
|
case tok::objc_protocol: {
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2012-01-02 05:23:57 +08:00
|
|
|
return ParseObjCAtProtocolDeclaration(AtLoc, attrs);
|
2010-12-24 10:08:15 +08:00
|
|
|
}
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_implementation:
|
2012-02-08 00:50:53 +08:00
|
|
|
return ParseObjCAtImplementationDeclaration(AtLoc);
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_end:
|
2011-09-01 01:37:55 +08:00
|
|
|
return ParseObjCAtEndDeclaration(AtLoc);
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_compatibility_alias:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
|
|
|
|
break;
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_synthesize:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCPropertySynthesize(AtLoc);
|
|
|
|
break;
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_dynamic:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
|
|
|
|
break;
|
2012-12-12 06:11:52 +08:00
|
|
|
case tok::objc_import:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().Modules)
|
2012-01-04 02:24:14 +08:00
|
|
|
return ParseModuleImport(AtLoc);
|
|
|
|
|
|
|
|
// Fall through
|
|
|
|
|
2008-08-23 10:02:23 +08:00
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = 0;
|
|
|
|
break;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2011-08-28 04:50:59 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(SingleDecl);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-class-declaration:
|
2006-11-05 10:08:13 +08:00
|
|
|
/// '@' 'class' identifier-list ';'
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2011-08-28 04:50:59 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken(); // the identifier "class"
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 8> ClassNames;
|
|
|
|
SmallVector<SourceLocation, 8> ClassLocs;
|
2009-11-18 07:12:20 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
while (1) {
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_class);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2006-11-10 13:19:25 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2006-11-05 10:08:13 +08:00
|
|
|
SkipUntil(tok::semi);
|
2011-08-28 04:50:59 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(0);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
ClassNames.push_back(Tok.getIdentifierInfo());
|
2009-11-18 07:12:20 +08:00
|
|
|
ClassLocs.push_back(Tok.getLocation());
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2006-11-05 10:08:13 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
// Consume the ';'.
|
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
|
2011-08-28 04:50:59 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-18 07:12:20 +08:00
|
|
|
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
|
|
|
|
ClassLocs.data(),
|
|
|
|
ClassNames.size());
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2011-12-06 17:25:23 +08:00
|
|
|
void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
|
|
|
|
{
|
|
|
|
Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
|
|
|
|
if (ock == Sema::OCK_None)
|
|
|
|
return;
|
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
Decl *Decl = Actions.getObjCDeclContext();
|
|
|
|
if (CurParsedObjCImpl) {
|
|
|
|
CurParsedObjCImpl->finish(AtLoc);
|
|
|
|
} else {
|
|
|
|
Actions.ActOnAtEnd(getCurScope(), AtLoc);
|
|
|
|
}
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
|
|
|
|
if (Decl)
|
|
|
|
Diag(Decl->getLocStart(), diag::note_objc_container_start)
|
|
|
|
<< (int) ock;
|
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-interface:
|
|
|
|
/// objc-class-interface-attributes[opt] objc-class-interface
|
|
|
|
/// objc-category-interface
|
|
|
|
///
|
|
|
|
/// objc-class-interface:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// '@' 'interface' identifier objc-superclass[opt]
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-protocol-refs[opt]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-class-instance-variables[opt]
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-category-interface:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// '@' 'interface' identifier '(' identifier[opt] ')'
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-protocol-refs[opt]
|
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-superclass:
|
|
|
|
/// ':' identifier
|
|
|
|
///
|
|
|
|
/// objc-class-interface-attributes:
|
|
|
|
/// __attribute__((visibility("default")))
|
|
|
|
/// __attribute__((visibility("hidden")))
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
/// __attribute__((unavailable))
|
|
|
|
/// __attribute__((objc_exception)) - used by NSException on 64-bit
|
2012-04-07 02:12:22 +08:00
|
|
|
/// __attribute__((objc_root_class))
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2011-12-06 17:25:23 +08:00
|
|
|
Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
2010-12-24 10:08:15 +08:00
|
|
|
ParsedAttributes &attrs) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
|
2007-08-21 05:31:48 +08:00
|
|
|
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
|
2011-12-06 17:25:23 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
2007-08-21 05:31:48 +08:00
|
|
|
ConsumeToken(); // the "interface" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 00:26:39 +08:00
|
|
|
// Code completion after '@interface'.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_interface);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing class or category name.
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2009-11-17 02:57:01 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
// We have a class or category name - consume it.
|
2007-08-23 06:17:26 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-08-21 05:31:48 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
2010-04-27 05:18:08 +08:00
|
|
|
if (Tok.is(tok::l_paren) &&
|
|
|
|
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
|
2011-10-13 00:37:45 +08:00
|
|
|
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
|
|
|
SourceLocation categoryLoc;
|
2007-08-21 05:31:48 +08:00
|
|
|
IdentifierInfo *categoryId = 0;
|
2009-11-19 03:08:43 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 03:08:43 +08:00
|
|
|
}
|
|
|
|
|
2007-08-24 03:56:30 +08:00
|
|
|
// For ObjC2, the category name is optional (not an error).
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
2010-04-03 07:15:40 +08:00
|
|
|
}
|
2012-03-11 15:00:24 +08:00
|
|
|
else if (!getLangOpts().ObjC2) {
|
2007-08-24 03:56:30 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing category name.
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
|
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid())
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2011-09-24 03:19:41 +08:00
|
|
|
|
|
|
|
if (!attrs.empty()) { // categories don't support attributes.
|
|
|
|
Diag(nameLoc, diag::err_objc_no_attributes_on_category);
|
|
|
|
attrs.clear();
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2011-09-24 03:19:41 +08:00
|
|
|
|
2010-04-27 05:18:08 +08:00
|
|
|
// Next, we need to check for any protocol references.
|
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolRefs;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2010-04-27 05:18:08 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
|
2009-09-30 03:41:44 +08:00
|
|
|
LAngleLoc, EndProtoLoc))
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2010-04-03 07:15:40 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *CategoryType =
|
2011-12-06 17:25:23 +08:00
|
|
|
Actions.ActOnStartCategoryInterface(AtLoc,
|
2010-04-27 05:18:08 +08:00
|
|
|
nameId, nameLoc,
|
|
|
|
categoryId, categoryLoc,
|
|
|
|
ProtocolRefs.data(),
|
|
|
|
ProtocolRefs.size(),
|
|
|
|
ProtocolLocs.data(),
|
|
|
|
EndProtoLoc);
|
2011-08-20 02:02:47 +08:00
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2011-12-06 17:25:23 +08:00
|
|
|
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
|
2010-04-27 05:18:08 +08:00
|
|
|
return CategoryType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
// Parse a class interface.
|
|
|
|
IdentifierInfo *superClassId = 0;
|
|
|
|
SourceLocation superClassLoc;
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) { // a super class is specified.
|
2007-08-21 05:31:48 +08:00
|
|
|
ConsumeToken();
|
2009-11-19 00:26:39 +08:00
|
|
|
|
|
|
|
// Code completion of superclass names.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing super class name.
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken();
|
|
|
|
}
|
|
|
|
// Next, we need to check for any protocol references.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolRefs;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2009-09-30 03:41:44 +08:00
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
2008-07-26 12:13:19 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
2009-09-30 03:41:44 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
|
|
|
|
LAngleLoc, EndProtoLoc))
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-09-26 03:36:32 +08:00
|
|
|
if (Tok.isNot(tok::less))
|
|
|
|
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
|
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *ClsType =
|
2011-12-06 17:25:23 +08:00
|
|
|
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
|
2008-07-26 12:13:19 +08:00
|
|
|
superClassId, superClassLoc,
|
2009-05-21 17:52:38 +08:00
|
|
|
ProtocolRefs.data(), ProtocolRefs.size(),
|
2010-01-16 23:02:53 +08:00
|
|
|
ProtocolLocs.data(),
|
2010-12-24 10:08:15 +08:00
|
|
|
EndProtoLoc, attrs.getList());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2011-12-06 17:25:23 +08:00
|
|
|
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
|
2007-08-21 05:31:48 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
|
2010-04-27 05:18:08 +08:00
|
|
|
return ClsType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
2009-12-04 06:31:13 +08:00
|
|
|
/// The Objective-C property callback. This should be defined where
|
|
|
|
/// it's used, but instead it's been lifted to here to support VS2005.
|
|
|
|
struct Parser::ObjCPropertyCallback : FieldCallback {
|
2011-12-20 10:48:34 +08:00
|
|
|
private:
|
|
|
|
virtual void anchor();
|
|
|
|
public:
|
2009-12-04 06:31:13 +08:00
|
|
|
Parser &P;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &Props;
|
2009-12-04 06:31:13 +08:00
|
|
|
ObjCDeclSpec &OCDS;
|
|
|
|
SourceLocation AtLoc;
|
2012-03-01 06:18:55 +08:00
|
|
|
SourceLocation LParenLoc;
|
2009-12-04 06:31:13 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind;
|
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
ObjCPropertyCallback(Parser &P,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &Props,
|
2009-12-04 06:31:13 +08:00
|
|
|
ObjCDeclSpec &OCDS, SourceLocation AtLoc,
|
2012-03-01 06:18:55 +08:00
|
|
|
SourceLocation LParenLoc,
|
2009-12-04 06:31:13 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind) :
|
2012-03-01 06:18:55 +08:00
|
|
|
P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc),
|
2009-12-04 06:31:13 +08:00
|
|
|
MethodImplKind(MethodImplKind) {
|
|
|
|
}
|
|
|
|
|
2012-08-09 07:53:27 +08:00
|
|
|
void invoke(ParsingFieldDeclarator &FD) {
|
2009-12-04 06:31:13 +08:00
|
|
|
if (FD.D.getIdentifier() == 0) {
|
|
|
|
P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
|
|
|
|
<< FD.D.getSourceRange();
|
2012-08-09 07:53:27 +08:00
|
|
|
return;
|
2009-12-04 06:31:13 +08:00
|
|
|
}
|
|
|
|
if (FD.BitfieldSize) {
|
|
|
|
P.Diag(AtLoc, diag::err_objc_property_bitfield)
|
|
|
|
<< FD.D.getSourceRange();
|
2012-08-09 07:53:27 +08:00
|
|
|
return;
|
2009-12-04 06:31:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Install the property declarator into interfaceDecl.
|
|
|
|
IdentifierInfo *SelName =
|
|
|
|
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
|
|
|
|
|
|
|
|
Selector GetterSel =
|
|
|
|
P.PP.getSelectorTable().getNullarySelector(SelName);
|
|
|
|
IdentifierInfo *SetterName = OCDS.getSetterName();
|
|
|
|
Selector SetterSel;
|
|
|
|
if (SetterName)
|
|
|
|
SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
|
|
|
|
else
|
2013-06-08 06:29:12 +08:00
|
|
|
SetterSel =
|
|
|
|
SelectorTable::constructSetterSelector(P.PP.getIdentifierTable(),
|
|
|
|
P.PP.getSelectorTable(),
|
|
|
|
FD.D.getIdentifier());
|
2009-12-04 06:31:13 +08:00
|
|
|
bool isOverridingProperty = false;
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Property =
|
2012-03-01 06:18:55 +08:00
|
|
|
P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc,
|
|
|
|
FD, OCDS,
|
2011-08-22 23:54:49 +08:00
|
|
|
GetterSel, SetterSel,
|
2009-12-04 06:31:13 +08:00
|
|
|
&isOverridingProperty,
|
|
|
|
MethodImplKind);
|
|
|
|
if (!isOverridingProperty)
|
|
|
|
Props.push_back(Property);
|
|
|
|
|
2012-08-09 07:04:35 +08:00
|
|
|
FD.complete(Property);
|
2009-12-04 06:31:13 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void Parser::ObjCPropertyCallback::anchor() {
|
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list:
|
|
|
|
/// empty
|
|
|
|
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-interface-decl-list objc-method-requirement [OBJC2]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-interface-decl-list objc-method-proto ';'
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list declaration
|
|
|
|
/// objc-interface-decl-list ';'
|
|
|
|
///
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-method-requirement: [OBJC2]
|
|
|
|
/// @required
|
|
|
|
/// @optional
|
|
|
|
///
|
2011-08-23 05:44:58 +08:00
|
|
|
void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
|
|
|
|
Decl *CDecl) {
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> allMethods;
|
|
|
|
SmallVector<Decl *, 16> allProperties;
|
|
|
|
SmallVector<DeclGroupPtrTy, 8> allTUVariables;
|
2007-09-18 08:25:23 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-07 09:20:12 +08:00
|
|
|
SourceRange AtEnd;
|
2011-08-23 05:44:58 +08:00
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
while (1) {
|
2008-10-20 13:46:22 +08:00
|
|
|
// If this is a method prototype, parse it.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
|
2012-07-27 01:32:28 +08:00
|
|
|
if (Decl *methodPrototype =
|
|
|
|
ParseObjCMethodPrototype(MethodImplKind, false))
|
|
|
|
allMethods.push_back(methodPrototype);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
|
|
|
|
// method definitions.
|
2011-12-17 12:13:22 +08:00
|
|
|
if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
|
|
|
|
// We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
|
2011-12-17 12:13:22 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-04-03 07:15:40 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected_minus_or_plus);
|
2010-08-21 17:40:31 +08:00
|
|
|
ParseObjCMethodDecl(Tok.getLocation(),
|
|
|
|
tok::minus,
|
2011-03-13 02:54:30 +08:00
|
|
|
MethodImplKind, false);
|
2010-04-03 07:15:40 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-10-20 13:46:22 +08:00
|
|
|
// Ignore excess semicolons.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken();
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// If we got to the end of the file, exit the loop.
|
2008-10-20 13:46:22 +08:00
|
|
|
if (Tok.is(tok::eof))
|
2007-09-11 04:33:04 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-14 05:24:21 +08:00
|
|
|
// Code completion within an Objective-C interface.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(),
|
2012-02-08 00:50:53 +08:00
|
|
|
CurParsedObjCImpl? Sema::PCC_ObjCImplementation
|
2010-08-27 07:41:50 +08:00
|
|
|
: Sema::PCC_ObjCInterface);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:24:21 +08:00
|
|
|
}
|
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// If we don't have an @ directive, parse it as a function definition.
|
|
|
|
if (Tok.isNot(tok::at)) {
|
2009-01-09 12:34:13 +08:00
|
|
|
// The code below does not consume '}'s because it is afraid of eating the
|
|
|
|
// end of a namespace. Because of the way this code is structured, an
|
|
|
|
// erroneous r_brace would cause an infinite loop if not handled here.
|
|
|
|
if (Tok.is(tok::r_brace))
|
|
|
|
break;
|
2012-06-23 13:07:58 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Otherwise, we have an @ directive, eat the @.
|
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-12-07 17:27:33 +08:00
|
|
|
}
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
|
2010-01-07 09:20:12 +08:00
|
|
|
AtEnd.setBegin(AtLoc);
|
|
|
|
AtEnd.setEnd(Tok.getLocation());
|
2008-10-20 13:46:22 +08:00
|
|
|
break;
|
2010-03-16 14:04:47 +08:00
|
|
|
} else if (DirectiveKind == tok::objc_not_keyword) {
|
|
|
|
Diag(Tok, diag::err_objc_unknown_at);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
continue;
|
2008-10-20 14:10:06 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
switch (DirectiveKind) {
|
|
|
|
default:
|
2008-10-20 14:10:06 +08:00
|
|
|
// FIXME: If someone forgets an @end on a protocol, this loop will
|
|
|
|
// continue to eat up tons of stuff and spew lots of nonsense errors. It
|
|
|
|
// would probably be better to bail out if we saw an @class or @interface
|
|
|
|
// or something like that.
|
2008-10-20 15:22:18 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_illegal_interface_qual);
|
2008-10-20 14:10:06 +08:00
|
|
|
// Skip until we see an '@' or '}' or ';'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, tok::at, StopAtSemi);
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2010-11-02 08:44:43 +08:00
|
|
|
|
|
|
|
case tok::objc_implementation:
|
2010-11-10 04:38:00 +08:00
|
|
|
case tok::objc_interface:
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
|
|
|
|
Diag(CDecl->getLocStart(), diag::note_objc_container_start)
|
|
|
|
<< (int) Actions.getObjCContainerKind();
|
2010-11-02 08:44:43 +08:00
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
case tok::objc_required:
|
|
|
|
case tok::objc_optional:
|
|
|
|
// This is only valid on protocols.
|
2008-10-20 14:10:06 +08:00
|
|
|
// FIXME: Should this check for ObjC2 being enabled?
|
2008-10-20 13:46:22 +08:00
|
|
|
if (contextKey != tok::objc_protocol)
|
2008-10-20 14:10:06 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
|
2008-10-20 13:57:40 +08:00
|
|
|
else
|
2008-10-20 14:10:06 +08:00
|
|
|
MethodImplKind = DirectiveKind;
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
case tok::objc_property:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().ObjC2)
|
2010-12-17 13:40:22 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_properties_require_objc2);
|
2008-10-20 15:22:18 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
ObjCDeclSpec OCDS;
|
2012-03-01 06:18:55 +08:00
|
|
|
SourceLocation LParenLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
// Parse property attribute list, if any.
|
2012-03-01 06:18:55 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
LParenLoc = Tok.getLocation();
|
2011-08-22 23:54:49 +08:00
|
|
|
ParseObjCPropertyAttribute(OCDS);
|
2012-03-01 06:18:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
ObjCPropertyCallback Callback(*this, allProperties,
|
2012-03-01 06:18:55 +08:00
|
|
|
OCDS, AtLoc, LParenLoc, MethodImplKind);
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Parse all the comma separated declarators.
|
2012-08-09 07:04:35 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2009-11-03 10:38:08 +08:00
|
|
|
ParseStructDeclaration(DS, Callback);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-26 09:53:26 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2007-09-06 07:30:30 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2008-10-20 14:10:06 +08:00
|
|
|
|
|
|
|
// We break out of the big loop in two cases: when we see @end or when we see
|
|
|
|
// EOF. In the former case, eat the @end. In the later case, emit an error.
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2011-12-06 17:25:23 +08:00
|
|
|
} else if (Tok.isObjCAtKeyword(tok::objc_end)) {
|
2008-10-20 14:10:06 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2011-12-06 17:25:23 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
|
|
|
|
Diag(CDecl->getLocStart(), diag::note_objc_container_start)
|
|
|
|
<< (int) Actions.getObjCContainerKind();
|
|
|
|
AtEnd.setBegin(Tok.getLocation());
|
|
|
|
AtEnd.setEnd(Tok.getLocation());
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
// Insert collected methods declarations into the @interface object.
|
2008-10-20 14:10:06 +08:00
|
|
|
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
|
2013-07-16 23:33:19 +08:00
|
|
|
Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2007-09-01 00:11:31 +08:00
|
|
|
/// Parse property attribute declarations.
|
|
|
|
///
|
|
|
|
/// property-attr-decl: '(' property-attrlist ')'
|
|
|
|
/// property-attrlist:
|
|
|
|
/// property-attribute
|
|
|
|
/// property-attrlist ',' property-attribute
|
|
|
|
/// property-attribute:
|
|
|
|
/// getter '=' identifier
|
|
|
|
/// setter '=' identifier ':'
|
|
|
|
/// readonly
|
|
|
|
/// readwrite
|
|
|
|
/// assign
|
|
|
|
/// retain
|
|
|
|
/// copy
|
|
|
|
/// nonatomic
|
2011-06-16 07:02:42 +08:00
|
|
|
/// atomic
|
|
|
|
/// strong
|
|
|
|
/// weak
|
|
|
|
/// unsafe_unretained
|
2007-09-01 00:11:31 +08:00
|
|
|
///
|
2011-08-22 23:54:49 +08:00
|
|
|
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
|
2008-10-20 15:24:39 +08:00
|
|
|
assert(Tok.getKind() == tok::l_paren);
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:15:22 +08:00
|
|
|
while (1) {
|
2009-10-09 05:55:05 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-10-09 05:55:05 +08:00
|
|
|
}
|
2007-09-01 00:11:31 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:22:18 +08:00
|
|
|
// If this is not an identifier at all, bail out early.
|
|
|
|
if (II == 0) {
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-10-20 15:22:18 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
SourceLocation AttrName = ConsumeToken(); // consume last attribute name
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-20 12:42:34 +08:00
|
|
|
if (II->isStr("readonly"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("assign"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("unsafe_unretained"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("readwrite"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("retain"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("strong"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("copy"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("nonatomic"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
|
2011-06-11 08:45:12 +08:00
|
|
|
else if (II->isStr("atomic"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("weak"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("getter") || II->isStr("setter")) {
|
2010-10-03 01:45:21 +08:00
|
|
|
bool IsSetter = II->getNameStart()[0] == 's';
|
|
|
|
|
2008-10-20 15:39:53 +08:00
|
|
|
// getter/setter require extra treatment.
|
2010-10-03 01:45:21 +08:00
|
|
|
unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
|
|
|
|
diag::err_objc_expected_equal_for_getter;
|
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::equal, DiagID, "", tok::r_paren))
|
2008-10-20 15:00:43 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 15:41:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-10-03 01:45:21 +08:00
|
|
|
if (IsSetter)
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertySetter(getCurScope());
|
2009-11-19 15:41:15 +08:00
|
|
|
else
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyGetter(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-11-19 15:41:15 +08:00
|
|
|
}
|
|
|
|
|
2010-10-03 01:45:21 +08:00
|
|
|
|
|
|
|
SourceLocation SelLoc;
|
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
|
|
|
|
|
|
|
|
if (!SelIdent) {
|
|
|
|
Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
|
|
|
|
<< IsSetter;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:24:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-03 01:45:21 +08:00
|
|
|
if (IsSetter) {
|
2008-10-20 15:24:39 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
|
2010-10-03 01:45:21 +08:00
|
|
|
DS.setSetterName(SelIdent);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 06:20:11 +08:00
|
|
|
if (ExpectAndConsume(tok::colon,
|
|
|
|
diag::err_expected_colon_after_setter_name, "",
|
2008-10-20 15:37:22 +08:00
|
|
|
tok::r_paren))
|
2008-10-20 15:24:39 +08:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
|
2010-10-03 01:45:21 +08:00
|
|
|
DS.setGetterName(SelIdent);
|
2008-10-20 15:24:39 +08:00
|
|
|
}
|
2008-10-20 15:39:53 +08:00
|
|
|
} else {
|
2008-11-19 15:49:38 +08:00
|
|
|
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:15:22 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
ConsumeToken();
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-proto:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-instance-method objc-method-decl objc-method-attributes[opt]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-class-method objc-method-decl objc-method-attributes[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-method: '-'
|
|
|
|
/// objc-class-method: '+'
|
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-method-attributes: [OBJC2]
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
///
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
|
2011-03-13 02:54:30 +08:00
|
|
|
bool MethodDefinition) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
tok::TokenKind methodType = Tok.getKind();
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation mLoc = ConsumeToken();
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
|
2011-03-13 02:54:30 +08:00
|
|
|
MethodDefinition);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Since this rule is used for both method declarations and definitions,
|
2007-09-11 04:51:04 +08:00
|
|
|
// the caller is (optionally) responsible for consuming the ';'.
|
2007-09-06 07:30:30 +08:00
|
|
|
return MDecl;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-selector:
|
|
|
|
/// identifier
|
|
|
|
/// one of
|
|
|
|
/// enum struct union if else while do for switch case default
|
|
|
|
/// break continue return goto asm sizeof typeof __alignof
|
|
|
|
/// unsigned long const short volatile signed restrict _Complex
|
|
|
|
/// in out inout bycopy byref oneway int char float double void _Bool
|
|
|
|
///
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
|
2010-09-03 09:26:16 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default:
|
|
|
|
return 0;
|
2010-09-04 01:33:04 +08:00
|
|
|
case tok::ampamp:
|
|
|
|
case tok::ampequal:
|
|
|
|
case tok::amp:
|
|
|
|
case tok::pipe:
|
|
|
|
case tok::tilde:
|
|
|
|
case tok::exclaim:
|
|
|
|
case tok::exclaimequal:
|
|
|
|
case tok::pipepipe:
|
|
|
|
case tok::pipeequal:
|
|
|
|
case tok::caret:
|
|
|
|
case tok::caretequal: {
|
2010-09-04 02:01:09 +08:00
|
|
|
std::string ThisTok(PP.getSpelling(Tok));
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isLetter(ThisTok[0])) {
|
2010-09-04 01:33:04 +08:00
|
|
|
IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data());
|
|
|
|
Tok.setKind(tok::identifier);
|
|
|
|
SelectorLoc = ConsumeToken();
|
|
|
|
return II;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::identifier:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_asm:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw_auto:
|
2007-11-15 13:25:19 +08:00
|
|
|
case tok::kw_bool:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_break:
|
|
|
|
case tok::kw_case:
|
|
|
|
case tok::kw_catch:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_const_cast:
|
|
|
|
case tok::kw_continue:
|
|
|
|
case tok::kw_default:
|
|
|
|
case tok::kw_delete:
|
|
|
|
case tok::kw_do:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_dynamic_cast:
|
|
|
|
case tok::kw_else:
|
|
|
|
case tok::kw_enum:
|
|
|
|
case tok::kw_explicit:
|
|
|
|
case tok::kw_export:
|
|
|
|
case tok::kw_extern:
|
|
|
|
case tok::kw_false:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_friend:
|
|
|
|
case tok::kw_goto:
|
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_inline:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_mutable:
|
|
|
|
case tok::kw_namespace:
|
|
|
|
case tok::kw_new:
|
|
|
|
case tok::kw_operator:
|
|
|
|
case tok::kw_private:
|
|
|
|
case tok::kw_protected:
|
|
|
|
case tok::kw_public:
|
|
|
|
case tok::kw_register:
|
|
|
|
case tok::kw_reinterpret_cast:
|
|
|
|
case tok::kw_restrict:
|
|
|
|
case tok::kw_return:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_sizeof:
|
|
|
|
case tok::kw_static:
|
|
|
|
case tok::kw_static_cast:
|
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_switch:
|
|
|
|
case tok::kw_template:
|
|
|
|
case tok::kw_this:
|
|
|
|
case tok::kw_throw:
|
|
|
|
case tok::kw_true:
|
|
|
|
case tok::kw_try:
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_typeid:
|
|
|
|
case tok::kw_typename:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
case tok::kw_union:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_using:
|
|
|
|
case tok::kw_virtual:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
case tok::kw_while:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Complex:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw___alignof:
|
2007-10-07 10:00:24 +08:00
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
2007-10-11 08:55:41 +08:00
|
|
|
SelectorLoc = ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
return II;
|
2007-09-28 03:52:15 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-01-03 06:54:34 +08:00
|
|
|
/// objc-for-collection-in: 'in'
|
|
|
|
///
|
2008-01-05 07:04:08 +08:00
|
|
|
bool Parser::isTokIdentifier_in() const {
|
2008-01-04 01:55:25 +08:00
|
|
|
// FIXME: May have to do additional look-ahead to only allow for
|
|
|
|
// valid tokens following an 'in'; such as an identifier, unary operators,
|
|
|
|
// '[' etc.
|
2012-03-11 15:00:24 +08:00
|
|
|
return (getLangOpts().ObjC2 && Tok.is(tok::identifier) &&
|
2008-08-23 10:02:23 +08:00
|
|
|
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
|
2008-01-03 06:54:34 +08:00
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
/// ParseObjCTypeQualifierList - This routine parses the objective-c's type
|
2007-12-12 14:56:32 +08:00
|
|
|
/// qualifier list and builds their bitmask representation in the input
|
|
|
|
/// argument.
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-type-qualifiers:
|
|
|
|
/// objc-type-qualifier
|
|
|
|
/// objc-type-qualifiers objc-type-qualifier
|
|
|
|
///
|
2011-03-09 03:17:54 +08:00
|
|
|
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
|
2011-10-01 17:56:14 +08:00
|
|
|
Declarator::TheContext Context) {
|
|
|
|
assert(Context == Declarator::ObjCParameterContext ||
|
|
|
|
Context == Declarator::ObjCResultContext);
|
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
while (1) {
|
2010-08-24 09:06:58 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-03-09 03:17:54 +08:00
|
|
|
Actions.CodeCompleteObjCPassingType(getCurScope(), DS,
|
2011-10-01 17:56:14 +08:00
|
|
|
Context == Declarator::ObjCParameterContext);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-24 09:06:58 +08:00
|
|
|
}
|
|
|
|
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2007-12-12 14:56:32 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
for (unsigned i = 0; i != objc_NumQuals; ++i) {
|
2008-01-08 03:49:32 +08:00
|
|
|
if (II != ObjCTypeQuals[i])
|
2007-12-12 14:56:32 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec::ObjCDeclQualifier Qual;
|
2007-12-12 14:56:32 +08:00
|
|
|
switch (i) {
|
2011-09-23 13:06:16 +08:00
|
|
|
default: llvm_unreachable("Unknown decl qualifier");
|
2008-01-08 03:49:32 +08:00
|
|
|
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
|
|
|
|
case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
|
|
|
|
case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
|
|
|
|
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
|
|
|
|
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
|
|
|
|
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
|
2007-12-12 14:56:32 +08:00
|
|
|
}
|
2008-01-08 03:49:32 +08:00
|
|
|
DS.setObjCDeclQualifier(Qual);
|
2007-12-12 14:56:32 +08:00
|
|
|
ConsumeToken();
|
|
|
|
II = 0;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
// If this wasn't a recognized qualifier, bail out.
|
|
|
|
if (II) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-01 17:56:14 +08:00
|
|
|
/// Take all the decl attributes out of the given list and add
|
|
|
|
/// them to the given attribute set.
|
|
|
|
static void takeDeclAttributes(ParsedAttributes &attrs,
|
|
|
|
AttributeList *list) {
|
|
|
|
while (list) {
|
|
|
|
AttributeList *cur = list;
|
|
|
|
list = cur->getNext();
|
|
|
|
|
|
|
|
if (!cur->isUsedAsTypeAttr()) {
|
|
|
|
// Clear out the next pointer. We're really completely
|
|
|
|
// destroying the internal invariants of the declarator here,
|
|
|
|
// but it doesn't matter because we're done with it.
|
|
|
|
cur->setNext(0);
|
|
|
|
attrs.add(cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takeDeclAttributes - Take all the decl attributes from the given
|
|
|
|
/// declarator and add them to the given list.
|
|
|
|
static void takeDeclAttributes(ParsedAttributes &attrs,
|
|
|
|
Declarator &D) {
|
|
|
|
// First, take ownership of all attributes.
|
|
|
|
attrs.getPool().takeAllFrom(D.getAttributePool());
|
|
|
|
attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
|
|
|
|
|
|
|
|
// Now actually move the attributes over.
|
|
|
|
takeDeclAttributes(attrs, D.getDeclSpec().getAttributes().getList());
|
|
|
|
takeDeclAttributes(attrs, D.getAttributes());
|
|
|
|
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
|
|
|
|
takeDeclAttributes(attrs,
|
|
|
|
const_cast<AttributeList*>(D.getTypeObject(i).getAttrs()));
|
|
|
|
}
|
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
/// objc-type-name:
|
|
|
|
/// '(' objc-type-qualifiers[opt] type-name ')'
|
|
|
|
/// '(' objc-type-qualifiers[opt] ')'
|
|
|
|
///
|
2011-03-09 03:17:54 +08:00
|
|
|
ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
|
2011-10-01 17:56:14 +08:00
|
|
|
Declarator::TheContext context,
|
|
|
|
ParsedAttributes *paramAttrs) {
|
|
|
|
assert(context == Declarator::ObjCParameterContext ||
|
|
|
|
context == Declarator::ObjCResultContext);
|
|
|
|
assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext));
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_paren) && "expected (");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2008-08-23 09:48:03 +08:00
|
|
|
SourceLocation TypeStartLoc = Tok.getLocation();
|
2011-08-23 01:59:19 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
|
|
|
|
2007-11-01 05:59:43 +08:00
|
|
|
// Parse type qualifiers, in, inout, etc.
|
2011-10-01 17:56:14 +08:00
|
|
|
ParseObjCTypeQualifierList(DS, context);
|
2007-08-23 07:18:22 +08:00
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType Ty;
|
2009-02-19 01:45:20 +08:00
|
|
|
if (isTypeSpecifierQualifier()) {
|
2011-10-01 17:56:14 +08:00
|
|
|
// Parse an abstract declarator.
|
|
|
|
DeclSpec declSpec(AttrFactory);
|
|
|
|
declSpec.setObjCQualifiers(&DS);
|
|
|
|
ParseSpecifierQualifierList(declSpec);
|
2012-05-30 05:52:45 +08:00
|
|
|
declSpec.SetRangeEnd(Tok.getLocation());
|
2011-10-01 17:56:14 +08:00
|
|
|
Declarator declarator(declSpec, context);
|
|
|
|
ParseDeclarator(declarator);
|
|
|
|
|
|
|
|
// If that's not invalid, extract a type.
|
|
|
|
if (!declarator.isInvalidType()) {
|
|
|
|
TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
|
|
|
|
if (!type.isInvalid())
|
|
|
|
Ty = type.get();
|
|
|
|
|
|
|
|
// If we're parsing a parameter, steal all the decl attributes
|
|
|
|
// and add them to the decl spec.
|
|
|
|
if (context == Declarator::ObjCParameterContext)
|
|
|
|
takeDeclAttributes(*paramAttrs, declarator);
|
|
|
|
}
|
|
|
|
} else if (context == Declarator::ObjCResultContext &&
|
|
|
|
Tok.is(tok::identifier)) {
|
2011-09-08 09:46:34 +08:00
|
|
|
if (!Ident_instancetype)
|
|
|
|
Ident_instancetype = PP.getIdentifierInfo("instancetype");
|
|
|
|
|
|
|
|
if (Tok.getIdentifierInfo() == Ident_instancetype) {
|
|
|
|
Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2009-02-19 01:45:20 +08:00
|
|
|
}
|
2011-09-08 09:46:34 +08:00
|
|
|
|
2008-10-22 11:52:06 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-10-22 11:52:06 +08:00
|
|
|
else if (Tok.getLocation() == TypeStartLoc) {
|
2008-08-23 09:48:03 +08:00
|
|
|
// If we didn't eat any tokens, then this isn't a type.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_type);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-22 11:52:06 +08:00
|
|
|
} else {
|
|
|
|
// Otherwise, we found *something*, but didn't get a ')' in the right
|
|
|
|
// place. Emit an error then return what we have as the type.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
return Ty;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-method-decl:
|
|
|
|
/// objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-type-name objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-type-name objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-keyword-selector:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-keyword-decl
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-keyword-selector objc-keyword-decl
|
|
|
|
///
|
|
|
|
/// objc-keyword-decl:
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// objc-selector ':' objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-keyword-attributes[opt] identifier
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parmlist:
|
|
|
|
/// objc-parms objc-ellipsis[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parms:
|
|
|
|
/// objc-parms , parameter-declaration
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-ellipsis:
|
2007-08-23 00:35:03 +08:00
|
|
|
/// , ...
|
|
|
|
///
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-keyword-attributes: [OBJC2]
|
|
|
|
/// __attribute__((unused))
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
2010-08-24 02:23:48 +08:00
|
|
|
tok::TokenKind mType,
|
2011-03-13 02:54:30 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind,
|
|
|
|
bool MethodDefinition) {
|
2012-05-07 14:16:41 +08:00
|
|
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
2009-11-04 10:18:39 +08:00
|
|
|
|
2010-04-07 08:21:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
|
2011-08-22 23:54:49 +08:00
|
|
|
/*ReturnType=*/ ParsedType());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2010-04-07 08:21:17 +08:00
|
|
|
}
|
|
|
|
|
2008-08-23 09:48:03 +08:00
|
|
|
// Parse the return type if present.
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReturnType;
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec DSRet;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren))
|
2011-10-01 17:56:14 +08:00
|
|
|
ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-19 07:05:16 +08:00
|
|
|
// If attributes exist before the method, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes methodAttrs(AttrFactory);
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC2)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2010-02-19 07:05:16 +08:00
|
|
|
|
2010-04-07 08:21:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
|
2011-08-22 23:54:49 +08:00
|
|
|
ReturnType);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2010-04-07 08:21:17 +08:00
|
|
|
}
|
|
|
|
|
2010-02-19 07:05:16 +08:00
|
|
|
// Now parse the selector.
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation selLoc;
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
|
2008-08-23 09:48:03 +08:00
|
|
|
|
2009-02-12 04:43:13 +08:00
|
|
|
// An unnamed colon is valid.
|
|
|
|
if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_selector_for_method)
|
|
|
|
<< SourceRange(mLoc, Tok.getLocation());
|
2012-07-27 01:32:28 +08:00
|
|
|
// Skip until we get a ; or @.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2008-08-23 09:48:03 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC2)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Result
|
2011-02-10 06:20:01 +08:00
|
|
|
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
|
2011-08-22 23:54:49 +08:00
|
|
|
mType, DSRet, ReturnType,
|
2011-06-11 09:09:30 +08:00
|
|
|
selLoc, Sel, 0,
|
2010-04-08 08:30:06 +08:00
|
|
|
CParamInfo.data(), CParamInfo.size(),
|
2011-03-24 19:26:52 +08:00
|
|
|
methodAttrs.getList(), MethodImplKind,
|
|
|
|
false, MethodDefinition);
|
2009-11-04 10:18:39 +08:00
|
|
|
PD.complete(Result);
|
|
|
|
return Result;
|
2007-10-07 10:00:24 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2011-10-03 14:36:36 +08:00
|
|
|
SmallVector<SourceLocation, 12> KeyLocs;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
|
2013-01-29 06:42:45 +08:00
|
|
|
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
|
|
|
Scope::FunctionDeclarationScope | Scope::DeclScope);
|
2011-03-24 19:26:52 +08:00
|
|
|
|
|
|
|
AttributePool allParamAttrs(AttrFactory);
|
2007-10-07 10:00:24 +08:00
|
|
|
while (1) {
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes paramAttrs(AttrFactory);
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::ObjCArgInfo ArgInfo;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Each iteration parses a single keyword argument.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
Diag(Tok, diag::err_expected_colon);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // Eat the ':'.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
ArgInfo.Type = ParsedType();
|
2009-04-12 02:57:04 +08:00
|
|
|
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
|
2011-10-01 17:56:14 +08:00
|
|
|
ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec,
|
|
|
|
Declarator::ObjCParameterContext,
|
|
|
|
¶mAttrs);
|
2009-04-12 02:57:04 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist before the argument name, parse them.
|
2011-10-01 17:56:14 +08:00
|
|
|
// Regardless, collect all the attributes we've parsed so far.
|
2009-04-12 02:57:04 +08:00
|
|
|
ArgInfo.ArgAttrs = 0;
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC2) {
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(paramAttrs);
|
|
|
|
ArgInfo.ArgAttrs = paramAttrs.getList();
|
2010-12-24 10:08:15 +08:00
|
|
|
}
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2010-07-09 07:37:41 +08:00
|
|
|
// Code completion for the next piece of the selector.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
KeyIdents.push_back(SelIdent);
|
|
|
|
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
|
|
|
|
mType == tok::minus,
|
|
|
|
/*AtParameterName=*/true,
|
2013-06-16 11:47:57 +08:00
|
|
|
ReturnType, KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2010-07-09 07:37:41 +08:00
|
|
|
}
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing argument name.
|
|
|
|
break;
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 02:57:04 +08:00
|
|
|
ArgInfo.Name = Tok.getIdentifierInfo();
|
|
|
|
ArgInfo.NameLoc = Tok.getLocation();
|
2007-10-07 10:00:24 +08:00
|
|
|
ConsumeToken(); // Eat the identifier.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 02:57:04 +08:00
|
|
|
ArgInfos.push_back(ArgInfo);
|
|
|
|
KeyIdents.push_back(SelIdent);
|
2011-10-03 14:36:36 +08:00
|
|
|
KeyLocs.push_back(selLoc);
|
2009-04-12 02:57:04 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
// Make sure the attributes persist.
|
|
|
|
allParamAttrs.takeAllFrom(paramAttrs.getPool());
|
|
|
|
|
2010-07-09 07:20:03 +08:00
|
|
|
// Code completion for the next piece of the selector.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
|
|
|
|
mType == tok::minus,
|
2010-07-09 07:37:41 +08:00
|
|
|
/*AtParameterName=*/false,
|
2013-06-16 11:47:57 +08:00
|
|
|
ReturnType, KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2010-07-09 07:20:03 +08:00
|
|
|
}
|
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Check for another keyword selector.
|
2011-10-03 14:36:36 +08:00
|
|
|
SelIdent = ParseObjCSelectorPiece(selLoc);
|
2012-09-13 00:50:35 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon))
|
|
|
|
break;
|
2012-09-18 07:09:59 +08:00
|
|
|
if (!SelIdent) {
|
2012-09-18 03:15:26 +08:00
|
|
|
SourceLocation ColonLoc = Tok.getLocation();
|
|
|
|
if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
|
2012-09-18 07:09:59 +08:00
|
|
|
Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
|
|
|
|
Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
|
|
|
|
Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
|
2012-09-18 03:15:26 +08:00
|
|
|
}
|
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-15 20:35:21 +08:00
|
|
|
bool isVariadic = false;
|
2012-06-22 02:43:08 +08:00
|
|
|
bool cStyleParamWarned = false;
|
2007-10-07 10:00:24 +08:00
|
|
|
// Parse the (optional) parameter list.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::ellipsis)) {
|
2007-11-15 20:35:21 +08:00
|
|
|
isVariadic = true;
|
2007-08-23 02:35:33 +08:00
|
|
|
ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
break;
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2012-06-22 02:43:08 +08:00
|
|
|
if (!cStyleParamWarned) {
|
|
|
|
Diag(Tok, diag::warn_cstyle_param);
|
|
|
|
cStyleParamWarned = true;
|
|
|
|
}
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2007-10-07 10:00:24 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2009-09-09 23:08:12 +08:00
|
|
|
// Parse the declarator.
|
2007-10-07 10:00:24 +08:00
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
2010-04-08 08:30:06 +08:00
|
|
|
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
|
2010-04-08 08:30:06 +08:00
|
|
|
CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
|
|
|
ParmDecl.getIdentifierLoc(),
|
|
|
|
Param,
|
|
|
|
0));
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-12 08:21:25 +08:00
|
|
|
// FIXME: Add support for optional parameter list...
|
2007-09-11 04:33:04 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC2)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2011-02-10 06:20:01 +08:00
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
if (KeyIdents.size() == 0)
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2011-02-10 06:20:01 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
|
|
|
|
&KeyIdents[0]);
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Result
|
2011-02-10 06:20:01 +08:00
|
|
|
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
|
2011-08-22 23:54:49 +08:00
|
|
|
mType, DSRet, ReturnType,
|
2011-10-03 14:36:36 +08:00
|
|
|
KeyLocs, Sel, &ArgInfos[0],
|
2010-04-08 08:30:06 +08:00
|
|
|
CParamInfo.data(), CParamInfo.size(),
|
2011-03-24 19:26:52 +08:00
|
|
|
methodAttrs.getList(),
|
2011-03-13 02:54:30 +08:00
|
|
|
MethodImplKind, isVariadic, MethodDefinition);
|
2011-02-10 06:20:01 +08:00
|
|
|
|
2009-11-04 10:18:39 +08:00
|
|
|
PD.complete(Result);
|
|
|
|
return Result;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
/// objc-protocol-refs:
|
|
|
|
/// '<' identifier-list '>'
|
|
|
|
///
|
|
|
|
bool Parser::
|
2011-07-23 18:55:15 +08:00
|
|
|
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
|
|
|
|
SmallVectorImpl<SourceLocation> &ProtocolLocs,
|
2009-09-30 03:41:44 +08:00
|
|
|
bool WarnOnDeclarations,
|
|
|
|
SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
|
2008-07-26 12:03:38 +08:00
|
|
|
assert(Tok.is(tok::less) && "expected <");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-30 03:41:44 +08:00
|
|
|
LAngleLoc = ConsumeToken(); // the "<"
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
while (1) {
|
2009-11-18 12:19:12 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
|
|
|
|
ProtocolIdents.size());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return true;
|
2009-11-18 12:19:12 +08:00
|
|
|
}
|
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::greater, StopAtSemi);
|
2008-07-26 12:03:38 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
2009-09-30 03:41:44 +08:00
|
|
|
ProtocolLocs.push_back(Tok.getLocation());
|
2008-07-26 12:03:38 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
// Consume the '>'.
|
2012-12-15 02:22:38 +08:00
|
|
|
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
|
2008-07-26 12:03:38 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
// Convert the list of protocols identifiers into a list of protocol decls.
|
|
|
|
Actions.FindProtocolDeclaration(WarnOnDeclarations,
|
|
|
|
&ProtocolIdents[0], ProtocolIdents.size(),
|
|
|
|
Protocols);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-22 07:17:00 +08:00
|
|
|
/// \brief Parse the Objective-C protocol qualifiers that follow a typename
|
|
|
|
/// in a decl-specifier-seq, starting at the '<'.
|
2010-11-20 01:10:50 +08:00
|
|
|
bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
|
2010-10-22 07:17:00 +08:00
|
|
|
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
|
2012-03-11 15:00:24 +08:00
|
|
|
assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
|
2010-10-22 07:17:00 +08:00
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolDecl;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2010-11-20 01:10:50 +08:00
|
|
|
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
|
|
|
|
LAngleLoc, EndProtoLoc);
|
2010-10-22 07:17:00 +08:00
|
|
|
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
|
|
|
|
ProtocolLocs.data(), LAngleLoc);
|
|
|
|
if (EndProtoLoc.isValid())
|
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
2010-11-20 01:10:50 +08:00
|
|
|
return Result;
|
2010-10-22 07:17:00 +08:00
|
|
|
}
|
|
|
|
|
2013-03-21 02:09:33 +08:00
|
|
|
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
|
|
|
BalancedDelimiterTracker &T,
|
|
|
|
SmallVectorImpl<Decl *> &AllIvarDecls,
|
|
|
|
bool RBraceMissing) {
|
|
|
|
if (!RBraceMissing)
|
|
|
|
T.consumeClose();
|
|
|
|
|
|
|
|
Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
|
|
|
|
Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
|
|
|
|
Actions.ActOnObjCContainerFinishDefinition();
|
|
|
|
// Call ActOnFields() even if we don't have any decls. This is useful
|
|
|
|
// for code rewriting tools that need to be aware of the empty list.
|
|
|
|
Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
|
|
|
|
AllIvarDecls,
|
|
|
|
T.getOpenLocation(), T.getCloseLocation(), 0);
|
|
|
|
}
|
2010-10-22 07:17:00 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-class-instance-variables:
|
|
|
|
/// '{' objc-instance-variable-decl-list[opt] '}'
|
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl-list:
|
|
|
|
/// objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl ';'
|
|
|
|
/// ';'
|
|
|
|
/// objc-instance-variable-decl-list objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
|
|
|
|
/// objc-instance-variable-decl-list ';'
|
|
|
|
///
|
|
|
|
/// objc-visibility-spec:
|
|
|
|
/// @private
|
|
|
|
/// @protected
|
|
|
|
/// @public
|
2007-08-22 05:17:12 +08:00
|
|
|
/// @package [OBJC2]
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// struct-declaration
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
|
2010-02-23 07:04:20 +08:00
|
|
|
tok::ObjCKeywordKind visibility,
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation atLoc) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_brace) && "expected {");
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> AllIvarDecls;
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2009-01-13 02:45:55 +08:00
|
|
|
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
|
2011-10-07 07:23:20 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
T.consumeOpen();
|
2007-08-22 05:17:12 +08:00
|
|
|
// While we still have something to read, read the instance variables.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
// Each iteration of this loop reads one objc-instance-variable-decl.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
// Check for extraneous top-level semicolon.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2012-05-17 03:04:59 +08:00
|
|
|
ConsumeExtraSemi(InstanceVariableList);
|
2007-08-22 05:17:12 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
// Set the default visibility to private.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::at)) { // parse objc-visibility-spec
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken(); // eat the @ sign
|
2010-01-14 05:54:15 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtVisibility(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:54:15 +08:00
|
|
|
}
|
|
|
|
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2007-08-22 05:17:12 +08:00
|
|
|
case tok::objc_private:
|
|
|
|
case tok::objc_public:
|
|
|
|
case tok::objc_protected:
|
|
|
|
case tok::objc_package:
|
2007-08-24 02:16:40 +08:00
|
|
|
visibility = Tok.getObjCKeywordID();
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
continue;
|
2013-03-21 02:45:49 +08:00
|
|
|
|
|
|
|
case tok::objc_end:
|
|
|
|
Diag(Tok, diag::err_objc_unexpected_atend);
|
2013-03-21 02:09:33 +08:00
|
|
|
Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
|
|
|
|
Tok.setKind(tok::at);
|
|
|
|
Tok.setLength(1);
|
|
|
|
PP.EnterToken(Tok);
|
|
|
|
HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
|
|
|
|
T, AllIvarDecls, true);
|
|
|
|
return;
|
2013-03-21 02:45:49 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
Diag(Tok, diag::err_objc_illegal_visibility_spec);
|
|
|
|
continue;
|
2007-08-22 05:17:12 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-14 05:54:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(),
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::PCC_ObjCInstanceVariableList);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:54:15 +08:00
|
|
|
}
|
|
|
|
|
2009-11-03 10:38:08 +08:00
|
|
|
struct ObjCIvarCallback : FieldCallback {
|
|
|
|
Parser &P;
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *IDecl;
|
2009-11-03 10:38:08 +08:00
|
|
|
tok::ObjCKeywordKind visibility;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &AllIvarDecls;
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &AllIvarDecls) :
|
2009-11-03 10:38:08 +08:00
|
|
|
P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
|
|
|
|
}
|
|
|
|
|
2012-08-09 07:53:27 +08:00
|
|
|
void invoke(ParsingFieldDeclarator &FD) {
|
2011-08-22 23:54:49 +08:00
|
|
|
P.Actions.ActOnObjCContainerStartDefinition(IDecl);
|
2009-11-03 10:38:08 +08:00
|
|
|
// Install the declarator into the interface decl.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Field
|
2010-07-03 01:43:08 +08:00
|
|
|
= P.Actions.ActOnIvar(P.getCurScope(),
|
2009-11-03 10:38:08 +08:00
|
|
|
FD.D.getDeclSpec().getSourceRange().getBegin(),
|
2011-08-22 23:54:49 +08:00
|
|
|
FD.D, FD.BitfieldSize, visibility);
|
2011-08-30 01:33:12 +08:00
|
|
|
P.Actions.ActOnObjCContainerFinishDefinition();
|
2010-04-07 06:43:48 +08:00
|
|
|
if (Field)
|
|
|
|
AllIvarDecls.push_back(Field);
|
2012-08-09 07:04:35 +08:00
|
|
|
FD.complete(Field);
|
2009-11-03 10:38:08 +08:00
|
|
|
}
|
|
|
|
} Callback(*this, interfaceDecl, visibility, AllIvarDecls);
|
2010-08-24 06:46:52 +08:00
|
|
|
|
2008-04-10 14:46:29 +08:00
|
|
|
// Parse all the comma separated declarators.
|
2012-08-09 07:04:35 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2009-11-03 10:38:08 +08:00
|
|
|
ParseStructDeclaration(DS, Callback);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2007-08-22 05:17:12 +08:00
|
|
|
}
|
|
|
|
}
|
2013-03-21 02:09:33 +08:00
|
|
|
HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
|
|
|
|
T, AllIvarDecls, false);
|
2007-08-22 05:17:12 +08:00
|
|
|
return;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-21 05:31:48 +08:00
|
|
|
|
|
|
|
/// objc-protocol-declaration:
|
|
|
|
/// objc-protocol-definition
|
|
|
|
/// objc-protocol-forward-reference
|
|
|
|
///
|
|
|
|
/// objc-protocol-definition:
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-protocol-refs[opt]
|
|
|
|
/// objc-interface-decl-list
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@end
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-protocol-forward-reference:
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol identifier-list ';'
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2012-06-11 14:19:40 +08:00
|
|
|
/// "\@protocol identifier ;" should be resolved as "\@protocol
|
2007-09-07 05:24:23 +08:00
|
|
|
/// identifier-list ;": objc-interface-decl-list may not start with a
|
2007-08-21 05:31:48 +08:00
|
|
|
/// semicolon in the first alternative if objc-protocol-refs are omitted.
|
2012-01-02 05:23:57 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
|
|
|
|
ParsedAttributes &attrs) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
|
2007-08-23 06:17:26 +08:00
|
|
|
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
|
|
|
|
ConsumeToken(); // the "protocol" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-18 12:49:41 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2012-01-02 05:23:57 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-11-18 12:49:41 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_protocol);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-23 06:17:26 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing protocol name.
|
2012-01-02 05:23:57 +08:00
|
|
|
return DeclGroupPtrTy();
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
|
|
|
// Save the protocol name, then consume it.
|
|
|
|
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) { // forward declaration of one protocol.
|
2008-07-22 06:17:28 +08:00
|
|
|
IdentifierLocPair ProtoInfo(protocolName, nameLoc);
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList());
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-12-08 17:58:43 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::comma)) { // list of forward declarations.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierLocPair, 8> ProtocolRefs;
|
2008-07-22 06:17:28 +08:00
|
|
|
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Parse the list of forward declarations.
|
|
|
|
while (1) {
|
|
|
|
ConsumeToken(); // the ','
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-23 06:17:26 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::semi);
|
2012-01-02 05:23:57 +08:00
|
|
|
return DeclGroupPtrTy();
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2008-07-22 06:17:28 +08:00
|
|
|
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken(); // the identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-08-23 06:17:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Consume the ';'.
|
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
|
2012-01-02 05:23:57 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
&ProtocolRefs[0],
|
2008-12-17 09:07:27 +08:00
|
|
|
ProtocolRefs.size(),
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList());
|
2008-07-22 06:17:28 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Last, and definitely not least, parse a protocol declaration.
|
2009-09-30 03:41:44 +08:00
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
2008-07-22 06:17:28 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolRefs;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2008-07-22 06:17:28 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
2009-09-30 03:41:44 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
|
|
|
|
LAngleLoc, EndProtoLoc))
|
2012-01-02 05:23:57 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *ProtoType =
|
2008-07-26 12:03:38 +08:00
|
|
|
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
|
2009-05-21 17:52:38 +08:00
|
|
|
ProtocolRefs.data(),
|
|
|
|
ProtocolRefs.size(),
|
2010-01-16 23:02:53 +08:00
|
|
|
ProtocolLocs.data(),
|
2010-12-24 10:08:15 +08:00
|
|
|
EndProtoLoc, attrs.getList());
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
|
2012-01-02 05:23:57 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(ProtoType);
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-implementation:
|
|
|
|
/// objc-class-implementation-prologue
|
|
|
|
/// objc-category-implementation-prologue
|
|
|
|
///
|
|
|
|
/// objc-class-implementation-prologue:
|
|
|
|
/// @implementation identifier objc-superclass[opt]
|
|
|
|
/// objc-class-instance-variables[opt]
|
|
|
|
///
|
|
|
|
/// objc-category-implementation-prologue:
|
|
|
|
/// @implementation identifier ( identifier )
|
2012-02-08 00:50:53 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
|
|
|
|
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
|
2011-12-06 17:25:23 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken(); // the "implementation" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 00:26:39 +08:00
|
|
|
// Code completion after '@implementation'.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_implementation);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing class or category name.
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
// We have a class or category name - consume it.
|
2007-09-26 02:38:09 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-09-01 08:26:16 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
2012-02-08 00:50:53 +08:00
|
|
|
Decl *ObjCImpDecl = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// we have a category implementation.
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeParen();
|
2007-09-01 08:26:16 +08:00
|
|
|
SourceLocation categoryLoc, rparenLoc;
|
|
|
|
IdentifierInfo *categoryId = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 03:08:43 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-11-19 03:08:43 +08:00
|
|
|
}
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing category name.
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren); // don't stop at ';'
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
2013-05-18 01:58:11 +08:00
|
|
|
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
|
|
|
|
Diag(Tok, diag::err_unexpected_protocol_qualifier);
|
|
|
|
AttributeFactory attr;
|
|
|
|
DeclSpec DS(attr);
|
|
|
|
(void)ParseObjCProtocolQualifiers(DS);
|
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
|
2011-12-06 17:25:23 +08:00
|
|
|
AtLoc, nameId, nameLoc, categoryId,
|
2007-10-03 00:38:50 +08:00
|
|
|
categoryLoc);
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
} else {
|
|
|
|
// We have a class implementation
|
|
|
|
SourceLocation superClassLoc;
|
|
|
|
IdentifierInfo *superClassId = 0;
|
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
// We have a super class
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing super class name.
|
|
|
|
return DeclGroupPtrTy();
|
|
|
|
}
|
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken(); // Consume super class name
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
ObjCImpDecl = Actions.ActOnStartClassImplementation(
|
|
|
|
AtLoc, nameId, nameLoc,
|
|
|
|
superClassId, superClassLoc);
|
|
|
|
|
|
|
|
if (Tok.is(tok::l_brace)) // we have ivars
|
|
|
|
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
|
2013-04-25 07:23:47 +08:00
|
|
|
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
|
|
|
|
Diag(Tok, diag::err_unexpected_protocol_qualifier);
|
|
|
|
// try to recover.
|
|
|
|
AttributeFactory attr;
|
|
|
|
DeclSpec DS(attr);
|
|
|
|
(void)ParseObjCProtocolQualifiers(DS);
|
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
assert(ObjCImpDecl);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
SmallVector<Decl *, 8> DeclsInGroup;
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
{
|
|
|
|
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
|
|
|
|
while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) {
|
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2012-02-08 00:50:53 +08:00
|
|
|
MaybeParseMicrosoftAttributes(attrs);
|
|
|
|
if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
|
|
|
|
DeclGroupRef DG = DGP.get();
|
|
|
|
DeclsInGroup.append(DG.begin(), DG.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-24 05:11:20 +08:00
|
|
|
return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-10-30 05:38:07 +08:00
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
|
|
|
|
"ParseObjCAtEndDeclaration(): Expected @end");
|
|
|
|
ConsumeToken(); // the "end" identifier
|
2012-02-08 00:50:53 +08:00
|
|
|
if (CurParsedObjCImpl)
|
|
|
|
CurParsedObjCImpl->finish(atEnd);
|
2011-09-01 06:24:06 +08:00
|
|
|
else
|
2010-01-07 09:20:12 +08:00
|
|
|
// missing @implementation
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(atEnd.getBegin(), diag::err_expected_objc_container);
|
2012-02-08 00:50:53 +08:00
|
|
|
return DeclGroupPtrTy();
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-09-05 03:26:51 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
|
|
|
|
if (!Finished) {
|
|
|
|
finish(P.Tok.getLocation());
|
|
|
|
if (P.Tok.is(tok::eof)) {
|
|
|
|
P.Diag(P.Tok, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
|
|
|
|
P.Diag(Dcl->getLocStart(), diag::note_objc_container_start)
|
|
|
|
<< Sema::OCK_Implementation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
P.CurParsedObjCImpl = 0;
|
|
|
|
assert(LateParsedObjCMethods.empty());
|
|
|
|
}
|
2011-12-06 17:25:23 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
|
|
|
|
assert(!Finished);
|
|
|
|
P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl);
|
|
|
|
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
2012-07-03 07:37:09 +08:00
|
|
|
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
|
|
|
true/*Methods*/);
|
2011-12-06 17:25:23 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
|
2009-11-17 02:57:01 +08:00
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
if (HasCFunction)
|
|
|
|
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
|
|
|
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
|
|
|
false/*c-functions*/);
|
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
/// \brief Clear and free the cached objc methods.
|
2011-11-29 16:14:54 +08:00
|
|
|
for (LateParsedObjCMethodContainer::iterator
|
|
|
|
I = LateParsedObjCMethods.begin(),
|
|
|
|
E = LateParsedObjCMethods.end(); I != E; ++I)
|
|
|
|
delete *I;
|
|
|
|
LateParsedObjCMethods.clear();
|
2012-02-08 00:50:53 +08:00
|
|
|
|
|
|
|
Finished = true;
|
2011-11-29 16:14:54 +08:00
|
|
|
}
|
|
|
|
|
2007-09-05 03:26:51 +08:00
|
|
|
/// compatibility-alias-decl:
|
|
|
|
/// @compatibility_alias alias-name class-name ';'
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
|
2007-09-05 03:26:51 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
|
|
|
|
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
|
|
|
|
ConsumeToken(); // consume compatibility_alias
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-05 03:26:51 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-09-05 03:26:51 +08:00
|
|
|
}
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-05 03:26:51 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-09-05 03:26:51 +08:00
|
|
|
}
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *classId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation classLoc = ConsumeToken(); // consume class-name;
|
2011-01-05 09:10:06 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
|
|
|
|
"@compatibility_alias");
|
2012-08-09 07:32:13 +08:00
|
|
|
return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
|
|
|
|
classId, classLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
/// property-synthesis:
|
|
|
|
/// @synthesize property-ivar-list ';'
|
|
|
|
///
|
|
|
|
/// property-ivar-list:
|
|
|
|
/// property-ivar
|
|
|
|
/// property-ivar-list ',' property-ivar
|
|
|
|
///
|
|
|
|
/// property-ivar:
|
|
|
|
/// identifier
|
|
|
|
/// identifier '=' identifier
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
|
2013-04-29 23:35:35 +08:00
|
|
|
"ParseObjCPropertySynthesize(): Expected '@synthesize'");
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeToken(); // consume synthesize
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 03:45:45 +08:00
|
|
|
while (true) {
|
2009-11-19 06:32:06 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 06:32:06 +08:00
|
|
|
}
|
|
|
|
|
2009-11-19 03:45:45 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_synthesized_property_name);
|
|
|
|
SkipUntil(tok::semi);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2009-11-19 03:45:45 +08:00
|
|
|
}
|
|
|
|
|
2008-04-18 08:19:30 +08:00
|
|
|
IdentifierInfo *propertyIvar = 0;
|
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
2010-11-17 09:03:52 +08:00
|
|
|
SourceLocation propertyIvarLoc;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// property '=' ivar-name
|
|
|
|
ConsumeToken(); // consume '='
|
2009-11-19 06:32:06 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 06:32:06 +08:00
|
|
|
}
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-18 08:19:30 +08:00
|
|
|
propertyIvar = Tok.getIdentifierInfo();
|
2010-11-17 09:03:52 +08:00
|
|
|
propertyIvarLoc = ConsumeToken(); // consume ivar-name
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true,
|
2010-11-17 09:03:52 +08:00
|
|
|
propertyId, propertyIvar, propertyIvarLoc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2011-01-05 09:10:06 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@synthesize");
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// property-dynamic:
|
|
|
|
/// @dynamic property-list
|
|
|
|
///
|
|
|
|
/// property-list:
|
|
|
|
/// identifier
|
|
|
|
/// property-list ',' identifier
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
|
|
|
|
"ParseObjCPropertyDynamic(): Expected '@dynamic'");
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeToken(); // consume dynamic
|
2009-11-19 06:56:13 +08:00
|
|
|
while (true) {
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2009-11-19 06:56:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::semi);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2009-11-19 06:56:13 +08:00
|
|
|
}
|
|
|
|
|
2008-04-22 05:05:54 +08:00
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false,
|
2010-11-17 09:03:52 +08:00
|
|
|
propertyId, 0, SourceLocation());
|
2008-04-22 05:05:54 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2011-01-05 09:10:06 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@dynamic");
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
/// objc-throw-statement:
|
|
|
|
/// throw expression[opt];
|
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
|
|
|
|
ExprResult Res;
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume throw
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2007-11-07 10:00:49 +08:00
|
|
|
Res = ParseExpression();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2007-09-20 03:14:32 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
}
|
2010-04-21 05:21:51 +08:00
|
|
|
// consume ';'
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw");
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnObjCAtThrowStmt(atLoc, Res.take(), getCurScope());
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
|
2008-01-30 02:21:32 +08:00
|
|
|
/// objc-synchronized-statement:
|
2008-01-31 01:38:29 +08:00
|
|
|
/// @synchronized '(' expression ')' compound-statement
|
2008-01-30 02:21:32 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
|
2008-01-30 03:14:59 +08:00
|
|
|
ConsumeToken(); // consume synchronized
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// The operand is surrounded with parentheses.
|
2008-01-30 03:14:59 +08:00
|
|
|
ConsumeParen(); // '('
|
2011-07-28 05:50:02 +08:00
|
|
|
ExprResult operand(ParseExpression());
|
|
|
|
|
|
|
|
if (Tok.is(tok::r_paren)) {
|
|
|
|
ConsumeParen(); // ')'
|
|
|
|
} else {
|
|
|
|
if (!operand.isInvalid())
|
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
|
|
|
|
|
|
|
// Skip forward until we see a left brace, but don't consume it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// Require a compound statement.
|
2008-01-31 01:38:29 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2011-07-28 05:50:02 +08:00
|
|
|
if (!operand.isInvalid())
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-31 01:38:29 +08:00
|
|
|
}
|
2008-06-05 04:36:13 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
// Check the @synchronized operand now.
|
|
|
|
if (!operand.isInvalid())
|
|
|
|
operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take());
|
|
|
|
|
|
|
|
// Parse the compound statement within a new scope.
|
|
|
|
ParseScope bodyScope(this, Scope::DeclScope);
|
|
|
|
StmtResult body(ParseCompoundStatementBody());
|
|
|
|
bodyScope.Exit();
|
|
|
|
|
|
|
|
// If there was a semantic or parse error earlier with the
|
|
|
|
// operand, fail now.
|
|
|
|
if (operand.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (body.isInvalid())
|
|
|
|
body = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
|
2008-01-30 02:21:32 +08:00
|
|
|
}
|
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
/// objc-try-catch-statement:
|
|
|
|
/// @try compound-statement objc-catch-list[opt]
|
|
|
|
/// @try compound-statement objc-catch-list[opt] @finally compound-statement
|
|
|
|
///
|
|
|
|
/// objc-catch-list:
|
|
|
|
/// @catch ( parameter-declaration ) compound-statement
|
|
|
|
/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
|
|
|
|
/// catch-parameter-declaration:
|
|
|
|
/// parameter-declaration
|
|
|
|
/// '...' [OBJC2]
|
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
2007-09-20 03:14:32 +08:00
|
|
|
bool catch_or_finally_seen = false;
|
2008-12-12 04:12:42 +08:00
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume try
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2012-08-24 06:51:59 +08:00
|
|
|
StmtVector CatchStmts;
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FinallyStmt;
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope TryScope(this, Scope::DeclScope);
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult TryBody(ParseCompoundStatementBody());
|
2008-12-10 14:34:36 +08:00
|
|
|
TryScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (TryBody.isInvalid())
|
2007-11-02 23:39:31 +08:00
|
|
|
TryBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-11-26 06:21:31 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
2008-03-10 14:06:04 +08:00
|
|
|
// At this point, we need to lookahead to determine if this @ is the start
|
|
|
|
// of an @catch or @finally. We don't want to consume the @ token if this
|
|
|
|
// is an @try or @encode or something else.
|
|
|
|
Token AfterAt = GetLookAheadToken(1);
|
|
|
|
if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
|
|
|
|
!AfterAt.isObjCAtKeyword(tok::objc_finally))
|
|
|
|
break;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-02 08:18:53 +08:00
|
|
|
SourceLocation AtCatchFinallyLoc = ConsumeToken();
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_catch)) {
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *FirstPart = 0;
|
2007-11-02 07:59:59 +08:00
|
|
|
ConsumeToken(); // consume catch
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeParen();
|
2009-02-12 04:05:44 +08:00
|
|
|
ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::ellipsis)) {
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2007-09-20 03:14:32 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2011-07-02 06:22:40 +08:00
|
|
|
Declarator ParmDecl(DS, Declarator::ObjCCatchContext);
|
2009-03-04 03:52:17 +08:00
|
|
|
ParseDeclarator(ParmDecl);
|
|
|
|
|
2010-04-24 07:01:43 +08:00
|
|
|
// Inform the actions module about the declarator, so it
|
2009-03-04 03:52:17 +08:00
|
|
|
// gets added to the current scope.
|
2010-07-03 01:43:08 +08:00
|
|
|
FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
|
2008-02-06 05:27:35 +08:00
|
|
|
} else
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume '...'
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-08 06:56:58 +08:00
|
|
|
SourceLocation RParenLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-08 06:56:58 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
RParenLoc = ConsumeParen();
|
|
|
|
else // Skip over garbage, until we get to ')'. Eat the ')'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2009-04-08 06:56:58 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult CatchBody(true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
CatchBody = ParseCompoundStatementBody();
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (CatchBody.isInvalid())
|
2007-11-02 07:59:59 +08:00
|
|
|
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2010-04-24 06:50:49 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
|
2010-04-24 06:50:49 +08:00
|
|
|
RParenLoc,
|
|
|
|
FirstPart,
|
2010-08-24 07:25:46 +08:00
|
|
|
CatchBody.take());
|
2010-04-24 06:50:49 +08:00
|
|
|
if (!Catch.isInvalid())
|
|
|
|
CatchStmts.push_back(Catch.release());
|
|
|
|
|
2008-02-06 05:27:35 +08:00
|
|
|
} else {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
|
|
|
|
<< "@catch clause";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
catch_or_finally_seen = true;
|
2008-03-10 14:06:04 +08:00
|
|
|
} else {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
|
2008-02-06 05:27:35 +08:00
|
|
|
ConsumeToken(); // consume finally
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope FinallyScope(this, Scope::DeclScope);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FinallyBody(true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
FinallyBody = ParseCompoundStatementBody();
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (FinallyBody.isInvalid())
|
2007-11-02 08:18:53 +08:00
|
|
|
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-12-09 21:15:23 +08:00
|
|
|
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
FinallyBody.take());
|
2007-09-20 03:14:32 +08:00
|
|
|
catch_or_finally_seen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
if (!catch_or_finally_seen) {
|
2007-09-20 03:14:32 +08:00
|
|
|
Diag(atLoc, diag::err_missing_catch_finally);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
2010-04-24 06:50:49 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(),
|
2012-08-24 05:35:17 +08:00
|
|
|
CatchStmts,
|
2010-08-24 07:25:46 +08:00
|
|
|
FinallyStmt.take());
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
/// objc-autoreleasepool-statement:
|
|
|
|
/// @autoreleasepool compound-statement
|
|
|
|
///
|
|
|
|
StmtResult
|
|
|
|
Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
|
|
|
|
ConsumeToken(); // consume autoreleasepool
|
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
// Enter a scope to hold everything within the compound stmt. Compound
|
|
|
|
// statements can always hold declarations.
|
|
|
|
ParseScope BodyScope(this, Scope::DeclScope);
|
|
|
|
|
|
|
|
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
|
|
|
|
|
|
|
|
BodyScope.Exit();
|
|
|
|
if (AutoreleasePoolBody.isInvalid())
|
|
|
|
AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
|
|
|
|
return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
|
|
|
|
AutoreleasePoolBody.take());
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
|
|
|
|
/// for later parsing.
|
|
|
|
void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
|
|
|
|
LexedMethod* LM = new LexedMethod(this, MDecl);
|
|
|
|
CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
|
|
|
|
CachedTokens &Toks = LM->Toks;
|
2012-08-11 05:15:06 +08:00
|
|
|
// Begin by storing the '{' or 'try' or ':' token.
|
2012-07-03 07:37:09 +08:00
|
|
|
Toks.push_back(Tok);
|
2012-08-11 02:10:56 +08:00
|
|
|
if (Tok.is(tok::kw_try)) {
|
|
|
|
ConsumeToken();
|
2012-08-11 04:34:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
Toks.push_back(Tok);
|
|
|
|
ConsumeToken();
|
|
|
|
while (Tok.isNot(tok::l_brace)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
|
|
|
}
|
2012-08-11 05:15:06 +08:00
|
|
|
Toks.push_back(Tok); // also store '{'
|
|
|
|
}
|
|
|
|
else if (Tok.is(tok::colon)) {
|
|
|
|
ConsumeToken();
|
|
|
|
while (Tok.isNot(tok::l_brace)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
2012-08-11 02:10:56 +08:00
|
|
|
Toks.push_back(Tok); // also store '{'
|
|
|
|
}
|
2012-07-03 07:37:09 +08:00
|
|
|
ConsumeBrace();
|
|
|
|
// Consume everything up to (and including) the matching right brace.
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
2012-08-11 02:10:56 +08:00
|
|
|
while (Tok.is(tok::kw_catch)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
2012-07-03 07:37:09 +08:00
|
|
|
}
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
|
2007-09-01 08:26:16 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCMethodDefinition() {
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *MDecl = ParseObjCMethodPrototype();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions, MDecl, Tok.getLocation(),
|
|
|
|
"parsing Objective-C method");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
// parse optional ';'
|
2009-10-21 00:39:13 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2012-02-08 00:50:53 +08:00
|
|
|
if (CurParsedObjCImpl) {
|
2009-11-11 06:55:49 +08:00
|
|
|
Diag(Tok, diag::warn_semicolon_before_method_body)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
2009-11-11 06:55:49 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken();
|
2009-10-21 00:39:13 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// We should have an opening brace now.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-03-01 05:48:07 +08:00
|
|
|
Diag(Tok, diag::err_expected_method_body);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// If we didn't find the '{', bail out.
|
|
|
|
if (Tok.isNot(tok::l_brace))
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
|
|
|
|
if (!MDecl) {
|
|
|
|
ConsumeBrace();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2012-02-08 00:50:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
// Allow the rest of sema to find private method decl implementations.
|
2012-02-08 00:50:53 +08:00
|
|
|
Actions.AddAnyMethodToGlobalPool(MDecl);
|
2012-08-10 01:15:00 +08:00
|
|
|
assert (CurParsedObjCImpl
|
|
|
|
&& "ParseObjCMethodDefinition - Method out of @implementation");
|
|
|
|
// Consume the tokens and store them for later parsing.
|
|
|
|
StashAwayMethodOrFunctionBodyTokens(MDecl);
|
2007-11-14 07:01:27 +08:00
|
|
|
return MDecl;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
|
2009-12-07 17:51:25 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtStatement(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2009-12-07 17:51:25 +08:00
|
|
|
return StmtError();
|
2009-12-08 00:33:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_try))
|
2008-03-10 14:06:04 +08:00
|
|
|
return ParseObjCTryStmt(AtLoc);
|
2009-12-08 00:33:19 +08:00
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_throw))
|
2008-02-06 05:27:35 +08:00
|
|
|
return ParseObjCThrowStmt(AtLoc);
|
2009-12-08 00:33:19 +08:00
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_synchronized))
|
2008-02-06 05:27:35 +08:00
|
|
|
return ParseObjCSynchronizedStmt(AtLoc);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
|
|
|
|
return ParseObjCAutoreleasePoolStmt(AtLoc);
|
2009-12-08 00:33:19 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-02-06 05:27:35 +08:00
|
|
|
// If the expression is invalid, skip ahead to the next semicolon. Not
|
|
|
|
// doing this opens us up to the possibility of infinite loops if
|
|
|
|
// ParseExpression does not consume any tokens.
|
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
2009-12-08 00:33:19 +08:00
|
|
|
|
2008-02-06 05:27:35 +08:00
|
|
|
// Otherwise, eat the semicolon.
|
2010-09-07 23:23:11 +08:00
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
|
2013-01-15 06:39:08 +08:00
|
|
|
return Actions.ActOnExprStmt(Res);
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
2007-08-22 01:43:55 +08:00
|
|
|
switch (Tok.getKind()) {
|
2009-12-07 17:51:25 +08:00
|
|
|
case tok::code_completion:
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtExpression(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2009-12-07 17:51:25 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::minus:
|
|
|
|
case tok::plus: {
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
SourceLocation OpLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (!Tok.is(tok::numeric_constant)) {
|
|
|
|
const char *Symbol = 0;
|
|
|
|
switch (Kind) {
|
|
|
|
case tok::minus: Symbol = "-"; break;
|
|
|
|
case tok::plus: Symbol = "+"; break;
|
|
|
|
default: llvm_unreachable("missing unary operator case");
|
|
|
|
}
|
|
|
|
Diag(Tok, diag::err_nsnumber_nonliteral_unary)
|
|
|
|
<< Symbol;
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take());
|
|
|
|
if (Lit.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
return ParsePostfixExpressionSuffix(
|
|
|
|
Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
|
|
|
|
}
|
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
case tok::string_literal: // primary-expression: string-literal
|
|
|
|
case tok::wide_string_literal:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
case tok::char_constant:
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
|
|
|
|
|
|
|
|
case tok::numeric_constant:
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
|
|
|
|
|
|
|
|
case tok::kw_true: // Objective-C++, etc.
|
|
|
|
case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
|
|
|
|
case tok::kw_false: // Objective-C++, etc.
|
|
|
|
case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
|
|
|
|
|
|
|
|
case tok::l_square:
|
|
|
|
// Objective-C array literal
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
|
|
|
|
|
|
|
|
case tok::l_brace:
|
|
|
|
// Objective-C dictionary literal
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
|
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
case tok::l_paren:
|
|
|
|
// Objective-C boxed expression
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
|
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
default:
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.getIdentifierInfo() == 0)
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
|
|
|
|
case tok::objc_encode:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_protocol:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_selector:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
|
2012-07-10 04:00:35 +08:00
|
|
|
default: {
|
|
|
|
const char *str = 0;
|
|
|
|
if (GetLookAheadToken(1).is(tok::l_brace)) {
|
|
|
|
char ch = Tok.getIdentifierInfo()->getNameStart()[0];
|
|
|
|
str =
|
|
|
|
ch == 't' ? "try"
|
|
|
|
: (ch == 'f' ? "finally"
|
|
|
|
: (ch == 'a' ? "autoreleasepool" : 0));
|
|
|
|
}
|
|
|
|
if (str) {
|
|
|
|
SourceLocation kwLoc = Tok.getLocation();
|
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
|
|
|
|
FixItHint::CreateReplacement(kwLoc, str));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
|
|
|
}
|
2008-08-05 14:19:09 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-13 01:01:48 +08:00
|
|
|
/// \brief Parse the receiver of an Objective-C++ message send.
|
2010-04-22 06:36:40 +08:00
|
|
|
///
|
|
|
|
/// This routine parses the receiver of a message send in
|
|
|
|
/// Objective-C++ either as a type or as an expression. Note that this
|
|
|
|
/// routine must not be called to parse a send to 'super', since it
|
|
|
|
/// has no way to return such a result.
|
|
|
|
///
|
|
|
|
/// \param IsExpr Whether the receiver was parsed as an expression.
|
|
|
|
///
|
|
|
|
/// \param TypeOrExpr If the receiver was parsed as an expression (\c
|
|
|
|
/// IsExpr is true), the parsed expression. If the receiver was parsed
|
|
|
|
/// as a type (\c IsExpr is false), the parsed type.
|
|
|
|
///
|
|
|
|
/// \returns True if an error occurred during parsing or semantic
|
|
|
|
/// analysis, in which case the arguments do not have valid
|
|
|
|
/// values. Otherwise, returns false for a successful parse.
|
|
|
|
///
|
|
|
|
/// objc-receiver: [C++]
|
|
|
|
/// 'super' [not parsed here]
|
|
|
|
/// expression
|
|
|
|
/// simple-type-specifier
|
|
|
|
/// typename-specifier
|
|
|
|
bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
|
|
|
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
|
|
|
|
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
|
|
|
|
TryAnnotateTypeOrScopeToken();
|
|
|
|
|
2012-06-16 07:45:51 +08:00
|
|
|
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
|
2010-04-22 06:36:40 +08:00
|
|
|
// objc-receiver:
|
|
|
|
// expression
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Receiver = ParseExpression();
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Receiver.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = true;
|
|
|
|
TypeOrExpr = Receiver.take();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// objc-receiver:
|
|
|
|
// typename-specifier
|
|
|
|
// simple-type-specifier
|
|
|
|
// expression (that starts with one of the above)
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2010-04-22 06:36:40 +08:00
|
|
|
ParseCXXSimpleTypeSpecifier(DS);
|
|
|
|
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
// If we see an opening parentheses at this point, we are
|
|
|
|
// actually parsing an expression that starts with a
|
|
|
|
// function-style cast, e.g.,
|
|
|
|
//
|
|
|
|
// postfix-expression:
|
|
|
|
// simple-type-specifier ( expression-list [opt] )
|
|
|
|
// typename-specifier ( expression-list [opt] )
|
|
|
|
//
|
|
|
|
// Parse the remainder of this case, then the (optional)
|
|
|
|
// postfix-expression suffix, followed by the (optional)
|
|
|
|
// right-hand side of the binary expression. We have an
|
|
|
|
// instance method.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (!Receiver.isInvalid())
|
2010-08-24 07:25:46 +08:00
|
|
|
Receiver = ParsePostfixExpressionSuffix(Receiver.take());
|
2010-04-22 06:36:40 +08:00
|
|
|
if (!Receiver.isInvalid())
|
2010-08-24 07:25:46 +08:00
|
|
|
Receiver = ParseRHSOfBinaryExpression(Receiver.take(), prec::Comma);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Receiver.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = true;
|
|
|
|
TypeOrExpr = Receiver.take();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a class message. Turn the simple-type-specifier or
|
|
|
|
// typename-specifier we parsed into a type and parse the
|
|
|
|
// remainder of the class message.
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
2010-07-03 01:43:08 +08:00
|
|
|
TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Type.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = false;
|
2010-08-24 13:47:05 +08:00
|
|
|
TypeOrExpr = Type.get().getAsOpaquePtr();
|
2010-04-22 06:36:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-05-31 22:40:22 +08:00
|
|
|
/// \brief Determine whether the parser is currently referring to a an
|
|
|
|
/// Objective-C message send, using a simplified heuristic to avoid overhead.
|
|
|
|
///
|
|
|
|
/// This routine will only return true for a subset of valid message-send
|
|
|
|
/// expressions.
|
|
|
|
bool Parser::isSimpleObjCMessageExpression() {
|
2012-03-11 15:00:24 +08:00
|
|
|
assert(Tok.is(tok::l_square) && getLangOpts().ObjC1 &&
|
2010-05-31 22:40:22 +08:00
|
|
|
"Incorrect start for isSimpleObjCMessageExpression");
|
|
|
|
return GetLookAheadToken(1).is(tok::identifier) &&
|
|
|
|
GetLookAheadToken(2).is(tok::identifier);
|
|
|
|
}
|
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().ObjC1 || !NextToken().is(tok::identifier) ||
|
2010-09-16 09:51:54 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-message-expr:
|
2007-09-06 03:52:07 +08:00
|
|
|
/// '[' objc-receiver objc-message-args ']'
|
|
|
|
///
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// objc-receiver: [C]
|
2010-04-11 16:28:14 +08:00
|
|
|
/// 'super'
|
2007-09-06 03:52:07 +08:00
|
|
|
/// expression
|
|
|
|
/// class-name
|
|
|
|
/// type-name
|
2010-04-22 06:36:40 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCMessageExpression() {
|
2008-01-26 02:59:06 +08:00
|
|
|
assert(Tok.is(tok::l_square) && "'[' expected");
|
|
|
|
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
|
|
|
|
|
2010-05-28 07:06:34 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-05-28 07:06:34 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2010-04-22 06:36:40 +08:00
|
|
|
// We completely separate the C and C++ cases because C++ requires
|
|
|
|
// more complicated (read: slower) parsing.
|
|
|
|
|
|
|
|
// Handle send to super.
|
|
|
|
// FIXME: This doesn't benefit from the same typo-correction we
|
|
|
|
// get in Objective-C.
|
|
|
|
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
|
2010-07-03 01:43:08 +08:00
|
|
|
NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
|
2010-08-24 13:47:05 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
|
|
|
|
ParsedType(), 0);
|
2010-04-22 06:36:40 +08:00
|
|
|
|
|
|
|
// Parse the receiver, which is either a type or an expression.
|
|
|
|
bool IsExpr;
|
2010-09-16 02:35:19 +08:00
|
|
|
void *TypeOrExpr = NULL;
|
2010-04-22 06:36:40 +08:00
|
|
|
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2010-04-22 06:36:40 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsExpr)
|
2010-08-24 13:47:05 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
|
|
|
ParsedType(),
|
2010-08-24 07:25:46 +08:00
|
|
|
static_cast<Expr*>(TypeOrExpr));
|
2010-04-22 06:36:40 +08:00
|
|
|
|
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType::getFromOpaquePtr(TypeOrExpr),
|
|
|
|
0);
|
2010-06-01 02:18:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::identifier)) {
|
2010-04-14 10:22:16 +08:00
|
|
|
IdentifierInfo *Name = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation NameLoc = Tok.getLocation();
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReceiverType;
|
2010-07-03 01:43:08 +08:00
|
|
|
switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
|
2010-04-14 10:22:16 +08:00
|
|
|
Name == Ident_super,
|
2010-04-22 04:38:13 +08:00
|
|
|
NextToken().is(tok::period),
|
|
|
|
ReceiverType)) {
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCSuperMessage:
|
2010-08-24 13:47:05 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
|
|
|
|
ParsedType(), 0);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCClassMessage:
|
2010-04-22 04:38:13 +08:00
|
|
|
if (!ReceiverType) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2010-04-22 04:38:13 +08:00
|
|
|
ConsumeToken(); // the type name
|
|
|
|
|
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
2010-08-24 07:25:46 +08:00
|
|
|
ReceiverType, 0);
|
2010-04-14 10:22:16 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCInstanceMessage:
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
// Fall through to parse an expression.
|
2010-04-14 10:22:16 +08:00
|
|
|
break;
|
2009-04-09 03:50:10 +08:00
|
|
|
}
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2010-04-11 16:28:14 +08:00
|
|
|
|
|
|
|
// Otherwise, an arbitrary expression can be the receiver of a send.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
|
|
|
ParsedType(), Res.take());
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// \brief Parse the remainder of an Objective-C message following the
|
|
|
|
/// '[' objc-receiver.
|
|
|
|
///
|
|
|
|
/// This routine handles sends to super, class messages (sent to a
|
|
|
|
/// class name), and instance messages (sent to an object), and the
|
|
|
|
/// target is represented by \p SuperLoc, \p ReceiverType, or \p
|
|
|
|
/// ReceiverExpr, respectively. Only one of these parameters may have
|
|
|
|
/// a valid value.
|
|
|
|
///
|
|
|
|
/// \param LBracLoc The location of the opening '['.
|
|
|
|
///
|
|
|
|
/// \param SuperLoc If this is a send to 'super', the location of the
|
|
|
|
/// 'super' keyword that indicates a send to the superclass.
|
|
|
|
///
|
|
|
|
/// \param ReceiverType If this is a class message, the type of the
|
|
|
|
/// class we are sending a message to.
|
|
|
|
///
|
|
|
|
/// \param ReceiverExpr If this is an instance message, the expression
|
|
|
|
/// used to compute the receiver object.
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2007-09-06 03:52:07 +08:00
|
|
|
/// objc-message-args:
|
|
|
|
/// objc-selector
|
|
|
|
/// objc-keywordarg-list
|
|
|
|
///
|
|
|
|
/// objc-keywordarg-list:
|
|
|
|
/// objc-keywordarg
|
|
|
|
/// objc-keywordarg-list objc-keywordarg
|
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-keywordarg:
|
2007-09-06 03:52:07 +08:00
|
|
|
/// selector-name[opt] ':' objc-keywordexpr
|
|
|
|
///
|
|
|
|
/// objc-keywordexpr:
|
|
|
|
/// nonempty-expr-list
|
|
|
|
///
|
|
|
|
/// nonempty-expr-list:
|
|
|
|
/// assignment-expression
|
|
|
|
/// nonempty-expr-list , assignment-expression
|
2008-12-13 23:32:12 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-01-26 02:59:06 +08:00
|
|
|
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
SourceLocation SuperLoc,
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReceiverType,
|
2008-12-13 23:32:12 +08:00
|
|
|
ExprArg ReceiverExpr) {
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
|
|
|
|
2009-11-07 10:08:14 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
|
2010-09-21 07:34:21 +08:00
|
|
|
false);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
|
2010-09-21 07:34:21 +08:00
|
|
|
false);
|
2009-11-07 10:08:14 +08:00
|
|
|
else
|
2010-08-24 07:25:46 +08:00
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
None, false);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return ExprError();
|
2009-11-07 10:08:14 +08:00
|
|
|
}
|
2009-11-19 09:08:35 +08:00
|
|
|
|
2007-09-06 07:08:20 +08:00
|
|
|
// Parse objc-selector
|
2007-10-11 08:55:41 +08:00
|
|
|
SourceLocation Loc;
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
|
2013-01-23 02:35:43 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2011-10-03 14:36:17 +08:00
|
|
|
SmallVector<SourceLocation, 12> KeyLocs;
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector KeyExprs;
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
while (1) {
|
|
|
|
// Each iteration parses a single keyword argument.
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
KeyIdents.push_back(selIdent);
|
2011-10-03 14:36:17 +08:00
|
|
|
KeyLocs.push_back(Loc);
|
2007-09-18 04:25:27 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
Diag(Tok, diag::err_expected_colon);
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
ConsumeToken(); // Eat the ':'.
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Parse the expression after ':'
|
2010-09-21 07:34:21 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
if (SuperLoc.isValid())
|
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/true);
|
|
|
|
else if (ReceiverType)
|
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/true);
|
|
|
|
else
|
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/true);
|
|
|
|
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-09-21 07:34:21 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2013-04-19 07:43:21 +08:00
|
|
|
ExprResult Expr;
|
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
Expr = ParseBraceInitializer();
|
|
|
|
} else
|
|
|
|
Expr = ParseAssignmentExpression();
|
|
|
|
|
|
|
|
ExprResult Res(Expr);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2007-09-18 04:25:27 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// We have a valid expression.
|
2008-12-10 08:02:53 +08:00
|
|
|
KeyExprs.push_back(Res.release());
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-11-19 09:08:35 +08:00
|
|
|
// Code completion after each argument.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/false);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/false);
|
2009-11-19 09:08:35 +08:00
|
|
|
else
|
2010-08-24 07:25:46 +08:00
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2010-09-21 07:34:21 +08:00
|
|
|
/*AtArgumentEpression=*/false);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-09-21 07:34:21 +08:00
|
|
|
return ExprError();
|
2009-11-19 09:08:35 +08:00
|
|
|
}
|
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// Check for another keyword selector.
|
2009-04-12 02:13:45 +08:00
|
|
|
selIdent = ParseObjCSelectorPiece(Loc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (!selIdent && Tok.isNot(tok::colon))
|
2007-09-06 07:08:20 +08:00
|
|
|
break;
|
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
|
|
|
// Parse the, optional, argument list, comma separated.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2012-05-22 06:43:44 +08:00
|
|
|
SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Parse the expression after ','
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2012-05-22 06:43:44 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
Diag(commaLoc, diag::note_extra_comma_message_arg) <<
|
|
|
|
FixItHint::CreateRemoval(commaLoc);
|
|
|
|
}
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2007-11-15 21:05:42 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-15 21:05:42 +08:00
|
|
|
// We have a valid expression.
|
2008-12-10 08:02:53 +08:00
|
|
|
KeyExprs.push_back(Res.release());
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
|
|
|
} else if (!selIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2010-04-01 04:22:35 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_square)) {
|
2010-04-01 04:22:35 +08:00
|
|
|
if (Tok.is(tok::identifier))
|
|
|
|
Diag(Tok, diag::err_expected_colon);
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_rsquare);
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2013-01-23 02:35:43 +08:00
|
|
|
|
2008-01-26 02:59:06 +08:00
|
|
|
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-06 02:42:47 +08:00
|
|
|
unsigned nKeys = KeyIdents.size();
|
2011-10-03 14:36:17 +08:00
|
|
|
if (nKeys == 0) {
|
2007-10-07 10:00:24 +08:00
|
|
|
KeyIdents.push_back(selIdent);
|
2011-10-03 14:36:17 +08:00
|
|
|
KeyLocs.push_back(Loc);
|
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
|
2008-12-13 23:32:12 +08:00
|
|
|
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
2007-09-06 03:52:07 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Res(ParseStringLiteralExpression());
|
2012-08-24 05:35:17 +08:00
|
|
|
if (Res.isInvalid()) return Res;
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
|
|
|
|
// expressions. At this point, we know that the only valid thing that starts
|
|
|
|
// with '@' is an @"".
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<SourceLocation, 4> AtLocs;
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector AtStrings;
|
2007-12-12 09:04:12 +08:00
|
|
|
AtLocs.push_back(AtLoc);
|
2008-12-10 08:02:53 +08:00
|
|
|
AtStrings.push_back(Res.release());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
|
|
|
AtLocs.push_back(ConsumeToken()); // eat the @.
|
|
|
|
|
2008-12-10 04:22:58 +08:00
|
|
|
// Invalid unless there is a string literal.
|
2009-02-18 13:56:09 +08:00
|
|
|
if (!isTokenStringLiteral())
|
|
|
|
return ExprError(Diag(Tok, diag::err_objc_concat_string));
|
2007-12-12 09:04:12 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Lit(ParseStringLiteralExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Lit.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-12-10 08:02:53 +08:00
|
|
|
AtStrings.push_back(Lit.release());
|
2007-12-12 09:04:12 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
|
|
|
|
AtStrings.size());
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
2007-08-22 23:14:15 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
/// ParseObjCBooleanLiteral -
|
|
|
|
/// objc-scalar-literal : '@' boolean-keyword
|
|
|
|
/// ;
|
|
|
|
/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
|
|
|
|
/// ;
|
|
|
|
ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
|
|
|
|
bool ArgValue) {
|
|
|
|
SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
|
|
|
|
return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObjCCharacterLiteral -
|
|
|
|
/// objc-scalar-literal : '@' character-literal
|
|
|
|
/// ;
|
|
|
|
ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObjCNumericLiteral -
|
|
|
|
/// objc-scalar-literal : '@' scalar-literal
|
|
|
|
/// ;
|
|
|
|
/// scalar-literal : | numeric-constant /* any numeric constant. */
|
|
|
|
/// ;
|
|
|
|
ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
/// ParseObjCBoxedExpr -
|
|
|
|
/// objc-box-expression:
|
|
|
|
/// @( assignment-expression )
|
|
|
|
ExprResult
|
|
|
|
Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
|
|
|
|
if (Tok.isNot(tok::l_paren))
|
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
|
|
|
|
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
ExprResult ValueExpr(ParseAssignmentExpression());
|
|
|
|
if (T.consumeClose())
|
|
|
|
return ExprError();
|
2012-05-11 04:02:36 +08:00
|
|
|
|
|
|
|
if (ValueExpr.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
// Wrap the sub-expression in a parenthesized expression, to distinguish
|
|
|
|
// a boxed expression from a literal.
|
|
|
|
SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
|
|
|
|
ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take());
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
|
|
|
|
ValueExpr.take());
|
2012-04-19 08:25:12 +08:00
|
|
|
}
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ElementExprs; // array elements.
|
2012-03-07 04:05:56 +08:00
|
|
|
ConsumeBracket(); // consume the l_square.
|
|
|
|
|
|
|
|
while (Tok.isNot(tok::r_square)) {
|
|
|
|
// Parse list of array element expressions (all must be id types).
|
|
|
|
ExprResult Res(ParseAssignmentExpression());
|
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the ellipsis that indicates a pack expansion.
|
|
|
|
if (Tok.is(tok::ellipsis))
|
|
|
|
Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
|
|
|
|
if (Res.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
ElementExprs.push_back(Res.release());
|
|
|
|
|
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken(); // Eat the ','.
|
|
|
|
else if (Tok.isNot(tok::r_square))
|
|
|
|
return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma));
|
|
|
|
}
|
|
|
|
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
|
2012-08-24 06:51:59 +08:00
|
|
|
MultiExprArg Args(ElementExprs);
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
|
|
|
|
SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
|
|
|
|
ConsumeBrace(); // consume the l_square.
|
|
|
|
while (Tok.isNot(tok::r_brace)) {
|
|
|
|
// Parse the comma separated key : value expressions.
|
|
|
|
ExprResult KeyExpr;
|
|
|
|
{
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
KeyExpr = ParseAssignmentExpression();
|
|
|
|
if (KeyExpr.isInvalid()) {
|
|
|
|
// We must manually skip to a '}', otherwise the expression skipper will
|
|
|
|
// stop at the '}' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return KeyExpr;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
2013-04-19 03:37:43 +08:00
|
|
|
Diag(Tok, diag::err_expected_colon);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2013-04-19 03:37:43 +08:00
|
|
|
return ExprError();
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult ValueExpr(ParseAssignmentExpression());
|
|
|
|
if (ValueExpr.isInvalid()) {
|
|
|
|
// We must manually skip to a '}', otherwise the expression skipper will
|
|
|
|
// stop at the '}' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return ValueExpr;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the ellipsis that designates this as a pack expansion.
|
|
|
|
SourceLocation EllipsisLoc;
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::ellipsis) && getLangOpts().CPlusPlus)
|
2012-03-07 04:05:56 +08:00
|
|
|
EllipsisLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// We have a valid expression. Collect it in a vector so we can
|
|
|
|
// build the argument list.
|
|
|
|
ObjCDictionaryElement Element = {
|
2013-02-21 09:47:18 +08:00
|
|
|
KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
|
2012-03-07 04:05:56 +08:00
|
|
|
};
|
|
|
|
Elements.push_back(Element);
|
|
|
|
|
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken(); // Eat the ','.
|
|
|
|
else if (Tok.isNot(tok::r_brace))
|
|
|
|
return ExprError(Diag(Tok, diag::err_expected_rbrace_or_comma));
|
|
|
|
}
|
|
|
|
SourceLocation EndLoc = ConsumeBrace();
|
|
|
|
|
|
|
|
// Create the ObjCDictionaryLiteral.
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
|
|
|
|
Elements.data(), Elements.size());
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
/// objc-encode-expression:
|
2012-09-13 01:01:48 +08:00
|
|
|
/// \@encode ( type-name )
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
SourceLocation EncLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
if (Ty.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
|
|
|
|
Ty.get(), T.getCloseLocation());
|
2007-08-22 23:14:15 +08:00
|
|
|
}
|
2007-08-23 23:25:28 +08:00
|
|
|
|
|
|
|
/// objc-protocol-expression
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol ( protocol-name )
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
|
2007-08-23 23:25:28 +08:00
|
|
|
SourceLocation ProtoLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_ident));
|
|
|
|
|
2007-10-18 00:58:11 +08:00
|
|
|
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
|
2012-05-16 08:50:02 +08:00
|
|
|
SourceLocation ProtoIdLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-08-23 23:25:28 +08:00
|
|
|
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
|
|
|
|
T.getOpenLocation(), ProtoIdLoc,
|
|
|
|
T.getCloseLocation());
|
2007-08-23 23:25:28 +08:00
|
|
|
}
|
2007-10-16 07:39:13 +08:00
|
|
|
|
|
|
|
/// objc-selector-expression
|
|
|
|
/// @selector '(' objc-keyword-selector ')'
|
2013-01-23 02:35:43 +08:00
|
|
|
ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation SelectorLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation sLoc;
|
2010-08-26 23:07:07 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2010-08-26 23:07:07 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-08-26 23:07:07 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
|
2010-08-28 06:32:41 +08:00
|
|
|
if (!SelIdent && // missing selector name.
|
|
|
|
Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_ident));
|
|
|
|
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2007-12-06 06:21:29 +08:00
|
|
|
unsigned nColons = 0;
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-10-16 07:39:13 +08:00
|
|
|
while (1) {
|
2010-08-28 06:32:41 +08:00
|
|
|
if (Tok.is(tok::coloncolon)) { // Handle :: in C++.
|
|
|
|
++nColons;
|
|
|
|
KeyIdents.push_back(0);
|
|
|
|
} else if (Tok.isNot(tok::colon))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_colon));
|
|
|
|
|
2010-08-28 06:32:41 +08:00
|
|
|
++nColons;
|
2011-03-27 02:11:38 +08:00
|
|
|
ConsumeToken(); // Eat the ':' or '::'.
|
2007-10-16 07:39:13 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
break;
|
2010-08-26 23:07:07 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-08-26 23:07:07 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2007-10-16 07:39:13 +08:00
|
|
|
// Check for another keyword selector.
|
|
|
|
SourceLocation Loc;
|
2009-04-12 02:13:45 +08:00
|
|
|
SelIdent = ParseObjCSelectorPiece(Loc);
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2011-03-27 02:11:38 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
|
2007-10-16 07:39:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-12-06 06:21:29 +08:00
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-12-06 06:21:29 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
|
|
|
|
T.getOpenLocation(),
|
2013-01-23 02:35:43 +08:00
|
|
|
T.getCloseLocation());
|
2007-10-19 23:38:32 +08:00
|
|
|
}
|
2011-09-01 01:37:55 +08:00
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
|
|
|
// MCDecl might be null due to error in method or c-function prototype, etc.
|
|
|
|
Decl *MCDecl = LM.D;
|
|
|
|
bool skip = MCDecl &&
|
|
|
|
((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
|
|
|
|
(!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
|
|
|
|
if (skip)
|
|
|
|
return;
|
|
|
|
|
2011-12-17 12:13:18 +08:00
|
|
|
// Save the current token position.
|
|
|
|
SourceLocation OrigLoc = Tok.getLocation();
|
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
|
|
|
|
// Append the current token at the end of the new token stream so that it
|
|
|
|
// doesn't get lost.
|
|
|
|
LM.Toks.push_back(Tok);
|
|
|
|
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
|
|
|
|
|
|
|
|
// Consume the previously pushed token.
|
2013-03-28 07:58:17 +08:00
|
|
|
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
|
2011-09-01 01:37:55 +08:00
|
|
|
|
2012-08-11 05:15:06 +08:00
|
|
|
assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
|
|
|
|
Tok.is(tok::colon)) &&
|
|
|
|
"Inline objective-c method not starting with '{' or 'try' or ':'");
|
2012-07-03 07:37:09 +08:00
|
|
|
// Enter a scope for the method or c-fucntion body.
|
2011-09-01 01:37:55 +08:00
|
|
|
ParseScope BodyScope(this,
|
2012-07-03 07:37:09 +08:00
|
|
|
parseMethod
|
|
|
|
? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope
|
|
|
|
: Scope::FnScope|Scope::DeclScope);
|
2011-09-01 01:37:55 +08:00
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
// Tell the actions module that we have entered a method or c-function definition
|
|
|
|
// with the specified Declarator for the method/function.
|
2012-08-09 07:41:08 +08:00
|
|
|
if (parseMethod)
|
|
|
|
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
|
|
|
|
else
|
|
|
|
Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
|
2012-08-11 02:10:56 +08:00
|
|
|
if (Tok.is(tok::kw_try))
|
|
|
|
MCDecl = ParseFunctionTryBlock(MCDecl, BodyScope);
|
2012-08-11 05:15:06 +08:00
|
|
|
else {
|
|
|
|
if (Tok.is(tok::colon))
|
|
|
|
ParseConstructorInitializer(MCDecl);
|
2012-08-11 02:10:56 +08:00
|
|
|
MCDecl = ParseFunctionStatementBody(MCDecl, BodyScope);
|
2012-08-11 05:15:06 +08:00
|
|
|
}
|
2012-08-10 05:12:39 +08:00
|
|
|
|
2011-12-17 12:13:18 +08:00
|
|
|
if (Tok.getLocation() != OrigLoc) {
|
|
|
|
// Due to parsing error, we either went over the cached tokens or
|
|
|
|
// there are still cached tokens left. If it's the latter case skip the
|
|
|
|
// leftover tokens.
|
|
|
|
// Since this is an uncommon situation that should be avoided, use the
|
|
|
|
// expensive isBeforeInTranslationUnit call.
|
|
|
|
if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
|
|
|
|
OrigLoc))
|
|
|
|
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
|
|
|
|
ConsumeAnyToken();
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
return;
|
2011-09-01 01:37:55 +08:00
|
|
|
}
|