Path: blob/main/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp
35233 views
//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the Objective-C portions of the Parser interface.9//10//===----------------------------------------------------------------------===//1112#include "clang/AST/ASTContext.h"13#include "clang/AST/ODRDiagsEmitter.h"14#include "clang/AST/PrettyDeclStackTrace.h"15#include "clang/Basic/CharInfo.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/Parse/ParseDiagnostic.h"18#include "clang/Parse/Parser.h"19#include "clang/Parse/RAIIObjectsForParser.h"20#include "clang/Sema/DeclSpec.h"21#include "clang/Sema/Scope.h"22#include "clang/Sema/SemaCodeCompletion.h"23#include "clang/Sema/SemaObjC.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/StringExtras.h"2627using namespace clang;2829/// Skips attributes after an Objective-C @ directive. Emits a diagnostic.30void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {31ParsedAttributes attrs(AttrFactory);32if (Tok.is(tok::kw___attribute)) {33if (Kind == tok::objc_interface || Kind == tok::objc_protocol)34Diag(Tok, diag::err_objc_postfix_attribute_hint)35<< (Kind == tok::objc_protocol);36else37Diag(Tok, diag::err_objc_postfix_attribute);38ParseGNUAttributes(attrs);39}40}4142/// ParseObjCAtDirectives - Handle parts of the external-declaration production:43/// external-declaration: [C99 6.9]44/// [OBJC] objc-class-definition45/// [OBJC] objc-class-declaration46/// [OBJC] objc-alias-declaration47/// [OBJC] objc-protocol-definition48/// [OBJC] objc-method-definition49/// [OBJC] '@' 'end'50Parser::DeclGroupPtrTy51Parser::ParseObjCAtDirectives(ParsedAttributes &DeclAttrs,52ParsedAttributes &DeclSpecAttrs) {53DeclAttrs.takeAllFrom(DeclSpecAttrs);5455SourceLocation AtLoc = ConsumeToken(); // the "@"5657if (Tok.is(tok::code_completion)) {58cutOffParsing();59Actions.CodeCompletion().CodeCompleteObjCAtDirective(getCurScope());60return nullptr;61}6263switch (Tok.getObjCKeywordID()) {64case tok::objc_interface:65case tok::objc_protocol:66case tok::objc_implementation:67break;68default:69for (const auto &Attr : DeclAttrs) {70if (Attr.isGNUAttribute())71Diag(Tok.getLocation(), diag::err_objc_unexpected_attr);72}73}7475Decl *SingleDecl = nullptr;76switch (Tok.getObjCKeywordID()) {77case tok::objc_class:78return ParseObjCAtClassDeclaration(AtLoc);79case tok::objc_interface:80SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DeclAttrs);81break;82case tok::objc_protocol:83return ParseObjCAtProtocolDeclaration(AtLoc, DeclAttrs);84case tok::objc_implementation:85return ParseObjCAtImplementationDeclaration(AtLoc, DeclAttrs);86case tok::objc_end:87return ParseObjCAtEndDeclaration(AtLoc);88case tok::objc_compatibility_alias:89SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);90break;91case tok::objc_synthesize:92SingleDecl = ParseObjCPropertySynthesize(AtLoc);93break;94case tok::objc_dynamic:95SingleDecl = ParseObjCPropertyDynamic(AtLoc);96break;97case tok::objc_import:98if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {99Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;100SingleDecl = ParseModuleImport(AtLoc, IS);101break;102}103Diag(AtLoc, diag::err_atimport);104SkipUntil(tok::semi);105return Actions.ConvertDeclToDeclGroup(nullptr);106default:107Diag(AtLoc, diag::err_unexpected_at);108SkipUntil(tok::semi);109SingleDecl = nullptr;110break;111}112return Actions.ConvertDeclToDeclGroup(SingleDecl);113}114115/// Class to handle popping type parameters when leaving the scope.116class Parser::ObjCTypeParamListScope {117Sema &Actions;118Scope *S;119ObjCTypeParamList *Params;120121public:122ObjCTypeParamListScope(Sema &Actions, Scope *S)123: Actions(Actions), S(S), Params(nullptr) {}124125~ObjCTypeParamListScope() {126leave();127}128129void enter(ObjCTypeParamList *P) {130assert(!Params);131Params = P;132}133134void leave() {135if (Params)136Actions.ObjC().popObjCTypeParamList(S, Params);137Params = nullptr;138}139};140141///142/// objc-class-declaration:143/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'144///145/// objc-class-forward-decl:146/// identifier objc-type-parameter-list[opt]147///148Parser::DeclGroupPtrTy149Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {150ConsumeToken(); // the identifier "class"151SmallVector<IdentifierInfo *, 8> ClassNames;152SmallVector<SourceLocation, 8> ClassLocs;153SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;154155while (true) {156MaybeSkipAttributes(tok::objc_class);157if (Tok.is(tok::code_completion)) {158cutOffParsing();159Actions.CodeCompletion().CodeCompleteObjCClassForwardDecl(getCurScope());160return Actions.ConvertDeclToDeclGroup(nullptr);161}162if (expectIdentifier()) {163SkipUntil(tok::semi);164return Actions.ConvertDeclToDeclGroup(nullptr);165}166ClassNames.push_back(Tok.getIdentifierInfo());167ClassLocs.push_back(Tok.getLocation());168ConsumeToken();169170// Parse the optional objc-type-parameter-list.171ObjCTypeParamList *TypeParams = nullptr;172if (Tok.is(tok::less))173TypeParams = parseObjCTypeParamList();174ClassTypeParams.push_back(TypeParams);175if (!TryConsumeToken(tok::comma))176break;177}178179// Consume the ';'.180if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))181return Actions.ConvertDeclToDeclGroup(nullptr);182183return Actions.ObjC().ActOnForwardClassDeclaration(184atLoc, ClassNames.data(), ClassLocs.data(), ClassTypeParams,185ClassNames.size());186}187188void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)189{190SemaObjC::ObjCContainerKind ock = Actions.ObjC().getObjCContainerKind();191if (ock == SemaObjC::OCK_None)192return;193194Decl *Decl = Actions.ObjC().getObjCDeclContext();195if (CurParsedObjCImpl) {196CurParsedObjCImpl->finish(AtLoc);197} else {198Actions.ObjC().ActOnAtEnd(getCurScope(), AtLoc);199}200Diag(AtLoc, diag::err_objc_missing_end)201<< FixItHint::CreateInsertion(AtLoc, "@end\n");202if (Decl)203Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;204}205206///207/// objc-interface:208/// objc-class-interface-attributes[opt] objc-class-interface209/// objc-category-interface210///211/// objc-class-interface:212/// '@' 'interface' identifier objc-type-parameter-list[opt]213/// objc-superclass[opt] objc-protocol-refs[opt]214/// objc-class-instance-variables[opt]215/// objc-interface-decl-list216/// @end217///218/// objc-category-interface:219/// '@' 'interface' identifier objc-type-parameter-list[opt]220/// '(' identifier[opt] ')' objc-protocol-refs[opt]221/// objc-interface-decl-list222/// @end223///224/// objc-superclass:225/// ':' identifier objc-type-arguments[opt]226///227/// objc-class-interface-attributes:228/// __attribute__((visibility("default")))229/// __attribute__((visibility("hidden")))230/// __attribute__((deprecated))231/// __attribute__((unavailable))232/// __attribute__((objc_exception)) - used by NSException on 64-bit233/// __attribute__((objc_root_class))234///235Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,236ParsedAttributes &attrs) {237assert(Tok.isObjCAtKeyword(tok::objc_interface) &&238"ParseObjCAtInterfaceDeclaration(): Expected @interface");239CheckNestedObjCContexts(AtLoc);240ConsumeToken(); // the "interface" identifier241242// Code completion after '@interface'.243if (Tok.is(tok::code_completion)) {244cutOffParsing();245Actions.CodeCompletion().CodeCompleteObjCInterfaceDecl(getCurScope());246return nullptr;247}248249MaybeSkipAttributes(tok::objc_interface);250251if (expectIdentifier())252return nullptr; // missing class or category name.253254// We have a class or category name - consume it.255IdentifierInfo *nameId = Tok.getIdentifierInfo();256SourceLocation nameLoc = ConsumeToken();257258// Parse the objc-type-parameter-list or objc-protocol-refs. For the latter259// case, LAngleLoc will be valid and ProtocolIdents will capture the260// protocol references (that have not yet been resolved).261SourceLocation LAngleLoc, EndProtoLoc;262SmallVector<IdentifierLocPair, 8> ProtocolIdents;263ObjCTypeParamList *typeParameterList = nullptr;264ObjCTypeParamListScope typeParamScope(Actions, getCurScope());265if (Tok.is(tok::less))266typeParameterList = parseObjCTypeParamListOrProtocolRefs(267typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);268269if (Tok.is(tok::l_paren) &&270!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.271272BalancedDelimiterTracker T(*this, tok::l_paren);273T.consumeOpen();274275SourceLocation categoryLoc;276IdentifierInfo *categoryId = nullptr;277if (Tok.is(tok::code_completion)) {278cutOffParsing();279Actions.CodeCompletion().CodeCompleteObjCInterfaceCategory(280getCurScope(), nameId, nameLoc);281return nullptr;282}283284// For ObjC2, the category name is optional (not an error).285if (Tok.is(tok::identifier)) {286categoryId = Tok.getIdentifierInfo();287categoryLoc = ConsumeToken();288}289else if (!getLangOpts().ObjC) {290Diag(Tok, diag::err_expected)291<< tok::identifier; // missing category name.292return nullptr;293}294295T.consumeClose();296if (T.getCloseLocation().isInvalid())297return nullptr;298299// Next, we need to check for any protocol references.300assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");301SmallVector<Decl *, 8> ProtocolRefs;302SmallVector<SourceLocation, 8> ProtocolLocs;303if (Tok.is(tok::less) &&304ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,305LAngleLoc, EndProtoLoc,306/*consumeLastToken=*/true))307return nullptr;308309ObjCCategoryDecl *CategoryType = Actions.ObjC().ActOnStartCategoryInterface(310AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,311ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),312EndProtoLoc, attrs);313314if (Tok.is(tok::l_brace))315ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);316317ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);318319return CategoryType;320}321// Parse a class interface.322IdentifierInfo *superClassId = nullptr;323SourceLocation superClassLoc;324SourceLocation typeArgsLAngleLoc;325SmallVector<ParsedType, 4> typeArgs;326SourceLocation typeArgsRAngleLoc;327SmallVector<Decl *, 4> protocols;328SmallVector<SourceLocation, 4> protocolLocs;329if (Tok.is(tok::colon)) { // a super class is specified.330ConsumeToken();331332// Code completion of superclass names.333if (Tok.is(tok::code_completion)) {334cutOffParsing();335Actions.CodeCompletion().CodeCompleteObjCSuperclass(getCurScope(), nameId,336nameLoc);337return nullptr;338}339340if (expectIdentifier())341return nullptr; // missing super class name.342superClassId = Tok.getIdentifierInfo();343superClassLoc = ConsumeToken();344345// Type arguments for the superclass or protocol conformances.346if (Tok.is(tok::less)) {347parseObjCTypeArgsOrProtocolQualifiers(348nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,349protocols, protocolLocs, EndProtoLoc,350/*consumeLastToken=*/true,351/*warnOnIncompleteProtocols=*/true);352if (Tok.is(tok::eof))353return nullptr;354}355}356357// Next, we need to check for any protocol references.358if (LAngleLoc.isValid()) {359if (!ProtocolIdents.empty()) {360// We already parsed the protocols named when we thought we had a361// type parameter list. Translate them into actual protocol references.362for (const auto &pair : ProtocolIdents) {363protocolLocs.push_back(pair.second);364}365Actions.ObjC().FindProtocolDeclaration(/*WarnOnDeclarations=*/true,366/*ForObjCContainer=*/true,367ProtocolIdents, protocols);368}369} else if (protocols.empty() && Tok.is(tok::less) &&370ParseObjCProtocolReferences(protocols, protocolLocs, true, true,371LAngleLoc, EndProtoLoc,372/*consumeLastToken=*/true)) {373return nullptr;374}375376if (Tok.isNot(tok::less))377Actions.ObjC().ActOnTypedefedProtocols(protocols, protocolLocs,378superClassId, superClassLoc);379380SkipBodyInfo SkipBody;381ObjCInterfaceDecl *ClsType = Actions.ObjC().ActOnStartClassInterface(382getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,383superClassLoc, typeArgs,384SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),385protocols.size(), protocolLocs.data(), EndProtoLoc, attrs, &SkipBody);386387if (Tok.is(tok::l_brace))388ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);389390ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);391392if (SkipBody.CheckSameAsPrevious) {393auto *PreviousDef = cast<ObjCInterfaceDecl>(SkipBody.Previous);394if (Actions.ActOnDuplicateODRHashDefinition(ClsType, PreviousDef)) {395ClsType->mergeDuplicateDefinitionWithCommon(PreviousDef->getDefinition());396} else {397ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),398getPreprocessor().getLangOpts());399DiagsEmitter.diagnoseMismatch(PreviousDef, ClsType);400ClsType->setInvalidDecl();401}402}403404return ClsType;405}406407/// Add an attribute for a context-sensitive type nullability to the given408/// declarator.409static void addContextSensitiveTypeNullability(Parser &P,410Declarator &D,411NullabilityKind nullability,412SourceLocation nullabilityLoc,413bool &addedToDeclSpec) {414// Create the attribute.415auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {416return Pool.create(P.getNullabilityKeyword(nullability),417SourceRange(nullabilityLoc), nullptr, SourceLocation(),418nullptr, 0, ParsedAttr::Form::ContextSensitiveKeyword());419};420421if (D.getNumTypeObjects() > 0) {422// Add the attribute to the declarator chunk nearest the declarator.423D.getTypeObject(0).getAttrs().addAtEnd(424getNullabilityAttr(D.getAttributePool()));425} else if (!addedToDeclSpec) {426// Otherwise, just put it on the declaration specifiers (if one427// isn't there already).428D.getMutableDeclSpec().getAttributes().addAtEnd(429getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));430addedToDeclSpec = true;431}432}433434/// Parse an Objective-C type parameter list, if present, or capture435/// the locations of the protocol identifiers for a list of protocol436/// references.437///438/// objc-type-parameter-list:439/// '<' objc-type-parameter (',' objc-type-parameter)* '>'440///441/// objc-type-parameter:442/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]443///444/// objc-type-parameter-bound:445/// ':' type-name446///447/// objc-type-parameter-variance:448/// '__covariant'449/// '__contravariant'450///451/// \param lAngleLoc The location of the starting '<'.452///453/// \param protocolIdents Will capture the list of identifiers, if the454/// angle brackets contain a list of protocol references rather than a455/// type parameter list.456///457/// \param rAngleLoc The location of the ending '>'.458ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(459ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,460SmallVectorImpl<IdentifierLocPair> &protocolIdents,461SourceLocation &rAngleLoc, bool mayBeProtocolList) {462assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");463464// Within the type parameter list, don't treat '>' as an operator.465GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);466467// Local function to "flush" the protocol identifiers, turning them into468// type parameters.469SmallVector<Decl *, 4> typeParams;470auto makeProtocolIdentsIntoTypeParameters = [&]() {471unsigned index = 0;472for (const auto &pair : protocolIdents) {473DeclResult typeParam = Actions.ObjC().actOnObjCTypeParam(474getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),475index++, pair.first, pair.second, SourceLocation(), nullptr);476if (typeParam.isUsable())477typeParams.push_back(typeParam.get());478}479480protocolIdents.clear();481mayBeProtocolList = false;482};483484bool invalid = false;485lAngleLoc = ConsumeToken();486487do {488// Parse the variance, if any.489SourceLocation varianceLoc;490ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;491if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {492variance = Tok.is(tok::kw___covariant)493? ObjCTypeParamVariance::Covariant494: ObjCTypeParamVariance::Contravariant;495varianceLoc = ConsumeToken();496497// Once we've seen a variance specific , we know this is not a498// list of protocol references.499if (mayBeProtocolList) {500// Up until now, we have been queuing up parameters because they501// might be protocol references. Turn them into parameters now.502makeProtocolIdentsIntoTypeParameters();503}504}505506// Parse the identifier.507if (!Tok.is(tok::identifier)) {508// Code completion.509if (Tok.is(tok::code_completion)) {510// FIXME: If these aren't protocol references, we'll need different511// completions.512cutOffParsing();513Actions.CodeCompletion().CodeCompleteObjCProtocolReferences(514protocolIdents);515516// FIXME: Better recovery here?.517return nullptr;518}519520Diag(Tok, diag::err_objc_expected_type_parameter);521invalid = true;522break;523}524525IdentifierInfo *paramName = Tok.getIdentifierInfo();526SourceLocation paramLoc = ConsumeToken();527528// If there is a bound, parse it.529SourceLocation colonLoc;530TypeResult boundType;531if (TryConsumeToken(tok::colon, colonLoc)) {532// Once we've seen a bound, we know this is not a list of protocol533// references.534if (mayBeProtocolList) {535// Up until now, we have been queuing up parameters because they536// might be protocol references. Turn them into parameters now.537makeProtocolIdentsIntoTypeParameters();538}539540// type-name541boundType = ParseTypeName();542if (boundType.isInvalid())543invalid = true;544} else if (mayBeProtocolList) {545// If this could still be a protocol list, just capture the identifier.546// We don't want to turn it into a parameter.547protocolIdents.push_back(std::make_pair(paramName, paramLoc));548continue;549}550551// Create the type parameter.552DeclResult typeParam = Actions.ObjC().actOnObjCTypeParam(553getCurScope(), variance, varianceLoc, typeParams.size(), paramName,554paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);555if (typeParam.isUsable())556typeParams.push_back(typeParam.get());557} while (TryConsumeToken(tok::comma));558559// Parse the '>'.560if (invalid) {561SkipUntil(tok::greater, tok::at, StopBeforeMatch);562if (Tok.is(tok::greater))563ConsumeToken();564} else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc,565/*ConsumeLastToken=*/true,566/*ObjCGenericList=*/true)) {567SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,568tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,569tok::comma, tok::semi },570StopBeforeMatch);571if (Tok.is(tok::greater))572ConsumeToken();573}574575if (mayBeProtocolList) {576// A type parameter list must be followed by either a ':' (indicating the577// presence of a superclass) or a '(' (indicating that this is a category578// or extension). This disambiguates between an objc-type-parameter-list579// and a objc-protocol-refs.580if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {581// Returning null indicates that we don't have a type parameter list.582// The results the caller needs to handle the protocol references are583// captured in the reference parameters already.584return nullptr;585}586587// We have a type parameter list that looks like a list of protocol588// references. Turn that parameter list into type parameters.589makeProtocolIdentsIntoTypeParameters();590}591592// Form the type parameter list and enter its scope.593ObjCTypeParamList *list = Actions.ObjC().actOnObjCTypeParamList(594getCurScope(), lAngleLoc, typeParams, rAngleLoc);595Scope.enter(list);596597// Clear out the angle locations; they're used by the caller to indicate598// whether there are any protocol references.599lAngleLoc = SourceLocation();600rAngleLoc = SourceLocation();601return invalid ? nullptr : list;602}603604/// Parse an objc-type-parameter-list.605ObjCTypeParamList *Parser::parseObjCTypeParamList() {606SourceLocation lAngleLoc;607SmallVector<IdentifierLocPair, 1> protocolIdents;608SourceLocation rAngleLoc;609610ObjCTypeParamListScope Scope(Actions, getCurScope());611return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,612rAngleLoc,613/*mayBeProtocolList=*/false);614}615616static bool isTopLevelObjCKeyword(tok::ObjCKeywordKind DirectiveKind) {617switch (DirectiveKind) {618case tok::objc_class:619case tok::objc_compatibility_alias:620case tok::objc_interface:621case tok::objc_implementation:622case tok::objc_protocol:623return true;624default:625return false;626}627}628629/// objc-interface-decl-list:630/// empty631/// objc-interface-decl-list objc-property-decl [OBJC2]632/// objc-interface-decl-list objc-method-requirement [OBJC2]633/// objc-interface-decl-list objc-method-proto ';'634/// objc-interface-decl-list declaration635/// objc-interface-decl-list ';'636///637/// objc-method-requirement: [OBJC2]638/// @required639/// @optional640///641void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,642Decl *CDecl) {643SmallVector<Decl *, 32> allMethods;644SmallVector<DeclGroupPtrTy, 8> allTUVariables;645tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;646647SourceRange AtEnd;648649while (true) {650// If this is a method prototype, parse it.651if (Tok.isOneOf(tok::minus, tok::plus)) {652if (Decl *methodPrototype =653ParseObjCMethodPrototype(MethodImplKind, false))654allMethods.push_back(methodPrototype);655// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for656// method definitions.657if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {658// We didn't find a semi and we error'ed out. Skip until a ';' or '@'.659SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);660if (Tok.is(tok::semi))661ConsumeToken();662}663continue;664}665if (Tok.is(tok::l_paren)) {666Diag(Tok, diag::err_expected_minus_or_plus);667ParseObjCMethodDecl(Tok.getLocation(),668tok::minus,669MethodImplKind, false);670continue;671}672// Ignore excess semicolons.673if (Tok.is(tok::semi)) {674// FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,675// to make -Wextra-semi diagnose them.676ConsumeToken();677continue;678}679680// If we got to the end of the file, exit the loop.681if (isEofOrEom())682break;683684// Code completion within an Objective-C interface.685if (Tok.is(tok::code_completion)) {686cutOffParsing();687Actions.CodeCompletion().CodeCompleteOrdinaryName(688getCurScope(), CurParsedObjCImpl689? SemaCodeCompletion::PCC_ObjCImplementation690: SemaCodeCompletion::PCC_ObjCInterface);691return;692}693694// If we don't have an @ directive, parse it as a function definition.695if (Tok.isNot(tok::at)) {696// The code below does not consume '}'s because it is afraid of eating the697// end of a namespace. Because of the way this code is structured, an698// erroneous r_brace would cause an infinite loop if not handled here.699if (Tok.is(tok::r_brace))700break;701702ParsedAttributes EmptyDeclAttrs(AttrFactory);703ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);704705// Since we call ParseDeclarationOrFunctionDefinition() instead of706// ParseExternalDeclaration() below (so that this doesn't parse nested707// @interfaces), this needs to duplicate some code from the latter.708if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {709SourceLocation DeclEnd;710ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);711allTUVariables.push_back(ParseDeclaration(DeclaratorContext::File,712DeclEnd, EmptyDeclAttrs,713EmptyDeclSpecAttrs));714continue;715}716717allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(718EmptyDeclAttrs, EmptyDeclSpecAttrs));719continue;720}721722// Otherwise, we have an @ directive, peak at the next token723SourceLocation AtLoc = Tok.getLocation();724const auto &NextTok = NextToken();725if (NextTok.is(tok::code_completion)) {726cutOffParsing();727Actions.CodeCompletion().CodeCompleteObjCAtDirective(getCurScope());728return;729}730731tok::ObjCKeywordKind DirectiveKind = NextTok.getObjCKeywordID();732if (DirectiveKind == tok::objc_end) { // @end -> terminate list733ConsumeToken(); // the "@"734AtEnd.setBegin(AtLoc);735AtEnd.setEnd(Tok.getLocation());736break;737} else if (DirectiveKind == tok::objc_not_keyword) {738Diag(NextTok, diag::err_objc_unknown_at);739SkipUntil(tok::semi);740continue;741}742743// If we see something like '@interface' that's only allowed at the top744// level, bail out as if we saw an '@end'. We'll diagnose this below.745if (isTopLevelObjCKeyword(DirectiveKind))746break;747748// Otherwise parse it as part of the current declaration. Eat "@identifier".749ConsumeToken();750ConsumeToken();751752switch (DirectiveKind) {753default:754// FIXME: If someone forgets an @end on a protocol, this loop will755// continue to eat up tons of stuff and spew lots of nonsense errors. It756// would probably be better to bail out if we saw an @class or @interface757// or something like that.758Diag(AtLoc, diag::err_objc_illegal_interface_qual);759// Skip until we see an '@' or '}' or ';'.760SkipUntil(tok::r_brace, tok::at, StopAtSemi);761break;762763case tok::objc_required:764case tok::objc_optional:765// This is only valid on protocols.766if (contextKey != tok::objc_protocol)767Diag(AtLoc, diag::err_objc_directive_only_in_protocol);768else769MethodImplKind = DirectiveKind;770break;771772case tok::objc_property:773ObjCDeclSpec OCDS;774SourceLocation LParenLoc;775// Parse property attribute list, if any.776if (Tok.is(tok::l_paren)) {777LParenLoc = Tok.getLocation();778ParseObjCPropertyAttribute(OCDS);779}780781bool addedToDeclSpec = false;782auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) -> Decl * {783if (FD.D.getIdentifier() == nullptr) {784Diag(AtLoc, diag::err_objc_property_requires_field_name)785<< FD.D.getSourceRange();786return nullptr;787}788if (FD.BitfieldSize) {789Diag(AtLoc, diag::err_objc_property_bitfield)790<< FD.D.getSourceRange();791return nullptr;792}793794// Map a nullability property attribute to a context-sensitive keyword795// attribute.796if (OCDS.getPropertyAttributes() &797ObjCPropertyAttribute::kind_nullability)798addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),799OCDS.getNullabilityLoc(),800addedToDeclSpec);801802// Install the property declarator into interfaceDecl.803const IdentifierInfo *SelName =804OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();805806Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);807const IdentifierInfo *SetterName = OCDS.getSetterName();808Selector SetterSel;809if (SetterName)810SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);811else812SetterSel = SelectorTable::constructSetterSelector(813PP.getIdentifierTable(), PP.getSelectorTable(),814FD.D.getIdentifier());815Decl *Property = Actions.ObjC().ActOnProperty(816getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,817MethodImplKind);818819FD.complete(Property);820return Property;821};822823// Parse all the comma separated declarators.824ParsingDeclSpec DS(*this);825ParseStructDeclaration(DS, ObjCPropertyCallback);826827ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);828break;829}830}831832// We break out of the big loop in 3 cases: when we see @end or when we see833// top-level ObjC keyword or EOF. In the former case, eat the @end. In the834// later cases, emit an error.835if (Tok.isObjCAtKeyword(tok::objc_end)) {836ConsumeToken(); // the "end" identifier837} else {838Diag(Tok, diag::err_objc_missing_end)839<< FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");840Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)841<< (int)Actions.ObjC().getObjCContainerKind();842AtEnd.setBegin(Tok.getLocation());843AtEnd.setEnd(Tok.getLocation());844}845846// Insert collected methods declarations into the @interface object.847// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.848Actions.ObjC().ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);849}850851/// Diagnose redundant or conflicting nullability information.852static void diagnoseRedundantPropertyNullability(Parser &P,853ObjCDeclSpec &DS,854NullabilityKind nullability,855SourceLocation nullabilityLoc){856if (DS.getNullability() == nullability) {857P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)858<< DiagNullabilityKind(nullability, true)859<< SourceRange(DS.getNullabilityLoc());860return;861}862863P.Diag(nullabilityLoc, diag::err_nullability_conflicting)864<< DiagNullabilityKind(nullability, true)865<< DiagNullabilityKind(DS.getNullability(), true)866<< SourceRange(DS.getNullabilityLoc());867}868869/// Parse property attribute declarations.870///871/// property-attr-decl: '(' property-attrlist ')'872/// property-attrlist:873/// property-attribute874/// property-attrlist ',' property-attribute875/// property-attribute:876/// getter '=' identifier877/// setter '=' identifier ':'878/// direct879/// readonly880/// readwrite881/// assign882/// retain883/// copy884/// nonatomic885/// atomic886/// strong887/// weak888/// unsafe_unretained889/// nonnull890/// nullable891/// null_unspecified892/// null_resettable893/// class894///895void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {896assert(Tok.getKind() == tok::l_paren);897BalancedDelimiterTracker T(*this, tok::l_paren);898T.consumeOpen();899900while (true) {901if (Tok.is(tok::code_completion)) {902cutOffParsing();903Actions.CodeCompletion().CodeCompleteObjCPropertyFlags(getCurScope(), DS);904return;905}906const IdentifierInfo *II = Tok.getIdentifierInfo();907908// If this is not an identifier at all, bail out early.909if (!II) {910T.consumeClose();911return;912}913914SourceLocation AttrName = ConsumeToken(); // consume last attribute name915916if (II->isStr("readonly"))917DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);918else if (II->isStr("assign"))919DS.setPropertyAttributes(ObjCPropertyAttribute::kind_assign);920else if (II->isStr("unsafe_unretained"))921DS.setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);922else if (II->isStr("readwrite"))923DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);924else if (II->isStr("retain"))925DS.setPropertyAttributes(ObjCPropertyAttribute::kind_retain);926else if (II->isStr("strong"))927DS.setPropertyAttributes(ObjCPropertyAttribute::kind_strong);928else if (II->isStr("copy"))929DS.setPropertyAttributes(ObjCPropertyAttribute::kind_copy);930else if (II->isStr("nonatomic"))931DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);932else if (II->isStr("atomic"))933DS.setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);934else if (II->isStr("weak"))935DS.setPropertyAttributes(ObjCPropertyAttribute::kind_weak);936else if (II->isStr("getter") || II->isStr("setter")) {937bool IsSetter = II->getNameStart()[0] == 's';938939// getter/setter require extra treatment.940unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :941diag::err_objc_expected_equal_for_getter;942943if (ExpectAndConsume(tok::equal, DiagID)) {944SkipUntil(tok::r_paren, StopAtSemi);945return;946}947948if (Tok.is(tok::code_completion)) {949cutOffParsing();950if (IsSetter)951Actions.CodeCompletion().CodeCompleteObjCPropertySetter(952getCurScope());953else954Actions.CodeCompletion().CodeCompleteObjCPropertyGetter(955getCurScope());956return;957}958959SourceLocation SelLoc;960IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);961962if (!SelIdent) {963Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)964<< IsSetter;965SkipUntil(tok::r_paren, StopAtSemi);966return;967}968969if (IsSetter) {970DS.setPropertyAttributes(ObjCPropertyAttribute::kind_setter);971DS.setSetterName(SelIdent, SelLoc);972973if (ExpectAndConsume(tok::colon,974diag::err_expected_colon_after_setter_name)) {975SkipUntil(tok::r_paren, StopAtSemi);976return;977}978} else {979DS.setPropertyAttributes(ObjCPropertyAttribute::kind_getter);980DS.setGetterName(SelIdent, SelLoc);981}982} else if (II->isStr("nonnull")) {983if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)984diagnoseRedundantPropertyNullability(*this, DS,985NullabilityKind::NonNull,986Tok.getLocation());987DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);988DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);989} else if (II->isStr("nullable")) {990if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)991diagnoseRedundantPropertyNullability(*this, DS,992NullabilityKind::Nullable,993Tok.getLocation());994DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);995DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);996} else if (II->isStr("null_unspecified")) {997if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)998diagnoseRedundantPropertyNullability(*this, DS,999NullabilityKind::Unspecified,1000Tok.getLocation());1001DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);1002DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);1003} else if (II->isStr("null_resettable")) {1004if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)1005diagnoseRedundantPropertyNullability(*this, DS,1006NullabilityKind::Unspecified,1007Tok.getLocation());1008DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);1009DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);10101011// Also set the null_resettable bit.1012DS.setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);1013} else if (II->isStr("class")) {1014DS.setPropertyAttributes(ObjCPropertyAttribute::kind_class);1015} else if (II->isStr("direct")) {1016DS.setPropertyAttributes(ObjCPropertyAttribute::kind_direct);1017} else {1018Diag(AttrName, diag::err_objc_expected_property_attr) << II;1019SkipUntil(tok::r_paren, StopAtSemi);1020return;1021}10221023if (Tok.isNot(tok::comma))1024break;10251026ConsumeToken();1027}10281029T.consumeClose();1030}10311032/// objc-method-proto:1033/// objc-instance-method objc-method-decl objc-method-attributes[opt]1034/// objc-class-method objc-method-decl objc-method-attributes[opt]1035///1036/// objc-instance-method: '-'1037/// objc-class-method: '+'1038///1039/// objc-method-attributes: [OBJC2]1040/// __attribute__((deprecated))1041///1042Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,1043bool MethodDefinition) {1044assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");10451046tok::TokenKind methodType = Tok.getKind();1047SourceLocation mLoc = ConsumeToken();1048Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,1049MethodDefinition);1050// Since this rule is used for both method declarations and definitions,1051// the caller is (optionally) responsible for consuming the ';'.1052return MDecl;1053}10541055/// objc-selector:1056/// identifier1057/// one of1058/// enum struct union if else while do for switch case default1059/// break continue return goto asm sizeof typeof __alignof1060/// unsigned long const short volatile signed restrict _Complex1061/// in out inout bycopy byref oneway int char float double void _Bool1062///1063IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {10641065switch (Tok.getKind()) {1066default:1067return nullptr;1068case tok::colon:1069// Empty selector piece uses the location of the ':'.1070SelectorLoc = Tok.getLocation();1071return nullptr;1072case tok::ampamp:1073case tok::ampequal:1074case tok::amp:1075case tok::pipe:1076case tok::tilde:1077case tok::exclaim:1078case tok::exclaimequal:1079case tok::pipepipe:1080case tok::pipeequal:1081case tok::caret:1082case tok::caretequal: {1083std::string ThisTok(PP.getSpelling(Tok));1084if (isLetter(ThisTok[0])) {1085IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);1086Tok.setKind(tok::identifier);1087SelectorLoc = ConsumeToken();1088return II;1089}1090return nullptr;1091}10921093case tok::identifier:1094case tok::kw_asm:1095case tok::kw_auto:1096case tok::kw_bool:1097case tok::kw_break:1098case tok::kw_case:1099case tok::kw_catch:1100case tok::kw_char:1101case tok::kw_class:1102case tok::kw_const:1103case tok::kw_const_cast:1104case tok::kw_continue:1105case tok::kw_default:1106case tok::kw_delete:1107case tok::kw_do:1108case tok::kw_double:1109case tok::kw_dynamic_cast:1110case tok::kw_else:1111case tok::kw_enum:1112case tok::kw_explicit:1113case tok::kw_export:1114case tok::kw_extern:1115case tok::kw_false:1116case tok::kw_float:1117case tok::kw_for:1118case tok::kw_friend:1119case tok::kw_goto:1120case tok::kw_if:1121case tok::kw_inline:1122case tok::kw_int:1123case tok::kw_long:1124case tok::kw_mutable:1125case tok::kw_namespace:1126case tok::kw_new:1127case tok::kw_operator:1128case tok::kw_private:1129case tok::kw_protected:1130case tok::kw_public:1131case tok::kw_register:1132case tok::kw_reinterpret_cast:1133case tok::kw_restrict:1134case tok::kw_return:1135case tok::kw_short:1136case tok::kw_signed:1137case tok::kw_sizeof:1138case tok::kw_static:1139case tok::kw_static_cast:1140case tok::kw_struct:1141case tok::kw_switch:1142case tok::kw_template:1143case tok::kw_this:1144case tok::kw_throw:1145case tok::kw_true:1146case tok::kw_try:1147case tok::kw_typedef:1148case tok::kw_typeid:1149case tok::kw_typename:1150case tok::kw_typeof:1151case tok::kw_union:1152case tok::kw_unsigned:1153case tok::kw_using:1154case tok::kw_virtual:1155case tok::kw_void:1156case tok::kw_volatile:1157case tok::kw_wchar_t:1158case tok::kw_while:1159case tok::kw__Bool:1160case tok::kw__Complex:1161case tok::kw___alignof:1162case tok::kw___auto_type:1163IdentifierInfo *II = Tok.getIdentifierInfo();1164SelectorLoc = ConsumeToken();1165return II;1166}1167}11681169/// objc-for-collection-in: 'in'1170///1171bool Parser::isTokIdentifier_in() const {1172// FIXME: May have to do additional look-ahead to only allow for1173// valid tokens following an 'in'; such as an identifier, unary operators,1174// '[' etc.1175return (getLangOpts().ObjC && Tok.is(tok::identifier) &&1176Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);1177}11781179/// ParseObjCTypeQualifierList - This routine parses the objective-c's type1180/// qualifier list and builds their bitmask representation in the input1181/// argument.1182///1183/// objc-type-qualifiers:1184/// objc-type-qualifier1185/// objc-type-qualifiers objc-type-qualifier1186///1187/// objc-type-qualifier:1188/// 'in'1189/// 'out'1190/// 'inout'1191/// 'oneway'1192/// 'bycopy'1193/// 'byref'1194/// 'nonnull'1195/// 'nullable'1196/// 'null_unspecified'1197///1198void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,1199DeclaratorContext Context) {1200assert(Context == DeclaratorContext::ObjCParameter ||1201Context == DeclaratorContext::ObjCResult);12021203while (true) {1204if (Tok.is(tok::code_completion)) {1205cutOffParsing();1206Actions.CodeCompletion().CodeCompleteObjCPassingType(1207getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);1208return;1209}12101211if (Tok.isNot(tok::identifier))1212return;12131214const IdentifierInfo *II = Tok.getIdentifierInfo();1215for (unsigned i = 0; i != objc_NumQuals; ++i) {1216if (II != ObjCTypeQuals[i] ||1217NextToken().is(tok::less) ||1218NextToken().is(tok::coloncolon))1219continue;12201221ObjCDeclSpec::ObjCDeclQualifier Qual;1222NullabilityKind Nullability;1223switch (i) {1224default: llvm_unreachable("Unknown decl qualifier");1225case objc_in: Qual = ObjCDeclSpec::DQ_In; break;1226case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;1227case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;1228case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;1229case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;1230case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;12311232case objc_nonnull:1233Qual = ObjCDeclSpec::DQ_CSNullability;1234Nullability = NullabilityKind::NonNull;1235break;12361237case objc_nullable:1238Qual = ObjCDeclSpec::DQ_CSNullability;1239Nullability = NullabilityKind::Nullable;1240break;12411242case objc_null_unspecified:1243Qual = ObjCDeclSpec::DQ_CSNullability;1244Nullability = NullabilityKind::Unspecified;1245break;1246}12471248// FIXME: Diagnose redundant specifiers.1249DS.setObjCDeclQualifier(Qual);1250if (Qual == ObjCDeclSpec::DQ_CSNullability)1251DS.setNullability(Tok.getLocation(), Nullability);12521253ConsumeToken();1254II = nullptr;1255break;1256}12571258// If this wasn't a recognized qualifier, bail out.1259if (II) return;1260}1261}12621263/// Take all the decl attributes out of the given list and add1264/// them to the given attribute set.1265static void takeDeclAttributes(ParsedAttributesView &attrs,1266ParsedAttributesView &from) {1267for (auto &AL : llvm::reverse(from)) {1268if (!AL.isUsedAsTypeAttr()) {1269from.remove(&AL);1270attrs.addAtEnd(&AL);1271}1272}1273}12741275/// takeDeclAttributes - Take all the decl attributes from the given1276/// declarator and add them to the given list.1277static void takeDeclAttributes(ParsedAttributes &attrs,1278Declarator &D) {1279// This gets called only from Parser::ParseObjCTypeName(), and that should1280// never add declaration attributes to the Declarator.1281assert(D.getDeclarationAttributes().empty());12821283// First, take ownership of all attributes.1284attrs.getPool().takeAllFrom(D.getAttributePool());1285attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());12861287// Now actually move the attributes over.1288takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());1289takeDeclAttributes(attrs, D.getAttributes());1290for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)1291takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());1292}12931294/// objc-type-name:1295/// '(' objc-type-qualifiers[opt] type-name ')'1296/// '(' objc-type-qualifiers[opt] ')'1297///1298ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,1299DeclaratorContext context,1300ParsedAttributes *paramAttrs) {1301assert(context == DeclaratorContext::ObjCParameter ||1302context == DeclaratorContext::ObjCResult);1303assert((paramAttrs != nullptr) ==1304(context == DeclaratorContext::ObjCParameter));13051306assert(Tok.is(tok::l_paren) && "expected (");13071308BalancedDelimiterTracker T(*this, tok::l_paren);1309T.consumeOpen();13101311ObjCDeclContextSwitch ObjCDC(*this);13121313// Parse type qualifiers, in, inout, etc.1314ParseObjCTypeQualifierList(DS, context);1315SourceLocation TypeStartLoc = Tok.getLocation();13161317ParsedType Ty;1318if (isTypeSpecifierQualifier() || isObjCInstancetype()) {1319// Parse an abstract declarator.1320DeclSpec declSpec(AttrFactory);1321declSpec.setObjCQualifiers(&DS);1322DeclSpecContext dsContext = DeclSpecContext::DSC_normal;1323if (context == DeclaratorContext::ObjCResult)1324dsContext = DeclSpecContext::DSC_objc_method_result;1325ParseSpecifierQualifierList(declSpec, AS_none, dsContext);1326Declarator declarator(declSpec, ParsedAttributesView::none(), context);1327ParseDeclarator(declarator);13281329// If that's not invalid, extract a type.1330if (!declarator.isInvalidType()) {1331// Map a nullability specifier to a context-sensitive keyword attribute.1332bool addedToDeclSpec = false;1333if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)1334addContextSensitiveTypeNullability(*this, declarator,1335DS.getNullability(),1336DS.getNullabilityLoc(),1337addedToDeclSpec);13381339TypeResult type = Actions.ActOnTypeName(declarator);1340if (!type.isInvalid())1341Ty = type.get();13421343// If we're parsing a parameter, steal all the decl attributes1344// and add them to the decl spec.1345if (context == DeclaratorContext::ObjCParameter)1346takeDeclAttributes(*paramAttrs, declarator);1347}1348}13491350if (Tok.is(tok::r_paren))1351T.consumeClose();1352else if (Tok.getLocation() == TypeStartLoc) {1353// If we didn't eat any tokens, then this isn't a type.1354Diag(Tok, diag::err_expected_type);1355SkipUntil(tok::r_paren, StopAtSemi);1356} else {1357// Otherwise, we found *something*, but didn't get a ')' in the right1358// place. Emit an error then return what we have as the type.1359T.consumeClose();1360}1361return Ty;1362}13631364/// objc-method-decl:1365/// objc-selector1366/// objc-keyword-selector objc-parmlist[opt]1367/// objc-type-name objc-selector1368/// objc-type-name objc-keyword-selector objc-parmlist[opt]1369///1370/// objc-keyword-selector:1371/// objc-keyword-decl1372/// objc-keyword-selector objc-keyword-decl1373///1374/// objc-keyword-decl:1375/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier1376/// objc-selector ':' objc-keyword-attributes[opt] identifier1377/// ':' objc-type-name objc-keyword-attributes[opt] identifier1378/// ':' objc-keyword-attributes[opt] identifier1379///1380/// objc-parmlist:1381/// objc-parms objc-ellipsis[opt]1382///1383/// objc-parms:1384/// objc-parms , parameter-declaration1385///1386/// objc-ellipsis:1387/// , ...1388///1389/// objc-keyword-attributes: [OBJC2]1390/// __attribute__((unused))1391///1392Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,1393tok::TokenKind mType,1394tok::ObjCKeywordKind MethodImplKind,1395bool MethodDefinition) {1396ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);13971398if (Tok.is(tok::code_completion)) {1399cutOffParsing();1400Actions.CodeCompletion().CodeCompleteObjCMethodDecl(getCurScope(),1401mType == tok::minus,1402/*ReturnType=*/nullptr);1403return nullptr;1404}14051406// Parse the return type if present.1407ParsedType ReturnType;1408ObjCDeclSpec DSRet;1409if (Tok.is(tok::l_paren))1410ReturnType =1411ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult, nullptr);14121413// If attributes exist before the method, parse them.1414ParsedAttributes methodAttrs(AttrFactory);1415MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),1416methodAttrs);14171418if (Tok.is(tok::code_completion)) {1419cutOffParsing();1420Actions.CodeCompletion().CodeCompleteObjCMethodDecl(1421getCurScope(), mType == tok::minus, ReturnType);1422return nullptr;1423}14241425// Now parse the selector.1426SourceLocation selLoc;1427IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);14281429// An unnamed colon is valid.1430if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.1431Diag(Tok, diag::err_expected_selector_for_method)1432<< SourceRange(mLoc, Tok.getLocation());1433// Skip until we get a ; or @.1434SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);1435return nullptr;1436}14371438SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;1439if (Tok.isNot(tok::colon)) {1440// If attributes exist after the method, parse them.1441MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),1442methodAttrs);14431444Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);1445Decl *Result = Actions.ObjC().ActOnMethodDeclaration(1446getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,1447selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,1448MethodImplKind, false, MethodDefinition);1449PD.complete(Result);1450return Result;1451}14521453SmallVector<const IdentifierInfo *, 12> KeyIdents;1454SmallVector<SourceLocation, 12> KeyLocs;1455SmallVector<SemaObjC::ObjCArgInfo, 12> ArgInfos;1456ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |1457Scope::FunctionDeclarationScope | Scope::DeclScope);14581459AttributePool allParamAttrs(AttrFactory);1460while (true) {1461ParsedAttributes paramAttrs(AttrFactory);1462SemaObjC::ObjCArgInfo ArgInfo;14631464// Each iteration parses a single keyword argument.1465if (ExpectAndConsume(tok::colon))1466break;14671468ArgInfo.Type = nullptr;1469if (Tok.is(tok::l_paren)) // Parse the argument type if present.1470ArgInfo.Type = ParseObjCTypeName(1471ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter, ¶mAttrs);14721473// If attributes exist before the argument name, parse them.1474// Regardless, collect all the attributes we've parsed so far.1475MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),1476paramAttrs);1477ArgInfo.ArgAttrs = paramAttrs;14781479// Code completion for the next piece of the selector.1480if (Tok.is(tok::code_completion)) {1481cutOffParsing();1482KeyIdents.push_back(SelIdent);1483Actions.CodeCompletion().CodeCompleteObjCMethodDeclSelector(1484getCurScope(), mType == tok::minus,1485/*AtParameterName=*/true, ReturnType, KeyIdents);1486return nullptr;1487}14881489if (expectIdentifier())1490break; // missing argument name.14911492ArgInfo.Name = Tok.getIdentifierInfo();1493ArgInfo.NameLoc = Tok.getLocation();1494ConsumeToken(); // Eat the identifier.14951496ArgInfos.push_back(ArgInfo);1497KeyIdents.push_back(SelIdent);1498KeyLocs.push_back(selLoc);14991500// Make sure the attributes persist.1501allParamAttrs.takeAllFrom(paramAttrs.getPool());15021503// Code completion for the next piece of the selector.1504if (Tok.is(tok::code_completion)) {1505cutOffParsing();1506Actions.CodeCompletion().CodeCompleteObjCMethodDeclSelector(1507getCurScope(), mType == tok::minus,1508/*AtParameterName=*/false, ReturnType, KeyIdents);1509return nullptr;1510}15111512// Check for another keyword selector.1513SelIdent = ParseObjCSelectorPiece(selLoc);1514if (!SelIdent && Tok.isNot(tok::colon))1515break;1516if (!SelIdent) {1517SourceLocation ColonLoc = Tok.getLocation();1518if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {1519Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;1520Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;1521Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;1522}1523}1524// We have a selector or a colon, continue parsing.1525}15261527bool isVariadic = false;1528bool cStyleParamWarned = false;1529// Parse the (optional) parameter list.1530while (Tok.is(tok::comma)) {1531ConsumeToken();1532if (Tok.is(tok::ellipsis)) {1533isVariadic = true;1534ConsumeToken();1535break;1536}1537if (!cStyleParamWarned) {1538Diag(Tok, diag::warn_cstyle_param);1539cStyleParamWarned = true;1540}1541DeclSpec DS(AttrFactory);1542ParsedTemplateInfo TemplateInfo;1543ParseDeclarationSpecifiers(DS, TemplateInfo);1544// Parse the declarator.1545Declarator ParmDecl(DS, ParsedAttributesView::none(),1546DeclaratorContext::Prototype);1547ParseDeclarator(ParmDecl);1548const IdentifierInfo *ParmII = ParmDecl.getIdentifier();1549Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);1550CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,1551ParmDecl.getIdentifierLoc(),1552Param,1553nullptr));1554}15551556// FIXME: Add support for optional parameter list...1557// If attributes exist after the method, parse them.1558MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),1559methodAttrs);15601561if (KeyIdents.size() == 0)1562return nullptr;15631564Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),1565&KeyIdents[0]);1566Decl *Result = Actions.ObjC().ActOnMethodDeclaration(1567getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,1568Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,1569MethodImplKind, isVariadic, MethodDefinition);15701571PD.complete(Result);1572return Result;1573}15741575/// objc-protocol-refs:1576/// '<' identifier-list '>'1577///1578bool Parser::1579ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,1580SmallVectorImpl<SourceLocation> &ProtocolLocs,1581bool WarnOnDeclarations, bool ForObjCContainer,1582SourceLocation &LAngleLoc, SourceLocation &EndLoc,1583bool consumeLastToken) {1584assert(Tok.is(tok::less) && "expected <");15851586LAngleLoc = ConsumeToken(); // the "<"15871588SmallVector<IdentifierLocPair, 8> ProtocolIdents;15891590while (true) {1591if (Tok.is(tok::code_completion)) {1592cutOffParsing();1593Actions.CodeCompletion().CodeCompleteObjCProtocolReferences(1594ProtocolIdents);1595return true;1596}15971598if (expectIdentifier()) {1599SkipUntil(tok::greater, StopAtSemi);1600return true;1601}1602ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),1603Tok.getLocation()));1604ProtocolLocs.push_back(Tok.getLocation());1605ConsumeToken();16061607if (!TryConsumeToken(tok::comma))1608break;1609}16101611// Consume the '>'.1612if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken,1613/*ObjCGenericList=*/false))1614return true;16151616// Convert the list of protocols identifiers into a list of protocol decls.1617Actions.ObjC().FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,1618ProtocolIdents, Protocols);1619return false;1620}16211622TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {1623assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");1624assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");16251626SourceLocation lAngleLoc;1627SmallVector<Decl *, 8> protocols;1628SmallVector<SourceLocation, 8> protocolLocs;1629(void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,1630lAngleLoc, rAngleLoc,1631/*consumeLastToken=*/true);1632TypeResult result = Actions.ObjC().actOnObjCProtocolQualifierType(1633lAngleLoc, protocols, protocolLocs, rAngleLoc);1634if (result.isUsable()) {1635Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)1636<< FixItHint::CreateInsertion(lAngleLoc, "id")1637<< SourceRange(lAngleLoc, rAngleLoc);1638}16391640return result;1641}16421643/// Parse Objective-C type arguments or protocol qualifiers.1644///1645/// objc-type-arguments:1646/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'1647///1648void Parser::parseObjCTypeArgsOrProtocolQualifiers(1649ParsedType baseType,1650SourceLocation &typeArgsLAngleLoc,1651SmallVectorImpl<ParsedType> &typeArgs,1652SourceLocation &typeArgsRAngleLoc,1653SourceLocation &protocolLAngleLoc,1654SmallVectorImpl<Decl *> &protocols,1655SmallVectorImpl<SourceLocation> &protocolLocs,1656SourceLocation &protocolRAngleLoc,1657bool consumeLastToken,1658bool warnOnIncompleteProtocols) {1659assert(Tok.is(tok::less) && "Not at the start of type args or protocols");1660SourceLocation lAngleLoc = ConsumeToken();16611662// Whether all of the elements we've parsed thus far are single1663// identifiers, which might be types or might be protocols.1664bool allSingleIdentifiers = true;1665SmallVector<IdentifierInfo *, 4> identifiers;1666SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;16671668// Parse a list of comma-separated identifiers, bailing out if we1669// see something different.1670do {1671// Parse a single identifier.1672if (Tok.is(tok::identifier) &&1673(NextToken().is(tok::comma) ||1674NextToken().is(tok::greater) ||1675NextToken().is(tok::greatergreater))) {1676identifiers.push_back(Tok.getIdentifierInfo());1677identifierLocs.push_back(ConsumeToken());1678continue;1679}16801681if (Tok.is(tok::code_completion)) {1682// FIXME: Also include types here.1683SmallVector<IdentifierLocPair, 4> identifierLocPairs;1684for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {1685identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],1686identifierLocs[i]));1687}16881689QualType BaseT = Actions.GetTypeFromParser(baseType);1690cutOffParsing();1691if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {1692Actions.CodeCompletion().CodeCompleteOrdinaryName(1693getCurScope(), SemaCodeCompletion::PCC_Type);1694} else {1695Actions.CodeCompletion().CodeCompleteObjCProtocolReferences(1696identifierLocPairs);1697}1698return;1699}17001701allSingleIdentifiers = false;1702break;1703} while (TryConsumeToken(tok::comma));17041705// If we parsed an identifier list, semantic analysis sorts out1706// whether it refers to protocols or to type arguments.1707if (allSingleIdentifiers) {1708// Parse the closing '>'.1709SourceLocation rAngleLoc;1710(void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,1711/*ObjCGenericList=*/true);17121713// Let Sema figure out what we parsed.1714Actions.ObjC().actOnObjCTypeArgsOrProtocolQualifiers(1715getCurScope(), baseType, lAngleLoc, identifiers, identifierLocs,1716rAngleLoc, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc,1717protocolLAngleLoc, protocols, protocolRAngleLoc,1718warnOnIncompleteProtocols);1719return;1720}17211722// We parsed an identifier list but stumbled into non single identifiers, this1723// means we might (a) check that what we already parsed is a legitimate type1724// (not a protocol or unknown type) and (b) parse the remaining ones, which1725// must all be type args.17261727// Convert the identifiers into type arguments.1728bool invalid = false;1729IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;1730SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;1731SmallVector<IdentifierInfo *, 2> unknownTypeArgs;1732SmallVector<SourceLocation, 2> unknownTypeArgsLoc;17331734for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {1735ParsedType typeArg1736= Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());1737if (typeArg) {1738DeclSpec DS(AttrFactory);1739const char *prevSpec = nullptr;1740unsigned diagID;1741DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,1742typeArg, Actions.getASTContext().getPrintingPolicy());17431744// Form a declarator to turn this into a type.1745Declarator D(DS, ParsedAttributesView::none(),1746DeclaratorContext::TypeName);1747TypeResult fullTypeArg = Actions.ActOnTypeName(D);1748if (fullTypeArg.isUsable()) {1749typeArgs.push_back(fullTypeArg.get());1750if (!foundValidTypeId) {1751foundValidTypeId = identifiers[i];1752foundValidTypeSrcLoc = identifierLocs[i];1753}1754} else {1755invalid = true;1756unknownTypeArgs.push_back(identifiers[i]);1757unknownTypeArgsLoc.push_back(identifierLocs[i]);1758}1759} else {1760invalid = true;1761if (!Actions.ObjC().LookupProtocol(identifiers[i], identifierLocs[i])) {1762unknownTypeArgs.push_back(identifiers[i]);1763unknownTypeArgsLoc.push_back(identifierLocs[i]);1764} else if (!foundProtocolId) {1765foundProtocolId = identifiers[i];1766foundProtocolSrcLoc = identifierLocs[i];1767}1768}1769}17701771// Continue parsing type-names.1772do {1773Token CurTypeTok = Tok;1774TypeResult typeArg = ParseTypeName();17751776// Consume the '...' for a pack expansion.1777SourceLocation ellipsisLoc;1778TryConsumeToken(tok::ellipsis, ellipsisLoc);1779if (typeArg.isUsable() && ellipsisLoc.isValid()) {1780typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);1781}17821783if (typeArg.isUsable()) {1784typeArgs.push_back(typeArg.get());1785if (!foundValidTypeId) {1786foundValidTypeId = CurTypeTok.getIdentifierInfo();1787foundValidTypeSrcLoc = CurTypeTok.getLocation();1788}1789} else {1790invalid = true;1791}1792} while (TryConsumeToken(tok::comma));17931794// Diagnose the mix between type args and protocols.1795if (foundProtocolId && foundValidTypeId)1796Actions.ObjC().DiagnoseTypeArgsAndProtocols(1797foundProtocolId, foundProtocolSrcLoc, foundValidTypeId,1798foundValidTypeSrcLoc);17991800// Diagnose unknown arg types.1801ParsedType T;1802if (unknownTypeArgs.size())1803for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)1804Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],1805getCurScope(), nullptr, T);18061807// Parse the closing '>'.1808SourceLocation rAngleLoc;1809(void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,1810/*ObjCGenericList=*/true);18111812if (invalid) {1813typeArgs.clear();1814return;1815}18161817// Record left/right angle locations.1818typeArgsLAngleLoc = lAngleLoc;1819typeArgsRAngleLoc = rAngleLoc;1820}18211822void Parser::parseObjCTypeArgsAndProtocolQualifiers(1823ParsedType baseType,1824SourceLocation &typeArgsLAngleLoc,1825SmallVectorImpl<ParsedType> &typeArgs,1826SourceLocation &typeArgsRAngleLoc,1827SourceLocation &protocolLAngleLoc,1828SmallVectorImpl<Decl *> &protocols,1829SmallVectorImpl<SourceLocation> &protocolLocs,1830SourceLocation &protocolRAngleLoc,1831bool consumeLastToken) {1832assert(Tok.is(tok::less));18331834// Parse the first angle-bracket-delimited clause.1835parseObjCTypeArgsOrProtocolQualifiers(baseType,1836typeArgsLAngleLoc,1837typeArgs,1838typeArgsRAngleLoc,1839protocolLAngleLoc,1840protocols,1841protocolLocs,1842protocolRAngleLoc,1843consumeLastToken,1844/*warnOnIncompleteProtocols=*/false);1845if (Tok.is(tok::eof)) // Nothing else to do here...1846return;18471848// An Objective-C object pointer followed by type arguments1849// can then be followed again by a set of protocol references, e.g.,1850// \c NSArray<NSView><NSTextDelegate>1851if ((consumeLastToken && Tok.is(tok::less)) ||1852(!consumeLastToken && NextToken().is(tok::less))) {1853// If we aren't consuming the last token, the prior '>' is still hanging1854// there. Consume it before we parse the protocol qualifiers.1855if (!consumeLastToken)1856ConsumeToken();18571858if (!protocols.empty()) {1859SkipUntilFlags skipFlags = SkipUntilFlags();1860if (!consumeLastToken)1861skipFlags = skipFlags | StopBeforeMatch;1862Diag(Tok, diag::err_objc_type_args_after_protocols)1863<< SourceRange(protocolLAngleLoc, protocolRAngleLoc);1864SkipUntil(tok::greater, tok::greatergreater, skipFlags);1865} else {1866ParseObjCProtocolReferences(protocols, protocolLocs,1867/*WarnOnDeclarations=*/false,1868/*ForObjCContainer=*/false,1869protocolLAngleLoc, protocolRAngleLoc,1870consumeLastToken);1871}1872}1873}18741875TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(1876SourceLocation loc,1877ParsedType type,1878bool consumeLastToken,1879SourceLocation &endLoc) {1880assert(Tok.is(tok::less));1881SourceLocation typeArgsLAngleLoc;1882SmallVector<ParsedType, 4> typeArgs;1883SourceLocation typeArgsRAngleLoc;1884SourceLocation protocolLAngleLoc;1885SmallVector<Decl *, 4> protocols;1886SmallVector<SourceLocation, 4> protocolLocs;1887SourceLocation protocolRAngleLoc;18881889// Parse type arguments and protocol qualifiers.1890parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,1891typeArgsRAngleLoc, protocolLAngleLoc,1892protocols, protocolLocs,1893protocolRAngleLoc, consumeLastToken);18941895if (Tok.is(tok::eof))1896return true; // Invalid type result.18971898// Compute the location of the last token.1899if (consumeLastToken)1900endLoc = PrevTokLocation;1901else1902endLoc = Tok.getLocation();19031904return Actions.ObjC().actOnObjCTypeArgsAndProtocolQualifiers(1905getCurScope(), loc, type, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc,1906protocolLAngleLoc, protocols, protocolLocs, protocolRAngleLoc);1907}19081909void Parser::HelperActionsForIvarDeclarations(1910ObjCContainerDecl *interfaceDecl, SourceLocation atLoc,1911BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls,1912bool RBraceMissing) {1913if (!RBraceMissing)1914T.consumeClose();19151916assert(getObjCDeclContext() == interfaceDecl &&1917"Ivars should have interfaceDecl as their decl context");1918Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);1919// Call ActOnFields() even if we don't have any decls. This is useful1920// for code rewriting tools that need to be aware of the empty list.1921Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,1922T.getOpenLocation(), T.getCloseLocation(),1923ParsedAttributesView());1924}19251926/// objc-class-instance-variables:1927/// '{' objc-instance-variable-decl-list[opt] '}'1928///1929/// objc-instance-variable-decl-list:1930/// objc-visibility-spec1931/// objc-instance-variable-decl ';'1932/// ';'1933/// objc-instance-variable-decl-list objc-visibility-spec1934/// objc-instance-variable-decl-list objc-instance-variable-decl ';'1935/// objc-instance-variable-decl-list static_assert-declaration1936/// objc-instance-variable-decl-list ';'1937///1938/// objc-visibility-spec:1939/// @private1940/// @protected1941/// @public1942/// @package [OBJC2]1943///1944/// objc-instance-variable-decl:1945/// struct-declaration1946///1947void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,1948tok::ObjCKeywordKind visibility,1949SourceLocation atLoc) {1950assert(Tok.is(tok::l_brace) && "expected {");1951SmallVector<Decl *, 32> AllIvarDecls;19521953ParseScope ClassScope(this, Scope::DeclScope | Scope::ClassScope);19541955BalancedDelimiterTracker T(*this, tok::l_brace);1956T.consumeOpen();1957// While we still have something to read, read the instance variables.1958while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {1959// Each iteration of this loop reads one objc-instance-variable-decl.19601961// Check for extraneous top-level semicolon.1962if (Tok.is(tok::semi)) {1963ConsumeExtraSemi(InstanceVariableList);1964continue;1965}19661967// Set the default visibility to private.1968if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec1969if (Tok.is(tok::code_completion)) {1970cutOffParsing();1971Actions.CodeCompletion().CodeCompleteObjCAtVisibility(getCurScope());1972return;1973}19741975switch (Tok.getObjCKeywordID()) {1976case tok::objc_private:1977case tok::objc_public:1978case tok::objc_protected:1979case tok::objc_package:1980visibility = Tok.getObjCKeywordID();1981ConsumeToken();1982continue;19831984case tok::objc_end:1985Diag(Tok, diag::err_objc_unexpected_atend);1986Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));1987Tok.setKind(tok::at);1988Tok.setLength(1);1989PP.EnterToken(Tok, /*IsReinject*/true);1990HelperActionsForIvarDeclarations(interfaceDecl, atLoc,1991T, AllIvarDecls, true);1992return;19931994default:1995Diag(Tok, diag::err_objc_illegal_visibility_spec);1996continue;1997}1998}19992000if (Tok.is(tok::code_completion)) {2001cutOffParsing();2002Actions.CodeCompletion().CodeCompleteOrdinaryName(2003getCurScope(), SemaCodeCompletion::PCC_ObjCInstanceVariableList);2004return;2005}20062007// This needs to duplicate a small amount of code from2008// ParseStructUnionBody() for things that should work in both2009// C struct and in Objective-C class instance variables.2010if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {2011SourceLocation DeclEnd;2012ParseStaticAssertDeclaration(DeclEnd);2013continue;2014}20152016auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) -> Decl * {2017assert(getObjCDeclContext() == interfaceDecl &&2018"Ivar should have interfaceDecl as its decl context");2019// Install the declarator into the interface decl.2020FD.D.setObjCIvar(true);2021Decl *Field = Actions.ObjC().ActOnIvar(2022getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,2023FD.BitfieldSize, visibility);2024if (Field)2025AllIvarDecls.push_back(Field);2026FD.complete(Field);2027return Field;2028};20292030// Parse all the comma separated declarators.2031ParsingDeclSpec DS(*this);2032ParseStructDeclaration(DS, ObjCIvarCallback);20332034if (Tok.is(tok::semi)) {2035ConsumeToken();2036} else {2037Diag(Tok, diag::err_expected_semi_decl_list);2038// Skip to end of block or statement2039SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);2040}2041}2042HelperActionsForIvarDeclarations(interfaceDecl, atLoc,2043T, AllIvarDecls, false);2044}20452046/// objc-protocol-declaration:2047/// objc-protocol-definition2048/// objc-protocol-forward-reference2049///2050/// objc-protocol-definition:2051/// \@protocol identifier2052/// objc-protocol-refs[opt]2053/// objc-interface-decl-list2054/// \@end2055///2056/// objc-protocol-forward-reference:2057/// \@protocol identifier-list ';'2058///2059/// "\@protocol identifier ;" should be resolved as "\@protocol2060/// identifier-list ;": objc-interface-decl-list may not start with a2061/// semicolon in the first alternative if objc-protocol-refs are omitted.2062Parser::DeclGroupPtrTy2063Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,2064ParsedAttributes &attrs) {2065assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&2066"ParseObjCAtProtocolDeclaration(): Expected @protocol");2067ConsumeToken(); // the "protocol" identifier20682069if (Tok.is(tok::code_completion)) {2070cutOffParsing();2071Actions.CodeCompletion().CodeCompleteObjCProtocolDecl(getCurScope());2072return nullptr;2073}20742075MaybeSkipAttributes(tok::objc_protocol);20762077if (expectIdentifier())2078return nullptr; // missing protocol name.2079// Save the protocol name, then consume it.2080IdentifierInfo *protocolName = Tok.getIdentifierInfo();2081SourceLocation nameLoc = ConsumeToken();20822083if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.2084IdentifierLocPair ProtoInfo(protocolName, nameLoc);2085return Actions.ObjC().ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo,2086attrs);2087}20882089CheckNestedObjCContexts(AtLoc);20902091if (Tok.is(tok::comma)) { // list of forward declarations.2092SmallVector<IdentifierLocPair, 8> ProtocolRefs;2093ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));20942095// Parse the list of forward declarations.2096while (true) {2097ConsumeToken(); // the ','2098if (expectIdentifier()) {2099SkipUntil(tok::semi);2100return nullptr;2101}2102ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),2103Tok.getLocation()));2104ConsumeToken(); // the identifier21052106if (Tok.isNot(tok::comma))2107break;2108}2109// Consume the ';'.2110if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))2111return nullptr;21122113return Actions.ObjC().ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs,2114attrs);2115}21162117// Last, and definitely not least, parse a protocol declaration.2118SourceLocation LAngleLoc, EndProtoLoc;21192120SmallVector<Decl *, 8> ProtocolRefs;2121SmallVector<SourceLocation, 8> ProtocolLocs;2122if (Tok.is(tok::less) &&2123ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,2124LAngleLoc, EndProtoLoc,2125/*consumeLastToken=*/true))2126return nullptr;21272128SkipBodyInfo SkipBody;2129ObjCProtocolDecl *ProtoType = Actions.ObjC().ActOnStartProtocolInterface(2130AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),2131ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody);21322133ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);2134if (SkipBody.CheckSameAsPrevious) {2135auto *PreviousDef = cast<ObjCProtocolDecl>(SkipBody.Previous);2136if (Actions.ActOnDuplicateODRHashDefinition(ProtoType, PreviousDef)) {2137ProtoType->mergeDuplicateDefinitionWithCommon(2138PreviousDef->getDefinition());2139} else {2140ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),2141getPreprocessor().getLangOpts());2142DiagsEmitter.diagnoseMismatch(PreviousDef, ProtoType);2143}2144}2145return Actions.ConvertDeclToDeclGroup(ProtoType);2146}21472148/// objc-implementation:2149/// objc-class-implementation-prologue2150/// objc-category-implementation-prologue2151///2152/// objc-class-implementation-prologue:2153/// @implementation identifier objc-superclass[opt]2154/// objc-class-instance-variables[opt]2155///2156/// objc-category-implementation-prologue:2157/// @implementation identifier ( identifier )2158Parser::DeclGroupPtrTy2159Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,2160ParsedAttributes &Attrs) {2161assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&2162"ParseObjCAtImplementationDeclaration(): Expected @implementation");2163CheckNestedObjCContexts(AtLoc);2164ConsumeToken(); // the "implementation" identifier21652166// Code completion after '@implementation'.2167if (Tok.is(tok::code_completion)) {2168cutOffParsing();2169Actions.CodeCompletion().CodeCompleteObjCImplementationDecl(getCurScope());2170return nullptr;2171}21722173MaybeSkipAttributes(tok::objc_implementation);21742175if (expectIdentifier())2176return nullptr; // missing class or category name.2177// We have a class or category name - consume it.2178IdentifierInfo *nameId = Tok.getIdentifierInfo();2179SourceLocation nameLoc = ConsumeToken(); // consume class or category name2180ObjCImplDecl *ObjCImpDecl = nullptr;21812182// Neither a type parameter list nor a list of protocol references is2183// permitted here. Parse and diagnose them.2184if (Tok.is(tok::less)) {2185SourceLocation lAngleLoc, rAngleLoc;2186SmallVector<IdentifierLocPair, 8> protocolIdents;2187SourceLocation diagLoc = Tok.getLocation();2188ObjCTypeParamListScope typeParamScope(Actions, getCurScope());2189if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,2190protocolIdents, rAngleLoc)) {2191Diag(diagLoc, diag::err_objc_parameterized_implementation)2192<< SourceRange(diagLoc, PrevTokLocation);2193} else if (lAngleLoc.isValid()) {2194Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)2195<< FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));2196}2197}21982199if (Tok.is(tok::l_paren)) {2200// we have a category implementation.2201ConsumeParen();2202SourceLocation categoryLoc, rparenLoc;2203IdentifierInfo *categoryId = nullptr;22042205if (Tok.is(tok::code_completion)) {2206cutOffParsing();2207Actions.CodeCompletion().CodeCompleteObjCImplementationCategory(2208getCurScope(), nameId, nameLoc);2209return nullptr;2210}22112212if (Tok.is(tok::identifier)) {2213categoryId = Tok.getIdentifierInfo();2214categoryLoc = ConsumeToken();2215} else {2216Diag(Tok, diag::err_expected)2217<< tok::identifier; // missing category name.2218return nullptr;2219}2220if (Tok.isNot(tok::r_paren)) {2221Diag(Tok, diag::err_expected) << tok::r_paren;2222SkipUntil(tok::r_paren); // don't stop at ';'2223return nullptr;2224}2225rparenLoc = ConsumeParen();2226if (Tok.is(tok::less)) { // we have illegal '<' try to recover2227Diag(Tok, diag::err_unexpected_protocol_qualifier);2228SourceLocation protocolLAngleLoc, protocolRAngleLoc;2229SmallVector<Decl *, 4> protocols;2230SmallVector<SourceLocation, 4> protocolLocs;2231(void)ParseObjCProtocolReferences(protocols, protocolLocs,2232/*warnOnIncompleteProtocols=*/false,2233/*ForObjCContainer=*/false,2234protocolLAngleLoc, protocolRAngleLoc,2235/*consumeLastToken=*/true);2236}2237ObjCImpDecl = Actions.ObjC().ActOnStartCategoryImplementation(2238AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);22392240} else {2241// We have a class implementation2242SourceLocation superClassLoc;2243IdentifierInfo *superClassId = nullptr;2244if (TryConsumeToken(tok::colon)) {2245// We have a super class2246if (expectIdentifier())2247return nullptr; // missing super class name.2248superClassId = Tok.getIdentifierInfo();2249superClassLoc = ConsumeToken(); // Consume super class name2250}2251ObjCImpDecl = Actions.ObjC().ActOnStartClassImplementation(2252AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);22532254if (Tok.is(tok::l_brace)) // we have ivars2255ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);2256else if (Tok.is(tok::less)) { // we have illegal '<' try to recover2257Diag(Tok, diag::err_unexpected_protocol_qualifier);22582259SourceLocation protocolLAngleLoc, protocolRAngleLoc;2260SmallVector<Decl *, 4> protocols;2261SmallVector<SourceLocation, 4> protocolLocs;2262(void)ParseObjCProtocolReferences(protocols, protocolLocs,2263/*warnOnIncompleteProtocols=*/false,2264/*ForObjCContainer=*/false,2265protocolLAngleLoc, protocolRAngleLoc,2266/*consumeLastToken=*/true);2267}2268}2269assert(ObjCImpDecl);22702271SmallVector<Decl *, 8> DeclsInGroup;22722273{2274ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);2275while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {2276ParsedAttributes DeclAttrs(AttrFactory);2277MaybeParseCXX11Attributes(DeclAttrs);2278ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);2279if (DeclGroupPtrTy DGP =2280ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs)) {2281DeclGroupRef DG = DGP.get();2282DeclsInGroup.append(DG.begin(), DG.end());2283}2284}2285}22862287return Actions.ObjC().ActOnFinishObjCImplementation(ObjCImpDecl,2288DeclsInGroup);2289}22902291Parser::DeclGroupPtrTy2292Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {2293assert(Tok.isObjCAtKeyword(tok::objc_end) &&2294"ParseObjCAtEndDeclaration(): Expected @end");2295ConsumeToken(); // the "end" identifier2296if (CurParsedObjCImpl)2297CurParsedObjCImpl->finish(atEnd);2298else2299// missing @implementation2300Diag(atEnd.getBegin(), diag::err_expected_objc_container);2301return nullptr;2302}23032304Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {2305if (!Finished) {2306finish(P.Tok.getLocation());2307if (P.isEofOrEom()) {2308P.Diag(P.Tok, diag::err_objc_missing_end)2309<< FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");2310P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)2311<< SemaObjC::OCK_Implementation;2312}2313}2314P.CurParsedObjCImpl = nullptr;2315assert(LateParsedObjCMethods.empty());2316}23172318void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {2319assert(!Finished);2320P.Actions.ObjC().DefaultSynthesizeProperties(P.getCurScope(), Dcl,2321AtEnd.getBegin());2322for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)2323P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],2324true/*Methods*/);23252326P.Actions.ObjC().ActOnAtEnd(P.getCurScope(), AtEnd);23272328if (HasCFunction)2329for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)2330P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],2331false/*c-functions*/);23322333/// Clear and free the cached objc methods.2334for (LateParsedObjCMethodContainer::iterator2335I = LateParsedObjCMethods.begin(),2336E = LateParsedObjCMethods.end(); I != E; ++I)2337delete *I;2338LateParsedObjCMethods.clear();23392340Finished = true;2341}23422343/// compatibility-alias-decl:2344/// @compatibility_alias alias-name class-name ';'2345///2346Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {2347assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&2348"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");2349ConsumeToken(); // consume compatibility_alias2350if (expectIdentifier())2351return nullptr;2352IdentifierInfo *aliasId = Tok.getIdentifierInfo();2353SourceLocation aliasLoc = ConsumeToken(); // consume alias-name2354if (expectIdentifier())2355return nullptr;2356IdentifierInfo *classId = Tok.getIdentifierInfo();2357SourceLocation classLoc = ConsumeToken(); // consume class-name;2358ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");2359return Actions.ObjC().ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,2360classId, classLoc);2361}23622363/// property-synthesis:2364/// @synthesize property-ivar-list ';'2365///2366/// property-ivar-list:2367/// property-ivar2368/// property-ivar-list ',' property-ivar2369///2370/// property-ivar:2371/// identifier2372/// identifier '=' identifier2373///2374Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {2375assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&2376"ParseObjCPropertySynthesize(): Expected '@synthesize'");2377ConsumeToken(); // consume synthesize23782379while (true) {2380if (Tok.is(tok::code_completion)) {2381cutOffParsing();2382Actions.CodeCompletion().CodeCompleteObjCPropertyDefinition(2383getCurScope());2384return nullptr;2385}23862387if (Tok.isNot(tok::identifier)) {2388Diag(Tok, diag::err_synthesized_property_name);2389SkipUntil(tok::semi);2390return nullptr;2391}23922393IdentifierInfo *propertyIvar = nullptr;2394IdentifierInfo *propertyId = Tok.getIdentifierInfo();2395SourceLocation propertyLoc = ConsumeToken(); // consume property name2396SourceLocation propertyIvarLoc;2397if (TryConsumeToken(tok::equal)) {2398// property '=' ivar-name2399if (Tok.is(tok::code_completion)) {2400cutOffParsing();2401Actions.CodeCompletion().CodeCompleteObjCPropertySynthesizeIvar(2402getCurScope(), propertyId);2403return nullptr;2404}24052406if (expectIdentifier())2407break;2408propertyIvar = Tok.getIdentifierInfo();2409propertyIvarLoc = ConsumeToken(); // consume ivar-name2410}2411Actions.ObjC().ActOnPropertyImplDecl(2412getCurScope(), atLoc, propertyLoc, true, propertyId, propertyIvar,2413propertyIvarLoc, ObjCPropertyQueryKind::OBJC_PR_query_unknown);2414if (Tok.isNot(tok::comma))2415break;2416ConsumeToken(); // consume ','2417}2418ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");2419return nullptr;2420}24212422/// property-dynamic:2423/// @dynamic property-list2424///2425/// property-list:2426/// identifier2427/// property-list ',' identifier2428///2429Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {2430assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&2431"ParseObjCPropertyDynamic(): Expected '@dynamic'");2432ConsumeToken(); // consume dynamic24332434bool isClassProperty = false;2435if (Tok.is(tok::l_paren)) {2436ConsumeParen();2437const IdentifierInfo *II = Tok.getIdentifierInfo();24382439if (!II) {2440Diag(Tok, diag::err_objc_expected_property_attr) << II;2441SkipUntil(tok::r_paren, StopAtSemi);2442} else {2443SourceLocation AttrName = ConsumeToken(); // consume attribute name2444if (II->isStr("class")) {2445isClassProperty = true;2446if (Tok.isNot(tok::r_paren)) {2447Diag(Tok, diag::err_expected) << tok::r_paren;2448SkipUntil(tok::r_paren, StopAtSemi);2449} else2450ConsumeParen();2451} else {2452Diag(AttrName, diag::err_objc_expected_property_attr) << II;2453SkipUntil(tok::r_paren, StopAtSemi);2454}2455}2456}24572458while (true) {2459if (Tok.is(tok::code_completion)) {2460cutOffParsing();2461Actions.CodeCompletion().CodeCompleteObjCPropertyDefinition(2462getCurScope());2463return nullptr;2464}24652466if (expectIdentifier()) {2467SkipUntil(tok::semi);2468return nullptr;2469}24702471IdentifierInfo *propertyId = Tok.getIdentifierInfo();2472SourceLocation propertyLoc = ConsumeToken(); // consume property name2473Actions.ObjC().ActOnPropertyImplDecl(2474getCurScope(), atLoc, propertyLoc, false, propertyId, nullptr,2475SourceLocation(),2476isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class2477: ObjCPropertyQueryKind::OBJC_PR_query_unknown);24782479if (Tok.isNot(tok::comma))2480break;2481ConsumeToken(); // consume ','2482}2483ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");2484return nullptr;2485}24862487/// objc-throw-statement:2488/// throw expression[opt];2489///2490StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {2491ExprResult Res;2492ConsumeToken(); // consume throw2493if (Tok.isNot(tok::semi)) {2494Res = ParseExpression();2495if (Res.isInvalid()) {2496SkipUntil(tok::semi);2497return StmtError();2498}2499}2500// consume ';'2501ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");2502return Actions.ObjC().ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());2503}25042505/// objc-synchronized-statement:2506/// @synchronized '(' expression ')' compound-statement2507///2508StmtResult2509Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {2510ConsumeToken(); // consume synchronized2511if (Tok.isNot(tok::l_paren)) {2512Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";2513return StmtError();2514}25152516// The operand is surrounded with parentheses.2517ConsumeParen(); // '('2518ExprResult operand(ParseExpression());25192520if (Tok.is(tok::r_paren)) {2521ConsumeParen(); // ')'2522} else {2523if (!operand.isInvalid())2524Diag(Tok, diag::err_expected) << tok::r_paren;25252526// Skip forward until we see a left brace, but don't consume it.2527SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);2528}25292530// Require a compound statement.2531if (Tok.isNot(tok::l_brace)) {2532if (!operand.isInvalid())2533Diag(Tok, diag::err_expected) << tok::l_brace;2534return StmtError();2535}25362537// Check the @synchronized operand now.2538if (!operand.isInvalid())2539operand =2540Actions.ObjC().ActOnObjCAtSynchronizedOperand(atLoc, operand.get());25412542// Parse the compound statement within a new scope.2543ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);2544StmtResult body(ParseCompoundStatementBody());2545bodyScope.Exit();25462547// If there was a semantic or parse error earlier with the2548// operand, fail now.2549if (operand.isInvalid())2550return StmtError();25512552if (body.isInvalid())2553body = Actions.ActOnNullStmt(Tok.getLocation());25542555return Actions.ObjC().ActOnObjCAtSynchronizedStmt(atLoc, operand.get(),2556body.get());2557}25582559/// objc-try-catch-statement:2560/// @try compound-statement objc-catch-list[opt]2561/// @try compound-statement objc-catch-list[opt] @finally compound-statement2562///2563/// objc-catch-list:2564/// @catch ( parameter-declaration ) compound-statement2565/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement2566/// catch-parameter-declaration:2567/// parameter-declaration2568/// '...' [OBJC2]2569///2570StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {2571bool catch_or_finally_seen = false;25722573ConsumeToken(); // consume try2574if (Tok.isNot(tok::l_brace)) {2575Diag(Tok, diag::err_expected) << tok::l_brace;2576return StmtError();2577}2578StmtVector CatchStmts;2579StmtResult FinallyStmt;2580ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);2581StmtResult TryBody(ParseCompoundStatementBody());2582TryScope.Exit();2583if (TryBody.isInvalid())2584TryBody = Actions.ActOnNullStmt(Tok.getLocation());25852586while (Tok.is(tok::at)) {2587// At this point, we need to lookahead to determine if this @ is the start2588// of an @catch or @finally. We don't want to consume the @ token if this2589// is an @try or @encode or something else.2590Token AfterAt = GetLookAheadToken(1);2591if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&2592!AfterAt.isObjCAtKeyword(tok::objc_finally))2593break;25942595SourceLocation AtCatchFinallyLoc = ConsumeToken();2596if (Tok.isObjCAtKeyword(tok::objc_catch)) {2597Decl *FirstPart = nullptr;2598ConsumeToken(); // consume catch2599if (Tok.is(tok::l_paren)) {2600ConsumeParen();2601ParseScope CatchScope(this, Scope::DeclScope |2602Scope::CompoundStmtScope |2603Scope::AtCatchScope);2604if (Tok.isNot(tok::ellipsis)) {2605DeclSpec DS(AttrFactory);2606ParsedTemplateInfo TemplateInfo;2607ParseDeclarationSpecifiers(DS, TemplateInfo);2608Declarator ParmDecl(DS, ParsedAttributesView::none(),2609DeclaratorContext::ObjCCatch);2610ParseDeclarator(ParmDecl);26112612// Inform the actions module about the declarator, so it2613// gets added to the current scope.2614FirstPart =2615Actions.ObjC().ActOnObjCExceptionDecl(getCurScope(), ParmDecl);2616} else2617ConsumeToken(); // consume '...'26182619SourceLocation RParenLoc;26202621if (Tok.is(tok::r_paren))2622RParenLoc = ConsumeParen();2623else // Skip over garbage, until we get to ')'. Eat the ')'.2624SkipUntil(tok::r_paren, StopAtSemi);26252626StmtResult CatchBody(true);2627if (Tok.is(tok::l_brace))2628CatchBody = ParseCompoundStatementBody();2629else2630Diag(Tok, diag::err_expected) << tok::l_brace;2631if (CatchBody.isInvalid())2632CatchBody = Actions.ActOnNullStmt(Tok.getLocation());26332634StmtResult Catch = Actions.ObjC().ActOnObjCAtCatchStmt(2635AtCatchFinallyLoc, RParenLoc, FirstPart, CatchBody.get());2636if (!Catch.isInvalid())2637CatchStmts.push_back(Catch.get());26382639} else {2640Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)2641<< "@catch clause";2642return StmtError();2643}2644catch_or_finally_seen = true;2645} else {2646assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");2647ConsumeToken(); // consume finally2648ParseScope FinallyScope(this,2649Scope::DeclScope | Scope::CompoundStmtScope);26502651bool ShouldCapture =2652getTargetInfo().getTriple().isWindowsMSVCEnvironment();2653if (ShouldCapture)2654Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),2655CR_ObjCAtFinally, 1);26562657StmtResult FinallyBody(true);2658if (Tok.is(tok::l_brace))2659FinallyBody = ParseCompoundStatementBody();2660else2661Diag(Tok, diag::err_expected) << tok::l_brace;26622663if (FinallyBody.isInvalid()) {2664FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());2665if (ShouldCapture)2666Actions.ActOnCapturedRegionError();2667} else if (ShouldCapture) {2668FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());2669}26702671FinallyStmt = Actions.ObjC().ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,2672FinallyBody.get());2673catch_or_finally_seen = true;2674break;2675}2676}2677if (!catch_or_finally_seen) {2678Diag(atLoc, diag::err_missing_catch_finally);2679return StmtError();2680}26812682return Actions.ObjC().ActOnObjCAtTryStmt(atLoc, TryBody.get(), CatchStmts,2683FinallyStmt.get());2684}26852686/// objc-autoreleasepool-statement:2687/// @autoreleasepool compound-statement2688///2689StmtResult2690Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {2691ConsumeToken(); // consume autoreleasepool2692if (Tok.isNot(tok::l_brace)) {2693Diag(Tok, diag::err_expected) << tok::l_brace;2694return StmtError();2695}2696// Enter a scope to hold everything within the compound stmt. Compound2697// statements can always hold declarations.2698ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);26992700StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());27012702BodyScope.Exit();2703if (AutoreleasePoolBody.isInvalid())2704AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());2705return Actions.ObjC().ActOnObjCAutoreleasePoolStmt(atLoc,2706AutoreleasePoolBody.get());2707}27082709/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them2710/// for later parsing.2711void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {2712if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&2713trySkippingFunctionBody()) {2714Actions.ActOnSkippedFunctionBody(MDecl);2715return;2716}27172718LexedMethod* LM = new LexedMethod(this, MDecl);2719CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);2720CachedTokens &Toks = LM->Toks;2721// Begin by storing the '{' or 'try' or ':' token.2722Toks.push_back(Tok);2723if (Tok.is(tok::kw_try)) {2724ConsumeToken();2725if (Tok.is(tok::colon)) {2726Toks.push_back(Tok);2727ConsumeToken();2728while (Tok.isNot(tok::l_brace)) {2729ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);2730ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);2731}2732}2733Toks.push_back(Tok); // also store '{'2734}2735else if (Tok.is(tok::colon)) {2736ConsumeToken();2737// FIXME: This is wrong, due to C++11 braced initialization.2738while (Tok.isNot(tok::l_brace)) {2739ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);2740ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);2741}2742Toks.push_back(Tok); // also store '{'2743}2744ConsumeBrace();2745// Consume everything up to (and including) the matching right brace.2746ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);2747while (Tok.is(tok::kw_catch)) {2748ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);2749ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);2750}2751}27522753/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'2754///2755Decl *Parser::ParseObjCMethodDefinition() {2756Decl *MDecl = ParseObjCMethodPrototype();27572758PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),2759"parsing Objective-C method");27602761// parse optional ';'2762if (Tok.is(tok::semi)) {2763if (CurParsedObjCImpl) {2764Diag(Tok, diag::warn_semicolon_before_method_body)2765<< FixItHint::CreateRemoval(Tok.getLocation());2766}2767ConsumeToken();2768}27692770// We should have an opening brace now.2771if (Tok.isNot(tok::l_brace)) {2772Diag(Tok, diag::err_expected_method_body);27732774// Skip over garbage, until we get to '{'. Don't eat the '{'.2775SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);27762777// If we didn't find the '{', bail out.2778if (Tok.isNot(tok::l_brace))2779return nullptr;2780}27812782if (!MDecl) {2783ConsumeBrace();2784SkipUntil(tok::r_brace);2785return nullptr;2786}27872788// Allow the rest of sema to find private method decl implementations.2789Actions.ObjC().AddAnyMethodToGlobalPool(MDecl);2790assert (CurParsedObjCImpl2791&& "ParseObjCMethodDefinition - Method out of @implementation");2792// Consume the tokens and store them for later parsing.2793StashAwayMethodOrFunctionBodyTokens(MDecl);2794return MDecl;2795}27962797StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,2798ParsedStmtContext StmtCtx) {2799if (Tok.is(tok::code_completion)) {2800cutOffParsing();2801Actions.CodeCompletion().CodeCompleteObjCAtStatement(getCurScope());2802return StmtError();2803}28042805if (Tok.isObjCAtKeyword(tok::objc_try))2806return ParseObjCTryStmt(AtLoc);28072808if (Tok.isObjCAtKeyword(tok::objc_throw))2809return ParseObjCThrowStmt(AtLoc);28102811if (Tok.isObjCAtKeyword(tok::objc_synchronized))2812return ParseObjCSynchronizedStmt(AtLoc);28132814if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))2815return ParseObjCAutoreleasePoolStmt(AtLoc);28162817if (Tok.isObjCAtKeyword(tok::objc_import) &&2818getLangOpts().DebuggerSupport) {2819SkipUntil(tok::semi);2820return Actions.ActOnNullStmt(Tok.getLocation());2821}28222823ExprStatementTokLoc = AtLoc;2824ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));2825if (Res.isInvalid()) {2826// If the expression is invalid, skip ahead to the next semicolon. Not2827// doing this opens us up to the possibility of infinite loops if2828// ParseExpression does not consume any tokens.2829SkipUntil(tok::semi);2830return StmtError();2831}28322833// Otherwise, eat the semicolon.2834ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);2835return handleExprStmt(Res, StmtCtx);2836}28372838ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {2839switch (Tok.getKind()) {2840case tok::code_completion:2841cutOffParsing();2842Actions.CodeCompletion().CodeCompleteObjCAtExpression(getCurScope());2843return ExprError();28442845case tok::minus:2846case tok::plus: {2847tok::TokenKind Kind = Tok.getKind();2848SourceLocation OpLoc = ConsumeToken();28492850if (!Tok.is(tok::numeric_constant)) {2851const char *Symbol = nullptr;2852switch (Kind) {2853case tok::minus: Symbol = "-"; break;2854case tok::plus: Symbol = "+"; break;2855default: llvm_unreachable("missing unary operator case");2856}2857Diag(Tok, diag::err_nsnumber_nonliteral_unary)2858<< Symbol;2859return ExprError();2860}28612862ExprResult Lit(Actions.ActOnNumericConstant(Tok));2863if (Lit.isInvalid()) {2864return Lit;2865}2866ConsumeToken(); // Consume the literal token.28672868Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());2869if (Lit.isInvalid())2870return Lit;28712872return ParsePostfixExpressionSuffix(2873Actions.ObjC().BuildObjCNumericLiteral(AtLoc, Lit.get()));2874}28752876case tok::string_literal: // primary-expression: string-literal2877case tok::wide_string_literal:2878return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));28792880case tok::char_constant:2881return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));28822883case tok::numeric_constant:2884return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));28852886case tok::kw_true: // Objective-C++, etc.2887case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes2888return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));2889case tok::kw_false: // Objective-C++, etc.2890case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no2891return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));28922893case tok::l_square:2894// Objective-C array literal2895return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));28962897case tok::l_brace:2898// Objective-C dictionary literal2899return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));29002901case tok::l_paren:2902// Objective-C boxed expression2903return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));29042905default:2906if (Tok.getIdentifierInfo() == nullptr)2907return ExprError(Diag(AtLoc, diag::err_unexpected_at));29082909switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {2910case tok::objc_encode:2911return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));2912case tok::objc_protocol:2913return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));2914case tok::objc_selector:2915return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));2916case tok::objc_available:2917return ParseAvailabilityCheckExpr(AtLoc);2918default: {2919const char *str = nullptr;2920// Only provide the @try/@finally/@autoreleasepool fixit when we're sure2921// that this is a proper statement where such directives could actually2922// occur.2923if (GetLookAheadToken(1).is(tok::l_brace) &&2924ExprStatementTokLoc == AtLoc) {2925char ch = Tok.getIdentifierInfo()->getNameStart()[0];2926str =2927ch == 't' ? "try"2928: (ch == 'f' ? "finally"2929: (ch == 'a' ? "autoreleasepool" : nullptr));2930}2931if (str) {2932SourceLocation kwLoc = Tok.getLocation();2933return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<2934FixItHint::CreateReplacement(kwLoc, str));2935}2936else2937return ExprError(Diag(AtLoc, diag::err_unexpected_at));2938}2939}2940}2941}29422943/// Parse the receiver of an Objective-C++ message send.2944///2945/// This routine parses the receiver of a message send in2946/// Objective-C++ either as a type or as an expression. Note that this2947/// routine must not be called to parse a send to 'super', since it2948/// has no way to return such a result.2949///2950/// \param IsExpr Whether the receiver was parsed as an expression.2951///2952/// \param TypeOrExpr If the receiver was parsed as an expression (\c2953/// IsExpr is true), the parsed expression. If the receiver was parsed2954/// as a type (\c IsExpr is false), the parsed type.2955///2956/// \returns True if an error occurred during parsing or semantic2957/// analysis, in which case the arguments do not have valid2958/// values. Otherwise, returns false for a successful parse.2959///2960/// objc-receiver: [C++]2961/// 'super' [not parsed here]2962/// expression2963/// simple-type-specifier2964/// typename-specifier2965bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {2966InMessageExpressionRAIIObject InMessage(*this, true);29672968if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,2969tok::annot_cxxscope))2970TryAnnotateTypeOrScopeToken();29712972if (!Tok.isSimpleTypeSpecifier(getLangOpts())) {2973// objc-receiver:2974// expression2975// Make sure any typos in the receiver are corrected or diagnosed, so that2976// proper recovery can happen. FIXME: Perhaps filter the corrected expr to2977// only the things that are valid ObjC receivers?2978ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());2979if (Receiver.isInvalid())2980return true;29812982IsExpr = true;2983TypeOrExpr = Receiver.get();2984return false;2985}29862987// objc-receiver:2988// typename-specifier2989// simple-type-specifier2990// expression (that starts with one of the above)2991DeclSpec DS(AttrFactory);2992ParseCXXSimpleTypeSpecifier(DS);29932994if (Tok.is(tok::l_paren)) {2995// If we see an opening parentheses at this point, we are2996// actually parsing an expression that starts with a2997// function-style cast, e.g.,2998//2999// postfix-expression:3000// simple-type-specifier ( expression-list [opt] )3001// typename-specifier ( expression-list [opt] )3002//3003// Parse the remainder of this case, then the (optional)3004// postfix-expression suffix, followed by the (optional)3005// right-hand side of the binary expression. We have an3006// instance method.3007ExprResult Receiver = ParseCXXTypeConstructExpression(DS);3008if (!Receiver.isInvalid())3009Receiver = ParsePostfixExpressionSuffix(Receiver.get());3010if (!Receiver.isInvalid())3011Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);3012if (Receiver.isInvalid())3013return true;30143015IsExpr = true;3016TypeOrExpr = Receiver.get();3017return false;3018}30193020// We have a class message. Turn the simple-type-specifier or3021// typename-specifier we parsed into a type and parse the3022// remainder of the class message.3023Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),3024DeclaratorContext::TypeName);3025TypeResult Type = Actions.ActOnTypeName(DeclaratorInfo);3026if (Type.isInvalid())3027return true;30283029IsExpr = false;3030TypeOrExpr = Type.get().getAsOpaquePtr();3031return false;3032}30333034/// Determine whether the parser is currently referring to a an3035/// Objective-C message send, using a simplified heuristic to avoid overhead.3036///3037/// This routine will only return true for a subset of valid message-send3038/// expressions.3039bool Parser::isSimpleObjCMessageExpression() {3040assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&3041"Incorrect start for isSimpleObjCMessageExpression");3042return GetLookAheadToken(1).is(tok::identifier) &&3043GetLookAheadToken(2).is(tok::identifier);3044}30453046bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {3047if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||3048InMessageExpression)3049return false;30503051TypeResult Type;30523053if (Tok.is(tok::annot_typename))3054Type = getTypeAnnotation(Tok);3055else if (Tok.is(tok::identifier))3056Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),3057getCurScope());3058else3059return false;30603061// FIXME: Should not be querying properties of types from the parser.3062if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) {3063const Token &AfterNext = GetLookAheadToken(2);3064if (AfterNext.isOneOf(tok::colon, tok::r_square)) {3065if (Tok.is(tok::identifier))3066TryAnnotateTypeOrScopeToken();30673068return Tok.is(tok::annot_typename);3069}3070}30713072return false;3073}30743075/// objc-message-expr:3076/// '[' objc-receiver objc-message-args ']'3077///3078/// objc-receiver: [C]3079/// 'super'3080/// expression3081/// class-name3082/// type-name3083///3084ExprResult Parser::ParseObjCMessageExpression() {3085assert(Tok.is(tok::l_square) && "'[' expected");3086SourceLocation LBracLoc = ConsumeBracket(); // consume '['30873088if (Tok.is(tok::code_completion)) {3089cutOffParsing();3090Actions.CodeCompletion().CodeCompleteObjCMessageReceiver(getCurScope());3091return ExprError();3092}30933094InMessageExpressionRAIIObject InMessage(*this, true);30953096if (getLangOpts().CPlusPlus) {3097// We completely separate the C and C++ cases because C++ requires3098// more complicated (read: slower) parsing.30993100// Handle send to super.3101// FIXME: This doesn't benefit from the same typo-correction we3102// get in Objective-C.3103if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&3104NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())3105return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,3106nullptr);31073108// Parse the receiver, which is either a type or an expression.3109bool IsExpr;3110void *TypeOrExpr = nullptr;3111if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {3112SkipUntil(tok::r_square, StopAtSemi);3113return ExprError();3114}31153116if (IsExpr)3117return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,3118static_cast<Expr *>(TypeOrExpr));31193120return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),3121ParsedType::getFromOpaquePtr(TypeOrExpr),3122nullptr);3123}31243125if (Tok.is(tok::identifier)) {3126IdentifierInfo *Name = Tok.getIdentifierInfo();3127SourceLocation NameLoc = Tok.getLocation();3128ParsedType ReceiverType;3129switch (Actions.ObjC().getObjCMessageKind(3130getCurScope(), Name, NameLoc, Name == Ident_super,3131NextToken().is(tok::period), ReceiverType)) {3132case SemaObjC::ObjCSuperMessage:3133return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,3134nullptr);31353136case SemaObjC::ObjCClassMessage:3137if (!ReceiverType) {3138SkipUntil(tok::r_square, StopAtSemi);3139return ExprError();3140}31413142ConsumeToken(); // the type name31433144// Parse type arguments and protocol qualifiers.3145if (Tok.is(tok::less)) {3146SourceLocation NewEndLoc;3147TypeResult NewReceiverType3148= parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,3149/*consumeLastToken=*/true,3150NewEndLoc);3151if (!NewReceiverType.isUsable()) {3152SkipUntil(tok::r_square, StopAtSemi);3153return ExprError();3154}31553156ReceiverType = NewReceiverType.get();3157}31583159return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),3160ReceiverType, nullptr);31613162case SemaObjC::ObjCInstanceMessage:3163// Fall through to parse an expression.3164break;3165}3166}31673168// Otherwise, an arbitrary expression can be the receiver of a send.3169ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());3170if (Res.isInvalid()) {3171SkipUntil(tok::r_square, StopAtSemi);3172return Res;3173}31743175return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,3176Res.get());3177}31783179/// Parse the remainder of an Objective-C message following the3180/// '[' objc-receiver.3181///3182/// This routine handles sends to super, class messages (sent to a3183/// class name), and instance messages (sent to an object), and the3184/// target is represented by \p SuperLoc, \p ReceiverType, or \p3185/// ReceiverExpr, respectively. Only one of these parameters may have3186/// a valid value.3187///3188/// \param LBracLoc The location of the opening '['.3189///3190/// \param SuperLoc If this is a send to 'super', the location of the3191/// 'super' keyword that indicates a send to the superclass.3192///3193/// \param ReceiverType If this is a class message, the type of the3194/// class we are sending a message to.3195///3196/// \param ReceiverExpr If this is an instance message, the expression3197/// used to compute the receiver object.3198///3199/// objc-message-args:3200/// objc-selector3201/// objc-keywordarg-list3202///3203/// objc-keywordarg-list:3204/// objc-keywordarg3205/// objc-keywordarg-list objc-keywordarg3206///3207/// objc-keywordarg:3208/// selector-name[opt] ':' objc-keywordexpr3209///3210/// objc-keywordexpr:3211/// nonempty-expr-list3212///3213/// nonempty-expr-list:3214/// assignment-expression3215/// nonempty-expr-list , assignment-expression3216///3217ExprResult3218Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,3219SourceLocation SuperLoc,3220ParsedType ReceiverType,3221Expr *ReceiverExpr) {3222InMessageExpressionRAIIObject InMessage(*this, true);32233224if (Tok.is(tok::code_completion)) {3225cutOffParsing();3226if (SuperLoc.isValid())3227Actions.CodeCompletion().CodeCompleteObjCSuperMessage(3228getCurScope(), SuperLoc, std::nullopt, false);3229else if (ReceiverType)3230Actions.CodeCompletion().CodeCompleteObjCClassMessage(3231getCurScope(), ReceiverType, std::nullopt, false);3232else3233Actions.CodeCompletion().CodeCompleteObjCInstanceMessage(3234getCurScope(), ReceiverExpr, std::nullopt, false);3235return ExprError();3236}32373238// Parse objc-selector3239SourceLocation Loc;3240IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);32413242SmallVector<const IdentifierInfo *, 12> KeyIdents;3243SmallVector<SourceLocation, 12> KeyLocs;3244ExprVector KeyExprs;32453246if (Tok.is(tok::colon)) {3247while (true) {3248// Each iteration parses a single keyword argument.3249KeyIdents.push_back(selIdent);3250KeyLocs.push_back(Loc);32513252if (ExpectAndConsume(tok::colon)) {3253// We must manually skip to a ']', otherwise the expression skipper will3254// stop at the ']' when it skips to the ';'. We want it to skip beyond3255// the enclosing expression.3256SkipUntil(tok::r_square, StopAtSemi);3257return ExprError();3258}32593260/// Parse the expression after ':'32613262if (Tok.is(tok::code_completion)) {3263cutOffParsing();3264if (SuperLoc.isValid())3265Actions.CodeCompletion().CodeCompleteObjCSuperMessage(3266getCurScope(), SuperLoc, KeyIdents,3267/*AtArgumentExpression=*/true);3268else if (ReceiverType)3269Actions.CodeCompletion().CodeCompleteObjCClassMessage(3270getCurScope(), ReceiverType, KeyIdents,3271/*AtArgumentExpression=*/true);3272else3273Actions.CodeCompletion().CodeCompleteObjCInstanceMessage(3274getCurScope(), ReceiverExpr, KeyIdents,3275/*AtArgumentExpression=*/true);32763277return ExprError();3278}32793280ExprResult Expr;3281if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {3282Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);3283Expr = ParseBraceInitializer();3284} else3285Expr = ParseAssignmentExpression();32863287ExprResult Res(Expr);3288if (Res.isInvalid()) {3289// We must manually skip to a ']', otherwise the expression skipper will3290// stop at the ']' when it skips to the ';'. We want it to skip beyond3291// the enclosing expression.3292SkipUntil(tok::r_square, StopAtSemi);3293return Res;3294}32953296// We have a valid expression.3297KeyExprs.push_back(Res.get());32983299// Code completion after each argument.3300if (Tok.is(tok::code_completion)) {3301cutOffParsing();3302if (SuperLoc.isValid())3303Actions.CodeCompletion().CodeCompleteObjCSuperMessage(3304getCurScope(), SuperLoc, KeyIdents,3305/*AtArgumentExpression=*/false);3306else if (ReceiverType)3307Actions.CodeCompletion().CodeCompleteObjCClassMessage(3308getCurScope(), ReceiverType, KeyIdents,3309/*AtArgumentExpression=*/false);3310else3311Actions.CodeCompletion().CodeCompleteObjCInstanceMessage(3312getCurScope(), ReceiverExpr, KeyIdents,3313/*AtArgumentExpression=*/false);3314return ExprError();3315}33163317// Check for another keyword selector.3318selIdent = ParseObjCSelectorPiece(Loc);3319if (!selIdent && Tok.isNot(tok::colon))3320break;3321// We have a selector or a colon, continue parsing.3322}3323// Parse the, optional, argument list, comma separated.3324while (Tok.is(tok::comma)) {3325SourceLocation commaLoc = ConsumeToken(); // Eat the ','.3326/// Parse the expression after ','3327ExprResult Res(ParseAssignmentExpression());3328if (Tok.is(tok::colon))3329Res = Actions.CorrectDelayedTyposInExpr(Res);3330if (Res.isInvalid()) {3331if (Tok.is(tok::colon)) {3332Diag(commaLoc, diag::note_extra_comma_message_arg) <<3333FixItHint::CreateRemoval(commaLoc);3334}3335// We must manually skip to a ']', otherwise the expression skipper will3336// stop at the ']' when it skips to the ';'. We want it to skip beyond3337// the enclosing expression.3338SkipUntil(tok::r_square, StopAtSemi);3339return Res;3340}33413342// We have a valid expression.3343KeyExprs.push_back(Res.get());3344}3345} else if (!selIdent) {3346Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.33473348// We must manually skip to a ']', otherwise the expression skipper will3349// stop at the ']' when it skips to the ';'. We want it to skip beyond3350// the enclosing expression.3351SkipUntil(tok::r_square, StopAtSemi);3352return ExprError();3353}33543355if (Tok.isNot(tok::r_square)) {3356Diag(Tok, diag::err_expected)3357<< (Tok.is(tok::identifier) ? tok::colon : tok::r_square);3358// We must manually skip to a ']', otherwise the expression skipper will3359// stop at the ']' when it skips to the ';'. We want it to skip beyond3360// the enclosing expression.3361SkipUntil(tok::r_square, StopAtSemi);3362return ExprError();3363}33643365SourceLocation RBracLoc = ConsumeBracket(); // consume ']'33663367unsigned nKeys = KeyIdents.size();3368if (nKeys == 0) {3369KeyIdents.push_back(selIdent);3370KeyLocs.push_back(Loc);3371}3372Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);33733374if (SuperLoc.isValid())3375return Actions.ObjC().ActOnSuperMessage(3376getCurScope(), SuperLoc, Sel, LBracLoc, KeyLocs, RBracLoc, KeyExprs);3377else if (ReceiverType)3378return Actions.ObjC().ActOnClassMessage(getCurScope(), ReceiverType, Sel,3379LBracLoc, KeyLocs, RBracLoc,3380KeyExprs);3381return Actions.ObjC().ActOnInstanceMessage(3382getCurScope(), ReceiverExpr, Sel, LBracLoc, KeyLocs, RBracLoc, KeyExprs);3383}33843385ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {3386ExprResult Res(ParseStringLiteralExpression());3387if (Res.isInvalid()) return Res;33883389// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string3390// expressions. At this point, we know that the only valid thing that starts3391// with '@' is an @"".3392SmallVector<SourceLocation, 4> AtLocs;3393ExprVector AtStrings;3394AtLocs.push_back(AtLoc);3395AtStrings.push_back(Res.get());33963397while (Tok.is(tok::at)) {3398AtLocs.push_back(ConsumeToken()); // eat the @.33993400// Invalid unless there is a string literal.3401if (!isTokenStringLiteral())3402return ExprError(Diag(Tok, diag::err_objc_concat_string));34033404ExprResult Lit(ParseStringLiteralExpression());3405if (Lit.isInvalid())3406return Lit;34073408AtStrings.push_back(Lit.get());3409}34103411return Actions.ObjC().ParseObjCStringLiteral(AtLocs.data(), AtStrings);3412}34133414/// ParseObjCBooleanLiteral -3415/// objc-scalar-literal : '@' boolean-keyword3416/// ;3417/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'3418/// ;3419ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,3420bool ArgValue) {3421SourceLocation EndLoc = ConsumeToken(); // consume the keyword.3422return Actions.ObjC().ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);3423}34243425/// ParseObjCCharacterLiteral -3426/// objc-scalar-literal : '@' character-literal3427/// ;3428ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {3429ExprResult Lit(Actions.ActOnCharacterConstant(Tok));3430if (Lit.isInvalid()) {3431return Lit;3432}3433ConsumeToken(); // Consume the literal token.3434return Actions.ObjC().BuildObjCNumericLiteral(AtLoc, Lit.get());3435}34363437/// ParseObjCNumericLiteral -3438/// objc-scalar-literal : '@' scalar-literal3439/// ;3440/// scalar-literal : | numeric-constant /* any numeric constant. */3441/// ;3442ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {3443ExprResult Lit(Actions.ActOnNumericConstant(Tok));3444if (Lit.isInvalid()) {3445return Lit;3446}3447ConsumeToken(); // Consume the literal token.3448return Actions.ObjC().BuildObjCNumericLiteral(AtLoc, Lit.get());3449}34503451/// ParseObjCBoxedExpr -3452/// objc-box-expression:3453/// @( assignment-expression )3454ExprResult3455Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {3456if (Tok.isNot(tok::l_paren))3457return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");34583459BalancedDelimiterTracker T(*this, tok::l_paren);3460T.consumeOpen();3461ExprResult ValueExpr(ParseAssignmentExpression());3462if (T.consumeClose())3463return ExprError();34643465if (ValueExpr.isInvalid())3466return ExprError();34673468// Wrap the sub-expression in a parenthesized expression, to distinguish3469// a boxed expression from a literal.3470SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();3471ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());3472return Actions.ObjC().BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),3473ValueExpr.get());3474}34753476ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {3477ExprVector ElementExprs; // array elements.3478ConsumeBracket(); // consume the l_square.34793480bool HasInvalidEltExpr = false;3481while (Tok.isNot(tok::r_square)) {3482// Parse list of array element expressions (all must be id types).3483ExprResult Res(ParseAssignmentExpression());3484if (Res.isInvalid()) {3485// We must manually skip to a ']', otherwise the expression skipper will3486// stop at the ']' when it skips to the ';'. We want it to skip beyond3487// the enclosing expression.3488SkipUntil(tok::r_square, StopAtSemi);3489return Res;3490}34913492Res = Actions.CorrectDelayedTyposInExpr(Res.get());3493if (Res.isInvalid())3494HasInvalidEltExpr = true;34953496// Parse the ellipsis that indicates a pack expansion.3497if (Tok.is(tok::ellipsis))3498Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());3499if (Res.isInvalid())3500HasInvalidEltExpr = true;35013502ElementExprs.push_back(Res.get());35033504if (Tok.is(tok::comma))3505ConsumeToken(); // Eat the ','.3506else if (Tok.isNot(tok::r_square))3507return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square3508<< tok::comma);3509}3510SourceLocation EndLoc = ConsumeBracket(); // location of ']'35113512if (HasInvalidEltExpr)3513return ExprError();35143515MultiExprArg Args(ElementExprs);3516return Actions.ObjC().BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);3517}35183519ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {3520SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.3521ConsumeBrace(); // consume the l_square.3522bool HasInvalidEltExpr = false;3523while (Tok.isNot(tok::r_brace)) {3524// Parse the comma separated key : value expressions.3525ExprResult KeyExpr;3526{3527ColonProtectionRAIIObject X(*this);3528KeyExpr = ParseAssignmentExpression();3529if (KeyExpr.isInvalid()) {3530// We must manually skip to a '}', otherwise the expression skipper will3531// stop at the '}' when it skips to the ';'. We want it to skip beyond3532// the enclosing expression.3533SkipUntil(tok::r_brace, StopAtSemi);3534return KeyExpr;3535}3536}35373538if (ExpectAndConsume(tok::colon)) {3539SkipUntil(tok::r_brace, StopAtSemi);3540return ExprError();3541}35423543ExprResult ValueExpr(ParseAssignmentExpression());3544if (ValueExpr.isInvalid()) {3545// We must manually skip to a '}', otherwise the expression skipper will3546// stop at the '}' when it skips to the ';'. We want it to skip beyond3547// the enclosing expression.3548SkipUntil(tok::r_brace, StopAtSemi);3549return ValueExpr;3550}35513552// Check the key and value for possible typos3553KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());3554ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());3555if (KeyExpr.isInvalid() || ValueExpr.isInvalid())3556HasInvalidEltExpr = true;35573558// Parse the ellipsis that designates this as a pack expansion. Do not3559// ActOnPackExpansion here, leave it to template instantiation time where3560// we can get better diagnostics.3561SourceLocation EllipsisLoc;3562if (getLangOpts().CPlusPlus)3563TryConsumeToken(tok::ellipsis, EllipsisLoc);35643565// We have a valid expression. Collect it in a vector so we can3566// build the argument list.3567ObjCDictionaryElement Element = {KeyExpr.get(), ValueExpr.get(),3568EllipsisLoc, std::nullopt};3569Elements.push_back(Element);35703571if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))3572return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace3573<< tok::comma);3574}3575SourceLocation EndLoc = ConsumeBrace();35763577if (HasInvalidEltExpr)3578return ExprError();35793580// Create the ObjCDictionaryLiteral.3581return Actions.ObjC().BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),3582Elements);3583}35843585/// objc-encode-expression:3586/// \@encode ( type-name )3587ExprResult3588Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {3589assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");35903591SourceLocation EncLoc = ConsumeToken();35923593if (Tok.isNot(tok::l_paren))3594return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");35953596BalancedDelimiterTracker T(*this, tok::l_paren);3597T.consumeOpen();35983599TypeResult Ty = ParseTypeName();36003601T.consumeClose();36023603if (Ty.isInvalid())3604return ExprError();36053606return Actions.ObjC().ParseObjCEncodeExpression(3607AtLoc, EncLoc, T.getOpenLocation(), Ty.get(), T.getCloseLocation());3608}36093610/// objc-protocol-expression3611/// \@protocol ( protocol-name )3612ExprResult3613Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {3614SourceLocation ProtoLoc = ConsumeToken();36153616if (Tok.isNot(tok::l_paren))3617return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");36183619BalancedDelimiterTracker T(*this, tok::l_paren);3620T.consumeOpen();36213622if (expectIdentifier())3623return ExprError();36243625IdentifierInfo *protocolId = Tok.getIdentifierInfo();3626SourceLocation ProtoIdLoc = ConsumeToken();36273628T.consumeClose();36293630return Actions.ObjC().ParseObjCProtocolExpression(3631protocolId, AtLoc, ProtoLoc, T.getOpenLocation(), ProtoIdLoc,3632T.getCloseLocation());3633}36343635/// objc-selector-expression3636/// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'3637ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {3638SourceLocation SelectorLoc = ConsumeToken();36393640if (Tok.isNot(tok::l_paren))3641return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");36423643SmallVector<const IdentifierInfo *, 12> KeyIdents;3644SourceLocation sLoc;36453646BalancedDelimiterTracker T(*this, tok::l_paren);3647T.consumeOpen();3648bool HasOptionalParen = Tok.is(tok::l_paren);3649if (HasOptionalParen)3650ConsumeParen();36513652if (Tok.is(tok::code_completion)) {3653cutOffParsing();3654Actions.CodeCompletion().CodeCompleteObjCSelector(getCurScope(), KeyIdents);3655return ExprError();3656}36573658IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);3659if (!SelIdent && // missing selector name.3660Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))3661return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);36623663KeyIdents.push_back(SelIdent);36643665unsigned nColons = 0;3666if (Tok.isNot(tok::r_paren)) {3667while (true) {3668if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.3669++nColons;3670KeyIdents.push_back(nullptr);3671} else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.3672return ExprError();3673++nColons;36743675if (Tok.is(tok::r_paren))3676break;36773678if (Tok.is(tok::code_completion)) {3679cutOffParsing();3680Actions.CodeCompletion().CodeCompleteObjCSelector(getCurScope(),3681KeyIdents);3682return ExprError();3683}36843685// Check for another keyword selector.3686SourceLocation Loc;3687SelIdent = ParseObjCSelectorPiece(Loc);3688KeyIdents.push_back(SelIdent);3689if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))3690break;3691}3692}3693if (HasOptionalParen && Tok.is(tok::r_paren))3694ConsumeParen(); // ')'3695T.consumeClose();3696Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);3697return Actions.ObjC().ParseObjCSelectorExpression(3698Sel, AtLoc, SelectorLoc, T.getOpenLocation(), T.getCloseLocation(),3699!HasOptionalParen);3700}37013702void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {3703// MCDecl might be null due to error in method or c-function prototype, etc.3704Decl *MCDecl = LM.D;3705bool skip =3706MCDecl && ((parseMethod && !Actions.ObjC().isObjCMethodDecl(MCDecl)) ||3707(!parseMethod && Actions.ObjC().isObjCMethodDecl(MCDecl)));3708if (skip)3709return;37103711// Save the current token position.3712SourceLocation OrigLoc = Tok.getLocation();37133714assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");3715// Store an artificial EOF token to ensure that we don't run off the end of3716// the method's body when we come to parse it.3717Token Eof;3718Eof.startToken();3719Eof.setKind(tok::eof);3720Eof.setEofData(MCDecl);3721Eof.setLocation(OrigLoc);3722LM.Toks.push_back(Eof);3723// Append the current token at the end of the new token stream so that it3724// doesn't get lost.3725LM.Toks.push_back(Tok);3726PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);37273728// Consume the previously pushed token.3729ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);37303731assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&3732"Inline objective-c method not starting with '{' or 'try' or ':'");3733// Enter a scope for the method or c-function body.3734ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |3735Scope::FnScope | Scope::DeclScope |3736Scope::CompoundStmtScope);3737Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);37383739// Tell the actions module that we have entered a method or c-function definition3740// with the specified Declarator for the method/function.3741if (parseMethod)3742Actions.ObjC().ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);3743else3744Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);3745if (Tok.is(tok::kw_try))3746ParseFunctionTryBlock(MCDecl, BodyScope);3747else {3748if (Tok.is(tok::colon))3749ParseConstructorInitializer(MCDecl);3750else3751Actions.ActOnDefaultCtorInitializers(MCDecl);3752ParseFunctionStatementBody(MCDecl, BodyScope);3753}37543755if (Tok.getLocation() != OrigLoc) {3756// Due to parsing error, we either went over the cached tokens or3757// there are still cached tokens left. If it's the latter case skip the3758// leftover tokens.3759// Since this is an uncommon situation that should be avoided, use the3760// expensive isBeforeInTranslationUnit call.3761if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),3762OrigLoc))3763while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))3764ConsumeAnyToken();3765}3766// Clean up the remaining EOF token, only if it's inserted by us. Otherwise3767// this might be code-completion token, which must be propagated to callers.3768if (Tok.is(tok::eof) && Tok.getEofData() == MCDecl)3769ConsumeAnyToken();3770}377137723773