17330f729Sjoerg //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the Objective-C portions of the Parser interface.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/AST/ASTContext.h"
147330f729Sjoerg #include "clang/AST/PrettyDeclStackTrace.h"
157330f729Sjoerg #include "clang/Basic/CharInfo.h"
16*e038c9c4Sjoerg #include "clang/Basic/TargetInfo.h"
177330f729Sjoerg #include "clang/Parse/ParseDiagnostic.h"
18*e038c9c4Sjoerg #include "clang/Parse/Parser.h"
197330f729Sjoerg #include "clang/Parse/RAIIObjectsForParser.h"
207330f729Sjoerg #include "clang/Sema/DeclSpec.h"
217330f729Sjoerg #include "clang/Sema/Scope.h"
227330f729Sjoerg #include "llvm/ADT/SmallVector.h"
237330f729Sjoerg #include "llvm/ADT/StringExtras.h"
247330f729Sjoerg
257330f729Sjoerg using namespace clang;
267330f729Sjoerg
277330f729Sjoerg /// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
MaybeSkipAttributes(tok::ObjCKeywordKind Kind)287330f729Sjoerg void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
297330f729Sjoerg ParsedAttributes attrs(AttrFactory);
307330f729Sjoerg if (Tok.is(tok::kw___attribute)) {
317330f729Sjoerg if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
327330f729Sjoerg Diag(Tok, diag::err_objc_postfix_attribute_hint)
337330f729Sjoerg << (Kind == tok::objc_protocol);
347330f729Sjoerg else
357330f729Sjoerg Diag(Tok, diag::err_objc_postfix_attribute);
367330f729Sjoerg ParseGNUAttributes(attrs);
377330f729Sjoerg }
387330f729Sjoerg }
397330f729Sjoerg
407330f729Sjoerg /// ParseObjCAtDirectives - Handle parts of the external-declaration production:
417330f729Sjoerg /// external-declaration: [C99 6.9]
427330f729Sjoerg /// [OBJC] objc-class-definition
437330f729Sjoerg /// [OBJC] objc-class-declaration
447330f729Sjoerg /// [OBJC] objc-alias-declaration
457330f729Sjoerg /// [OBJC] objc-protocol-definition
467330f729Sjoerg /// [OBJC] objc-method-definition
477330f729Sjoerg /// [OBJC] '@' 'end'
487330f729Sjoerg Parser::DeclGroupPtrTy
ParseObjCAtDirectives(ParsedAttributesWithRange & Attrs)497330f729Sjoerg Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
507330f729Sjoerg SourceLocation AtLoc = ConsumeToken(); // the "@"
517330f729Sjoerg
527330f729Sjoerg if (Tok.is(tok::code_completion)) {
537330f729Sjoerg cutOffParsing();
54*e038c9c4Sjoerg Actions.CodeCompleteObjCAtDirective(getCurScope());
557330f729Sjoerg return nullptr;
567330f729Sjoerg }
577330f729Sjoerg
587330f729Sjoerg Decl *SingleDecl = nullptr;
597330f729Sjoerg switch (Tok.getObjCKeywordID()) {
607330f729Sjoerg case tok::objc_class:
617330f729Sjoerg return ParseObjCAtClassDeclaration(AtLoc);
627330f729Sjoerg case tok::objc_interface:
637330f729Sjoerg SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, Attrs);
647330f729Sjoerg break;
657330f729Sjoerg case tok::objc_protocol:
667330f729Sjoerg return ParseObjCAtProtocolDeclaration(AtLoc, Attrs);
677330f729Sjoerg case tok::objc_implementation:
687330f729Sjoerg return ParseObjCAtImplementationDeclaration(AtLoc, Attrs);
697330f729Sjoerg case tok::objc_end:
707330f729Sjoerg return ParseObjCAtEndDeclaration(AtLoc);
717330f729Sjoerg case tok::objc_compatibility_alias:
727330f729Sjoerg SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
737330f729Sjoerg break;
747330f729Sjoerg case tok::objc_synthesize:
757330f729Sjoerg SingleDecl = ParseObjCPropertySynthesize(AtLoc);
767330f729Sjoerg break;
777330f729Sjoerg case tok::objc_dynamic:
787330f729Sjoerg SingleDecl = ParseObjCPropertyDynamic(AtLoc);
797330f729Sjoerg break;
807330f729Sjoerg case tok::objc_import:
817330f729Sjoerg if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {
827330f729Sjoerg SingleDecl = ParseModuleImport(AtLoc);
837330f729Sjoerg break;
847330f729Sjoerg }
857330f729Sjoerg Diag(AtLoc, diag::err_atimport);
867330f729Sjoerg SkipUntil(tok::semi);
877330f729Sjoerg return Actions.ConvertDeclToDeclGroup(nullptr);
887330f729Sjoerg default:
897330f729Sjoerg Diag(AtLoc, diag::err_unexpected_at);
907330f729Sjoerg SkipUntil(tok::semi);
917330f729Sjoerg SingleDecl = nullptr;
927330f729Sjoerg break;
937330f729Sjoerg }
947330f729Sjoerg return Actions.ConvertDeclToDeclGroup(SingleDecl);
957330f729Sjoerg }
967330f729Sjoerg
977330f729Sjoerg /// Class to handle popping type parameters when leaving the scope.
987330f729Sjoerg class Parser::ObjCTypeParamListScope {
997330f729Sjoerg Sema &Actions;
1007330f729Sjoerg Scope *S;
1017330f729Sjoerg ObjCTypeParamList *Params;
1027330f729Sjoerg
1037330f729Sjoerg public:
ObjCTypeParamListScope(Sema & Actions,Scope * S)1047330f729Sjoerg ObjCTypeParamListScope(Sema &Actions, Scope *S)
1057330f729Sjoerg : Actions(Actions), S(S), Params(nullptr) {}
1067330f729Sjoerg
~ObjCTypeParamListScope()1077330f729Sjoerg ~ObjCTypeParamListScope() {
1087330f729Sjoerg leave();
1097330f729Sjoerg }
1107330f729Sjoerg
enter(ObjCTypeParamList * P)1117330f729Sjoerg void enter(ObjCTypeParamList *P) {
1127330f729Sjoerg assert(!Params);
1137330f729Sjoerg Params = P;
1147330f729Sjoerg }
1157330f729Sjoerg
leave()1167330f729Sjoerg void leave() {
1177330f729Sjoerg if (Params)
1187330f729Sjoerg Actions.popObjCTypeParamList(S, Params);
1197330f729Sjoerg Params = nullptr;
1207330f729Sjoerg }
1217330f729Sjoerg };
1227330f729Sjoerg
1237330f729Sjoerg ///
1247330f729Sjoerg /// objc-class-declaration:
1257330f729Sjoerg /// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
1267330f729Sjoerg ///
1277330f729Sjoerg /// objc-class-forward-decl:
1287330f729Sjoerg /// identifier objc-type-parameter-list[opt]
1297330f729Sjoerg ///
1307330f729Sjoerg Parser::DeclGroupPtrTy
ParseObjCAtClassDeclaration(SourceLocation atLoc)1317330f729Sjoerg Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
1327330f729Sjoerg ConsumeToken(); // the identifier "class"
1337330f729Sjoerg SmallVector<IdentifierInfo *, 8> ClassNames;
1347330f729Sjoerg SmallVector<SourceLocation, 8> ClassLocs;
1357330f729Sjoerg SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
1367330f729Sjoerg
1377330f729Sjoerg while (1) {
1387330f729Sjoerg MaybeSkipAttributes(tok::objc_class);
1397330f729Sjoerg if (expectIdentifier()) {
1407330f729Sjoerg SkipUntil(tok::semi);
1417330f729Sjoerg return Actions.ConvertDeclToDeclGroup(nullptr);
1427330f729Sjoerg }
1437330f729Sjoerg ClassNames.push_back(Tok.getIdentifierInfo());
1447330f729Sjoerg ClassLocs.push_back(Tok.getLocation());
1457330f729Sjoerg ConsumeToken();
1467330f729Sjoerg
1477330f729Sjoerg // Parse the optional objc-type-parameter-list.
1487330f729Sjoerg ObjCTypeParamList *TypeParams = nullptr;
1497330f729Sjoerg if (Tok.is(tok::less))
1507330f729Sjoerg TypeParams = parseObjCTypeParamList();
1517330f729Sjoerg ClassTypeParams.push_back(TypeParams);
1527330f729Sjoerg if (!TryConsumeToken(tok::comma))
1537330f729Sjoerg break;
1547330f729Sjoerg }
1557330f729Sjoerg
1567330f729Sjoerg // Consume the ';'.
1577330f729Sjoerg if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
1587330f729Sjoerg return Actions.ConvertDeclToDeclGroup(nullptr);
1597330f729Sjoerg
1607330f729Sjoerg return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
1617330f729Sjoerg ClassLocs.data(),
1627330f729Sjoerg ClassTypeParams,
1637330f729Sjoerg ClassNames.size());
1647330f729Sjoerg }
1657330f729Sjoerg
CheckNestedObjCContexts(SourceLocation AtLoc)1667330f729Sjoerg void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
1677330f729Sjoerg {
1687330f729Sjoerg Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
1697330f729Sjoerg if (ock == Sema::OCK_None)
1707330f729Sjoerg return;
1717330f729Sjoerg
1727330f729Sjoerg Decl *Decl = Actions.getObjCDeclContext();
1737330f729Sjoerg if (CurParsedObjCImpl) {
1747330f729Sjoerg CurParsedObjCImpl->finish(AtLoc);
1757330f729Sjoerg } else {
1767330f729Sjoerg Actions.ActOnAtEnd(getCurScope(), AtLoc);
1777330f729Sjoerg }
1787330f729Sjoerg Diag(AtLoc, diag::err_objc_missing_end)
1797330f729Sjoerg << FixItHint::CreateInsertion(AtLoc, "@end\n");
1807330f729Sjoerg if (Decl)
1817330f729Sjoerg Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;
1827330f729Sjoerg }
1837330f729Sjoerg
1847330f729Sjoerg ///
1857330f729Sjoerg /// objc-interface:
1867330f729Sjoerg /// objc-class-interface-attributes[opt] objc-class-interface
1877330f729Sjoerg /// objc-category-interface
1887330f729Sjoerg ///
1897330f729Sjoerg /// objc-class-interface:
1907330f729Sjoerg /// '@' 'interface' identifier objc-type-parameter-list[opt]
1917330f729Sjoerg /// objc-superclass[opt] objc-protocol-refs[opt]
1927330f729Sjoerg /// objc-class-instance-variables[opt]
1937330f729Sjoerg /// objc-interface-decl-list
1947330f729Sjoerg /// @end
1957330f729Sjoerg ///
1967330f729Sjoerg /// objc-category-interface:
1977330f729Sjoerg /// '@' 'interface' identifier objc-type-parameter-list[opt]
1987330f729Sjoerg /// '(' identifier[opt] ')' objc-protocol-refs[opt]
1997330f729Sjoerg /// objc-interface-decl-list
2007330f729Sjoerg /// @end
2017330f729Sjoerg ///
2027330f729Sjoerg /// objc-superclass:
2037330f729Sjoerg /// ':' identifier objc-type-arguments[opt]
2047330f729Sjoerg ///
2057330f729Sjoerg /// objc-class-interface-attributes:
2067330f729Sjoerg /// __attribute__((visibility("default")))
2077330f729Sjoerg /// __attribute__((visibility("hidden")))
2087330f729Sjoerg /// __attribute__((deprecated))
2097330f729Sjoerg /// __attribute__((unavailable))
2107330f729Sjoerg /// __attribute__((objc_exception)) - used by NSException on 64-bit
2117330f729Sjoerg /// __attribute__((objc_root_class))
2127330f729Sjoerg ///
ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)2137330f729Sjoerg Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
2147330f729Sjoerg ParsedAttributes &attrs) {
2157330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
2167330f729Sjoerg "ParseObjCAtInterfaceDeclaration(): Expected @interface");
2177330f729Sjoerg CheckNestedObjCContexts(AtLoc);
2187330f729Sjoerg ConsumeToken(); // the "interface" identifier
2197330f729Sjoerg
2207330f729Sjoerg // Code completion after '@interface'.
2217330f729Sjoerg if (Tok.is(tok::code_completion)) {
2227330f729Sjoerg cutOffParsing();
223*e038c9c4Sjoerg Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
2247330f729Sjoerg return nullptr;
2257330f729Sjoerg }
2267330f729Sjoerg
2277330f729Sjoerg MaybeSkipAttributes(tok::objc_interface);
2287330f729Sjoerg
2297330f729Sjoerg if (expectIdentifier())
2307330f729Sjoerg return nullptr; // missing class or category name.
2317330f729Sjoerg
2327330f729Sjoerg // We have a class or category name - consume it.
2337330f729Sjoerg IdentifierInfo *nameId = Tok.getIdentifierInfo();
2347330f729Sjoerg SourceLocation nameLoc = ConsumeToken();
2357330f729Sjoerg
2367330f729Sjoerg // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
2377330f729Sjoerg // case, LAngleLoc will be valid and ProtocolIdents will capture the
2387330f729Sjoerg // protocol references (that have not yet been resolved).
2397330f729Sjoerg SourceLocation LAngleLoc, EndProtoLoc;
2407330f729Sjoerg SmallVector<IdentifierLocPair, 8> ProtocolIdents;
2417330f729Sjoerg ObjCTypeParamList *typeParameterList = nullptr;
2427330f729Sjoerg ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
2437330f729Sjoerg if (Tok.is(tok::less))
2447330f729Sjoerg typeParameterList = parseObjCTypeParamListOrProtocolRefs(
2457330f729Sjoerg typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);
2467330f729Sjoerg
2477330f729Sjoerg if (Tok.is(tok::l_paren) &&
2487330f729Sjoerg !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
2497330f729Sjoerg
2507330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
2517330f729Sjoerg T.consumeOpen();
2527330f729Sjoerg
2537330f729Sjoerg SourceLocation categoryLoc;
2547330f729Sjoerg IdentifierInfo *categoryId = nullptr;
2557330f729Sjoerg if (Tok.is(tok::code_completion)) {
2567330f729Sjoerg cutOffParsing();
257*e038c9c4Sjoerg Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
2587330f729Sjoerg return nullptr;
2597330f729Sjoerg }
2607330f729Sjoerg
2617330f729Sjoerg // For ObjC2, the category name is optional (not an error).
2627330f729Sjoerg if (Tok.is(tok::identifier)) {
2637330f729Sjoerg categoryId = Tok.getIdentifierInfo();
2647330f729Sjoerg categoryLoc = ConsumeToken();
2657330f729Sjoerg }
2667330f729Sjoerg else if (!getLangOpts().ObjC) {
2677330f729Sjoerg Diag(Tok, diag::err_expected)
2687330f729Sjoerg << tok::identifier; // missing category name.
2697330f729Sjoerg return nullptr;
2707330f729Sjoerg }
2717330f729Sjoerg
2727330f729Sjoerg T.consumeClose();
2737330f729Sjoerg if (T.getCloseLocation().isInvalid())
2747330f729Sjoerg return nullptr;
2757330f729Sjoerg
2767330f729Sjoerg // Next, we need to check for any protocol references.
2777330f729Sjoerg assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
2787330f729Sjoerg SmallVector<Decl *, 8> ProtocolRefs;
2797330f729Sjoerg SmallVector<SourceLocation, 8> ProtocolLocs;
2807330f729Sjoerg if (Tok.is(tok::less) &&
2817330f729Sjoerg ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
2827330f729Sjoerg LAngleLoc, EndProtoLoc,
2837330f729Sjoerg /*consumeLastToken=*/true))
2847330f729Sjoerg return nullptr;
2857330f729Sjoerg
2867330f729Sjoerg Decl *CategoryType = Actions.ActOnStartCategoryInterface(
2877330f729Sjoerg AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
2887330f729Sjoerg ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
2897330f729Sjoerg EndProtoLoc, attrs);
2907330f729Sjoerg
2917330f729Sjoerg if (Tok.is(tok::l_brace))
2927330f729Sjoerg ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
2937330f729Sjoerg
2947330f729Sjoerg ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
2957330f729Sjoerg
2967330f729Sjoerg return CategoryType;
2977330f729Sjoerg }
2987330f729Sjoerg // Parse a class interface.
2997330f729Sjoerg IdentifierInfo *superClassId = nullptr;
3007330f729Sjoerg SourceLocation superClassLoc;
3017330f729Sjoerg SourceLocation typeArgsLAngleLoc;
3027330f729Sjoerg SmallVector<ParsedType, 4> typeArgs;
3037330f729Sjoerg SourceLocation typeArgsRAngleLoc;
3047330f729Sjoerg SmallVector<Decl *, 4> protocols;
3057330f729Sjoerg SmallVector<SourceLocation, 4> protocolLocs;
3067330f729Sjoerg if (Tok.is(tok::colon)) { // a super class is specified.
3077330f729Sjoerg ConsumeToken();
3087330f729Sjoerg
3097330f729Sjoerg // Code completion of superclass names.
3107330f729Sjoerg if (Tok.is(tok::code_completion)) {
3117330f729Sjoerg cutOffParsing();
312*e038c9c4Sjoerg Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
3137330f729Sjoerg return nullptr;
3147330f729Sjoerg }
3157330f729Sjoerg
3167330f729Sjoerg if (expectIdentifier())
3177330f729Sjoerg return nullptr; // missing super class name.
3187330f729Sjoerg superClassId = Tok.getIdentifierInfo();
3197330f729Sjoerg superClassLoc = ConsumeToken();
3207330f729Sjoerg
3217330f729Sjoerg // Type arguments for the superclass or protocol conformances.
3227330f729Sjoerg if (Tok.is(tok::less)) {
3237330f729Sjoerg parseObjCTypeArgsOrProtocolQualifiers(
3247330f729Sjoerg nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
3257330f729Sjoerg protocols, protocolLocs, EndProtoLoc,
3267330f729Sjoerg /*consumeLastToken=*/true,
3277330f729Sjoerg /*warnOnIncompleteProtocols=*/true);
3287330f729Sjoerg if (Tok.is(tok::eof))
3297330f729Sjoerg return nullptr;
3307330f729Sjoerg }
3317330f729Sjoerg }
3327330f729Sjoerg
3337330f729Sjoerg // Next, we need to check for any protocol references.
3347330f729Sjoerg if (LAngleLoc.isValid()) {
3357330f729Sjoerg if (!ProtocolIdents.empty()) {
3367330f729Sjoerg // We already parsed the protocols named when we thought we had a
3377330f729Sjoerg // type parameter list. Translate them into actual protocol references.
3387330f729Sjoerg for (const auto &pair : ProtocolIdents) {
3397330f729Sjoerg protocolLocs.push_back(pair.second);
3407330f729Sjoerg }
3417330f729Sjoerg Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
3427330f729Sjoerg /*ForObjCContainer=*/true,
3437330f729Sjoerg ProtocolIdents, protocols);
3447330f729Sjoerg }
3457330f729Sjoerg } else if (protocols.empty() && Tok.is(tok::less) &&
3467330f729Sjoerg ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
3477330f729Sjoerg LAngleLoc, EndProtoLoc,
3487330f729Sjoerg /*consumeLastToken=*/true)) {
3497330f729Sjoerg return nullptr;
3507330f729Sjoerg }
3517330f729Sjoerg
3527330f729Sjoerg if (Tok.isNot(tok::less))
3537330f729Sjoerg Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
3547330f729Sjoerg superClassId, superClassLoc);
3557330f729Sjoerg
3567330f729Sjoerg Decl *ClsType = Actions.ActOnStartClassInterface(
3577330f729Sjoerg getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
3587330f729Sjoerg superClassLoc, typeArgs,
3597330f729Sjoerg SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
3607330f729Sjoerg protocols.size(), protocolLocs.data(), EndProtoLoc, attrs);
3617330f729Sjoerg
3627330f729Sjoerg if (Tok.is(tok::l_brace))
3637330f729Sjoerg ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
3647330f729Sjoerg
3657330f729Sjoerg ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
3667330f729Sjoerg
3677330f729Sjoerg return ClsType;
3687330f729Sjoerg }
3697330f729Sjoerg
3707330f729Sjoerg /// Add an attribute for a context-sensitive type nullability to the given
3717330f729Sjoerg /// declarator.
addContextSensitiveTypeNullability(Parser & P,Declarator & D,NullabilityKind nullability,SourceLocation nullabilityLoc,bool & addedToDeclSpec)3727330f729Sjoerg static void addContextSensitiveTypeNullability(Parser &P,
3737330f729Sjoerg Declarator &D,
3747330f729Sjoerg NullabilityKind nullability,
3757330f729Sjoerg SourceLocation nullabilityLoc,
3767330f729Sjoerg bool &addedToDeclSpec) {
3777330f729Sjoerg // Create the attribute.
3787330f729Sjoerg auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {
3797330f729Sjoerg return Pool.create(P.getNullabilityKeyword(nullability),
3807330f729Sjoerg SourceRange(nullabilityLoc), nullptr, SourceLocation(),
3817330f729Sjoerg nullptr, 0, ParsedAttr::AS_ContextSensitiveKeyword);
3827330f729Sjoerg };
3837330f729Sjoerg
3847330f729Sjoerg if (D.getNumTypeObjects() > 0) {
3857330f729Sjoerg // Add the attribute to the declarator chunk nearest the declarator.
3867330f729Sjoerg D.getTypeObject(0).getAttrs().addAtEnd(
3877330f729Sjoerg getNullabilityAttr(D.getAttributePool()));
3887330f729Sjoerg } else if (!addedToDeclSpec) {
3897330f729Sjoerg // Otherwise, just put it on the declaration specifiers (if one
3907330f729Sjoerg // isn't there already).
3917330f729Sjoerg D.getMutableDeclSpec().getAttributes().addAtEnd(
3927330f729Sjoerg getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));
3937330f729Sjoerg addedToDeclSpec = true;
3947330f729Sjoerg }
3957330f729Sjoerg }
3967330f729Sjoerg
3977330f729Sjoerg /// Parse an Objective-C type parameter list, if present, or capture
3987330f729Sjoerg /// the locations of the protocol identifiers for a list of protocol
3997330f729Sjoerg /// references.
4007330f729Sjoerg ///
4017330f729Sjoerg /// objc-type-parameter-list:
4027330f729Sjoerg /// '<' objc-type-parameter (',' objc-type-parameter)* '>'
4037330f729Sjoerg ///
4047330f729Sjoerg /// objc-type-parameter:
4057330f729Sjoerg /// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
4067330f729Sjoerg ///
4077330f729Sjoerg /// objc-type-parameter-bound:
4087330f729Sjoerg /// ':' type-name
4097330f729Sjoerg ///
4107330f729Sjoerg /// objc-type-parameter-variance:
4117330f729Sjoerg /// '__covariant'
4127330f729Sjoerg /// '__contravariant'
4137330f729Sjoerg ///
4147330f729Sjoerg /// \param lAngleLoc The location of the starting '<'.
4157330f729Sjoerg ///
4167330f729Sjoerg /// \param protocolIdents Will capture the list of identifiers, if the
4177330f729Sjoerg /// angle brackets contain a list of protocol references rather than a
4187330f729Sjoerg /// type parameter list.
4197330f729Sjoerg ///
4207330f729Sjoerg /// \param rAngleLoc The location of the ending '>'.
parseObjCTypeParamListOrProtocolRefs(ObjCTypeParamListScope & Scope,SourceLocation & lAngleLoc,SmallVectorImpl<IdentifierLocPair> & protocolIdents,SourceLocation & rAngleLoc,bool mayBeProtocolList)4217330f729Sjoerg ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
4227330f729Sjoerg ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,
4237330f729Sjoerg SmallVectorImpl<IdentifierLocPair> &protocolIdents,
4247330f729Sjoerg SourceLocation &rAngleLoc, bool mayBeProtocolList) {
4257330f729Sjoerg assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
4267330f729Sjoerg
4277330f729Sjoerg // Within the type parameter list, don't treat '>' as an operator.
4287330f729Sjoerg GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
4297330f729Sjoerg
4307330f729Sjoerg // Local function to "flush" the protocol identifiers, turning them into
4317330f729Sjoerg // type parameters.
4327330f729Sjoerg SmallVector<Decl *, 4> typeParams;
4337330f729Sjoerg auto makeProtocolIdentsIntoTypeParameters = [&]() {
4347330f729Sjoerg unsigned index = 0;
4357330f729Sjoerg for (const auto &pair : protocolIdents) {
4367330f729Sjoerg DeclResult typeParam = Actions.actOnObjCTypeParam(
4377330f729Sjoerg getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
4387330f729Sjoerg index++, pair.first, pair.second, SourceLocation(), nullptr);
4397330f729Sjoerg if (typeParam.isUsable())
4407330f729Sjoerg typeParams.push_back(typeParam.get());
4417330f729Sjoerg }
4427330f729Sjoerg
4437330f729Sjoerg protocolIdents.clear();
4447330f729Sjoerg mayBeProtocolList = false;
4457330f729Sjoerg };
4467330f729Sjoerg
4477330f729Sjoerg bool invalid = false;
4487330f729Sjoerg lAngleLoc = ConsumeToken();
4497330f729Sjoerg
4507330f729Sjoerg do {
4517330f729Sjoerg // Parse the variance, if any.
4527330f729Sjoerg SourceLocation varianceLoc;
4537330f729Sjoerg ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
4547330f729Sjoerg if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
4557330f729Sjoerg variance = Tok.is(tok::kw___covariant)
4567330f729Sjoerg ? ObjCTypeParamVariance::Covariant
4577330f729Sjoerg : ObjCTypeParamVariance::Contravariant;
4587330f729Sjoerg varianceLoc = ConsumeToken();
4597330f729Sjoerg
4607330f729Sjoerg // Once we've seen a variance specific , we know this is not a
4617330f729Sjoerg // list of protocol references.
4627330f729Sjoerg if (mayBeProtocolList) {
4637330f729Sjoerg // Up until now, we have been queuing up parameters because they
4647330f729Sjoerg // might be protocol references. Turn them into parameters now.
4657330f729Sjoerg makeProtocolIdentsIntoTypeParameters();
4667330f729Sjoerg }
4677330f729Sjoerg }
4687330f729Sjoerg
4697330f729Sjoerg // Parse the identifier.
4707330f729Sjoerg if (!Tok.is(tok::identifier)) {
4717330f729Sjoerg // Code completion.
4727330f729Sjoerg if (Tok.is(tok::code_completion)) {
4737330f729Sjoerg // FIXME: If these aren't protocol references, we'll need different
4747330f729Sjoerg // completions.
4757330f729Sjoerg cutOffParsing();
476*e038c9c4Sjoerg Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
4777330f729Sjoerg
4787330f729Sjoerg // FIXME: Better recovery here?.
4797330f729Sjoerg return nullptr;
4807330f729Sjoerg }
4817330f729Sjoerg
4827330f729Sjoerg Diag(Tok, diag::err_objc_expected_type_parameter);
4837330f729Sjoerg invalid = true;
4847330f729Sjoerg break;
4857330f729Sjoerg }
4867330f729Sjoerg
4877330f729Sjoerg IdentifierInfo *paramName = Tok.getIdentifierInfo();
4887330f729Sjoerg SourceLocation paramLoc = ConsumeToken();
4897330f729Sjoerg
4907330f729Sjoerg // If there is a bound, parse it.
4917330f729Sjoerg SourceLocation colonLoc;
4927330f729Sjoerg TypeResult boundType;
4937330f729Sjoerg if (TryConsumeToken(tok::colon, colonLoc)) {
4947330f729Sjoerg // Once we've seen a bound, we know this is not a list of protocol
4957330f729Sjoerg // references.
4967330f729Sjoerg if (mayBeProtocolList) {
4977330f729Sjoerg // Up until now, we have been queuing up parameters because they
4987330f729Sjoerg // might be protocol references. Turn them into parameters now.
4997330f729Sjoerg makeProtocolIdentsIntoTypeParameters();
5007330f729Sjoerg }
5017330f729Sjoerg
5027330f729Sjoerg // type-name
5037330f729Sjoerg boundType = ParseTypeName();
5047330f729Sjoerg if (boundType.isInvalid())
5057330f729Sjoerg invalid = true;
5067330f729Sjoerg } else if (mayBeProtocolList) {
5077330f729Sjoerg // If this could still be a protocol list, just capture the identifier.
5087330f729Sjoerg // We don't want to turn it into a parameter.
5097330f729Sjoerg protocolIdents.push_back(std::make_pair(paramName, paramLoc));
5107330f729Sjoerg continue;
5117330f729Sjoerg }
5127330f729Sjoerg
5137330f729Sjoerg // Create the type parameter.
5147330f729Sjoerg DeclResult typeParam = Actions.actOnObjCTypeParam(
5157330f729Sjoerg getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
5167330f729Sjoerg paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
5177330f729Sjoerg if (typeParam.isUsable())
5187330f729Sjoerg typeParams.push_back(typeParam.get());
5197330f729Sjoerg } while (TryConsumeToken(tok::comma));
5207330f729Sjoerg
5217330f729Sjoerg // Parse the '>'.
5227330f729Sjoerg if (invalid) {
5237330f729Sjoerg SkipUntil(tok::greater, tok::at, StopBeforeMatch);
5247330f729Sjoerg if (Tok.is(tok::greater))
5257330f729Sjoerg ConsumeToken();
526*e038c9c4Sjoerg } else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc,
5277330f729Sjoerg /*ConsumeLastToken=*/true,
5287330f729Sjoerg /*ObjCGenericList=*/true)) {
5297330f729Sjoerg SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
5307330f729Sjoerg tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
5317330f729Sjoerg tok::comma, tok::semi },
5327330f729Sjoerg StopBeforeMatch);
5337330f729Sjoerg if (Tok.is(tok::greater))
5347330f729Sjoerg ConsumeToken();
5357330f729Sjoerg }
5367330f729Sjoerg
5377330f729Sjoerg if (mayBeProtocolList) {
5387330f729Sjoerg // A type parameter list must be followed by either a ':' (indicating the
5397330f729Sjoerg // presence of a superclass) or a '(' (indicating that this is a category
5407330f729Sjoerg // or extension). This disambiguates between an objc-type-parameter-list
5417330f729Sjoerg // and a objc-protocol-refs.
5427330f729Sjoerg if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
5437330f729Sjoerg // Returning null indicates that we don't have a type parameter list.
5447330f729Sjoerg // The results the caller needs to handle the protocol references are
5457330f729Sjoerg // captured in the reference parameters already.
5467330f729Sjoerg return nullptr;
5477330f729Sjoerg }
5487330f729Sjoerg
5497330f729Sjoerg // We have a type parameter list that looks like a list of protocol
5507330f729Sjoerg // references. Turn that parameter list into type parameters.
5517330f729Sjoerg makeProtocolIdentsIntoTypeParameters();
5527330f729Sjoerg }
5537330f729Sjoerg
5547330f729Sjoerg // Form the type parameter list and enter its scope.
5557330f729Sjoerg ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
5567330f729Sjoerg getCurScope(),
5577330f729Sjoerg lAngleLoc,
5587330f729Sjoerg typeParams,
5597330f729Sjoerg rAngleLoc);
5607330f729Sjoerg Scope.enter(list);
5617330f729Sjoerg
5627330f729Sjoerg // Clear out the angle locations; they're used by the caller to indicate
5637330f729Sjoerg // whether there are any protocol references.
5647330f729Sjoerg lAngleLoc = SourceLocation();
5657330f729Sjoerg rAngleLoc = SourceLocation();
5667330f729Sjoerg return invalid ? nullptr : list;
5677330f729Sjoerg }
5687330f729Sjoerg
5697330f729Sjoerg /// Parse an objc-type-parameter-list.
parseObjCTypeParamList()5707330f729Sjoerg ObjCTypeParamList *Parser::parseObjCTypeParamList() {
5717330f729Sjoerg SourceLocation lAngleLoc;
5727330f729Sjoerg SmallVector<IdentifierLocPair, 1> protocolIdents;
5737330f729Sjoerg SourceLocation rAngleLoc;
5747330f729Sjoerg
5757330f729Sjoerg ObjCTypeParamListScope Scope(Actions, getCurScope());
5767330f729Sjoerg return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,
5777330f729Sjoerg rAngleLoc,
5787330f729Sjoerg /*mayBeProtocolList=*/false);
5797330f729Sjoerg }
5807330f729Sjoerg
5817330f729Sjoerg /// objc-interface-decl-list:
5827330f729Sjoerg /// empty
5837330f729Sjoerg /// objc-interface-decl-list objc-property-decl [OBJC2]
5847330f729Sjoerg /// objc-interface-decl-list objc-method-requirement [OBJC2]
5857330f729Sjoerg /// objc-interface-decl-list objc-method-proto ';'
5867330f729Sjoerg /// objc-interface-decl-list declaration
5877330f729Sjoerg /// objc-interface-decl-list ';'
5887330f729Sjoerg ///
5897330f729Sjoerg /// objc-method-requirement: [OBJC2]
5907330f729Sjoerg /// @required
5917330f729Sjoerg /// @optional
5927330f729Sjoerg ///
ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,Decl * CDecl)5937330f729Sjoerg void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
5947330f729Sjoerg Decl *CDecl) {
5957330f729Sjoerg SmallVector<Decl *, 32> allMethods;
5967330f729Sjoerg SmallVector<DeclGroupPtrTy, 8> allTUVariables;
5977330f729Sjoerg tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
5987330f729Sjoerg
5997330f729Sjoerg SourceRange AtEnd;
6007330f729Sjoerg
6017330f729Sjoerg while (1) {
6027330f729Sjoerg // If this is a method prototype, parse it.
6037330f729Sjoerg if (Tok.isOneOf(tok::minus, tok::plus)) {
6047330f729Sjoerg if (Decl *methodPrototype =
6057330f729Sjoerg ParseObjCMethodPrototype(MethodImplKind, false))
6067330f729Sjoerg allMethods.push_back(methodPrototype);
6077330f729Sjoerg // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
6087330f729Sjoerg // method definitions.
6097330f729Sjoerg if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
6107330f729Sjoerg // We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
6117330f729Sjoerg SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
6127330f729Sjoerg if (Tok.is(tok::semi))
6137330f729Sjoerg ConsumeToken();
6147330f729Sjoerg }
6157330f729Sjoerg continue;
6167330f729Sjoerg }
6177330f729Sjoerg if (Tok.is(tok::l_paren)) {
6187330f729Sjoerg Diag(Tok, diag::err_expected_minus_or_plus);
6197330f729Sjoerg ParseObjCMethodDecl(Tok.getLocation(),
6207330f729Sjoerg tok::minus,
6217330f729Sjoerg MethodImplKind, false);
6227330f729Sjoerg continue;
6237330f729Sjoerg }
6247330f729Sjoerg // Ignore excess semicolons.
6257330f729Sjoerg if (Tok.is(tok::semi)) {
6267330f729Sjoerg // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,
6277330f729Sjoerg // to make -Wextra-semi diagnose them.
6287330f729Sjoerg ConsumeToken();
6297330f729Sjoerg continue;
6307330f729Sjoerg }
6317330f729Sjoerg
6327330f729Sjoerg // If we got to the end of the file, exit the loop.
6337330f729Sjoerg if (isEofOrEom())
6347330f729Sjoerg break;
6357330f729Sjoerg
6367330f729Sjoerg // Code completion within an Objective-C interface.
6377330f729Sjoerg if (Tok.is(tok::code_completion)) {
638*e038c9c4Sjoerg cutOffParsing();
6397330f729Sjoerg Actions.CodeCompleteOrdinaryName(getCurScope(),
6407330f729Sjoerg CurParsedObjCImpl? Sema::PCC_ObjCImplementation
6417330f729Sjoerg : Sema::PCC_ObjCInterface);
642*e038c9c4Sjoerg return;
6437330f729Sjoerg }
6447330f729Sjoerg
6457330f729Sjoerg // If we don't have an @ directive, parse it as a function definition.
6467330f729Sjoerg if (Tok.isNot(tok::at)) {
6477330f729Sjoerg // The code below does not consume '}'s because it is afraid of eating the
6487330f729Sjoerg // end of a namespace. Because of the way this code is structured, an
6497330f729Sjoerg // erroneous r_brace would cause an infinite loop if not handled here.
6507330f729Sjoerg if (Tok.is(tok::r_brace))
6517330f729Sjoerg break;
6527330f729Sjoerg
6537330f729Sjoerg ParsedAttributesWithRange attrs(AttrFactory);
6547330f729Sjoerg
6557330f729Sjoerg // Since we call ParseDeclarationOrFunctionDefinition() instead of
6567330f729Sjoerg // ParseExternalDeclaration() below (so that this doesn't parse nested
6577330f729Sjoerg // @interfaces), this needs to duplicate some code from the latter.
6587330f729Sjoerg if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
6597330f729Sjoerg SourceLocation DeclEnd;
6607330f729Sjoerg allTUVariables.push_back(
661*e038c9c4Sjoerg ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs));
6627330f729Sjoerg continue;
6637330f729Sjoerg }
6647330f729Sjoerg
6657330f729Sjoerg allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
6667330f729Sjoerg continue;
6677330f729Sjoerg }
6687330f729Sjoerg
6697330f729Sjoerg // Otherwise, we have an @ directive, eat the @.
6707330f729Sjoerg SourceLocation AtLoc = ConsumeToken(); // the "@"
6717330f729Sjoerg if (Tok.is(tok::code_completion)) {
672*e038c9c4Sjoerg cutOffParsing();
6737330f729Sjoerg Actions.CodeCompleteObjCAtDirective(getCurScope());
674*e038c9c4Sjoerg return;
6757330f729Sjoerg }
6767330f729Sjoerg
6777330f729Sjoerg tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
6787330f729Sjoerg
6797330f729Sjoerg if (DirectiveKind == tok::objc_end) { // @end -> terminate list
6807330f729Sjoerg AtEnd.setBegin(AtLoc);
6817330f729Sjoerg AtEnd.setEnd(Tok.getLocation());
6827330f729Sjoerg break;
6837330f729Sjoerg } else if (DirectiveKind == tok::objc_not_keyword) {
6847330f729Sjoerg Diag(Tok, diag::err_objc_unknown_at);
6857330f729Sjoerg SkipUntil(tok::semi);
6867330f729Sjoerg continue;
6877330f729Sjoerg }
6887330f729Sjoerg
6897330f729Sjoerg // Eat the identifier.
6907330f729Sjoerg ConsumeToken();
6917330f729Sjoerg
6927330f729Sjoerg switch (DirectiveKind) {
6937330f729Sjoerg default:
6947330f729Sjoerg // FIXME: If someone forgets an @end on a protocol, this loop will
6957330f729Sjoerg // continue to eat up tons of stuff and spew lots of nonsense errors. It
6967330f729Sjoerg // would probably be better to bail out if we saw an @class or @interface
6977330f729Sjoerg // or something like that.
6987330f729Sjoerg Diag(AtLoc, diag::err_objc_illegal_interface_qual);
6997330f729Sjoerg // Skip until we see an '@' or '}' or ';'.
7007330f729Sjoerg SkipUntil(tok::r_brace, tok::at, StopAtSemi);
7017330f729Sjoerg break;
7027330f729Sjoerg
7037330f729Sjoerg case tok::objc_implementation:
7047330f729Sjoerg case tok::objc_interface:
7057330f729Sjoerg Diag(AtLoc, diag::err_objc_missing_end)
7067330f729Sjoerg << FixItHint::CreateInsertion(AtLoc, "@end\n");
7077330f729Sjoerg Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
7087330f729Sjoerg << (int)Actions.getObjCContainerKind();
7097330f729Sjoerg ConsumeToken();
7107330f729Sjoerg break;
7117330f729Sjoerg
7127330f729Sjoerg case tok::objc_required:
7137330f729Sjoerg case tok::objc_optional:
7147330f729Sjoerg // This is only valid on protocols.
7157330f729Sjoerg if (contextKey != tok::objc_protocol)
7167330f729Sjoerg Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
7177330f729Sjoerg else
7187330f729Sjoerg MethodImplKind = DirectiveKind;
7197330f729Sjoerg break;
7207330f729Sjoerg
7217330f729Sjoerg case tok::objc_property:
7227330f729Sjoerg ObjCDeclSpec OCDS;
7237330f729Sjoerg SourceLocation LParenLoc;
7247330f729Sjoerg // Parse property attribute list, if any.
7257330f729Sjoerg if (Tok.is(tok::l_paren)) {
7267330f729Sjoerg LParenLoc = Tok.getLocation();
7277330f729Sjoerg ParseObjCPropertyAttribute(OCDS);
7287330f729Sjoerg }
7297330f729Sjoerg
7307330f729Sjoerg bool addedToDeclSpec = false;
7317330f729Sjoerg auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
7327330f729Sjoerg if (FD.D.getIdentifier() == nullptr) {
7337330f729Sjoerg Diag(AtLoc, diag::err_objc_property_requires_field_name)
7347330f729Sjoerg << FD.D.getSourceRange();
7357330f729Sjoerg return;
7367330f729Sjoerg }
7377330f729Sjoerg if (FD.BitfieldSize) {
7387330f729Sjoerg Diag(AtLoc, diag::err_objc_property_bitfield)
7397330f729Sjoerg << FD.D.getSourceRange();
7407330f729Sjoerg return;
7417330f729Sjoerg }
7427330f729Sjoerg
7437330f729Sjoerg // Map a nullability property attribute to a context-sensitive keyword
7447330f729Sjoerg // attribute.
745*e038c9c4Sjoerg if (OCDS.getPropertyAttributes() &
746*e038c9c4Sjoerg ObjCPropertyAttribute::kind_nullability)
7477330f729Sjoerg addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
7487330f729Sjoerg OCDS.getNullabilityLoc(),
7497330f729Sjoerg addedToDeclSpec);
7507330f729Sjoerg
7517330f729Sjoerg // Install the property declarator into interfaceDecl.
7527330f729Sjoerg IdentifierInfo *SelName =
7537330f729Sjoerg OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
7547330f729Sjoerg
7557330f729Sjoerg Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
7567330f729Sjoerg IdentifierInfo *SetterName = OCDS.getSetterName();
7577330f729Sjoerg Selector SetterSel;
7587330f729Sjoerg if (SetterName)
7597330f729Sjoerg SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
7607330f729Sjoerg else
7617330f729Sjoerg SetterSel = SelectorTable::constructSetterSelector(
7627330f729Sjoerg PP.getIdentifierTable(), PP.getSelectorTable(),
7637330f729Sjoerg FD.D.getIdentifier());
7647330f729Sjoerg Decl *Property = Actions.ActOnProperty(
7657330f729Sjoerg getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
7667330f729Sjoerg MethodImplKind);
7677330f729Sjoerg
7687330f729Sjoerg FD.complete(Property);
7697330f729Sjoerg };
7707330f729Sjoerg
7717330f729Sjoerg // Parse all the comma separated declarators.
7727330f729Sjoerg ParsingDeclSpec DS(*this);
7737330f729Sjoerg ParseStructDeclaration(DS, ObjCPropertyCallback);
7747330f729Sjoerg
7757330f729Sjoerg ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
7767330f729Sjoerg break;
7777330f729Sjoerg }
7787330f729Sjoerg }
7797330f729Sjoerg
7807330f729Sjoerg // We break out of the big loop in two cases: when we see @end or when we see
7817330f729Sjoerg // EOF. In the former case, eat the @end. In the later case, emit an error.
7827330f729Sjoerg if (Tok.is(tok::code_completion)) {
783*e038c9c4Sjoerg cutOffParsing();
7847330f729Sjoerg Actions.CodeCompleteObjCAtDirective(getCurScope());
785*e038c9c4Sjoerg return;
7867330f729Sjoerg } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
7877330f729Sjoerg ConsumeToken(); // the "end" identifier
7887330f729Sjoerg } else {
7897330f729Sjoerg Diag(Tok, diag::err_objc_missing_end)
7907330f729Sjoerg << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
7917330f729Sjoerg Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
7927330f729Sjoerg << (int)Actions.getObjCContainerKind();
7937330f729Sjoerg AtEnd.setBegin(Tok.getLocation());
7947330f729Sjoerg AtEnd.setEnd(Tok.getLocation());
7957330f729Sjoerg }
7967330f729Sjoerg
7977330f729Sjoerg // Insert collected methods declarations into the @interface object.
7987330f729Sjoerg // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
7997330f729Sjoerg Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
8007330f729Sjoerg }
8017330f729Sjoerg
8027330f729Sjoerg /// Diagnose redundant or conflicting nullability information.
diagnoseRedundantPropertyNullability(Parser & P,ObjCDeclSpec & DS,NullabilityKind nullability,SourceLocation nullabilityLoc)8037330f729Sjoerg static void diagnoseRedundantPropertyNullability(Parser &P,
8047330f729Sjoerg ObjCDeclSpec &DS,
8057330f729Sjoerg NullabilityKind nullability,
8067330f729Sjoerg SourceLocation nullabilityLoc){
8077330f729Sjoerg if (DS.getNullability() == nullability) {
8087330f729Sjoerg P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
8097330f729Sjoerg << DiagNullabilityKind(nullability, true)
8107330f729Sjoerg << SourceRange(DS.getNullabilityLoc());
8117330f729Sjoerg return;
8127330f729Sjoerg }
8137330f729Sjoerg
8147330f729Sjoerg P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
8157330f729Sjoerg << DiagNullabilityKind(nullability, true)
8167330f729Sjoerg << DiagNullabilityKind(DS.getNullability(), true)
8177330f729Sjoerg << SourceRange(DS.getNullabilityLoc());
8187330f729Sjoerg }
8197330f729Sjoerg
8207330f729Sjoerg /// Parse property attribute declarations.
8217330f729Sjoerg ///
8227330f729Sjoerg /// property-attr-decl: '(' property-attrlist ')'
8237330f729Sjoerg /// property-attrlist:
8247330f729Sjoerg /// property-attribute
8257330f729Sjoerg /// property-attrlist ',' property-attribute
8267330f729Sjoerg /// property-attribute:
8277330f729Sjoerg /// getter '=' identifier
8287330f729Sjoerg /// setter '=' identifier ':'
829*e038c9c4Sjoerg /// direct
8307330f729Sjoerg /// readonly
8317330f729Sjoerg /// readwrite
8327330f729Sjoerg /// assign
8337330f729Sjoerg /// retain
8347330f729Sjoerg /// copy
8357330f729Sjoerg /// nonatomic
8367330f729Sjoerg /// atomic
8377330f729Sjoerg /// strong
8387330f729Sjoerg /// weak
8397330f729Sjoerg /// unsafe_unretained
8407330f729Sjoerg /// nonnull
8417330f729Sjoerg /// nullable
8427330f729Sjoerg /// null_unspecified
8437330f729Sjoerg /// null_resettable
8447330f729Sjoerg /// class
8457330f729Sjoerg ///
ParseObjCPropertyAttribute(ObjCDeclSpec & DS)8467330f729Sjoerg void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
8477330f729Sjoerg assert(Tok.getKind() == tok::l_paren);
8487330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
8497330f729Sjoerg T.consumeOpen();
8507330f729Sjoerg
8517330f729Sjoerg while (1) {
8527330f729Sjoerg if (Tok.is(tok::code_completion)) {
853*e038c9c4Sjoerg cutOffParsing();
8547330f729Sjoerg Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
855*e038c9c4Sjoerg return;
8567330f729Sjoerg }
8577330f729Sjoerg const IdentifierInfo *II = Tok.getIdentifierInfo();
8587330f729Sjoerg
8597330f729Sjoerg // If this is not an identifier at all, bail out early.
8607330f729Sjoerg if (!II) {
8617330f729Sjoerg T.consumeClose();
8627330f729Sjoerg return;
8637330f729Sjoerg }
8647330f729Sjoerg
8657330f729Sjoerg SourceLocation AttrName = ConsumeToken(); // consume last attribute name
8667330f729Sjoerg
8677330f729Sjoerg if (II->isStr("readonly"))
868*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
8697330f729Sjoerg else if (II->isStr("assign"))
870*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
8717330f729Sjoerg else if (II->isStr("unsafe_unretained"))
872*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
8737330f729Sjoerg else if (II->isStr("readwrite"))
874*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
8757330f729Sjoerg else if (II->isStr("retain"))
876*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
8777330f729Sjoerg else if (II->isStr("strong"))
878*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
8797330f729Sjoerg else if (II->isStr("copy"))
880*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
8817330f729Sjoerg else if (II->isStr("nonatomic"))
882*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
8837330f729Sjoerg else if (II->isStr("atomic"))
884*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
8857330f729Sjoerg else if (II->isStr("weak"))
886*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
8877330f729Sjoerg else if (II->isStr("getter") || II->isStr("setter")) {
8887330f729Sjoerg bool IsSetter = II->getNameStart()[0] == 's';
8897330f729Sjoerg
8907330f729Sjoerg // getter/setter require extra treatment.
8917330f729Sjoerg unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
8927330f729Sjoerg diag::err_objc_expected_equal_for_getter;
8937330f729Sjoerg
8947330f729Sjoerg if (ExpectAndConsume(tok::equal, DiagID)) {
8957330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
8967330f729Sjoerg return;
8977330f729Sjoerg }
8987330f729Sjoerg
8997330f729Sjoerg if (Tok.is(tok::code_completion)) {
900*e038c9c4Sjoerg cutOffParsing();
9017330f729Sjoerg if (IsSetter)
9027330f729Sjoerg Actions.CodeCompleteObjCPropertySetter(getCurScope());
9037330f729Sjoerg else
9047330f729Sjoerg Actions.CodeCompleteObjCPropertyGetter(getCurScope());
905*e038c9c4Sjoerg return;
9067330f729Sjoerg }
9077330f729Sjoerg
9087330f729Sjoerg SourceLocation SelLoc;
9097330f729Sjoerg IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
9107330f729Sjoerg
9117330f729Sjoerg if (!SelIdent) {
9127330f729Sjoerg Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
9137330f729Sjoerg << IsSetter;
9147330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
9157330f729Sjoerg return;
9167330f729Sjoerg }
9177330f729Sjoerg
9187330f729Sjoerg if (IsSetter) {
919*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
9207330f729Sjoerg DS.setSetterName(SelIdent, SelLoc);
9217330f729Sjoerg
9227330f729Sjoerg if (ExpectAndConsume(tok::colon,
9237330f729Sjoerg diag::err_expected_colon_after_setter_name)) {
9247330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
9257330f729Sjoerg return;
9267330f729Sjoerg }
9277330f729Sjoerg } else {
928*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
9297330f729Sjoerg DS.setGetterName(SelIdent, SelLoc);
9307330f729Sjoerg }
9317330f729Sjoerg } else if (II->isStr("nonnull")) {
932*e038c9c4Sjoerg if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
9337330f729Sjoerg diagnoseRedundantPropertyNullability(*this, DS,
9347330f729Sjoerg NullabilityKind::NonNull,
9357330f729Sjoerg Tok.getLocation());
936*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
9377330f729Sjoerg DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
9387330f729Sjoerg } else if (II->isStr("nullable")) {
939*e038c9c4Sjoerg if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
9407330f729Sjoerg diagnoseRedundantPropertyNullability(*this, DS,
9417330f729Sjoerg NullabilityKind::Nullable,
9427330f729Sjoerg Tok.getLocation());
943*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
9447330f729Sjoerg DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
9457330f729Sjoerg } else if (II->isStr("null_unspecified")) {
946*e038c9c4Sjoerg if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
9477330f729Sjoerg diagnoseRedundantPropertyNullability(*this, DS,
9487330f729Sjoerg NullabilityKind::Unspecified,
9497330f729Sjoerg Tok.getLocation());
950*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
9517330f729Sjoerg DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
9527330f729Sjoerg } else if (II->isStr("null_resettable")) {
953*e038c9c4Sjoerg if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
9547330f729Sjoerg diagnoseRedundantPropertyNullability(*this, DS,
9557330f729Sjoerg NullabilityKind::Unspecified,
9567330f729Sjoerg Tok.getLocation());
957*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
9587330f729Sjoerg DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
9597330f729Sjoerg
9607330f729Sjoerg // Also set the null_resettable bit.
961*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
9627330f729Sjoerg } else if (II->isStr("class")) {
963*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_class);
964*e038c9c4Sjoerg } else if (II->isStr("direct")) {
965*e038c9c4Sjoerg DS.setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
9667330f729Sjoerg } else {
9677330f729Sjoerg Diag(AttrName, diag::err_objc_expected_property_attr) << II;
9687330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
9697330f729Sjoerg return;
9707330f729Sjoerg }
9717330f729Sjoerg
9727330f729Sjoerg if (Tok.isNot(tok::comma))
9737330f729Sjoerg break;
9747330f729Sjoerg
9757330f729Sjoerg ConsumeToken();
9767330f729Sjoerg }
9777330f729Sjoerg
9787330f729Sjoerg T.consumeClose();
9797330f729Sjoerg }
9807330f729Sjoerg
9817330f729Sjoerg /// objc-method-proto:
9827330f729Sjoerg /// objc-instance-method objc-method-decl objc-method-attributes[opt]
9837330f729Sjoerg /// objc-class-method objc-method-decl objc-method-attributes[opt]
9847330f729Sjoerg ///
9857330f729Sjoerg /// objc-instance-method: '-'
9867330f729Sjoerg /// objc-class-method: '+'
9877330f729Sjoerg ///
9887330f729Sjoerg /// objc-method-attributes: [OBJC2]
9897330f729Sjoerg /// __attribute__((deprecated))
9907330f729Sjoerg ///
ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)9917330f729Sjoerg Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
9927330f729Sjoerg bool MethodDefinition) {
9937330f729Sjoerg assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
9947330f729Sjoerg
9957330f729Sjoerg tok::TokenKind methodType = Tok.getKind();
9967330f729Sjoerg SourceLocation mLoc = ConsumeToken();
9977330f729Sjoerg Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
9987330f729Sjoerg MethodDefinition);
9997330f729Sjoerg // Since this rule is used for both method declarations and definitions,
10007330f729Sjoerg // the caller is (optionally) responsible for consuming the ';'.
10017330f729Sjoerg return MDecl;
10027330f729Sjoerg }
10037330f729Sjoerg
10047330f729Sjoerg /// objc-selector:
10057330f729Sjoerg /// identifier
10067330f729Sjoerg /// one of
10077330f729Sjoerg /// enum struct union if else while do for switch case default
10087330f729Sjoerg /// break continue return goto asm sizeof typeof __alignof
10097330f729Sjoerg /// unsigned long const short volatile signed restrict _Complex
10107330f729Sjoerg /// in out inout bycopy byref oneway int char float double void _Bool
10117330f729Sjoerg ///
ParseObjCSelectorPiece(SourceLocation & SelectorLoc)10127330f729Sjoerg IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
10137330f729Sjoerg
10147330f729Sjoerg switch (Tok.getKind()) {
10157330f729Sjoerg default:
10167330f729Sjoerg return nullptr;
10177330f729Sjoerg case tok::colon:
10187330f729Sjoerg // Empty selector piece uses the location of the ':'.
10197330f729Sjoerg SelectorLoc = Tok.getLocation();
10207330f729Sjoerg return nullptr;
10217330f729Sjoerg case tok::ampamp:
10227330f729Sjoerg case tok::ampequal:
10237330f729Sjoerg case tok::amp:
10247330f729Sjoerg case tok::pipe:
10257330f729Sjoerg case tok::tilde:
10267330f729Sjoerg case tok::exclaim:
10277330f729Sjoerg case tok::exclaimequal:
10287330f729Sjoerg case tok::pipepipe:
10297330f729Sjoerg case tok::pipeequal:
10307330f729Sjoerg case tok::caret:
10317330f729Sjoerg case tok::caretequal: {
10327330f729Sjoerg std::string ThisTok(PP.getSpelling(Tok));
10337330f729Sjoerg if (isLetter(ThisTok[0])) {
10347330f729Sjoerg IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);
10357330f729Sjoerg Tok.setKind(tok::identifier);
10367330f729Sjoerg SelectorLoc = ConsumeToken();
10377330f729Sjoerg return II;
10387330f729Sjoerg }
10397330f729Sjoerg return nullptr;
10407330f729Sjoerg }
10417330f729Sjoerg
10427330f729Sjoerg case tok::identifier:
10437330f729Sjoerg case tok::kw_asm:
10447330f729Sjoerg case tok::kw_auto:
10457330f729Sjoerg case tok::kw_bool:
10467330f729Sjoerg case tok::kw_break:
10477330f729Sjoerg case tok::kw_case:
10487330f729Sjoerg case tok::kw_catch:
10497330f729Sjoerg case tok::kw_char:
10507330f729Sjoerg case tok::kw_class:
10517330f729Sjoerg case tok::kw_const:
10527330f729Sjoerg case tok::kw_const_cast:
10537330f729Sjoerg case tok::kw_continue:
10547330f729Sjoerg case tok::kw_default:
10557330f729Sjoerg case tok::kw_delete:
10567330f729Sjoerg case tok::kw_do:
10577330f729Sjoerg case tok::kw_double:
10587330f729Sjoerg case tok::kw_dynamic_cast:
10597330f729Sjoerg case tok::kw_else:
10607330f729Sjoerg case tok::kw_enum:
10617330f729Sjoerg case tok::kw_explicit:
10627330f729Sjoerg case tok::kw_export:
10637330f729Sjoerg case tok::kw_extern:
10647330f729Sjoerg case tok::kw_false:
10657330f729Sjoerg case tok::kw_float:
10667330f729Sjoerg case tok::kw_for:
10677330f729Sjoerg case tok::kw_friend:
10687330f729Sjoerg case tok::kw_goto:
10697330f729Sjoerg case tok::kw_if:
10707330f729Sjoerg case tok::kw_inline:
10717330f729Sjoerg case tok::kw_int:
10727330f729Sjoerg case tok::kw_long:
10737330f729Sjoerg case tok::kw_mutable:
10747330f729Sjoerg case tok::kw_namespace:
10757330f729Sjoerg case tok::kw_new:
10767330f729Sjoerg case tok::kw_operator:
10777330f729Sjoerg case tok::kw_private:
10787330f729Sjoerg case tok::kw_protected:
10797330f729Sjoerg case tok::kw_public:
10807330f729Sjoerg case tok::kw_register:
10817330f729Sjoerg case tok::kw_reinterpret_cast:
10827330f729Sjoerg case tok::kw_restrict:
10837330f729Sjoerg case tok::kw_return:
10847330f729Sjoerg case tok::kw_short:
10857330f729Sjoerg case tok::kw_signed:
10867330f729Sjoerg case tok::kw_sizeof:
10877330f729Sjoerg case tok::kw_static:
10887330f729Sjoerg case tok::kw_static_cast:
10897330f729Sjoerg case tok::kw_struct:
10907330f729Sjoerg case tok::kw_switch:
10917330f729Sjoerg case tok::kw_template:
10927330f729Sjoerg case tok::kw_this:
10937330f729Sjoerg case tok::kw_throw:
10947330f729Sjoerg case tok::kw_true:
10957330f729Sjoerg case tok::kw_try:
10967330f729Sjoerg case tok::kw_typedef:
10977330f729Sjoerg case tok::kw_typeid:
10987330f729Sjoerg case tok::kw_typename:
10997330f729Sjoerg case tok::kw_typeof:
11007330f729Sjoerg case tok::kw_union:
11017330f729Sjoerg case tok::kw_unsigned:
11027330f729Sjoerg case tok::kw_using:
11037330f729Sjoerg case tok::kw_virtual:
11047330f729Sjoerg case tok::kw_void:
11057330f729Sjoerg case tok::kw_volatile:
11067330f729Sjoerg case tok::kw_wchar_t:
11077330f729Sjoerg case tok::kw_while:
11087330f729Sjoerg case tok::kw__Bool:
11097330f729Sjoerg case tok::kw__Complex:
11107330f729Sjoerg case tok::kw___alignof:
11117330f729Sjoerg case tok::kw___auto_type:
11127330f729Sjoerg IdentifierInfo *II = Tok.getIdentifierInfo();
11137330f729Sjoerg SelectorLoc = ConsumeToken();
11147330f729Sjoerg return II;
11157330f729Sjoerg }
11167330f729Sjoerg }
11177330f729Sjoerg
11187330f729Sjoerg /// objc-for-collection-in: 'in'
11197330f729Sjoerg ///
isTokIdentifier_in() const11207330f729Sjoerg bool Parser::isTokIdentifier_in() const {
11217330f729Sjoerg // FIXME: May have to do additional look-ahead to only allow for
11227330f729Sjoerg // valid tokens following an 'in'; such as an identifier, unary operators,
11237330f729Sjoerg // '[' etc.
11247330f729Sjoerg return (getLangOpts().ObjC && Tok.is(tok::identifier) &&
11257330f729Sjoerg Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
11267330f729Sjoerg }
11277330f729Sjoerg
11287330f729Sjoerg /// ParseObjCTypeQualifierList - This routine parses the objective-c's type
11297330f729Sjoerg /// qualifier list and builds their bitmask representation in the input
11307330f729Sjoerg /// argument.
11317330f729Sjoerg ///
11327330f729Sjoerg /// objc-type-qualifiers:
11337330f729Sjoerg /// objc-type-qualifier
11347330f729Sjoerg /// objc-type-qualifiers objc-type-qualifier
11357330f729Sjoerg ///
11367330f729Sjoerg /// objc-type-qualifier:
11377330f729Sjoerg /// 'in'
11387330f729Sjoerg /// 'out'
11397330f729Sjoerg /// 'inout'
11407330f729Sjoerg /// 'oneway'
11417330f729Sjoerg /// 'bycopy'
11427330f729Sjoerg /// 'byref'
11437330f729Sjoerg /// 'nonnull'
11447330f729Sjoerg /// 'nullable'
11457330f729Sjoerg /// 'null_unspecified'
11467330f729Sjoerg ///
ParseObjCTypeQualifierList(ObjCDeclSpec & DS,DeclaratorContext Context)11477330f729Sjoerg void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
11487330f729Sjoerg DeclaratorContext Context) {
1149*e038c9c4Sjoerg assert(Context == DeclaratorContext::ObjCParameter ||
1150*e038c9c4Sjoerg Context == DeclaratorContext::ObjCResult);
11517330f729Sjoerg
11527330f729Sjoerg while (1) {
11537330f729Sjoerg if (Tok.is(tok::code_completion)) {
1154*e038c9c4Sjoerg cutOffParsing();
1155*e038c9c4Sjoerg Actions.CodeCompleteObjCPassingType(
1156*e038c9c4Sjoerg getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);
1157*e038c9c4Sjoerg return;
11587330f729Sjoerg }
11597330f729Sjoerg
11607330f729Sjoerg if (Tok.isNot(tok::identifier))
11617330f729Sjoerg return;
11627330f729Sjoerg
11637330f729Sjoerg const IdentifierInfo *II = Tok.getIdentifierInfo();
11647330f729Sjoerg for (unsigned i = 0; i != objc_NumQuals; ++i) {
11657330f729Sjoerg if (II != ObjCTypeQuals[i] ||
11667330f729Sjoerg NextToken().is(tok::less) ||
11677330f729Sjoerg NextToken().is(tok::coloncolon))
11687330f729Sjoerg continue;
11697330f729Sjoerg
11707330f729Sjoerg ObjCDeclSpec::ObjCDeclQualifier Qual;
11717330f729Sjoerg NullabilityKind Nullability;
11727330f729Sjoerg switch (i) {
11737330f729Sjoerg default: llvm_unreachable("Unknown decl qualifier");
11747330f729Sjoerg case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
11757330f729Sjoerg case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
11767330f729Sjoerg case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
11777330f729Sjoerg case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
11787330f729Sjoerg case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
11797330f729Sjoerg case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
11807330f729Sjoerg
11817330f729Sjoerg case objc_nonnull:
11827330f729Sjoerg Qual = ObjCDeclSpec::DQ_CSNullability;
11837330f729Sjoerg Nullability = NullabilityKind::NonNull;
11847330f729Sjoerg break;
11857330f729Sjoerg
11867330f729Sjoerg case objc_nullable:
11877330f729Sjoerg Qual = ObjCDeclSpec::DQ_CSNullability;
11887330f729Sjoerg Nullability = NullabilityKind::Nullable;
11897330f729Sjoerg break;
11907330f729Sjoerg
11917330f729Sjoerg case objc_null_unspecified:
11927330f729Sjoerg Qual = ObjCDeclSpec::DQ_CSNullability;
11937330f729Sjoerg Nullability = NullabilityKind::Unspecified;
11947330f729Sjoerg break;
11957330f729Sjoerg }
11967330f729Sjoerg
11977330f729Sjoerg // FIXME: Diagnose redundant specifiers.
11987330f729Sjoerg DS.setObjCDeclQualifier(Qual);
11997330f729Sjoerg if (Qual == ObjCDeclSpec::DQ_CSNullability)
12007330f729Sjoerg DS.setNullability(Tok.getLocation(), Nullability);
12017330f729Sjoerg
12027330f729Sjoerg ConsumeToken();
12037330f729Sjoerg II = nullptr;
12047330f729Sjoerg break;
12057330f729Sjoerg }
12067330f729Sjoerg
12077330f729Sjoerg // If this wasn't a recognized qualifier, bail out.
12087330f729Sjoerg if (II) return;
12097330f729Sjoerg }
12107330f729Sjoerg }
12117330f729Sjoerg
12127330f729Sjoerg /// Take all the decl attributes out of the given list and add
12137330f729Sjoerg /// them to the given attribute set.
takeDeclAttributes(ParsedAttributesView & attrs,ParsedAttributesView & from)12147330f729Sjoerg static void takeDeclAttributes(ParsedAttributesView &attrs,
12157330f729Sjoerg ParsedAttributesView &from) {
12167330f729Sjoerg for (auto &AL : llvm::reverse(from)) {
12177330f729Sjoerg if (!AL.isUsedAsTypeAttr()) {
12187330f729Sjoerg from.remove(&AL);
12197330f729Sjoerg attrs.addAtEnd(&AL);
12207330f729Sjoerg }
12217330f729Sjoerg }
12227330f729Sjoerg }
12237330f729Sjoerg
12247330f729Sjoerg /// takeDeclAttributes - Take all the decl attributes from the given
12257330f729Sjoerg /// declarator and add them to the given list.
takeDeclAttributes(ParsedAttributes & attrs,Declarator & D)12267330f729Sjoerg static void takeDeclAttributes(ParsedAttributes &attrs,
12277330f729Sjoerg Declarator &D) {
12287330f729Sjoerg // First, take ownership of all attributes.
12297330f729Sjoerg attrs.getPool().takeAllFrom(D.getAttributePool());
12307330f729Sjoerg attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
12317330f729Sjoerg
12327330f729Sjoerg // Now actually move the attributes over.
12337330f729Sjoerg takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
12347330f729Sjoerg takeDeclAttributes(attrs, D.getAttributes());
12357330f729Sjoerg for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
12367330f729Sjoerg takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
12377330f729Sjoerg }
12387330f729Sjoerg
12397330f729Sjoerg /// objc-type-name:
12407330f729Sjoerg /// '(' objc-type-qualifiers[opt] type-name ')'
12417330f729Sjoerg /// '(' objc-type-qualifiers[opt] ')'
12427330f729Sjoerg ///
ParseObjCTypeName(ObjCDeclSpec & DS,DeclaratorContext context,ParsedAttributes * paramAttrs)12437330f729Sjoerg ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
12447330f729Sjoerg DeclaratorContext context,
12457330f729Sjoerg ParsedAttributes *paramAttrs) {
1246*e038c9c4Sjoerg assert(context == DeclaratorContext::ObjCParameter ||
1247*e038c9c4Sjoerg context == DeclaratorContext::ObjCResult);
12487330f729Sjoerg assert((paramAttrs != nullptr) ==
1249*e038c9c4Sjoerg (context == DeclaratorContext::ObjCParameter));
12507330f729Sjoerg
12517330f729Sjoerg assert(Tok.is(tok::l_paren) && "expected (");
12527330f729Sjoerg
12537330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
12547330f729Sjoerg T.consumeOpen();
12557330f729Sjoerg
12567330f729Sjoerg ObjCDeclContextSwitch ObjCDC(*this);
12577330f729Sjoerg
12587330f729Sjoerg // Parse type qualifiers, in, inout, etc.
12597330f729Sjoerg ParseObjCTypeQualifierList(DS, context);
12607330f729Sjoerg SourceLocation TypeStartLoc = Tok.getLocation();
12617330f729Sjoerg
12627330f729Sjoerg ParsedType Ty;
12637330f729Sjoerg if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
12647330f729Sjoerg // Parse an abstract declarator.
12657330f729Sjoerg DeclSpec declSpec(AttrFactory);
12667330f729Sjoerg declSpec.setObjCQualifiers(&DS);
12677330f729Sjoerg DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
1268*e038c9c4Sjoerg if (context == DeclaratorContext::ObjCResult)
12697330f729Sjoerg dsContext = DeclSpecContext::DSC_objc_method_result;
12707330f729Sjoerg ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
12717330f729Sjoerg Declarator declarator(declSpec, context);
12727330f729Sjoerg ParseDeclarator(declarator);
12737330f729Sjoerg
12747330f729Sjoerg // If that's not invalid, extract a type.
12757330f729Sjoerg if (!declarator.isInvalidType()) {
12767330f729Sjoerg // Map a nullability specifier to a context-sensitive keyword attribute.
12777330f729Sjoerg bool addedToDeclSpec = false;
12787330f729Sjoerg if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
12797330f729Sjoerg addContextSensitiveTypeNullability(*this, declarator,
12807330f729Sjoerg DS.getNullability(),
12817330f729Sjoerg DS.getNullabilityLoc(),
12827330f729Sjoerg addedToDeclSpec);
12837330f729Sjoerg
12847330f729Sjoerg TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
12857330f729Sjoerg if (!type.isInvalid())
12867330f729Sjoerg Ty = type.get();
12877330f729Sjoerg
12887330f729Sjoerg // If we're parsing a parameter, steal all the decl attributes
12897330f729Sjoerg // and add them to the decl spec.
1290*e038c9c4Sjoerg if (context == DeclaratorContext::ObjCParameter)
12917330f729Sjoerg takeDeclAttributes(*paramAttrs, declarator);
12927330f729Sjoerg }
12937330f729Sjoerg }
12947330f729Sjoerg
12957330f729Sjoerg if (Tok.is(tok::r_paren))
12967330f729Sjoerg T.consumeClose();
12977330f729Sjoerg else if (Tok.getLocation() == TypeStartLoc) {
12987330f729Sjoerg // If we didn't eat any tokens, then this isn't a type.
12997330f729Sjoerg Diag(Tok, diag::err_expected_type);
13007330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
13017330f729Sjoerg } else {
13027330f729Sjoerg // Otherwise, we found *something*, but didn't get a ')' in the right
13037330f729Sjoerg // place. Emit an error then return what we have as the type.
13047330f729Sjoerg T.consumeClose();
13057330f729Sjoerg }
13067330f729Sjoerg return Ty;
13077330f729Sjoerg }
13087330f729Sjoerg
13097330f729Sjoerg /// objc-method-decl:
13107330f729Sjoerg /// objc-selector
13117330f729Sjoerg /// objc-keyword-selector objc-parmlist[opt]
13127330f729Sjoerg /// objc-type-name objc-selector
13137330f729Sjoerg /// objc-type-name objc-keyword-selector objc-parmlist[opt]
13147330f729Sjoerg ///
13157330f729Sjoerg /// objc-keyword-selector:
13167330f729Sjoerg /// objc-keyword-decl
13177330f729Sjoerg /// objc-keyword-selector objc-keyword-decl
13187330f729Sjoerg ///
13197330f729Sjoerg /// objc-keyword-decl:
13207330f729Sjoerg /// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
13217330f729Sjoerg /// objc-selector ':' objc-keyword-attributes[opt] identifier
13227330f729Sjoerg /// ':' objc-type-name objc-keyword-attributes[opt] identifier
13237330f729Sjoerg /// ':' objc-keyword-attributes[opt] identifier
13247330f729Sjoerg ///
13257330f729Sjoerg /// objc-parmlist:
13267330f729Sjoerg /// objc-parms objc-ellipsis[opt]
13277330f729Sjoerg ///
13287330f729Sjoerg /// objc-parms:
13297330f729Sjoerg /// objc-parms , parameter-declaration
13307330f729Sjoerg ///
13317330f729Sjoerg /// objc-ellipsis:
13327330f729Sjoerg /// , ...
13337330f729Sjoerg ///
13347330f729Sjoerg /// objc-keyword-attributes: [OBJC2]
13357330f729Sjoerg /// __attribute__((unused))
13367330f729Sjoerg ///
ParseObjCMethodDecl(SourceLocation mLoc,tok::TokenKind mType,tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)13377330f729Sjoerg Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
13387330f729Sjoerg tok::TokenKind mType,
13397330f729Sjoerg tok::ObjCKeywordKind MethodImplKind,
13407330f729Sjoerg bool MethodDefinition) {
13417330f729Sjoerg ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
13427330f729Sjoerg
13437330f729Sjoerg if (Tok.is(tok::code_completion)) {
1344*e038c9c4Sjoerg cutOffParsing();
13457330f729Sjoerg Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
13467330f729Sjoerg /*ReturnType=*/nullptr);
13477330f729Sjoerg return nullptr;
13487330f729Sjoerg }
13497330f729Sjoerg
13507330f729Sjoerg // Parse the return type if present.
13517330f729Sjoerg ParsedType ReturnType;
13527330f729Sjoerg ObjCDeclSpec DSRet;
13537330f729Sjoerg if (Tok.is(tok::l_paren))
1354*e038c9c4Sjoerg ReturnType =
1355*e038c9c4Sjoerg ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult, nullptr);
13567330f729Sjoerg
13577330f729Sjoerg // If attributes exist before the method, parse them.
13587330f729Sjoerg ParsedAttributes methodAttrs(AttrFactory);
1359*e038c9c4Sjoerg MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1360*e038c9c4Sjoerg methodAttrs);
13617330f729Sjoerg
13627330f729Sjoerg if (Tok.is(tok::code_completion)) {
1363*e038c9c4Sjoerg cutOffParsing();
13647330f729Sjoerg Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
13657330f729Sjoerg ReturnType);
13667330f729Sjoerg return nullptr;
13677330f729Sjoerg }
13687330f729Sjoerg
13697330f729Sjoerg // Now parse the selector.
13707330f729Sjoerg SourceLocation selLoc;
13717330f729Sjoerg IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
13727330f729Sjoerg
13737330f729Sjoerg // An unnamed colon is valid.
13747330f729Sjoerg if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
13757330f729Sjoerg Diag(Tok, diag::err_expected_selector_for_method)
13767330f729Sjoerg << SourceRange(mLoc, Tok.getLocation());
13777330f729Sjoerg // Skip until we get a ; or @.
13787330f729Sjoerg SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
13797330f729Sjoerg return nullptr;
13807330f729Sjoerg }
13817330f729Sjoerg
13827330f729Sjoerg SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
13837330f729Sjoerg if (Tok.isNot(tok::colon)) {
13847330f729Sjoerg // If attributes exist after the method, parse them.
1385*e038c9c4Sjoerg MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1386*e038c9c4Sjoerg methodAttrs);
13877330f729Sjoerg
13887330f729Sjoerg Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
13897330f729Sjoerg Decl *Result = Actions.ActOnMethodDeclaration(
13907330f729Sjoerg getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,
13917330f729Sjoerg selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
13927330f729Sjoerg MethodImplKind, false, MethodDefinition);
13937330f729Sjoerg PD.complete(Result);
13947330f729Sjoerg return Result;
13957330f729Sjoerg }
13967330f729Sjoerg
13977330f729Sjoerg SmallVector<IdentifierInfo *, 12> KeyIdents;
13987330f729Sjoerg SmallVector<SourceLocation, 12> KeyLocs;
13997330f729Sjoerg SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
14007330f729Sjoerg ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
14017330f729Sjoerg Scope::FunctionDeclarationScope | Scope::DeclScope);
14027330f729Sjoerg
14037330f729Sjoerg AttributePool allParamAttrs(AttrFactory);
14047330f729Sjoerg while (1) {
14057330f729Sjoerg ParsedAttributes paramAttrs(AttrFactory);
14067330f729Sjoerg Sema::ObjCArgInfo ArgInfo;
14077330f729Sjoerg
14087330f729Sjoerg // Each iteration parses a single keyword argument.
14097330f729Sjoerg if (ExpectAndConsume(tok::colon))
14107330f729Sjoerg break;
14117330f729Sjoerg
14127330f729Sjoerg ArgInfo.Type = nullptr;
14137330f729Sjoerg if (Tok.is(tok::l_paren)) // Parse the argument type if present.
1414*e038c9c4Sjoerg ArgInfo.Type = ParseObjCTypeName(
1415*e038c9c4Sjoerg ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter, ¶mAttrs);
14167330f729Sjoerg
14177330f729Sjoerg // If attributes exist before the argument name, parse them.
14187330f729Sjoerg // Regardless, collect all the attributes we've parsed so far.
1419*e038c9c4Sjoerg MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1420*e038c9c4Sjoerg paramAttrs);
14217330f729Sjoerg ArgInfo.ArgAttrs = paramAttrs;
14227330f729Sjoerg
14237330f729Sjoerg // Code completion for the next piece of the selector.
14247330f729Sjoerg if (Tok.is(tok::code_completion)) {
1425*e038c9c4Sjoerg cutOffParsing();
14267330f729Sjoerg KeyIdents.push_back(SelIdent);
14277330f729Sjoerg Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
14287330f729Sjoerg mType == tok::minus,
14297330f729Sjoerg /*AtParameterName=*/true,
14307330f729Sjoerg ReturnType, KeyIdents);
14317330f729Sjoerg return nullptr;
14327330f729Sjoerg }
14337330f729Sjoerg
14347330f729Sjoerg if (expectIdentifier())
14357330f729Sjoerg break; // missing argument name.
14367330f729Sjoerg
14377330f729Sjoerg ArgInfo.Name = Tok.getIdentifierInfo();
14387330f729Sjoerg ArgInfo.NameLoc = Tok.getLocation();
14397330f729Sjoerg ConsumeToken(); // Eat the identifier.
14407330f729Sjoerg
14417330f729Sjoerg ArgInfos.push_back(ArgInfo);
14427330f729Sjoerg KeyIdents.push_back(SelIdent);
14437330f729Sjoerg KeyLocs.push_back(selLoc);
14447330f729Sjoerg
14457330f729Sjoerg // Make sure the attributes persist.
14467330f729Sjoerg allParamAttrs.takeAllFrom(paramAttrs.getPool());
14477330f729Sjoerg
14487330f729Sjoerg // Code completion for the next piece of the selector.
14497330f729Sjoerg if (Tok.is(tok::code_completion)) {
1450*e038c9c4Sjoerg cutOffParsing();
14517330f729Sjoerg Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
14527330f729Sjoerg mType == tok::minus,
14537330f729Sjoerg /*AtParameterName=*/false,
14547330f729Sjoerg ReturnType, KeyIdents);
14557330f729Sjoerg return nullptr;
14567330f729Sjoerg }
14577330f729Sjoerg
14587330f729Sjoerg // Check for another keyword selector.
14597330f729Sjoerg SelIdent = ParseObjCSelectorPiece(selLoc);
14607330f729Sjoerg if (!SelIdent && Tok.isNot(tok::colon))
14617330f729Sjoerg break;
14627330f729Sjoerg if (!SelIdent) {
14637330f729Sjoerg SourceLocation ColonLoc = Tok.getLocation();
14647330f729Sjoerg if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
14657330f729Sjoerg Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
14667330f729Sjoerg Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
14677330f729Sjoerg Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
14687330f729Sjoerg }
14697330f729Sjoerg }
14707330f729Sjoerg // We have a selector or a colon, continue parsing.
14717330f729Sjoerg }
14727330f729Sjoerg
14737330f729Sjoerg bool isVariadic = false;
14747330f729Sjoerg bool cStyleParamWarned = false;
14757330f729Sjoerg // Parse the (optional) parameter list.
14767330f729Sjoerg while (Tok.is(tok::comma)) {
14777330f729Sjoerg ConsumeToken();
14787330f729Sjoerg if (Tok.is(tok::ellipsis)) {
14797330f729Sjoerg isVariadic = true;
14807330f729Sjoerg ConsumeToken();
14817330f729Sjoerg break;
14827330f729Sjoerg }
14837330f729Sjoerg if (!cStyleParamWarned) {
14847330f729Sjoerg Diag(Tok, diag::warn_cstyle_param);
14857330f729Sjoerg cStyleParamWarned = true;
14867330f729Sjoerg }
14877330f729Sjoerg DeclSpec DS(AttrFactory);
14887330f729Sjoerg ParseDeclarationSpecifiers(DS);
14897330f729Sjoerg // Parse the declarator.
1490*e038c9c4Sjoerg Declarator ParmDecl(DS, DeclaratorContext::Prototype);
14917330f729Sjoerg ParseDeclarator(ParmDecl);
14927330f729Sjoerg IdentifierInfo *ParmII = ParmDecl.getIdentifier();
14937330f729Sjoerg Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
14947330f729Sjoerg CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
14957330f729Sjoerg ParmDecl.getIdentifierLoc(),
14967330f729Sjoerg Param,
14977330f729Sjoerg nullptr));
14987330f729Sjoerg }
14997330f729Sjoerg
15007330f729Sjoerg // FIXME: Add support for optional parameter list...
15017330f729Sjoerg // If attributes exist after the method, parse them.
1502*e038c9c4Sjoerg MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1503*e038c9c4Sjoerg methodAttrs);
15047330f729Sjoerg
15057330f729Sjoerg if (KeyIdents.size() == 0)
15067330f729Sjoerg return nullptr;
15077330f729Sjoerg
15087330f729Sjoerg Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
15097330f729Sjoerg &KeyIdents[0]);
15107330f729Sjoerg Decl *Result = Actions.ActOnMethodDeclaration(
15117330f729Sjoerg getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
15127330f729Sjoerg Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
15137330f729Sjoerg MethodImplKind, isVariadic, MethodDefinition);
15147330f729Sjoerg
15157330f729Sjoerg PD.complete(Result);
15167330f729Sjoerg return Result;
15177330f729Sjoerg }
15187330f729Sjoerg
15197330f729Sjoerg /// objc-protocol-refs:
15207330f729Sjoerg /// '<' identifier-list '>'
15217330f729Sjoerg ///
15227330f729Sjoerg bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl * > & Protocols,SmallVectorImpl<SourceLocation> & ProtocolLocs,bool WarnOnDeclarations,bool ForObjCContainer,SourceLocation & LAngleLoc,SourceLocation & EndLoc,bool consumeLastToken)15237330f729Sjoerg ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
15247330f729Sjoerg SmallVectorImpl<SourceLocation> &ProtocolLocs,
15257330f729Sjoerg bool WarnOnDeclarations, bool ForObjCContainer,
15267330f729Sjoerg SourceLocation &LAngleLoc, SourceLocation &EndLoc,
15277330f729Sjoerg bool consumeLastToken) {
15287330f729Sjoerg assert(Tok.is(tok::less) && "expected <");
15297330f729Sjoerg
15307330f729Sjoerg LAngleLoc = ConsumeToken(); // the "<"
15317330f729Sjoerg
15327330f729Sjoerg SmallVector<IdentifierLocPair, 8> ProtocolIdents;
15337330f729Sjoerg
15347330f729Sjoerg while (1) {
15357330f729Sjoerg if (Tok.is(tok::code_completion)) {
15367330f729Sjoerg cutOffParsing();
1537*e038c9c4Sjoerg Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
15387330f729Sjoerg return true;
15397330f729Sjoerg }
15407330f729Sjoerg
15417330f729Sjoerg if (expectIdentifier()) {
15427330f729Sjoerg SkipUntil(tok::greater, StopAtSemi);
15437330f729Sjoerg return true;
15447330f729Sjoerg }
15457330f729Sjoerg ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
15467330f729Sjoerg Tok.getLocation()));
15477330f729Sjoerg ProtocolLocs.push_back(Tok.getLocation());
15487330f729Sjoerg ConsumeToken();
15497330f729Sjoerg
15507330f729Sjoerg if (!TryConsumeToken(tok::comma))
15517330f729Sjoerg break;
15527330f729Sjoerg }
15537330f729Sjoerg
15547330f729Sjoerg // Consume the '>'.
1555*e038c9c4Sjoerg if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken,
15567330f729Sjoerg /*ObjCGenericList=*/false))
15577330f729Sjoerg return true;
15587330f729Sjoerg
15597330f729Sjoerg // Convert the list of protocols identifiers into a list of protocol decls.
15607330f729Sjoerg Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
15617330f729Sjoerg ProtocolIdents, Protocols);
15627330f729Sjoerg return false;
15637330f729Sjoerg }
15647330f729Sjoerg
parseObjCProtocolQualifierType(SourceLocation & rAngleLoc)15657330f729Sjoerg TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
15667330f729Sjoerg assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
15677330f729Sjoerg assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");
15687330f729Sjoerg
15697330f729Sjoerg SourceLocation lAngleLoc;
15707330f729Sjoerg SmallVector<Decl *, 8> protocols;
15717330f729Sjoerg SmallVector<SourceLocation, 8> protocolLocs;
15727330f729Sjoerg (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
15737330f729Sjoerg lAngleLoc, rAngleLoc,
15747330f729Sjoerg /*consumeLastToken=*/true);
15757330f729Sjoerg TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
15767330f729Sjoerg protocols,
15777330f729Sjoerg protocolLocs,
15787330f729Sjoerg rAngleLoc);
15797330f729Sjoerg if (result.isUsable()) {
15807330f729Sjoerg Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
15817330f729Sjoerg << FixItHint::CreateInsertion(lAngleLoc, "id")
15827330f729Sjoerg << SourceRange(lAngleLoc, rAngleLoc);
15837330f729Sjoerg }
15847330f729Sjoerg
15857330f729Sjoerg return result;
15867330f729Sjoerg }
15877330f729Sjoerg
15887330f729Sjoerg /// Parse Objective-C type arguments or protocol qualifiers.
15897330f729Sjoerg ///
15907330f729Sjoerg /// objc-type-arguments:
15917330f729Sjoerg /// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
15927330f729Sjoerg ///
parseObjCTypeArgsOrProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken,bool warnOnIncompleteProtocols)15937330f729Sjoerg void Parser::parseObjCTypeArgsOrProtocolQualifiers(
15947330f729Sjoerg ParsedType baseType,
15957330f729Sjoerg SourceLocation &typeArgsLAngleLoc,
15967330f729Sjoerg SmallVectorImpl<ParsedType> &typeArgs,
15977330f729Sjoerg SourceLocation &typeArgsRAngleLoc,
15987330f729Sjoerg SourceLocation &protocolLAngleLoc,
15997330f729Sjoerg SmallVectorImpl<Decl *> &protocols,
16007330f729Sjoerg SmallVectorImpl<SourceLocation> &protocolLocs,
16017330f729Sjoerg SourceLocation &protocolRAngleLoc,
16027330f729Sjoerg bool consumeLastToken,
16037330f729Sjoerg bool warnOnIncompleteProtocols) {
16047330f729Sjoerg assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
16057330f729Sjoerg SourceLocation lAngleLoc = ConsumeToken();
16067330f729Sjoerg
16077330f729Sjoerg // Whether all of the elements we've parsed thus far are single
16087330f729Sjoerg // identifiers, which might be types or might be protocols.
16097330f729Sjoerg bool allSingleIdentifiers = true;
16107330f729Sjoerg SmallVector<IdentifierInfo *, 4> identifiers;
16117330f729Sjoerg SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
16127330f729Sjoerg
16137330f729Sjoerg // Parse a list of comma-separated identifiers, bailing out if we
16147330f729Sjoerg // see something different.
16157330f729Sjoerg do {
16167330f729Sjoerg // Parse a single identifier.
16177330f729Sjoerg if (Tok.is(tok::identifier) &&
16187330f729Sjoerg (NextToken().is(tok::comma) ||
16197330f729Sjoerg NextToken().is(tok::greater) ||
16207330f729Sjoerg NextToken().is(tok::greatergreater))) {
16217330f729Sjoerg identifiers.push_back(Tok.getIdentifierInfo());
16227330f729Sjoerg identifierLocs.push_back(ConsumeToken());
16237330f729Sjoerg continue;
16247330f729Sjoerg }
16257330f729Sjoerg
16267330f729Sjoerg if (Tok.is(tok::code_completion)) {
16277330f729Sjoerg // FIXME: Also include types here.
16287330f729Sjoerg SmallVector<IdentifierLocPair, 4> identifierLocPairs;
16297330f729Sjoerg for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
16307330f729Sjoerg identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
16317330f729Sjoerg identifierLocs[i]));
16327330f729Sjoerg }
16337330f729Sjoerg
16347330f729Sjoerg QualType BaseT = Actions.GetTypeFromParser(baseType);
1635*e038c9c4Sjoerg cutOffParsing();
16367330f729Sjoerg if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
16377330f729Sjoerg Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
16387330f729Sjoerg } else {
16397330f729Sjoerg Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
16407330f729Sjoerg }
16417330f729Sjoerg return;
16427330f729Sjoerg }
16437330f729Sjoerg
16447330f729Sjoerg allSingleIdentifiers = false;
16457330f729Sjoerg break;
16467330f729Sjoerg } while (TryConsumeToken(tok::comma));
16477330f729Sjoerg
16487330f729Sjoerg // If we parsed an identifier list, semantic analysis sorts out
16497330f729Sjoerg // whether it refers to protocols or to type arguments.
16507330f729Sjoerg if (allSingleIdentifiers) {
16517330f729Sjoerg // Parse the closing '>'.
16527330f729Sjoerg SourceLocation rAngleLoc;
1653*e038c9c4Sjoerg (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
16547330f729Sjoerg /*ObjCGenericList=*/true);
16557330f729Sjoerg
16567330f729Sjoerg // Let Sema figure out what we parsed.
16577330f729Sjoerg Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
16587330f729Sjoerg baseType,
16597330f729Sjoerg lAngleLoc,
16607330f729Sjoerg identifiers,
16617330f729Sjoerg identifierLocs,
16627330f729Sjoerg rAngleLoc,
16637330f729Sjoerg typeArgsLAngleLoc,
16647330f729Sjoerg typeArgs,
16657330f729Sjoerg typeArgsRAngleLoc,
16667330f729Sjoerg protocolLAngleLoc,
16677330f729Sjoerg protocols,
16687330f729Sjoerg protocolRAngleLoc,
16697330f729Sjoerg warnOnIncompleteProtocols);
16707330f729Sjoerg return;
16717330f729Sjoerg }
16727330f729Sjoerg
16737330f729Sjoerg // We parsed an identifier list but stumbled into non single identifiers, this
16747330f729Sjoerg // means we might (a) check that what we already parsed is a legitimate type
16757330f729Sjoerg // (not a protocol or unknown type) and (b) parse the remaining ones, which
16767330f729Sjoerg // must all be type args.
16777330f729Sjoerg
16787330f729Sjoerg // Convert the identifiers into type arguments.
16797330f729Sjoerg bool invalid = false;
16807330f729Sjoerg IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;
16817330f729Sjoerg SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;
16827330f729Sjoerg SmallVector<IdentifierInfo *, 2> unknownTypeArgs;
16837330f729Sjoerg SmallVector<SourceLocation, 2> unknownTypeArgsLoc;
16847330f729Sjoerg
16857330f729Sjoerg for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
16867330f729Sjoerg ParsedType typeArg
16877330f729Sjoerg = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
16887330f729Sjoerg if (typeArg) {
16897330f729Sjoerg DeclSpec DS(AttrFactory);
16907330f729Sjoerg const char *prevSpec = nullptr;
16917330f729Sjoerg unsigned diagID;
16927330f729Sjoerg DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
16937330f729Sjoerg typeArg, Actions.getASTContext().getPrintingPolicy());
16947330f729Sjoerg
16957330f729Sjoerg // Form a declarator to turn this into a type.
1696*e038c9c4Sjoerg Declarator D(DS, DeclaratorContext::TypeName);
16977330f729Sjoerg TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
16987330f729Sjoerg if (fullTypeArg.isUsable()) {
16997330f729Sjoerg typeArgs.push_back(fullTypeArg.get());
17007330f729Sjoerg if (!foundValidTypeId) {
17017330f729Sjoerg foundValidTypeId = identifiers[i];
17027330f729Sjoerg foundValidTypeSrcLoc = identifierLocs[i];
17037330f729Sjoerg }
17047330f729Sjoerg } else {
17057330f729Sjoerg invalid = true;
17067330f729Sjoerg unknownTypeArgs.push_back(identifiers[i]);
17077330f729Sjoerg unknownTypeArgsLoc.push_back(identifierLocs[i]);
17087330f729Sjoerg }
17097330f729Sjoerg } else {
17107330f729Sjoerg invalid = true;
17117330f729Sjoerg if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) {
17127330f729Sjoerg unknownTypeArgs.push_back(identifiers[i]);
17137330f729Sjoerg unknownTypeArgsLoc.push_back(identifierLocs[i]);
17147330f729Sjoerg } else if (!foundProtocolId) {
17157330f729Sjoerg foundProtocolId = identifiers[i];
17167330f729Sjoerg foundProtocolSrcLoc = identifierLocs[i];
17177330f729Sjoerg }
17187330f729Sjoerg }
17197330f729Sjoerg }
17207330f729Sjoerg
17217330f729Sjoerg // Continue parsing type-names.
17227330f729Sjoerg do {
17237330f729Sjoerg Token CurTypeTok = Tok;
17247330f729Sjoerg TypeResult typeArg = ParseTypeName();
17257330f729Sjoerg
17267330f729Sjoerg // Consume the '...' for a pack expansion.
17277330f729Sjoerg SourceLocation ellipsisLoc;
17287330f729Sjoerg TryConsumeToken(tok::ellipsis, ellipsisLoc);
17297330f729Sjoerg if (typeArg.isUsable() && ellipsisLoc.isValid()) {
17307330f729Sjoerg typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
17317330f729Sjoerg }
17327330f729Sjoerg
17337330f729Sjoerg if (typeArg.isUsable()) {
17347330f729Sjoerg typeArgs.push_back(typeArg.get());
17357330f729Sjoerg if (!foundValidTypeId) {
17367330f729Sjoerg foundValidTypeId = CurTypeTok.getIdentifierInfo();
17377330f729Sjoerg foundValidTypeSrcLoc = CurTypeTok.getLocation();
17387330f729Sjoerg }
17397330f729Sjoerg } else {
17407330f729Sjoerg invalid = true;
17417330f729Sjoerg }
17427330f729Sjoerg } while (TryConsumeToken(tok::comma));
17437330f729Sjoerg
17447330f729Sjoerg // Diagnose the mix between type args and protocols.
17457330f729Sjoerg if (foundProtocolId && foundValidTypeId)
17467330f729Sjoerg Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
17477330f729Sjoerg foundValidTypeId,
17487330f729Sjoerg foundValidTypeSrcLoc);
17497330f729Sjoerg
17507330f729Sjoerg // Diagnose unknown arg types.
17517330f729Sjoerg ParsedType T;
17527330f729Sjoerg if (unknownTypeArgs.size())
17537330f729Sjoerg for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)
17547330f729Sjoerg Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],
17557330f729Sjoerg getCurScope(), nullptr, T);
17567330f729Sjoerg
17577330f729Sjoerg // Parse the closing '>'.
17587330f729Sjoerg SourceLocation rAngleLoc;
1759*e038c9c4Sjoerg (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
17607330f729Sjoerg /*ObjCGenericList=*/true);
17617330f729Sjoerg
17627330f729Sjoerg if (invalid) {
17637330f729Sjoerg typeArgs.clear();
17647330f729Sjoerg return;
17657330f729Sjoerg }
17667330f729Sjoerg
17677330f729Sjoerg // Record left/right angle locations.
17687330f729Sjoerg typeArgsLAngleLoc = lAngleLoc;
17697330f729Sjoerg typeArgsRAngleLoc = rAngleLoc;
17707330f729Sjoerg }
17717330f729Sjoerg
parseObjCTypeArgsAndProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken)17727330f729Sjoerg void Parser::parseObjCTypeArgsAndProtocolQualifiers(
17737330f729Sjoerg ParsedType baseType,
17747330f729Sjoerg SourceLocation &typeArgsLAngleLoc,
17757330f729Sjoerg SmallVectorImpl<ParsedType> &typeArgs,
17767330f729Sjoerg SourceLocation &typeArgsRAngleLoc,
17777330f729Sjoerg SourceLocation &protocolLAngleLoc,
17787330f729Sjoerg SmallVectorImpl<Decl *> &protocols,
17797330f729Sjoerg SmallVectorImpl<SourceLocation> &protocolLocs,
17807330f729Sjoerg SourceLocation &protocolRAngleLoc,
17817330f729Sjoerg bool consumeLastToken) {
17827330f729Sjoerg assert(Tok.is(tok::less));
17837330f729Sjoerg
17847330f729Sjoerg // Parse the first angle-bracket-delimited clause.
17857330f729Sjoerg parseObjCTypeArgsOrProtocolQualifiers(baseType,
17867330f729Sjoerg typeArgsLAngleLoc,
17877330f729Sjoerg typeArgs,
17887330f729Sjoerg typeArgsRAngleLoc,
17897330f729Sjoerg protocolLAngleLoc,
17907330f729Sjoerg protocols,
17917330f729Sjoerg protocolLocs,
17927330f729Sjoerg protocolRAngleLoc,
17937330f729Sjoerg consumeLastToken,
17947330f729Sjoerg /*warnOnIncompleteProtocols=*/false);
17957330f729Sjoerg if (Tok.is(tok::eof)) // Nothing else to do here...
17967330f729Sjoerg return;
17977330f729Sjoerg
17987330f729Sjoerg // An Objective-C object pointer followed by type arguments
17997330f729Sjoerg // can then be followed again by a set of protocol references, e.g.,
18007330f729Sjoerg // \c NSArray<NSView><NSTextDelegate>
18017330f729Sjoerg if ((consumeLastToken && Tok.is(tok::less)) ||
18027330f729Sjoerg (!consumeLastToken && NextToken().is(tok::less))) {
18037330f729Sjoerg // If we aren't consuming the last token, the prior '>' is still hanging
18047330f729Sjoerg // there. Consume it before we parse the protocol qualifiers.
18057330f729Sjoerg if (!consumeLastToken)
18067330f729Sjoerg ConsumeToken();
18077330f729Sjoerg
18087330f729Sjoerg if (!protocols.empty()) {
18097330f729Sjoerg SkipUntilFlags skipFlags = SkipUntilFlags();
18107330f729Sjoerg if (!consumeLastToken)
18117330f729Sjoerg skipFlags = skipFlags | StopBeforeMatch;
18127330f729Sjoerg Diag(Tok, diag::err_objc_type_args_after_protocols)
18137330f729Sjoerg << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
18147330f729Sjoerg SkipUntil(tok::greater, tok::greatergreater, skipFlags);
18157330f729Sjoerg } else {
18167330f729Sjoerg ParseObjCProtocolReferences(protocols, protocolLocs,
18177330f729Sjoerg /*WarnOnDeclarations=*/false,
18187330f729Sjoerg /*ForObjCContainer=*/false,
18197330f729Sjoerg protocolLAngleLoc, protocolRAngleLoc,
18207330f729Sjoerg consumeLastToken);
18217330f729Sjoerg }
18227330f729Sjoerg }
18237330f729Sjoerg }
18247330f729Sjoerg
parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,ParsedType type,bool consumeLastToken,SourceLocation & endLoc)18257330f729Sjoerg TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
18267330f729Sjoerg SourceLocation loc,
18277330f729Sjoerg ParsedType type,
18287330f729Sjoerg bool consumeLastToken,
18297330f729Sjoerg SourceLocation &endLoc) {
18307330f729Sjoerg assert(Tok.is(tok::less));
18317330f729Sjoerg SourceLocation typeArgsLAngleLoc;
18327330f729Sjoerg SmallVector<ParsedType, 4> typeArgs;
18337330f729Sjoerg SourceLocation typeArgsRAngleLoc;
18347330f729Sjoerg SourceLocation protocolLAngleLoc;
18357330f729Sjoerg SmallVector<Decl *, 4> protocols;
18367330f729Sjoerg SmallVector<SourceLocation, 4> protocolLocs;
18377330f729Sjoerg SourceLocation protocolRAngleLoc;
18387330f729Sjoerg
18397330f729Sjoerg // Parse type arguments and protocol qualifiers.
18407330f729Sjoerg parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
18417330f729Sjoerg typeArgsRAngleLoc, protocolLAngleLoc,
18427330f729Sjoerg protocols, protocolLocs,
18437330f729Sjoerg protocolRAngleLoc, consumeLastToken);
18447330f729Sjoerg
18457330f729Sjoerg if (Tok.is(tok::eof))
18467330f729Sjoerg return true; // Invalid type result.
18477330f729Sjoerg
18487330f729Sjoerg // Compute the location of the last token.
18497330f729Sjoerg if (consumeLastToken)
18507330f729Sjoerg endLoc = PrevTokLocation;
18517330f729Sjoerg else
18527330f729Sjoerg endLoc = Tok.getLocation();
18537330f729Sjoerg
18547330f729Sjoerg return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
18557330f729Sjoerg getCurScope(),
18567330f729Sjoerg loc,
18577330f729Sjoerg type,
18587330f729Sjoerg typeArgsLAngleLoc,
18597330f729Sjoerg typeArgs,
18607330f729Sjoerg typeArgsRAngleLoc,
18617330f729Sjoerg protocolLAngleLoc,
18627330f729Sjoerg protocols,
18637330f729Sjoerg protocolLocs,
18647330f729Sjoerg protocolRAngleLoc);
18657330f729Sjoerg }
18667330f729Sjoerg
HelperActionsForIvarDeclarations(Decl * interfaceDecl,SourceLocation atLoc,BalancedDelimiterTracker & T,SmallVectorImpl<Decl * > & AllIvarDecls,bool RBraceMissing)18677330f729Sjoerg void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
18687330f729Sjoerg BalancedDelimiterTracker &T,
18697330f729Sjoerg SmallVectorImpl<Decl *> &AllIvarDecls,
18707330f729Sjoerg bool RBraceMissing) {
18717330f729Sjoerg if (!RBraceMissing)
18727330f729Sjoerg T.consumeClose();
18737330f729Sjoerg
18747330f729Sjoerg Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
18757330f729Sjoerg Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
18767330f729Sjoerg Actions.ActOnObjCContainerFinishDefinition();
18777330f729Sjoerg // Call ActOnFields() even if we don't have any decls. This is useful
18787330f729Sjoerg // for code rewriting tools that need to be aware of the empty list.
18797330f729Sjoerg Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,
18807330f729Sjoerg T.getOpenLocation(), T.getCloseLocation(),
18817330f729Sjoerg ParsedAttributesView());
18827330f729Sjoerg }
18837330f729Sjoerg
18847330f729Sjoerg /// objc-class-instance-variables:
18857330f729Sjoerg /// '{' objc-instance-variable-decl-list[opt] '}'
18867330f729Sjoerg ///
18877330f729Sjoerg /// objc-instance-variable-decl-list:
18887330f729Sjoerg /// objc-visibility-spec
18897330f729Sjoerg /// objc-instance-variable-decl ';'
18907330f729Sjoerg /// ';'
18917330f729Sjoerg /// objc-instance-variable-decl-list objc-visibility-spec
18927330f729Sjoerg /// objc-instance-variable-decl-list objc-instance-variable-decl ';'
18937330f729Sjoerg /// objc-instance-variable-decl-list static_assert-declaration
18947330f729Sjoerg /// objc-instance-variable-decl-list ';'
18957330f729Sjoerg ///
18967330f729Sjoerg /// objc-visibility-spec:
18977330f729Sjoerg /// @private
18987330f729Sjoerg /// @protected
18997330f729Sjoerg /// @public
19007330f729Sjoerg /// @package [OBJC2]
19017330f729Sjoerg ///
19027330f729Sjoerg /// objc-instance-variable-decl:
19037330f729Sjoerg /// struct-declaration
19047330f729Sjoerg ///
ParseObjCClassInstanceVariables(Decl * interfaceDecl,tok::ObjCKeywordKind visibility,SourceLocation atLoc)19057330f729Sjoerg void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
19067330f729Sjoerg tok::ObjCKeywordKind visibility,
19077330f729Sjoerg SourceLocation atLoc) {
19087330f729Sjoerg assert(Tok.is(tok::l_brace) && "expected {");
19097330f729Sjoerg SmallVector<Decl *, 32> AllIvarDecls;
19107330f729Sjoerg
19117330f729Sjoerg ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
19127330f729Sjoerg ObjCDeclContextSwitch ObjCDC(*this);
19137330f729Sjoerg
19147330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_brace);
19157330f729Sjoerg T.consumeOpen();
19167330f729Sjoerg // While we still have something to read, read the instance variables.
19177330f729Sjoerg while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
19187330f729Sjoerg // Each iteration of this loop reads one objc-instance-variable-decl.
19197330f729Sjoerg
19207330f729Sjoerg // Check for extraneous top-level semicolon.
19217330f729Sjoerg if (Tok.is(tok::semi)) {
19227330f729Sjoerg ConsumeExtraSemi(InstanceVariableList);
19237330f729Sjoerg continue;
19247330f729Sjoerg }
19257330f729Sjoerg
19267330f729Sjoerg // Set the default visibility to private.
19277330f729Sjoerg if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
19287330f729Sjoerg if (Tok.is(tok::code_completion)) {
1929*e038c9c4Sjoerg cutOffParsing();
19307330f729Sjoerg Actions.CodeCompleteObjCAtVisibility(getCurScope());
1931*e038c9c4Sjoerg return;
19327330f729Sjoerg }
19337330f729Sjoerg
19347330f729Sjoerg switch (Tok.getObjCKeywordID()) {
19357330f729Sjoerg case tok::objc_private:
19367330f729Sjoerg case tok::objc_public:
19377330f729Sjoerg case tok::objc_protected:
19387330f729Sjoerg case tok::objc_package:
19397330f729Sjoerg visibility = Tok.getObjCKeywordID();
19407330f729Sjoerg ConsumeToken();
19417330f729Sjoerg continue;
19427330f729Sjoerg
19437330f729Sjoerg case tok::objc_end:
19447330f729Sjoerg Diag(Tok, diag::err_objc_unexpected_atend);
19457330f729Sjoerg Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
19467330f729Sjoerg Tok.setKind(tok::at);
19477330f729Sjoerg Tok.setLength(1);
19487330f729Sjoerg PP.EnterToken(Tok, /*IsReinject*/true);
19497330f729Sjoerg HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
19507330f729Sjoerg T, AllIvarDecls, true);
19517330f729Sjoerg return;
19527330f729Sjoerg
19537330f729Sjoerg default:
19547330f729Sjoerg Diag(Tok, diag::err_objc_illegal_visibility_spec);
19557330f729Sjoerg continue;
19567330f729Sjoerg }
19577330f729Sjoerg }
19587330f729Sjoerg
19597330f729Sjoerg if (Tok.is(tok::code_completion)) {
1960*e038c9c4Sjoerg cutOffParsing();
19617330f729Sjoerg Actions.CodeCompleteOrdinaryName(getCurScope(),
19627330f729Sjoerg Sema::PCC_ObjCInstanceVariableList);
1963*e038c9c4Sjoerg return;
19647330f729Sjoerg }
19657330f729Sjoerg
19667330f729Sjoerg // This needs to duplicate a small amount of code from
19677330f729Sjoerg // ParseStructUnionBody() for things that should work in both
19687330f729Sjoerg // C struct and in Objective-C class instance variables.
19697330f729Sjoerg if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
19707330f729Sjoerg SourceLocation DeclEnd;
19717330f729Sjoerg ParseStaticAssertDeclaration(DeclEnd);
19727330f729Sjoerg continue;
19737330f729Sjoerg }
19747330f729Sjoerg
19757330f729Sjoerg auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
19767330f729Sjoerg Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
19777330f729Sjoerg // Install the declarator into the interface decl.
19787330f729Sjoerg FD.D.setObjCIvar(true);
19797330f729Sjoerg Decl *Field = Actions.ActOnIvar(
19807330f729Sjoerg getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
19817330f729Sjoerg FD.BitfieldSize, visibility);
19827330f729Sjoerg Actions.ActOnObjCContainerFinishDefinition();
19837330f729Sjoerg if (Field)
19847330f729Sjoerg AllIvarDecls.push_back(Field);
19857330f729Sjoerg FD.complete(Field);
19867330f729Sjoerg };
19877330f729Sjoerg
19887330f729Sjoerg // Parse all the comma separated declarators.
19897330f729Sjoerg ParsingDeclSpec DS(*this);
19907330f729Sjoerg ParseStructDeclaration(DS, ObjCIvarCallback);
19917330f729Sjoerg
19927330f729Sjoerg if (Tok.is(tok::semi)) {
19937330f729Sjoerg ConsumeToken();
19947330f729Sjoerg } else {
19957330f729Sjoerg Diag(Tok, diag::err_expected_semi_decl_list);
19967330f729Sjoerg // Skip to end of block or statement
19977330f729Sjoerg SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
19987330f729Sjoerg }
19997330f729Sjoerg }
20007330f729Sjoerg HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
20017330f729Sjoerg T, AllIvarDecls, false);
20027330f729Sjoerg }
20037330f729Sjoerg
20047330f729Sjoerg /// objc-protocol-declaration:
20057330f729Sjoerg /// objc-protocol-definition
20067330f729Sjoerg /// objc-protocol-forward-reference
20077330f729Sjoerg ///
20087330f729Sjoerg /// objc-protocol-definition:
20097330f729Sjoerg /// \@protocol identifier
20107330f729Sjoerg /// objc-protocol-refs[opt]
20117330f729Sjoerg /// objc-interface-decl-list
20127330f729Sjoerg /// \@end
20137330f729Sjoerg ///
20147330f729Sjoerg /// objc-protocol-forward-reference:
20157330f729Sjoerg /// \@protocol identifier-list ';'
20167330f729Sjoerg ///
20177330f729Sjoerg /// "\@protocol identifier ;" should be resolved as "\@protocol
20187330f729Sjoerg /// identifier-list ;": objc-interface-decl-list may not start with a
20197330f729Sjoerg /// semicolon in the first alternative if objc-protocol-refs are omitted.
20207330f729Sjoerg Parser::DeclGroupPtrTy
ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)20217330f729Sjoerg Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
20227330f729Sjoerg ParsedAttributes &attrs) {
20237330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
20247330f729Sjoerg "ParseObjCAtProtocolDeclaration(): Expected @protocol");
20257330f729Sjoerg ConsumeToken(); // the "protocol" identifier
20267330f729Sjoerg
20277330f729Sjoerg if (Tok.is(tok::code_completion)) {
20287330f729Sjoerg cutOffParsing();
2029*e038c9c4Sjoerg Actions.CodeCompleteObjCProtocolDecl(getCurScope());
20307330f729Sjoerg return nullptr;
20317330f729Sjoerg }
20327330f729Sjoerg
20337330f729Sjoerg MaybeSkipAttributes(tok::objc_protocol);
20347330f729Sjoerg
20357330f729Sjoerg if (expectIdentifier())
20367330f729Sjoerg return nullptr; // missing protocol name.
20377330f729Sjoerg // Save the protocol name, then consume it.
20387330f729Sjoerg IdentifierInfo *protocolName = Tok.getIdentifierInfo();
20397330f729Sjoerg SourceLocation nameLoc = ConsumeToken();
20407330f729Sjoerg
20417330f729Sjoerg if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
20427330f729Sjoerg IdentifierLocPair ProtoInfo(protocolName, nameLoc);
20437330f729Sjoerg return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo, attrs);
20447330f729Sjoerg }
20457330f729Sjoerg
20467330f729Sjoerg CheckNestedObjCContexts(AtLoc);
20477330f729Sjoerg
20487330f729Sjoerg if (Tok.is(tok::comma)) { // list of forward declarations.
20497330f729Sjoerg SmallVector<IdentifierLocPair, 8> ProtocolRefs;
20507330f729Sjoerg ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
20517330f729Sjoerg
20527330f729Sjoerg // Parse the list of forward declarations.
20537330f729Sjoerg while (1) {
20547330f729Sjoerg ConsumeToken(); // the ','
20557330f729Sjoerg if (expectIdentifier()) {
20567330f729Sjoerg SkipUntil(tok::semi);
20577330f729Sjoerg return nullptr;
20587330f729Sjoerg }
20597330f729Sjoerg ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
20607330f729Sjoerg Tok.getLocation()));
20617330f729Sjoerg ConsumeToken(); // the identifier
20627330f729Sjoerg
20637330f729Sjoerg if (Tok.isNot(tok::comma))
20647330f729Sjoerg break;
20657330f729Sjoerg }
20667330f729Sjoerg // Consume the ';'.
20677330f729Sjoerg if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
20687330f729Sjoerg return nullptr;
20697330f729Sjoerg
20707330f729Sjoerg return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs);
20717330f729Sjoerg }
20727330f729Sjoerg
20737330f729Sjoerg // Last, and definitely not least, parse a protocol declaration.
20747330f729Sjoerg SourceLocation LAngleLoc, EndProtoLoc;
20757330f729Sjoerg
20767330f729Sjoerg SmallVector<Decl *, 8> ProtocolRefs;
20777330f729Sjoerg SmallVector<SourceLocation, 8> ProtocolLocs;
20787330f729Sjoerg if (Tok.is(tok::less) &&
20797330f729Sjoerg ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
20807330f729Sjoerg LAngleLoc, EndProtoLoc,
20817330f729Sjoerg /*consumeLastToken=*/true))
20827330f729Sjoerg return nullptr;
20837330f729Sjoerg
20847330f729Sjoerg Decl *ProtoType = Actions.ActOnStartProtocolInterface(
20857330f729Sjoerg AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
20867330f729Sjoerg ProtocolLocs.data(), EndProtoLoc, attrs);
20877330f729Sjoerg
20887330f729Sjoerg ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
20897330f729Sjoerg return Actions.ConvertDeclToDeclGroup(ProtoType);
20907330f729Sjoerg }
20917330f729Sjoerg
20927330f729Sjoerg /// objc-implementation:
20937330f729Sjoerg /// objc-class-implementation-prologue
20947330f729Sjoerg /// objc-category-implementation-prologue
20957330f729Sjoerg ///
20967330f729Sjoerg /// objc-class-implementation-prologue:
20977330f729Sjoerg /// @implementation identifier objc-superclass[opt]
20987330f729Sjoerg /// objc-class-instance-variables[opt]
20997330f729Sjoerg ///
21007330f729Sjoerg /// objc-category-implementation-prologue:
21017330f729Sjoerg /// @implementation identifier ( identifier )
21027330f729Sjoerg Parser::DeclGroupPtrTy
ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,ParsedAttributes & Attrs)21037330f729Sjoerg Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
21047330f729Sjoerg ParsedAttributes &Attrs) {
21057330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
21067330f729Sjoerg "ParseObjCAtImplementationDeclaration(): Expected @implementation");
21077330f729Sjoerg CheckNestedObjCContexts(AtLoc);
21087330f729Sjoerg ConsumeToken(); // the "implementation" identifier
21097330f729Sjoerg
21107330f729Sjoerg // Code completion after '@implementation'.
21117330f729Sjoerg if (Tok.is(tok::code_completion)) {
21127330f729Sjoerg cutOffParsing();
2113*e038c9c4Sjoerg Actions.CodeCompleteObjCImplementationDecl(getCurScope());
21147330f729Sjoerg return nullptr;
21157330f729Sjoerg }
21167330f729Sjoerg
21177330f729Sjoerg MaybeSkipAttributes(tok::objc_implementation);
21187330f729Sjoerg
21197330f729Sjoerg if (expectIdentifier())
21207330f729Sjoerg return nullptr; // missing class or category name.
21217330f729Sjoerg // We have a class or category name - consume it.
21227330f729Sjoerg IdentifierInfo *nameId = Tok.getIdentifierInfo();
21237330f729Sjoerg SourceLocation nameLoc = ConsumeToken(); // consume class or category name
21247330f729Sjoerg Decl *ObjCImpDecl = nullptr;
21257330f729Sjoerg
21267330f729Sjoerg // Neither a type parameter list nor a list of protocol references is
21277330f729Sjoerg // permitted here. Parse and diagnose them.
21287330f729Sjoerg if (Tok.is(tok::less)) {
21297330f729Sjoerg SourceLocation lAngleLoc, rAngleLoc;
21307330f729Sjoerg SmallVector<IdentifierLocPair, 8> protocolIdents;
21317330f729Sjoerg SourceLocation diagLoc = Tok.getLocation();
21327330f729Sjoerg ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
21337330f729Sjoerg if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,
21347330f729Sjoerg protocolIdents, rAngleLoc)) {
21357330f729Sjoerg Diag(diagLoc, diag::err_objc_parameterized_implementation)
21367330f729Sjoerg << SourceRange(diagLoc, PrevTokLocation);
21377330f729Sjoerg } else if (lAngleLoc.isValid()) {
21387330f729Sjoerg Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
21397330f729Sjoerg << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
21407330f729Sjoerg }
21417330f729Sjoerg }
21427330f729Sjoerg
21437330f729Sjoerg if (Tok.is(tok::l_paren)) {
21447330f729Sjoerg // we have a category implementation.
21457330f729Sjoerg ConsumeParen();
21467330f729Sjoerg SourceLocation categoryLoc, rparenLoc;
21477330f729Sjoerg IdentifierInfo *categoryId = nullptr;
21487330f729Sjoerg
21497330f729Sjoerg if (Tok.is(tok::code_completion)) {
21507330f729Sjoerg cutOffParsing();
2151*e038c9c4Sjoerg Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
21527330f729Sjoerg return nullptr;
21537330f729Sjoerg }
21547330f729Sjoerg
21557330f729Sjoerg if (Tok.is(tok::identifier)) {
21567330f729Sjoerg categoryId = Tok.getIdentifierInfo();
21577330f729Sjoerg categoryLoc = ConsumeToken();
21587330f729Sjoerg } else {
21597330f729Sjoerg Diag(Tok, diag::err_expected)
21607330f729Sjoerg << tok::identifier; // missing category name.
21617330f729Sjoerg return nullptr;
21627330f729Sjoerg }
21637330f729Sjoerg if (Tok.isNot(tok::r_paren)) {
21647330f729Sjoerg Diag(Tok, diag::err_expected) << tok::r_paren;
21657330f729Sjoerg SkipUntil(tok::r_paren); // don't stop at ';'
21667330f729Sjoerg return nullptr;
21677330f729Sjoerg }
21687330f729Sjoerg rparenLoc = ConsumeParen();
21697330f729Sjoerg if (Tok.is(tok::less)) { // we have illegal '<' try to recover
21707330f729Sjoerg Diag(Tok, diag::err_unexpected_protocol_qualifier);
21717330f729Sjoerg SourceLocation protocolLAngleLoc, protocolRAngleLoc;
21727330f729Sjoerg SmallVector<Decl *, 4> protocols;
21737330f729Sjoerg SmallVector<SourceLocation, 4> protocolLocs;
21747330f729Sjoerg (void)ParseObjCProtocolReferences(protocols, protocolLocs,
21757330f729Sjoerg /*warnOnIncompleteProtocols=*/false,
21767330f729Sjoerg /*ForObjCContainer=*/false,
21777330f729Sjoerg protocolLAngleLoc, protocolRAngleLoc,
21787330f729Sjoerg /*consumeLastToken=*/true);
21797330f729Sjoerg }
21807330f729Sjoerg ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
21817330f729Sjoerg AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);
21827330f729Sjoerg
21837330f729Sjoerg } else {
21847330f729Sjoerg // We have a class implementation
21857330f729Sjoerg SourceLocation superClassLoc;
21867330f729Sjoerg IdentifierInfo *superClassId = nullptr;
21877330f729Sjoerg if (TryConsumeToken(tok::colon)) {
21887330f729Sjoerg // We have a super class
21897330f729Sjoerg if (expectIdentifier())
21907330f729Sjoerg return nullptr; // missing super class name.
21917330f729Sjoerg superClassId = Tok.getIdentifierInfo();
21927330f729Sjoerg superClassLoc = ConsumeToken(); // Consume super class name
21937330f729Sjoerg }
21947330f729Sjoerg ObjCImpDecl = Actions.ActOnStartClassImplementation(
21957330f729Sjoerg AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);
21967330f729Sjoerg
21977330f729Sjoerg if (Tok.is(tok::l_brace)) // we have ivars
21987330f729Sjoerg ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
21997330f729Sjoerg else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
22007330f729Sjoerg Diag(Tok, diag::err_unexpected_protocol_qualifier);
22017330f729Sjoerg
22027330f729Sjoerg SourceLocation protocolLAngleLoc, protocolRAngleLoc;
22037330f729Sjoerg SmallVector<Decl *, 4> protocols;
22047330f729Sjoerg SmallVector<SourceLocation, 4> protocolLocs;
22057330f729Sjoerg (void)ParseObjCProtocolReferences(protocols, protocolLocs,
22067330f729Sjoerg /*warnOnIncompleteProtocols=*/false,
22077330f729Sjoerg /*ForObjCContainer=*/false,
22087330f729Sjoerg protocolLAngleLoc, protocolRAngleLoc,
22097330f729Sjoerg /*consumeLastToken=*/true);
22107330f729Sjoerg }
22117330f729Sjoerg }
22127330f729Sjoerg assert(ObjCImpDecl);
22137330f729Sjoerg
22147330f729Sjoerg SmallVector<Decl *, 8> DeclsInGroup;
22157330f729Sjoerg
22167330f729Sjoerg {
22177330f729Sjoerg ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
22187330f729Sjoerg while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
22197330f729Sjoerg ParsedAttributesWithRange attrs(AttrFactory);
22207330f729Sjoerg MaybeParseCXX11Attributes(attrs);
22217330f729Sjoerg if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
22227330f729Sjoerg DeclGroupRef DG = DGP.get();
22237330f729Sjoerg DeclsInGroup.append(DG.begin(), DG.end());
22247330f729Sjoerg }
22257330f729Sjoerg }
22267330f729Sjoerg }
22277330f729Sjoerg
22287330f729Sjoerg return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
22297330f729Sjoerg }
22307330f729Sjoerg
22317330f729Sjoerg Parser::DeclGroupPtrTy
ParseObjCAtEndDeclaration(SourceRange atEnd)22327330f729Sjoerg Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
22337330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_end) &&
22347330f729Sjoerg "ParseObjCAtEndDeclaration(): Expected @end");
22357330f729Sjoerg ConsumeToken(); // the "end" identifier
22367330f729Sjoerg if (CurParsedObjCImpl)
22377330f729Sjoerg CurParsedObjCImpl->finish(atEnd);
22387330f729Sjoerg else
22397330f729Sjoerg // missing @implementation
22407330f729Sjoerg Diag(atEnd.getBegin(), diag::err_expected_objc_container);
22417330f729Sjoerg return nullptr;
22427330f729Sjoerg }
22437330f729Sjoerg
~ObjCImplParsingDataRAII()22447330f729Sjoerg Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
22457330f729Sjoerg if (!Finished) {
22467330f729Sjoerg finish(P.Tok.getLocation());
22477330f729Sjoerg if (P.isEofOrEom()) {
22487330f729Sjoerg P.Diag(P.Tok, diag::err_objc_missing_end)
22497330f729Sjoerg << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
22507330f729Sjoerg P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)
22517330f729Sjoerg << Sema::OCK_Implementation;
22527330f729Sjoerg }
22537330f729Sjoerg }
22547330f729Sjoerg P.CurParsedObjCImpl = nullptr;
22557330f729Sjoerg assert(LateParsedObjCMethods.empty());
22567330f729Sjoerg }
22577330f729Sjoerg
finish(SourceRange AtEnd)22587330f729Sjoerg void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
22597330f729Sjoerg assert(!Finished);
22607330f729Sjoerg P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
22617330f729Sjoerg for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
22627330f729Sjoerg P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
22637330f729Sjoerg true/*Methods*/);
22647330f729Sjoerg
22657330f729Sjoerg P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
22667330f729Sjoerg
22677330f729Sjoerg if (HasCFunction)
22687330f729Sjoerg for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
22697330f729Sjoerg P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
22707330f729Sjoerg false/*c-functions*/);
22717330f729Sjoerg
22727330f729Sjoerg /// Clear and free the cached objc methods.
22737330f729Sjoerg for (LateParsedObjCMethodContainer::iterator
22747330f729Sjoerg I = LateParsedObjCMethods.begin(),
22757330f729Sjoerg E = LateParsedObjCMethods.end(); I != E; ++I)
22767330f729Sjoerg delete *I;
22777330f729Sjoerg LateParsedObjCMethods.clear();
22787330f729Sjoerg
22797330f729Sjoerg Finished = true;
22807330f729Sjoerg }
22817330f729Sjoerg
22827330f729Sjoerg /// compatibility-alias-decl:
22837330f729Sjoerg /// @compatibility_alias alias-name class-name ';'
22847330f729Sjoerg ///
ParseObjCAtAliasDeclaration(SourceLocation atLoc)22857330f729Sjoerg Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
22867330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
22877330f729Sjoerg "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
22887330f729Sjoerg ConsumeToken(); // consume compatibility_alias
22897330f729Sjoerg if (expectIdentifier())
22907330f729Sjoerg return nullptr;
22917330f729Sjoerg IdentifierInfo *aliasId = Tok.getIdentifierInfo();
22927330f729Sjoerg SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
22937330f729Sjoerg if (expectIdentifier())
22947330f729Sjoerg return nullptr;
22957330f729Sjoerg IdentifierInfo *classId = Tok.getIdentifierInfo();
22967330f729Sjoerg SourceLocation classLoc = ConsumeToken(); // consume class-name;
22977330f729Sjoerg ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
22987330f729Sjoerg return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
22997330f729Sjoerg classId, classLoc);
23007330f729Sjoerg }
23017330f729Sjoerg
23027330f729Sjoerg /// property-synthesis:
23037330f729Sjoerg /// @synthesize property-ivar-list ';'
23047330f729Sjoerg ///
23057330f729Sjoerg /// property-ivar-list:
23067330f729Sjoerg /// property-ivar
23077330f729Sjoerg /// property-ivar-list ',' property-ivar
23087330f729Sjoerg ///
23097330f729Sjoerg /// property-ivar:
23107330f729Sjoerg /// identifier
23117330f729Sjoerg /// identifier '=' identifier
23127330f729Sjoerg ///
ParseObjCPropertySynthesize(SourceLocation atLoc)23137330f729Sjoerg Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
23147330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
23157330f729Sjoerg "ParseObjCPropertySynthesize(): Expected '@synthesize'");
23167330f729Sjoerg ConsumeToken(); // consume synthesize
23177330f729Sjoerg
23187330f729Sjoerg while (true) {
23197330f729Sjoerg if (Tok.is(tok::code_completion)) {
23207330f729Sjoerg cutOffParsing();
2321*e038c9c4Sjoerg Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
23227330f729Sjoerg return nullptr;
23237330f729Sjoerg }
23247330f729Sjoerg
23257330f729Sjoerg if (Tok.isNot(tok::identifier)) {
23267330f729Sjoerg Diag(Tok, diag::err_synthesized_property_name);
23277330f729Sjoerg SkipUntil(tok::semi);
23287330f729Sjoerg return nullptr;
23297330f729Sjoerg }
23307330f729Sjoerg
23317330f729Sjoerg IdentifierInfo *propertyIvar = nullptr;
23327330f729Sjoerg IdentifierInfo *propertyId = Tok.getIdentifierInfo();
23337330f729Sjoerg SourceLocation propertyLoc = ConsumeToken(); // consume property name
23347330f729Sjoerg SourceLocation propertyIvarLoc;
23357330f729Sjoerg if (TryConsumeToken(tok::equal)) {
23367330f729Sjoerg // property '=' ivar-name
23377330f729Sjoerg if (Tok.is(tok::code_completion)) {
23387330f729Sjoerg cutOffParsing();
2339*e038c9c4Sjoerg Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
23407330f729Sjoerg return nullptr;
23417330f729Sjoerg }
23427330f729Sjoerg
23437330f729Sjoerg if (expectIdentifier())
23447330f729Sjoerg break;
23457330f729Sjoerg propertyIvar = Tok.getIdentifierInfo();
23467330f729Sjoerg propertyIvarLoc = ConsumeToken(); // consume ivar-name
23477330f729Sjoerg }
23487330f729Sjoerg Actions.ActOnPropertyImplDecl(
23497330f729Sjoerg getCurScope(), atLoc, propertyLoc, true,
23507330f729Sjoerg propertyId, propertyIvar, propertyIvarLoc,
23517330f729Sjoerg ObjCPropertyQueryKind::OBJC_PR_query_unknown);
23527330f729Sjoerg if (Tok.isNot(tok::comma))
23537330f729Sjoerg break;
23547330f729Sjoerg ConsumeToken(); // consume ','
23557330f729Sjoerg }
23567330f729Sjoerg ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
23577330f729Sjoerg return nullptr;
23587330f729Sjoerg }
23597330f729Sjoerg
23607330f729Sjoerg /// property-dynamic:
23617330f729Sjoerg /// @dynamic property-list
23627330f729Sjoerg ///
23637330f729Sjoerg /// property-list:
23647330f729Sjoerg /// identifier
23657330f729Sjoerg /// property-list ',' identifier
23667330f729Sjoerg ///
ParseObjCPropertyDynamic(SourceLocation atLoc)23677330f729Sjoerg Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
23687330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
23697330f729Sjoerg "ParseObjCPropertyDynamic(): Expected '@dynamic'");
23707330f729Sjoerg ConsumeToken(); // consume dynamic
23717330f729Sjoerg
23727330f729Sjoerg bool isClassProperty = false;
23737330f729Sjoerg if (Tok.is(tok::l_paren)) {
23747330f729Sjoerg ConsumeParen();
23757330f729Sjoerg const IdentifierInfo *II = Tok.getIdentifierInfo();
23767330f729Sjoerg
23777330f729Sjoerg if (!II) {
23787330f729Sjoerg Diag(Tok, diag::err_objc_expected_property_attr) << II;
23797330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
23807330f729Sjoerg } else {
23817330f729Sjoerg SourceLocation AttrName = ConsumeToken(); // consume attribute name
23827330f729Sjoerg if (II->isStr("class")) {
23837330f729Sjoerg isClassProperty = true;
23847330f729Sjoerg if (Tok.isNot(tok::r_paren)) {
23857330f729Sjoerg Diag(Tok, diag::err_expected) << tok::r_paren;
23867330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
23877330f729Sjoerg } else
23887330f729Sjoerg ConsumeParen();
23897330f729Sjoerg } else {
23907330f729Sjoerg Diag(AttrName, diag::err_objc_expected_property_attr) << II;
23917330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
23927330f729Sjoerg }
23937330f729Sjoerg }
23947330f729Sjoerg }
23957330f729Sjoerg
23967330f729Sjoerg while (true) {
23977330f729Sjoerg if (Tok.is(tok::code_completion)) {
23987330f729Sjoerg cutOffParsing();
2399*e038c9c4Sjoerg Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
24007330f729Sjoerg return nullptr;
24017330f729Sjoerg }
24027330f729Sjoerg
24037330f729Sjoerg if (expectIdentifier()) {
24047330f729Sjoerg SkipUntil(tok::semi);
24057330f729Sjoerg return nullptr;
24067330f729Sjoerg }
24077330f729Sjoerg
24087330f729Sjoerg IdentifierInfo *propertyId = Tok.getIdentifierInfo();
24097330f729Sjoerg SourceLocation propertyLoc = ConsumeToken(); // consume property name
24107330f729Sjoerg Actions.ActOnPropertyImplDecl(
24117330f729Sjoerg getCurScope(), atLoc, propertyLoc, false,
24127330f729Sjoerg propertyId, nullptr, SourceLocation(),
24137330f729Sjoerg isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
24147330f729Sjoerg ObjCPropertyQueryKind::OBJC_PR_query_unknown);
24157330f729Sjoerg
24167330f729Sjoerg if (Tok.isNot(tok::comma))
24177330f729Sjoerg break;
24187330f729Sjoerg ConsumeToken(); // consume ','
24197330f729Sjoerg }
24207330f729Sjoerg ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
24217330f729Sjoerg return nullptr;
24227330f729Sjoerg }
24237330f729Sjoerg
24247330f729Sjoerg /// objc-throw-statement:
24257330f729Sjoerg /// throw expression[opt];
24267330f729Sjoerg ///
ParseObjCThrowStmt(SourceLocation atLoc)24277330f729Sjoerg StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
24287330f729Sjoerg ExprResult Res;
24297330f729Sjoerg ConsumeToken(); // consume throw
24307330f729Sjoerg if (Tok.isNot(tok::semi)) {
24317330f729Sjoerg Res = ParseExpression();
24327330f729Sjoerg if (Res.isInvalid()) {
24337330f729Sjoerg SkipUntil(tok::semi);
24347330f729Sjoerg return StmtError();
24357330f729Sjoerg }
24367330f729Sjoerg }
24377330f729Sjoerg // consume ';'
24387330f729Sjoerg ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
24397330f729Sjoerg return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
24407330f729Sjoerg }
24417330f729Sjoerg
24427330f729Sjoerg /// objc-synchronized-statement:
24437330f729Sjoerg /// @synchronized '(' expression ')' compound-statement
24447330f729Sjoerg ///
24457330f729Sjoerg StmtResult
ParseObjCSynchronizedStmt(SourceLocation atLoc)24467330f729Sjoerg Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
24477330f729Sjoerg ConsumeToken(); // consume synchronized
24487330f729Sjoerg if (Tok.isNot(tok::l_paren)) {
24497330f729Sjoerg Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
24507330f729Sjoerg return StmtError();
24517330f729Sjoerg }
24527330f729Sjoerg
24537330f729Sjoerg // The operand is surrounded with parentheses.
24547330f729Sjoerg ConsumeParen(); // '('
24557330f729Sjoerg ExprResult operand(ParseExpression());
24567330f729Sjoerg
24577330f729Sjoerg if (Tok.is(tok::r_paren)) {
24587330f729Sjoerg ConsumeParen(); // ')'
24597330f729Sjoerg } else {
24607330f729Sjoerg if (!operand.isInvalid())
24617330f729Sjoerg Diag(Tok, diag::err_expected) << tok::r_paren;
24627330f729Sjoerg
24637330f729Sjoerg // Skip forward until we see a left brace, but don't consume it.
24647330f729Sjoerg SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
24657330f729Sjoerg }
24667330f729Sjoerg
24677330f729Sjoerg // Require a compound statement.
24687330f729Sjoerg if (Tok.isNot(tok::l_brace)) {
24697330f729Sjoerg if (!operand.isInvalid())
24707330f729Sjoerg Diag(Tok, diag::err_expected) << tok::l_brace;
24717330f729Sjoerg return StmtError();
24727330f729Sjoerg }
24737330f729Sjoerg
24747330f729Sjoerg // Check the @synchronized operand now.
24757330f729Sjoerg if (!operand.isInvalid())
24767330f729Sjoerg operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
24777330f729Sjoerg
24787330f729Sjoerg // Parse the compound statement within a new scope.
24797330f729Sjoerg ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
24807330f729Sjoerg StmtResult body(ParseCompoundStatementBody());
24817330f729Sjoerg bodyScope.Exit();
24827330f729Sjoerg
24837330f729Sjoerg // If there was a semantic or parse error earlier with the
24847330f729Sjoerg // operand, fail now.
24857330f729Sjoerg if (operand.isInvalid())
24867330f729Sjoerg return StmtError();
24877330f729Sjoerg
24887330f729Sjoerg if (body.isInvalid())
24897330f729Sjoerg body = Actions.ActOnNullStmt(Tok.getLocation());
24907330f729Sjoerg
24917330f729Sjoerg return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
24927330f729Sjoerg }
24937330f729Sjoerg
24947330f729Sjoerg /// objc-try-catch-statement:
24957330f729Sjoerg /// @try compound-statement objc-catch-list[opt]
24967330f729Sjoerg /// @try compound-statement objc-catch-list[opt] @finally compound-statement
24977330f729Sjoerg ///
24987330f729Sjoerg /// objc-catch-list:
24997330f729Sjoerg /// @catch ( parameter-declaration ) compound-statement
25007330f729Sjoerg /// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
25017330f729Sjoerg /// catch-parameter-declaration:
25027330f729Sjoerg /// parameter-declaration
25037330f729Sjoerg /// '...' [OBJC2]
25047330f729Sjoerg ///
ParseObjCTryStmt(SourceLocation atLoc)25057330f729Sjoerg StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
25067330f729Sjoerg bool catch_or_finally_seen = false;
25077330f729Sjoerg
25087330f729Sjoerg ConsumeToken(); // consume try
25097330f729Sjoerg if (Tok.isNot(tok::l_brace)) {
25107330f729Sjoerg Diag(Tok, diag::err_expected) << tok::l_brace;
25117330f729Sjoerg return StmtError();
25127330f729Sjoerg }
25137330f729Sjoerg StmtVector CatchStmts;
25147330f729Sjoerg StmtResult FinallyStmt;
25157330f729Sjoerg ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
25167330f729Sjoerg StmtResult TryBody(ParseCompoundStatementBody());
25177330f729Sjoerg TryScope.Exit();
25187330f729Sjoerg if (TryBody.isInvalid())
25197330f729Sjoerg TryBody = Actions.ActOnNullStmt(Tok.getLocation());
25207330f729Sjoerg
25217330f729Sjoerg while (Tok.is(tok::at)) {
25227330f729Sjoerg // At this point, we need to lookahead to determine if this @ is the start
25237330f729Sjoerg // of an @catch or @finally. We don't want to consume the @ token if this
25247330f729Sjoerg // is an @try or @encode or something else.
25257330f729Sjoerg Token AfterAt = GetLookAheadToken(1);
25267330f729Sjoerg if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
25277330f729Sjoerg !AfterAt.isObjCAtKeyword(tok::objc_finally))
25287330f729Sjoerg break;
25297330f729Sjoerg
25307330f729Sjoerg SourceLocation AtCatchFinallyLoc = ConsumeToken();
25317330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_catch)) {
25327330f729Sjoerg Decl *FirstPart = nullptr;
25337330f729Sjoerg ConsumeToken(); // consume catch
25347330f729Sjoerg if (Tok.is(tok::l_paren)) {
25357330f729Sjoerg ConsumeParen();
25367330f729Sjoerg ParseScope CatchScope(this, Scope::DeclScope |
25377330f729Sjoerg Scope::CompoundStmtScope |
25387330f729Sjoerg Scope::AtCatchScope);
25397330f729Sjoerg if (Tok.isNot(tok::ellipsis)) {
25407330f729Sjoerg DeclSpec DS(AttrFactory);
25417330f729Sjoerg ParseDeclarationSpecifiers(DS);
2542*e038c9c4Sjoerg Declarator ParmDecl(DS, DeclaratorContext::ObjCCatch);
25437330f729Sjoerg ParseDeclarator(ParmDecl);
25447330f729Sjoerg
25457330f729Sjoerg // Inform the actions module about the declarator, so it
25467330f729Sjoerg // gets added to the current scope.
25477330f729Sjoerg FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
25487330f729Sjoerg } else
25497330f729Sjoerg ConsumeToken(); // consume '...'
25507330f729Sjoerg
25517330f729Sjoerg SourceLocation RParenLoc;
25527330f729Sjoerg
25537330f729Sjoerg if (Tok.is(tok::r_paren))
25547330f729Sjoerg RParenLoc = ConsumeParen();
25557330f729Sjoerg else // Skip over garbage, until we get to ')'. Eat the ')'.
25567330f729Sjoerg SkipUntil(tok::r_paren, StopAtSemi);
25577330f729Sjoerg
25587330f729Sjoerg StmtResult CatchBody(true);
25597330f729Sjoerg if (Tok.is(tok::l_brace))
25607330f729Sjoerg CatchBody = ParseCompoundStatementBody();
25617330f729Sjoerg else
25627330f729Sjoerg Diag(Tok, diag::err_expected) << tok::l_brace;
25637330f729Sjoerg if (CatchBody.isInvalid())
25647330f729Sjoerg CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
25657330f729Sjoerg
25667330f729Sjoerg StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
25677330f729Sjoerg RParenLoc,
25687330f729Sjoerg FirstPart,
25697330f729Sjoerg CatchBody.get());
25707330f729Sjoerg if (!Catch.isInvalid())
25717330f729Sjoerg CatchStmts.push_back(Catch.get());
25727330f729Sjoerg
25737330f729Sjoerg } else {
25747330f729Sjoerg Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
25757330f729Sjoerg << "@catch clause";
25767330f729Sjoerg return StmtError();
25777330f729Sjoerg }
25787330f729Sjoerg catch_or_finally_seen = true;
25797330f729Sjoerg } else {
25807330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
25817330f729Sjoerg ConsumeToken(); // consume finally
25827330f729Sjoerg ParseScope FinallyScope(this,
25837330f729Sjoerg Scope::DeclScope | Scope::CompoundStmtScope);
25847330f729Sjoerg
25857330f729Sjoerg bool ShouldCapture =
25867330f729Sjoerg getTargetInfo().getTriple().isWindowsMSVCEnvironment();
25877330f729Sjoerg if (ShouldCapture)
25887330f729Sjoerg Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),
25897330f729Sjoerg CR_ObjCAtFinally, 1);
25907330f729Sjoerg
25917330f729Sjoerg StmtResult FinallyBody(true);
25927330f729Sjoerg if (Tok.is(tok::l_brace))
25937330f729Sjoerg FinallyBody = ParseCompoundStatementBody();
25947330f729Sjoerg else
25957330f729Sjoerg Diag(Tok, diag::err_expected) << tok::l_brace;
25967330f729Sjoerg
25977330f729Sjoerg if (FinallyBody.isInvalid()) {
25987330f729Sjoerg FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
25997330f729Sjoerg if (ShouldCapture)
26007330f729Sjoerg Actions.ActOnCapturedRegionError();
26017330f729Sjoerg } else if (ShouldCapture) {
26027330f729Sjoerg FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());
26037330f729Sjoerg }
26047330f729Sjoerg
26057330f729Sjoerg FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
26067330f729Sjoerg FinallyBody.get());
26077330f729Sjoerg catch_or_finally_seen = true;
26087330f729Sjoerg break;
26097330f729Sjoerg }
26107330f729Sjoerg }
26117330f729Sjoerg if (!catch_or_finally_seen) {
26127330f729Sjoerg Diag(atLoc, diag::err_missing_catch_finally);
26137330f729Sjoerg return StmtError();
26147330f729Sjoerg }
26157330f729Sjoerg
26167330f729Sjoerg return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
26177330f729Sjoerg CatchStmts,
26187330f729Sjoerg FinallyStmt.get());
26197330f729Sjoerg }
26207330f729Sjoerg
26217330f729Sjoerg /// objc-autoreleasepool-statement:
26227330f729Sjoerg /// @autoreleasepool compound-statement
26237330f729Sjoerg ///
26247330f729Sjoerg StmtResult
ParseObjCAutoreleasePoolStmt(SourceLocation atLoc)26257330f729Sjoerg Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
26267330f729Sjoerg ConsumeToken(); // consume autoreleasepool
26277330f729Sjoerg if (Tok.isNot(tok::l_brace)) {
26287330f729Sjoerg Diag(Tok, diag::err_expected) << tok::l_brace;
26297330f729Sjoerg return StmtError();
26307330f729Sjoerg }
26317330f729Sjoerg // Enter a scope to hold everything within the compound stmt. Compound
26327330f729Sjoerg // statements can always hold declarations.
26337330f729Sjoerg ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
26347330f729Sjoerg
26357330f729Sjoerg StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
26367330f729Sjoerg
26377330f729Sjoerg BodyScope.Exit();
26387330f729Sjoerg if (AutoreleasePoolBody.isInvalid())
26397330f729Sjoerg AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
26407330f729Sjoerg return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
26417330f729Sjoerg AutoreleasePoolBody.get());
26427330f729Sjoerg }
26437330f729Sjoerg
26447330f729Sjoerg /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
26457330f729Sjoerg /// for later parsing.
StashAwayMethodOrFunctionBodyTokens(Decl * MDecl)26467330f729Sjoerg void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
26477330f729Sjoerg if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
26487330f729Sjoerg trySkippingFunctionBody()) {
26497330f729Sjoerg Actions.ActOnSkippedFunctionBody(MDecl);
26507330f729Sjoerg return;
26517330f729Sjoerg }
26527330f729Sjoerg
26537330f729Sjoerg LexedMethod* LM = new LexedMethod(this, MDecl);
26547330f729Sjoerg CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
26557330f729Sjoerg CachedTokens &Toks = LM->Toks;
26567330f729Sjoerg // Begin by storing the '{' or 'try' or ':' token.
26577330f729Sjoerg Toks.push_back(Tok);
26587330f729Sjoerg if (Tok.is(tok::kw_try)) {
26597330f729Sjoerg ConsumeToken();
26607330f729Sjoerg if (Tok.is(tok::colon)) {
26617330f729Sjoerg Toks.push_back(Tok);
26627330f729Sjoerg ConsumeToken();
26637330f729Sjoerg while (Tok.isNot(tok::l_brace)) {
26647330f729Sjoerg ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
26657330f729Sjoerg ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
26667330f729Sjoerg }
26677330f729Sjoerg }
26687330f729Sjoerg Toks.push_back(Tok); // also store '{'
26697330f729Sjoerg }
26707330f729Sjoerg else if (Tok.is(tok::colon)) {
26717330f729Sjoerg ConsumeToken();
26727330f729Sjoerg // FIXME: This is wrong, due to C++11 braced initialization.
26737330f729Sjoerg while (Tok.isNot(tok::l_brace)) {
26747330f729Sjoerg ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
26757330f729Sjoerg ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
26767330f729Sjoerg }
26777330f729Sjoerg Toks.push_back(Tok); // also store '{'
26787330f729Sjoerg }
26797330f729Sjoerg ConsumeBrace();
26807330f729Sjoerg // Consume everything up to (and including) the matching right brace.
26817330f729Sjoerg ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
26827330f729Sjoerg while (Tok.is(tok::kw_catch)) {
26837330f729Sjoerg ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
26847330f729Sjoerg ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
26857330f729Sjoerg }
26867330f729Sjoerg }
26877330f729Sjoerg
26887330f729Sjoerg /// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
26897330f729Sjoerg ///
ParseObjCMethodDefinition()26907330f729Sjoerg Decl *Parser::ParseObjCMethodDefinition() {
26917330f729Sjoerg Decl *MDecl = ParseObjCMethodPrototype();
26927330f729Sjoerg
26937330f729Sjoerg PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),
26947330f729Sjoerg "parsing Objective-C method");
26957330f729Sjoerg
26967330f729Sjoerg // parse optional ';'
26977330f729Sjoerg if (Tok.is(tok::semi)) {
26987330f729Sjoerg if (CurParsedObjCImpl) {
26997330f729Sjoerg Diag(Tok, diag::warn_semicolon_before_method_body)
27007330f729Sjoerg << FixItHint::CreateRemoval(Tok.getLocation());
27017330f729Sjoerg }
27027330f729Sjoerg ConsumeToken();
27037330f729Sjoerg }
27047330f729Sjoerg
27057330f729Sjoerg // We should have an opening brace now.
27067330f729Sjoerg if (Tok.isNot(tok::l_brace)) {
27077330f729Sjoerg Diag(Tok, diag::err_expected_method_body);
27087330f729Sjoerg
27097330f729Sjoerg // Skip over garbage, until we get to '{'. Don't eat the '{'.
27107330f729Sjoerg SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
27117330f729Sjoerg
27127330f729Sjoerg // If we didn't find the '{', bail out.
27137330f729Sjoerg if (Tok.isNot(tok::l_brace))
27147330f729Sjoerg return nullptr;
27157330f729Sjoerg }
27167330f729Sjoerg
27177330f729Sjoerg if (!MDecl) {
27187330f729Sjoerg ConsumeBrace();
27197330f729Sjoerg SkipUntil(tok::r_brace);
27207330f729Sjoerg return nullptr;
27217330f729Sjoerg }
27227330f729Sjoerg
27237330f729Sjoerg // Allow the rest of sema to find private method decl implementations.
27247330f729Sjoerg Actions.AddAnyMethodToGlobalPool(MDecl);
27257330f729Sjoerg assert (CurParsedObjCImpl
27267330f729Sjoerg && "ParseObjCMethodDefinition - Method out of @implementation");
27277330f729Sjoerg // Consume the tokens and store them for later parsing.
27287330f729Sjoerg StashAwayMethodOrFunctionBodyTokens(MDecl);
27297330f729Sjoerg return MDecl;
27307330f729Sjoerg }
27317330f729Sjoerg
ParseObjCAtStatement(SourceLocation AtLoc,ParsedStmtContext StmtCtx)27327330f729Sjoerg StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
27337330f729Sjoerg ParsedStmtContext StmtCtx) {
27347330f729Sjoerg if (Tok.is(tok::code_completion)) {
27357330f729Sjoerg cutOffParsing();
2736*e038c9c4Sjoerg Actions.CodeCompleteObjCAtStatement(getCurScope());
27377330f729Sjoerg return StmtError();
27387330f729Sjoerg }
27397330f729Sjoerg
27407330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_try))
27417330f729Sjoerg return ParseObjCTryStmt(AtLoc);
27427330f729Sjoerg
27437330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_throw))
27447330f729Sjoerg return ParseObjCThrowStmt(AtLoc);
27457330f729Sjoerg
27467330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_synchronized))
27477330f729Sjoerg return ParseObjCSynchronizedStmt(AtLoc);
27487330f729Sjoerg
27497330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
27507330f729Sjoerg return ParseObjCAutoreleasePoolStmt(AtLoc);
27517330f729Sjoerg
27527330f729Sjoerg if (Tok.isObjCAtKeyword(tok::objc_import) &&
27537330f729Sjoerg getLangOpts().DebuggerSupport) {
27547330f729Sjoerg SkipUntil(tok::semi);
27557330f729Sjoerg return Actions.ActOnNullStmt(Tok.getLocation());
27567330f729Sjoerg }
27577330f729Sjoerg
27587330f729Sjoerg ExprStatementTokLoc = AtLoc;
27597330f729Sjoerg ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
27607330f729Sjoerg if (Res.isInvalid()) {
27617330f729Sjoerg // If the expression is invalid, skip ahead to the next semicolon. Not
27627330f729Sjoerg // doing this opens us up to the possibility of infinite loops if
27637330f729Sjoerg // ParseExpression does not consume any tokens.
27647330f729Sjoerg SkipUntil(tok::semi);
27657330f729Sjoerg return StmtError();
27667330f729Sjoerg }
27677330f729Sjoerg
27687330f729Sjoerg // Otherwise, eat the semicolon.
27697330f729Sjoerg ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
27707330f729Sjoerg return handleExprStmt(Res, StmtCtx);
27717330f729Sjoerg }
27727330f729Sjoerg
ParseObjCAtExpression(SourceLocation AtLoc)27737330f729Sjoerg ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
27747330f729Sjoerg switch (Tok.getKind()) {
27757330f729Sjoerg case tok::code_completion:
27767330f729Sjoerg cutOffParsing();
2777*e038c9c4Sjoerg Actions.CodeCompleteObjCAtExpression(getCurScope());
27787330f729Sjoerg return ExprError();
27797330f729Sjoerg
27807330f729Sjoerg case tok::minus:
27817330f729Sjoerg case tok::plus: {
27827330f729Sjoerg tok::TokenKind Kind = Tok.getKind();
27837330f729Sjoerg SourceLocation OpLoc = ConsumeToken();
27847330f729Sjoerg
27857330f729Sjoerg if (!Tok.is(tok::numeric_constant)) {
27867330f729Sjoerg const char *Symbol = nullptr;
27877330f729Sjoerg switch (Kind) {
27887330f729Sjoerg case tok::minus: Symbol = "-"; break;
27897330f729Sjoerg case tok::plus: Symbol = "+"; break;
27907330f729Sjoerg default: llvm_unreachable("missing unary operator case");
27917330f729Sjoerg }
27927330f729Sjoerg Diag(Tok, diag::err_nsnumber_nonliteral_unary)
27937330f729Sjoerg << Symbol;
27947330f729Sjoerg return ExprError();
27957330f729Sjoerg }
27967330f729Sjoerg
27977330f729Sjoerg ExprResult Lit(Actions.ActOnNumericConstant(Tok));
27987330f729Sjoerg if (Lit.isInvalid()) {
27997330f729Sjoerg return Lit;
28007330f729Sjoerg }
28017330f729Sjoerg ConsumeToken(); // Consume the literal token.
28027330f729Sjoerg
28037330f729Sjoerg Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
28047330f729Sjoerg if (Lit.isInvalid())
28057330f729Sjoerg return Lit;
28067330f729Sjoerg
28077330f729Sjoerg return ParsePostfixExpressionSuffix(
28087330f729Sjoerg Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
28097330f729Sjoerg }
28107330f729Sjoerg
28117330f729Sjoerg case tok::string_literal: // primary-expression: string-literal
28127330f729Sjoerg case tok::wide_string_literal:
28137330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
28147330f729Sjoerg
28157330f729Sjoerg case tok::char_constant:
28167330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
28177330f729Sjoerg
28187330f729Sjoerg case tok::numeric_constant:
28197330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
28207330f729Sjoerg
28217330f729Sjoerg case tok::kw_true: // Objective-C++, etc.
28227330f729Sjoerg case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
28237330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
28247330f729Sjoerg case tok::kw_false: // Objective-C++, etc.
28257330f729Sjoerg case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
28267330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
28277330f729Sjoerg
28287330f729Sjoerg case tok::l_square:
28297330f729Sjoerg // Objective-C array literal
28307330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
28317330f729Sjoerg
28327330f729Sjoerg case tok::l_brace:
28337330f729Sjoerg // Objective-C dictionary literal
28347330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
28357330f729Sjoerg
28367330f729Sjoerg case tok::l_paren:
28377330f729Sjoerg // Objective-C boxed expression
28387330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
28397330f729Sjoerg
28407330f729Sjoerg default:
28417330f729Sjoerg if (Tok.getIdentifierInfo() == nullptr)
28427330f729Sjoerg return ExprError(Diag(AtLoc, diag::err_unexpected_at));
28437330f729Sjoerg
28447330f729Sjoerg switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
28457330f729Sjoerg case tok::objc_encode:
28467330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
28477330f729Sjoerg case tok::objc_protocol:
28487330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
28497330f729Sjoerg case tok::objc_selector:
28507330f729Sjoerg return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
28517330f729Sjoerg case tok::objc_available:
28527330f729Sjoerg return ParseAvailabilityCheckExpr(AtLoc);
28537330f729Sjoerg default: {
28547330f729Sjoerg const char *str = nullptr;
28557330f729Sjoerg // Only provide the @try/@finally/@autoreleasepool fixit when we're sure
28567330f729Sjoerg // that this is a proper statement where such directives could actually
28577330f729Sjoerg // occur.
28587330f729Sjoerg if (GetLookAheadToken(1).is(tok::l_brace) &&
28597330f729Sjoerg ExprStatementTokLoc == AtLoc) {
28607330f729Sjoerg char ch = Tok.getIdentifierInfo()->getNameStart()[0];
28617330f729Sjoerg str =
28627330f729Sjoerg ch == 't' ? "try"
28637330f729Sjoerg : (ch == 'f' ? "finally"
28647330f729Sjoerg : (ch == 'a' ? "autoreleasepool" : nullptr));
28657330f729Sjoerg }
28667330f729Sjoerg if (str) {
28677330f729Sjoerg SourceLocation kwLoc = Tok.getLocation();
28687330f729Sjoerg return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
28697330f729Sjoerg FixItHint::CreateReplacement(kwLoc, str));
28707330f729Sjoerg }
28717330f729Sjoerg else
28727330f729Sjoerg return ExprError(Diag(AtLoc, diag::err_unexpected_at));
28737330f729Sjoerg }
28747330f729Sjoerg }
28757330f729Sjoerg }
28767330f729Sjoerg }
28777330f729Sjoerg
28787330f729Sjoerg /// Parse the receiver of an Objective-C++ message send.
28797330f729Sjoerg ///
28807330f729Sjoerg /// This routine parses the receiver of a message send in
28817330f729Sjoerg /// Objective-C++ either as a type or as an expression. Note that this
28827330f729Sjoerg /// routine must not be called to parse a send to 'super', since it
28837330f729Sjoerg /// has no way to return such a result.
28847330f729Sjoerg ///
28857330f729Sjoerg /// \param IsExpr Whether the receiver was parsed as an expression.
28867330f729Sjoerg ///
28877330f729Sjoerg /// \param TypeOrExpr If the receiver was parsed as an expression (\c
28887330f729Sjoerg /// IsExpr is true), the parsed expression. If the receiver was parsed
28897330f729Sjoerg /// as a type (\c IsExpr is false), the parsed type.
28907330f729Sjoerg ///
28917330f729Sjoerg /// \returns True if an error occurred during parsing or semantic
28927330f729Sjoerg /// analysis, in which case the arguments do not have valid
28937330f729Sjoerg /// values. Otherwise, returns false for a successful parse.
28947330f729Sjoerg ///
28957330f729Sjoerg /// objc-receiver: [C++]
28967330f729Sjoerg /// 'super' [not parsed here]
28977330f729Sjoerg /// expression
28987330f729Sjoerg /// simple-type-specifier
28997330f729Sjoerg /// typename-specifier
ParseObjCXXMessageReceiver(bool & IsExpr,void * & TypeOrExpr)29007330f729Sjoerg bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
29017330f729Sjoerg InMessageExpressionRAIIObject InMessage(*this, true);
29027330f729Sjoerg
29037330f729Sjoerg if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
29047330f729Sjoerg tok::annot_cxxscope))
29057330f729Sjoerg TryAnnotateTypeOrScopeToken();
29067330f729Sjoerg
29077330f729Sjoerg if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
29087330f729Sjoerg // objc-receiver:
29097330f729Sjoerg // expression
29107330f729Sjoerg // Make sure any typos in the receiver are corrected or diagnosed, so that
29117330f729Sjoerg // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
29127330f729Sjoerg // only the things that are valid ObjC receivers?
29137330f729Sjoerg ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
29147330f729Sjoerg if (Receiver.isInvalid())
29157330f729Sjoerg return true;
29167330f729Sjoerg
29177330f729Sjoerg IsExpr = true;
29187330f729Sjoerg TypeOrExpr = Receiver.get();
29197330f729Sjoerg return false;
29207330f729Sjoerg }
29217330f729Sjoerg
29227330f729Sjoerg // objc-receiver:
29237330f729Sjoerg // typename-specifier
29247330f729Sjoerg // simple-type-specifier
29257330f729Sjoerg // expression (that starts with one of the above)
29267330f729Sjoerg DeclSpec DS(AttrFactory);
29277330f729Sjoerg ParseCXXSimpleTypeSpecifier(DS);
29287330f729Sjoerg
29297330f729Sjoerg if (Tok.is(tok::l_paren)) {
29307330f729Sjoerg // If we see an opening parentheses at this point, we are
29317330f729Sjoerg // actually parsing an expression that starts with a
29327330f729Sjoerg // function-style cast, e.g.,
29337330f729Sjoerg //
29347330f729Sjoerg // postfix-expression:
29357330f729Sjoerg // simple-type-specifier ( expression-list [opt] )
29367330f729Sjoerg // typename-specifier ( expression-list [opt] )
29377330f729Sjoerg //
29387330f729Sjoerg // Parse the remainder of this case, then the (optional)
29397330f729Sjoerg // postfix-expression suffix, followed by the (optional)
29407330f729Sjoerg // right-hand side of the binary expression. We have an
29417330f729Sjoerg // instance method.
29427330f729Sjoerg ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
29437330f729Sjoerg if (!Receiver.isInvalid())
29447330f729Sjoerg Receiver = ParsePostfixExpressionSuffix(Receiver.get());
29457330f729Sjoerg if (!Receiver.isInvalid())
29467330f729Sjoerg Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
29477330f729Sjoerg if (Receiver.isInvalid())
29487330f729Sjoerg return true;
29497330f729Sjoerg
29507330f729Sjoerg IsExpr = true;
29517330f729Sjoerg TypeOrExpr = Receiver.get();
29527330f729Sjoerg return false;
29537330f729Sjoerg }
29547330f729Sjoerg
29557330f729Sjoerg // We have a class message. Turn the simple-type-specifier or
29567330f729Sjoerg // typename-specifier we parsed into a type and parse the
29577330f729Sjoerg // remainder of the class message.
2958*e038c9c4Sjoerg Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
29597330f729Sjoerg TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
29607330f729Sjoerg if (Type.isInvalid())
29617330f729Sjoerg return true;
29627330f729Sjoerg
29637330f729Sjoerg IsExpr = false;
29647330f729Sjoerg TypeOrExpr = Type.get().getAsOpaquePtr();
29657330f729Sjoerg return false;
29667330f729Sjoerg }
29677330f729Sjoerg
29687330f729Sjoerg /// Determine whether the parser is currently referring to a an
29697330f729Sjoerg /// Objective-C message send, using a simplified heuristic to avoid overhead.
29707330f729Sjoerg ///
29717330f729Sjoerg /// This routine will only return true for a subset of valid message-send
29727330f729Sjoerg /// expressions.
isSimpleObjCMessageExpression()29737330f729Sjoerg bool Parser::isSimpleObjCMessageExpression() {
29747330f729Sjoerg assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&
29757330f729Sjoerg "Incorrect start for isSimpleObjCMessageExpression");
29767330f729Sjoerg return GetLookAheadToken(1).is(tok::identifier) &&
29777330f729Sjoerg GetLookAheadToken(2).is(tok::identifier);
29787330f729Sjoerg }
29797330f729Sjoerg
isStartOfObjCClassMessageMissingOpenBracket()29807330f729Sjoerg bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
29817330f729Sjoerg if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||
29827330f729Sjoerg InMessageExpression)
29837330f729Sjoerg return false;
29847330f729Sjoerg
2985*e038c9c4Sjoerg TypeResult Type;
29867330f729Sjoerg
29877330f729Sjoerg if (Tok.is(tok::annot_typename))
29887330f729Sjoerg Type = getTypeAnnotation(Tok);
29897330f729Sjoerg else if (Tok.is(tok::identifier))
29907330f729Sjoerg Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
29917330f729Sjoerg getCurScope());
29927330f729Sjoerg else
29937330f729Sjoerg return false;
29947330f729Sjoerg
2995*e038c9c4Sjoerg // FIXME: Should not be querying properties of types from the parser.
2996*e038c9c4Sjoerg if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) {
29977330f729Sjoerg const Token &AfterNext = GetLookAheadToken(2);
29987330f729Sjoerg if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
29997330f729Sjoerg if (Tok.is(tok::identifier))
30007330f729Sjoerg TryAnnotateTypeOrScopeToken();
30017330f729Sjoerg
30027330f729Sjoerg return Tok.is(tok::annot_typename);
30037330f729Sjoerg }
30047330f729Sjoerg }
30057330f729Sjoerg
30067330f729Sjoerg return false;
30077330f729Sjoerg }
30087330f729Sjoerg
30097330f729Sjoerg /// objc-message-expr:
30107330f729Sjoerg /// '[' objc-receiver objc-message-args ']'
30117330f729Sjoerg ///
30127330f729Sjoerg /// objc-receiver: [C]
30137330f729Sjoerg /// 'super'
30147330f729Sjoerg /// expression
30157330f729Sjoerg /// class-name
30167330f729Sjoerg /// type-name
30177330f729Sjoerg ///
ParseObjCMessageExpression()30187330f729Sjoerg ExprResult Parser::ParseObjCMessageExpression() {
30197330f729Sjoerg assert(Tok.is(tok::l_square) && "'[' expected");
30207330f729Sjoerg SourceLocation LBracLoc = ConsumeBracket(); // consume '['
30217330f729Sjoerg
30227330f729Sjoerg if (Tok.is(tok::code_completion)) {
30237330f729Sjoerg cutOffParsing();
3024*e038c9c4Sjoerg Actions.CodeCompleteObjCMessageReceiver(getCurScope());
30257330f729Sjoerg return ExprError();
30267330f729Sjoerg }
30277330f729Sjoerg
30287330f729Sjoerg InMessageExpressionRAIIObject InMessage(*this, true);
30297330f729Sjoerg
30307330f729Sjoerg if (getLangOpts().CPlusPlus) {
30317330f729Sjoerg // We completely separate the C and C++ cases because C++ requires
30327330f729Sjoerg // more complicated (read: slower) parsing.
30337330f729Sjoerg
30347330f729Sjoerg // Handle send to super.
30357330f729Sjoerg // FIXME: This doesn't benefit from the same typo-correction we
30367330f729Sjoerg // get in Objective-C.
30377330f729Sjoerg if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
30387330f729Sjoerg NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
30397330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
30407330f729Sjoerg nullptr);
30417330f729Sjoerg
30427330f729Sjoerg // Parse the receiver, which is either a type or an expression.
30437330f729Sjoerg bool IsExpr;
30447330f729Sjoerg void *TypeOrExpr = nullptr;
30457330f729Sjoerg if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
30467330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
30477330f729Sjoerg return ExprError();
30487330f729Sjoerg }
30497330f729Sjoerg
30507330f729Sjoerg if (IsExpr)
30517330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
30527330f729Sjoerg static_cast<Expr *>(TypeOrExpr));
30537330f729Sjoerg
30547330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
30557330f729Sjoerg ParsedType::getFromOpaquePtr(TypeOrExpr),
30567330f729Sjoerg nullptr);
30577330f729Sjoerg }
30587330f729Sjoerg
30597330f729Sjoerg if (Tok.is(tok::identifier)) {
30607330f729Sjoerg IdentifierInfo *Name = Tok.getIdentifierInfo();
30617330f729Sjoerg SourceLocation NameLoc = Tok.getLocation();
30627330f729Sjoerg ParsedType ReceiverType;
30637330f729Sjoerg switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
30647330f729Sjoerg Name == Ident_super,
30657330f729Sjoerg NextToken().is(tok::period),
30667330f729Sjoerg ReceiverType)) {
30677330f729Sjoerg case Sema::ObjCSuperMessage:
30687330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
30697330f729Sjoerg nullptr);
30707330f729Sjoerg
30717330f729Sjoerg case Sema::ObjCClassMessage:
30727330f729Sjoerg if (!ReceiverType) {
30737330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
30747330f729Sjoerg return ExprError();
30757330f729Sjoerg }
30767330f729Sjoerg
30777330f729Sjoerg ConsumeToken(); // the type name
30787330f729Sjoerg
30797330f729Sjoerg // Parse type arguments and protocol qualifiers.
30807330f729Sjoerg if (Tok.is(tok::less)) {
30817330f729Sjoerg SourceLocation NewEndLoc;
30827330f729Sjoerg TypeResult NewReceiverType
30837330f729Sjoerg = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
30847330f729Sjoerg /*consumeLastToken=*/true,
30857330f729Sjoerg NewEndLoc);
30867330f729Sjoerg if (!NewReceiverType.isUsable()) {
30877330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
30887330f729Sjoerg return ExprError();
30897330f729Sjoerg }
30907330f729Sjoerg
30917330f729Sjoerg ReceiverType = NewReceiverType.get();
30927330f729Sjoerg }
30937330f729Sjoerg
30947330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
30957330f729Sjoerg ReceiverType, nullptr);
30967330f729Sjoerg
30977330f729Sjoerg case Sema::ObjCInstanceMessage:
30987330f729Sjoerg // Fall through to parse an expression.
30997330f729Sjoerg break;
31007330f729Sjoerg }
31017330f729Sjoerg }
31027330f729Sjoerg
31037330f729Sjoerg // Otherwise, an arbitrary expression can be the receiver of a send.
31047330f729Sjoerg ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
31057330f729Sjoerg if (Res.isInvalid()) {
31067330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
31077330f729Sjoerg return Res;
31087330f729Sjoerg }
31097330f729Sjoerg
31107330f729Sjoerg return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
31117330f729Sjoerg Res.get());
31127330f729Sjoerg }
31137330f729Sjoerg
31147330f729Sjoerg /// Parse the remainder of an Objective-C message following the
31157330f729Sjoerg /// '[' objc-receiver.
31167330f729Sjoerg ///
31177330f729Sjoerg /// This routine handles sends to super, class messages (sent to a
31187330f729Sjoerg /// class name), and instance messages (sent to an object), and the
31197330f729Sjoerg /// target is represented by \p SuperLoc, \p ReceiverType, or \p
31207330f729Sjoerg /// ReceiverExpr, respectively. Only one of these parameters may have
31217330f729Sjoerg /// a valid value.
31227330f729Sjoerg ///
31237330f729Sjoerg /// \param LBracLoc The location of the opening '['.
31247330f729Sjoerg ///
31257330f729Sjoerg /// \param SuperLoc If this is a send to 'super', the location of the
31267330f729Sjoerg /// 'super' keyword that indicates a send to the superclass.
31277330f729Sjoerg ///
31287330f729Sjoerg /// \param ReceiverType If this is a class message, the type of the
31297330f729Sjoerg /// class we are sending a message to.
31307330f729Sjoerg ///
31317330f729Sjoerg /// \param ReceiverExpr If this is an instance message, the expression
31327330f729Sjoerg /// used to compute the receiver object.
31337330f729Sjoerg ///
31347330f729Sjoerg /// objc-message-args:
31357330f729Sjoerg /// objc-selector
31367330f729Sjoerg /// objc-keywordarg-list
31377330f729Sjoerg ///
31387330f729Sjoerg /// objc-keywordarg-list:
31397330f729Sjoerg /// objc-keywordarg
31407330f729Sjoerg /// objc-keywordarg-list objc-keywordarg
31417330f729Sjoerg ///
31427330f729Sjoerg /// objc-keywordarg:
31437330f729Sjoerg /// selector-name[opt] ':' objc-keywordexpr
31447330f729Sjoerg ///
31457330f729Sjoerg /// objc-keywordexpr:
31467330f729Sjoerg /// nonempty-expr-list
31477330f729Sjoerg ///
31487330f729Sjoerg /// nonempty-expr-list:
31497330f729Sjoerg /// assignment-expression
31507330f729Sjoerg /// nonempty-expr-list , assignment-expression
31517330f729Sjoerg ///
31527330f729Sjoerg ExprResult
ParseObjCMessageExpressionBody(SourceLocation LBracLoc,SourceLocation SuperLoc,ParsedType ReceiverType,Expr * ReceiverExpr)31537330f729Sjoerg Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
31547330f729Sjoerg SourceLocation SuperLoc,
31557330f729Sjoerg ParsedType ReceiverType,
31567330f729Sjoerg Expr *ReceiverExpr) {
31577330f729Sjoerg InMessageExpressionRAIIObject InMessage(*this, true);
31587330f729Sjoerg
31597330f729Sjoerg if (Tok.is(tok::code_completion)) {
3160*e038c9c4Sjoerg cutOffParsing();
31617330f729Sjoerg if (SuperLoc.isValid())
31627330f729Sjoerg Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
31637330f729Sjoerg false);
31647330f729Sjoerg else if (ReceiverType)
31657330f729Sjoerg Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
31667330f729Sjoerg false);
31677330f729Sjoerg else
31687330f729Sjoerg Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
31697330f729Sjoerg None, false);
31707330f729Sjoerg return ExprError();
31717330f729Sjoerg }
31727330f729Sjoerg
31737330f729Sjoerg // Parse objc-selector
31747330f729Sjoerg SourceLocation Loc;
31757330f729Sjoerg IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
31767330f729Sjoerg
31777330f729Sjoerg SmallVector<IdentifierInfo *, 12> KeyIdents;
31787330f729Sjoerg SmallVector<SourceLocation, 12> KeyLocs;
31797330f729Sjoerg ExprVector KeyExprs;
31807330f729Sjoerg
31817330f729Sjoerg if (Tok.is(tok::colon)) {
31827330f729Sjoerg while (1) {
31837330f729Sjoerg // Each iteration parses a single keyword argument.
31847330f729Sjoerg KeyIdents.push_back(selIdent);
31857330f729Sjoerg KeyLocs.push_back(Loc);
31867330f729Sjoerg
31877330f729Sjoerg if (ExpectAndConsume(tok::colon)) {
31887330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
31897330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
31907330f729Sjoerg // the enclosing expression.
31917330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
31927330f729Sjoerg return ExprError();
31937330f729Sjoerg }
31947330f729Sjoerg
31957330f729Sjoerg /// Parse the expression after ':'
31967330f729Sjoerg
31977330f729Sjoerg if (Tok.is(tok::code_completion)) {
3198*e038c9c4Sjoerg cutOffParsing();
31997330f729Sjoerg if (SuperLoc.isValid())
32007330f729Sjoerg Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
32017330f729Sjoerg KeyIdents,
32027330f729Sjoerg /*AtArgumentExpression=*/true);
32037330f729Sjoerg else if (ReceiverType)
32047330f729Sjoerg Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
32057330f729Sjoerg KeyIdents,
32067330f729Sjoerg /*AtArgumentExpression=*/true);
32077330f729Sjoerg else
32087330f729Sjoerg Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
32097330f729Sjoerg KeyIdents,
32107330f729Sjoerg /*AtArgumentExpression=*/true);
32117330f729Sjoerg
32127330f729Sjoerg return ExprError();
32137330f729Sjoerg }
32147330f729Sjoerg
32157330f729Sjoerg ExprResult Expr;
32167330f729Sjoerg if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
32177330f729Sjoerg Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
32187330f729Sjoerg Expr = ParseBraceInitializer();
32197330f729Sjoerg } else
32207330f729Sjoerg Expr = ParseAssignmentExpression();
32217330f729Sjoerg
32227330f729Sjoerg ExprResult Res(Expr);
32237330f729Sjoerg if (Res.isInvalid()) {
32247330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
32257330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
32267330f729Sjoerg // the enclosing expression.
32277330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
32287330f729Sjoerg return Res;
32297330f729Sjoerg }
32307330f729Sjoerg
32317330f729Sjoerg // We have a valid expression.
32327330f729Sjoerg KeyExprs.push_back(Res.get());
32337330f729Sjoerg
32347330f729Sjoerg // Code completion after each argument.
32357330f729Sjoerg if (Tok.is(tok::code_completion)) {
3236*e038c9c4Sjoerg cutOffParsing();
32377330f729Sjoerg if (SuperLoc.isValid())
32387330f729Sjoerg Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
32397330f729Sjoerg KeyIdents,
32407330f729Sjoerg /*AtArgumentExpression=*/false);
32417330f729Sjoerg else if (ReceiverType)
32427330f729Sjoerg Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
32437330f729Sjoerg KeyIdents,
32447330f729Sjoerg /*AtArgumentExpression=*/false);
32457330f729Sjoerg else
32467330f729Sjoerg Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
32477330f729Sjoerg KeyIdents,
32487330f729Sjoerg /*AtArgumentExpression=*/false);
32497330f729Sjoerg return ExprError();
32507330f729Sjoerg }
32517330f729Sjoerg
32527330f729Sjoerg // Check for another keyword selector.
32537330f729Sjoerg selIdent = ParseObjCSelectorPiece(Loc);
32547330f729Sjoerg if (!selIdent && Tok.isNot(tok::colon))
32557330f729Sjoerg break;
32567330f729Sjoerg // We have a selector or a colon, continue parsing.
32577330f729Sjoerg }
32587330f729Sjoerg // Parse the, optional, argument list, comma separated.
32597330f729Sjoerg while (Tok.is(tok::comma)) {
32607330f729Sjoerg SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
32617330f729Sjoerg /// Parse the expression after ','
32627330f729Sjoerg ExprResult Res(ParseAssignmentExpression());
32637330f729Sjoerg if (Tok.is(tok::colon))
32647330f729Sjoerg Res = Actions.CorrectDelayedTyposInExpr(Res);
32657330f729Sjoerg if (Res.isInvalid()) {
32667330f729Sjoerg if (Tok.is(tok::colon)) {
32677330f729Sjoerg Diag(commaLoc, diag::note_extra_comma_message_arg) <<
32687330f729Sjoerg FixItHint::CreateRemoval(commaLoc);
32697330f729Sjoerg }
32707330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
32717330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
32727330f729Sjoerg // the enclosing expression.
32737330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
32747330f729Sjoerg return Res;
32757330f729Sjoerg }
32767330f729Sjoerg
32777330f729Sjoerg // We have a valid expression.
32787330f729Sjoerg KeyExprs.push_back(Res.get());
32797330f729Sjoerg }
32807330f729Sjoerg } else if (!selIdent) {
32817330f729Sjoerg Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
32827330f729Sjoerg
32837330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
32847330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
32857330f729Sjoerg // the enclosing expression.
32867330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
32877330f729Sjoerg return ExprError();
32887330f729Sjoerg }
32897330f729Sjoerg
32907330f729Sjoerg if (Tok.isNot(tok::r_square)) {
32917330f729Sjoerg Diag(Tok, diag::err_expected)
32927330f729Sjoerg << (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
32937330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
32947330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
32957330f729Sjoerg // the enclosing expression.
32967330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
32977330f729Sjoerg return ExprError();
32987330f729Sjoerg }
32997330f729Sjoerg
33007330f729Sjoerg SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
33017330f729Sjoerg
33027330f729Sjoerg unsigned nKeys = KeyIdents.size();
33037330f729Sjoerg if (nKeys == 0) {
33047330f729Sjoerg KeyIdents.push_back(selIdent);
33057330f729Sjoerg KeyLocs.push_back(Loc);
33067330f729Sjoerg }
33077330f729Sjoerg Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
33087330f729Sjoerg
33097330f729Sjoerg if (SuperLoc.isValid())
33107330f729Sjoerg return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
33117330f729Sjoerg LBracLoc, KeyLocs, RBracLoc, KeyExprs);
33127330f729Sjoerg else if (ReceiverType)
33137330f729Sjoerg return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
33147330f729Sjoerg LBracLoc, KeyLocs, RBracLoc, KeyExprs);
33157330f729Sjoerg return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
33167330f729Sjoerg LBracLoc, KeyLocs, RBracLoc, KeyExprs);
33177330f729Sjoerg }
33187330f729Sjoerg
ParseObjCStringLiteral(SourceLocation AtLoc)33197330f729Sjoerg ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
33207330f729Sjoerg ExprResult Res(ParseStringLiteralExpression());
33217330f729Sjoerg if (Res.isInvalid()) return Res;
33227330f729Sjoerg
33237330f729Sjoerg // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
33247330f729Sjoerg // expressions. At this point, we know that the only valid thing that starts
33257330f729Sjoerg // with '@' is an @"".
33267330f729Sjoerg SmallVector<SourceLocation, 4> AtLocs;
33277330f729Sjoerg ExprVector AtStrings;
33287330f729Sjoerg AtLocs.push_back(AtLoc);
33297330f729Sjoerg AtStrings.push_back(Res.get());
33307330f729Sjoerg
33317330f729Sjoerg while (Tok.is(tok::at)) {
33327330f729Sjoerg AtLocs.push_back(ConsumeToken()); // eat the @.
33337330f729Sjoerg
33347330f729Sjoerg // Invalid unless there is a string literal.
33357330f729Sjoerg if (!isTokenStringLiteral())
33367330f729Sjoerg return ExprError(Diag(Tok, diag::err_objc_concat_string));
33377330f729Sjoerg
33387330f729Sjoerg ExprResult Lit(ParseStringLiteralExpression());
33397330f729Sjoerg if (Lit.isInvalid())
33407330f729Sjoerg return Lit;
33417330f729Sjoerg
33427330f729Sjoerg AtStrings.push_back(Lit.get());
33437330f729Sjoerg }
33447330f729Sjoerg
33457330f729Sjoerg return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
33467330f729Sjoerg }
33477330f729Sjoerg
33487330f729Sjoerg /// ParseObjCBooleanLiteral -
33497330f729Sjoerg /// objc-scalar-literal : '@' boolean-keyword
33507330f729Sjoerg /// ;
33517330f729Sjoerg /// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
33527330f729Sjoerg /// ;
ParseObjCBooleanLiteral(SourceLocation AtLoc,bool ArgValue)33537330f729Sjoerg ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
33547330f729Sjoerg bool ArgValue) {
33557330f729Sjoerg SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
33567330f729Sjoerg return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
33577330f729Sjoerg }
33587330f729Sjoerg
33597330f729Sjoerg /// ParseObjCCharacterLiteral -
33607330f729Sjoerg /// objc-scalar-literal : '@' character-literal
33617330f729Sjoerg /// ;
ParseObjCCharacterLiteral(SourceLocation AtLoc)33627330f729Sjoerg ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
33637330f729Sjoerg ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
33647330f729Sjoerg if (Lit.isInvalid()) {
33657330f729Sjoerg return Lit;
33667330f729Sjoerg }
33677330f729Sjoerg ConsumeToken(); // Consume the literal token.
33687330f729Sjoerg return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
33697330f729Sjoerg }
33707330f729Sjoerg
33717330f729Sjoerg /// ParseObjCNumericLiteral -
33727330f729Sjoerg /// objc-scalar-literal : '@' scalar-literal
33737330f729Sjoerg /// ;
33747330f729Sjoerg /// scalar-literal : | numeric-constant /* any numeric constant. */
33757330f729Sjoerg /// ;
ParseObjCNumericLiteral(SourceLocation AtLoc)33767330f729Sjoerg ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
33777330f729Sjoerg ExprResult Lit(Actions.ActOnNumericConstant(Tok));
33787330f729Sjoerg if (Lit.isInvalid()) {
33797330f729Sjoerg return Lit;
33807330f729Sjoerg }
33817330f729Sjoerg ConsumeToken(); // Consume the literal token.
33827330f729Sjoerg return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
33837330f729Sjoerg }
33847330f729Sjoerg
33857330f729Sjoerg /// ParseObjCBoxedExpr -
33867330f729Sjoerg /// objc-box-expression:
33877330f729Sjoerg /// @( assignment-expression )
33887330f729Sjoerg ExprResult
ParseObjCBoxedExpr(SourceLocation AtLoc)33897330f729Sjoerg Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
33907330f729Sjoerg if (Tok.isNot(tok::l_paren))
33917330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
33927330f729Sjoerg
33937330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
33947330f729Sjoerg T.consumeOpen();
33957330f729Sjoerg ExprResult ValueExpr(ParseAssignmentExpression());
33967330f729Sjoerg if (T.consumeClose())
33977330f729Sjoerg return ExprError();
33987330f729Sjoerg
33997330f729Sjoerg if (ValueExpr.isInvalid())
34007330f729Sjoerg return ExprError();
34017330f729Sjoerg
34027330f729Sjoerg // Wrap the sub-expression in a parenthesized expression, to distinguish
34037330f729Sjoerg // a boxed expression from a literal.
34047330f729Sjoerg SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
34057330f729Sjoerg ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
34067330f729Sjoerg return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
34077330f729Sjoerg ValueExpr.get());
34087330f729Sjoerg }
34097330f729Sjoerg
ParseObjCArrayLiteral(SourceLocation AtLoc)34107330f729Sjoerg ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
34117330f729Sjoerg ExprVector ElementExprs; // array elements.
34127330f729Sjoerg ConsumeBracket(); // consume the l_square.
34137330f729Sjoerg
34147330f729Sjoerg bool HasInvalidEltExpr = false;
34157330f729Sjoerg while (Tok.isNot(tok::r_square)) {
34167330f729Sjoerg // Parse list of array element expressions (all must be id types).
34177330f729Sjoerg ExprResult Res(ParseAssignmentExpression());
34187330f729Sjoerg if (Res.isInvalid()) {
34197330f729Sjoerg // We must manually skip to a ']', otherwise the expression skipper will
34207330f729Sjoerg // stop at the ']' when it skips to the ';'. We want it to skip beyond
34217330f729Sjoerg // the enclosing expression.
34227330f729Sjoerg SkipUntil(tok::r_square, StopAtSemi);
34237330f729Sjoerg return Res;
34247330f729Sjoerg }
34257330f729Sjoerg
34267330f729Sjoerg Res = Actions.CorrectDelayedTyposInExpr(Res.get());
34277330f729Sjoerg if (Res.isInvalid())
34287330f729Sjoerg HasInvalidEltExpr = true;
34297330f729Sjoerg
34307330f729Sjoerg // Parse the ellipsis that indicates a pack expansion.
34317330f729Sjoerg if (Tok.is(tok::ellipsis))
34327330f729Sjoerg Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
34337330f729Sjoerg if (Res.isInvalid())
34347330f729Sjoerg HasInvalidEltExpr = true;
34357330f729Sjoerg
34367330f729Sjoerg ElementExprs.push_back(Res.get());
34377330f729Sjoerg
34387330f729Sjoerg if (Tok.is(tok::comma))
34397330f729Sjoerg ConsumeToken(); // Eat the ','.
34407330f729Sjoerg else if (Tok.isNot(tok::r_square))
34417330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
34427330f729Sjoerg << tok::comma);
34437330f729Sjoerg }
34447330f729Sjoerg SourceLocation EndLoc = ConsumeBracket(); // location of ']'
34457330f729Sjoerg
34467330f729Sjoerg if (HasInvalidEltExpr)
34477330f729Sjoerg return ExprError();
34487330f729Sjoerg
34497330f729Sjoerg MultiExprArg Args(ElementExprs);
34507330f729Sjoerg return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
34517330f729Sjoerg }
34527330f729Sjoerg
ParseObjCDictionaryLiteral(SourceLocation AtLoc)34537330f729Sjoerg ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
34547330f729Sjoerg SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
34557330f729Sjoerg ConsumeBrace(); // consume the l_square.
34567330f729Sjoerg bool HasInvalidEltExpr = false;
34577330f729Sjoerg while (Tok.isNot(tok::r_brace)) {
34587330f729Sjoerg // Parse the comma separated key : value expressions.
34597330f729Sjoerg ExprResult KeyExpr;
34607330f729Sjoerg {
34617330f729Sjoerg ColonProtectionRAIIObject X(*this);
34627330f729Sjoerg KeyExpr = ParseAssignmentExpression();
34637330f729Sjoerg if (KeyExpr.isInvalid()) {
34647330f729Sjoerg // We must manually skip to a '}', otherwise the expression skipper will
34657330f729Sjoerg // stop at the '}' when it skips to the ';'. We want it to skip beyond
34667330f729Sjoerg // the enclosing expression.
34677330f729Sjoerg SkipUntil(tok::r_brace, StopAtSemi);
34687330f729Sjoerg return KeyExpr;
34697330f729Sjoerg }
34707330f729Sjoerg }
34717330f729Sjoerg
34727330f729Sjoerg if (ExpectAndConsume(tok::colon)) {
34737330f729Sjoerg SkipUntil(tok::r_brace, StopAtSemi);
34747330f729Sjoerg return ExprError();
34757330f729Sjoerg }
34767330f729Sjoerg
34777330f729Sjoerg ExprResult ValueExpr(ParseAssignmentExpression());
34787330f729Sjoerg if (ValueExpr.isInvalid()) {
34797330f729Sjoerg // We must manually skip to a '}', otherwise the expression skipper will
34807330f729Sjoerg // stop at the '}' when it skips to the ';'. We want it to skip beyond
34817330f729Sjoerg // the enclosing expression.
34827330f729Sjoerg SkipUntil(tok::r_brace, StopAtSemi);
34837330f729Sjoerg return ValueExpr;
34847330f729Sjoerg }
34857330f729Sjoerg
34867330f729Sjoerg // Check the key and value for possible typos
34877330f729Sjoerg KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
34887330f729Sjoerg ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
34897330f729Sjoerg if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
34907330f729Sjoerg HasInvalidEltExpr = true;
34917330f729Sjoerg
34927330f729Sjoerg // Parse the ellipsis that designates this as a pack expansion. Do not
34937330f729Sjoerg // ActOnPackExpansion here, leave it to template instantiation time where
34947330f729Sjoerg // we can get better diagnostics.
34957330f729Sjoerg SourceLocation EllipsisLoc;
34967330f729Sjoerg if (getLangOpts().CPlusPlus)
34977330f729Sjoerg TryConsumeToken(tok::ellipsis, EllipsisLoc);
34987330f729Sjoerg
34997330f729Sjoerg // We have a valid expression. Collect it in a vector so we can
35007330f729Sjoerg // build the argument list.
35017330f729Sjoerg ObjCDictionaryElement Element = {
35027330f729Sjoerg KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
35037330f729Sjoerg };
35047330f729Sjoerg Elements.push_back(Element);
35057330f729Sjoerg
35067330f729Sjoerg if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
35077330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
35087330f729Sjoerg << tok::comma);
35097330f729Sjoerg }
35107330f729Sjoerg SourceLocation EndLoc = ConsumeBrace();
35117330f729Sjoerg
35127330f729Sjoerg if (HasInvalidEltExpr)
35137330f729Sjoerg return ExprError();
35147330f729Sjoerg
35157330f729Sjoerg // Create the ObjCDictionaryLiteral.
35167330f729Sjoerg return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
35177330f729Sjoerg Elements);
35187330f729Sjoerg }
35197330f729Sjoerg
35207330f729Sjoerg /// objc-encode-expression:
35217330f729Sjoerg /// \@encode ( type-name )
35227330f729Sjoerg ExprResult
ParseObjCEncodeExpression(SourceLocation AtLoc)35237330f729Sjoerg Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
35247330f729Sjoerg assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
35257330f729Sjoerg
35267330f729Sjoerg SourceLocation EncLoc = ConsumeToken();
35277330f729Sjoerg
35287330f729Sjoerg if (Tok.isNot(tok::l_paren))
35297330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
35307330f729Sjoerg
35317330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
35327330f729Sjoerg T.consumeOpen();
35337330f729Sjoerg
35347330f729Sjoerg TypeResult Ty = ParseTypeName();
35357330f729Sjoerg
35367330f729Sjoerg T.consumeClose();
35377330f729Sjoerg
35387330f729Sjoerg if (Ty.isInvalid())
35397330f729Sjoerg return ExprError();
35407330f729Sjoerg
35417330f729Sjoerg return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
35427330f729Sjoerg Ty.get(), T.getCloseLocation());
35437330f729Sjoerg }
35447330f729Sjoerg
35457330f729Sjoerg /// objc-protocol-expression
35467330f729Sjoerg /// \@protocol ( protocol-name )
35477330f729Sjoerg ExprResult
ParseObjCProtocolExpression(SourceLocation AtLoc)35487330f729Sjoerg Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
35497330f729Sjoerg SourceLocation ProtoLoc = ConsumeToken();
35507330f729Sjoerg
35517330f729Sjoerg if (Tok.isNot(tok::l_paren))
35527330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
35537330f729Sjoerg
35547330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
35557330f729Sjoerg T.consumeOpen();
35567330f729Sjoerg
35577330f729Sjoerg if (expectIdentifier())
35587330f729Sjoerg return ExprError();
35597330f729Sjoerg
35607330f729Sjoerg IdentifierInfo *protocolId = Tok.getIdentifierInfo();
35617330f729Sjoerg SourceLocation ProtoIdLoc = ConsumeToken();
35627330f729Sjoerg
35637330f729Sjoerg T.consumeClose();
35647330f729Sjoerg
35657330f729Sjoerg return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
35667330f729Sjoerg T.getOpenLocation(), ProtoIdLoc,
35677330f729Sjoerg T.getCloseLocation());
35687330f729Sjoerg }
35697330f729Sjoerg
35707330f729Sjoerg /// objc-selector-expression
35717330f729Sjoerg /// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
ParseObjCSelectorExpression(SourceLocation AtLoc)35727330f729Sjoerg ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
35737330f729Sjoerg SourceLocation SelectorLoc = ConsumeToken();
35747330f729Sjoerg
35757330f729Sjoerg if (Tok.isNot(tok::l_paren))
35767330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
35777330f729Sjoerg
35787330f729Sjoerg SmallVector<IdentifierInfo *, 12> KeyIdents;
35797330f729Sjoerg SourceLocation sLoc;
35807330f729Sjoerg
35817330f729Sjoerg BalancedDelimiterTracker T(*this, tok::l_paren);
35827330f729Sjoerg T.consumeOpen();
35837330f729Sjoerg bool HasOptionalParen = Tok.is(tok::l_paren);
35847330f729Sjoerg if (HasOptionalParen)
35857330f729Sjoerg ConsumeParen();
35867330f729Sjoerg
35877330f729Sjoerg if (Tok.is(tok::code_completion)) {
35887330f729Sjoerg cutOffParsing();
3589*e038c9c4Sjoerg Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
35907330f729Sjoerg return ExprError();
35917330f729Sjoerg }
35927330f729Sjoerg
35937330f729Sjoerg IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
35947330f729Sjoerg if (!SelIdent && // missing selector name.
35957330f729Sjoerg Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
35967330f729Sjoerg return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
35977330f729Sjoerg
35987330f729Sjoerg KeyIdents.push_back(SelIdent);
35997330f729Sjoerg
36007330f729Sjoerg unsigned nColons = 0;
36017330f729Sjoerg if (Tok.isNot(tok::r_paren)) {
36027330f729Sjoerg while (1) {
36037330f729Sjoerg if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
36047330f729Sjoerg ++nColons;
36057330f729Sjoerg KeyIdents.push_back(nullptr);
36067330f729Sjoerg } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
36077330f729Sjoerg return ExprError();
36087330f729Sjoerg ++nColons;
36097330f729Sjoerg
36107330f729Sjoerg if (Tok.is(tok::r_paren))
36117330f729Sjoerg break;
36127330f729Sjoerg
36137330f729Sjoerg if (Tok.is(tok::code_completion)) {
36147330f729Sjoerg cutOffParsing();
3615*e038c9c4Sjoerg Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
36167330f729Sjoerg return ExprError();
36177330f729Sjoerg }
36187330f729Sjoerg
36197330f729Sjoerg // Check for another keyword selector.
36207330f729Sjoerg SourceLocation Loc;
36217330f729Sjoerg SelIdent = ParseObjCSelectorPiece(Loc);
36227330f729Sjoerg KeyIdents.push_back(SelIdent);
36237330f729Sjoerg if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
36247330f729Sjoerg break;
36257330f729Sjoerg }
36267330f729Sjoerg }
36277330f729Sjoerg if (HasOptionalParen && Tok.is(tok::r_paren))
36287330f729Sjoerg ConsumeParen(); // ')'
36297330f729Sjoerg T.consumeClose();
36307330f729Sjoerg Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
36317330f729Sjoerg return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
36327330f729Sjoerg T.getOpenLocation(),
36337330f729Sjoerg T.getCloseLocation(),
36347330f729Sjoerg !HasOptionalParen);
36357330f729Sjoerg }
36367330f729Sjoerg
ParseLexedObjCMethodDefs(LexedMethod & LM,bool parseMethod)36377330f729Sjoerg void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
36387330f729Sjoerg // MCDecl might be null due to error in method or c-function prototype, etc.
36397330f729Sjoerg Decl *MCDecl = LM.D;
36407330f729Sjoerg bool skip = MCDecl &&
36417330f729Sjoerg ((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
36427330f729Sjoerg (!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
36437330f729Sjoerg if (skip)
36447330f729Sjoerg return;
36457330f729Sjoerg
36467330f729Sjoerg // Save the current token position.
36477330f729Sjoerg SourceLocation OrigLoc = Tok.getLocation();
36487330f729Sjoerg
36497330f729Sjoerg assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
36507330f729Sjoerg // Store an artificial EOF token to ensure that we don't run off the end of
36517330f729Sjoerg // the method's body when we come to parse it.
36527330f729Sjoerg Token Eof;
36537330f729Sjoerg Eof.startToken();
36547330f729Sjoerg Eof.setKind(tok::eof);
36557330f729Sjoerg Eof.setEofData(MCDecl);
36567330f729Sjoerg Eof.setLocation(OrigLoc);
36577330f729Sjoerg LM.Toks.push_back(Eof);
36587330f729Sjoerg // Append the current token at the end of the new token stream so that it
36597330f729Sjoerg // doesn't get lost.
36607330f729Sjoerg LM.Toks.push_back(Tok);
36617330f729Sjoerg PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);
36627330f729Sjoerg
36637330f729Sjoerg // Consume the previously pushed token.
36647330f729Sjoerg ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
36657330f729Sjoerg
36667330f729Sjoerg assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
36677330f729Sjoerg "Inline objective-c method not starting with '{' or 'try' or ':'");
36687330f729Sjoerg // Enter a scope for the method or c-function body.
36697330f729Sjoerg ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
36707330f729Sjoerg Scope::FnScope | Scope::DeclScope |
36717330f729Sjoerg Scope::CompoundStmtScope);
36727330f729Sjoerg
36737330f729Sjoerg // Tell the actions module that we have entered a method or c-function definition
36747330f729Sjoerg // with the specified Declarator for the method/function.
36757330f729Sjoerg if (parseMethod)
36767330f729Sjoerg Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
36777330f729Sjoerg else
36787330f729Sjoerg Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
36797330f729Sjoerg if (Tok.is(tok::kw_try))
36807330f729Sjoerg ParseFunctionTryBlock(MCDecl, BodyScope);
36817330f729Sjoerg else {
36827330f729Sjoerg if (Tok.is(tok::colon))
36837330f729Sjoerg ParseConstructorInitializer(MCDecl);
36847330f729Sjoerg else
36857330f729Sjoerg Actions.ActOnDefaultCtorInitializers(MCDecl);
36867330f729Sjoerg ParseFunctionStatementBody(MCDecl, BodyScope);
36877330f729Sjoerg }
36887330f729Sjoerg
36897330f729Sjoerg if (Tok.getLocation() != OrigLoc) {
36907330f729Sjoerg // Due to parsing error, we either went over the cached tokens or
36917330f729Sjoerg // there are still cached tokens left. If it's the latter case skip the
36927330f729Sjoerg // leftover tokens.
36937330f729Sjoerg // Since this is an uncommon situation that should be avoided, use the
36947330f729Sjoerg // expensive isBeforeInTranslationUnit call.
36957330f729Sjoerg if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
36967330f729Sjoerg OrigLoc))
36977330f729Sjoerg while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
36987330f729Sjoerg ConsumeAnyToken();
36997330f729Sjoerg }
37007330f729Sjoerg // Clean up the remaining EOF token.
37017330f729Sjoerg ConsumeAnyToken();
37027330f729Sjoerg }
3703