1e5dd7070Spatrick //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the Objective-C portions of the Parser interface.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/AST/ASTContext.h"
14*12c85518Srobert #include "clang/AST/ODRDiagsEmitter.h"
15e5dd7070Spatrick #include "clang/AST/PrettyDeclStackTrace.h"
16e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
17ec727ea7Spatrick #include "clang/Basic/TargetInfo.h"
18e5dd7070Spatrick #include "clang/Parse/ParseDiagnostic.h"
19ec727ea7Spatrick #include "clang/Parse/Parser.h"
20e5dd7070Spatrick #include "clang/Parse/RAIIObjectsForParser.h"
21e5dd7070Spatrick #include "clang/Sema/DeclSpec.h"
22e5dd7070Spatrick #include "clang/Sema/Scope.h"
23e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
24e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
25e5dd7070Spatrick
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick
28e5dd7070Spatrick /// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
MaybeSkipAttributes(tok::ObjCKeywordKind Kind)29e5dd7070Spatrick void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
30e5dd7070Spatrick ParsedAttributes attrs(AttrFactory);
31e5dd7070Spatrick if (Tok.is(tok::kw___attribute)) {
32e5dd7070Spatrick if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
33e5dd7070Spatrick Diag(Tok, diag::err_objc_postfix_attribute_hint)
34e5dd7070Spatrick << (Kind == tok::objc_protocol);
35e5dd7070Spatrick else
36e5dd7070Spatrick Diag(Tok, diag::err_objc_postfix_attribute);
37e5dd7070Spatrick ParseGNUAttributes(attrs);
38e5dd7070Spatrick }
39e5dd7070Spatrick }
40e5dd7070Spatrick
41e5dd7070Spatrick /// ParseObjCAtDirectives - Handle parts of the external-declaration production:
42e5dd7070Spatrick /// external-declaration: [C99 6.9]
43e5dd7070Spatrick /// [OBJC] objc-class-definition
44e5dd7070Spatrick /// [OBJC] objc-class-declaration
45e5dd7070Spatrick /// [OBJC] objc-alias-declaration
46e5dd7070Spatrick /// [OBJC] objc-protocol-definition
47e5dd7070Spatrick /// [OBJC] objc-method-definition
48e5dd7070Spatrick /// [OBJC] '@' 'end'
49e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtDirectives(ParsedAttributes & DeclAttrs,ParsedAttributes & DeclSpecAttrs)50*12c85518Srobert Parser::ParseObjCAtDirectives(ParsedAttributes &DeclAttrs,
51*12c85518Srobert ParsedAttributes &DeclSpecAttrs) {
52*12c85518Srobert DeclAttrs.takeAllFrom(DeclSpecAttrs);
53*12c85518Srobert
54e5dd7070Spatrick SourceLocation AtLoc = ConsumeToken(); // the "@"
55e5dd7070Spatrick
56e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
57e5dd7070Spatrick cutOffParsing();
58a9ac8606Spatrick Actions.CodeCompleteObjCAtDirective(getCurScope());
59e5dd7070Spatrick return nullptr;
60e5dd7070Spatrick }
61e5dd7070Spatrick
62*12c85518Srobert switch (Tok.getObjCKeywordID()) {
63*12c85518Srobert case tok::objc_interface:
64*12c85518Srobert case tok::objc_protocol:
65*12c85518Srobert case tok::objc_implementation:
66*12c85518Srobert break;
67*12c85518Srobert default:
68*12c85518Srobert llvm::for_each(DeclAttrs, [this](const auto &Attr) {
69*12c85518Srobert if (Attr.isGNUAttribute())
70*12c85518Srobert Diag(Tok.getLocation(), diag::err_objc_unexpected_attr);
71*12c85518Srobert });
72*12c85518Srobert }
73*12c85518Srobert
74e5dd7070Spatrick Decl *SingleDecl = nullptr;
75e5dd7070Spatrick switch (Tok.getObjCKeywordID()) {
76e5dd7070Spatrick case tok::objc_class:
77e5dd7070Spatrick return ParseObjCAtClassDeclaration(AtLoc);
78e5dd7070Spatrick case tok::objc_interface:
79*12c85518Srobert SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DeclAttrs);
80e5dd7070Spatrick break;
81e5dd7070Spatrick case tok::objc_protocol:
82*12c85518Srobert return ParseObjCAtProtocolDeclaration(AtLoc, DeclAttrs);
83e5dd7070Spatrick case tok::objc_implementation:
84*12c85518Srobert return ParseObjCAtImplementationDeclaration(AtLoc, DeclAttrs);
85e5dd7070Spatrick case tok::objc_end:
86e5dd7070Spatrick return ParseObjCAtEndDeclaration(AtLoc);
87e5dd7070Spatrick case tok::objc_compatibility_alias:
88e5dd7070Spatrick SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
89e5dd7070Spatrick break;
90e5dd7070Spatrick case tok::objc_synthesize:
91e5dd7070Spatrick SingleDecl = ParseObjCPropertySynthesize(AtLoc);
92e5dd7070Spatrick break;
93e5dd7070Spatrick case tok::objc_dynamic:
94e5dd7070Spatrick SingleDecl = ParseObjCPropertyDynamic(AtLoc);
95e5dd7070Spatrick break;
96e5dd7070Spatrick case tok::objc_import:
97e5dd7070Spatrick if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {
98*12c85518Srobert Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;
99*12c85518Srobert SingleDecl = ParseModuleImport(AtLoc, IS);
100e5dd7070Spatrick break;
101e5dd7070Spatrick }
102e5dd7070Spatrick Diag(AtLoc, diag::err_atimport);
103e5dd7070Spatrick SkipUntil(tok::semi);
104e5dd7070Spatrick return Actions.ConvertDeclToDeclGroup(nullptr);
105e5dd7070Spatrick default:
106e5dd7070Spatrick Diag(AtLoc, diag::err_unexpected_at);
107e5dd7070Spatrick SkipUntil(tok::semi);
108e5dd7070Spatrick SingleDecl = nullptr;
109e5dd7070Spatrick break;
110e5dd7070Spatrick }
111e5dd7070Spatrick return Actions.ConvertDeclToDeclGroup(SingleDecl);
112e5dd7070Spatrick }
113e5dd7070Spatrick
114e5dd7070Spatrick /// Class to handle popping type parameters when leaving the scope.
115e5dd7070Spatrick class Parser::ObjCTypeParamListScope {
116e5dd7070Spatrick Sema &Actions;
117e5dd7070Spatrick Scope *S;
118e5dd7070Spatrick ObjCTypeParamList *Params;
119e5dd7070Spatrick
120e5dd7070Spatrick public:
ObjCTypeParamListScope(Sema & Actions,Scope * S)121e5dd7070Spatrick ObjCTypeParamListScope(Sema &Actions, Scope *S)
122e5dd7070Spatrick : Actions(Actions), S(S), Params(nullptr) {}
123e5dd7070Spatrick
~ObjCTypeParamListScope()124e5dd7070Spatrick ~ObjCTypeParamListScope() {
125e5dd7070Spatrick leave();
126e5dd7070Spatrick }
127e5dd7070Spatrick
enter(ObjCTypeParamList * P)128e5dd7070Spatrick void enter(ObjCTypeParamList *P) {
129e5dd7070Spatrick assert(!Params);
130e5dd7070Spatrick Params = P;
131e5dd7070Spatrick }
132e5dd7070Spatrick
leave()133e5dd7070Spatrick void leave() {
134e5dd7070Spatrick if (Params)
135e5dd7070Spatrick Actions.popObjCTypeParamList(S, Params);
136e5dd7070Spatrick Params = nullptr;
137e5dd7070Spatrick }
138e5dd7070Spatrick };
139e5dd7070Spatrick
140e5dd7070Spatrick ///
141e5dd7070Spatrick /// objc-class-declaration:
142e5dd7070Spatrick /// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
143e5dd7070Spatrick ///
144e5dd7070Spatrick /// objc-class-forward-decl:
145e5dd7070Spatrick /// identifier objc-type-parameter-list[opt]
146e5dd7070Spatrick ///
147e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtClassDeclaration(SourceLocation atLoc)148e5dd7070Spatrick Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
149e5dd7070Spatrick ConsumeToken(); // the identifier "class"
150e5dd7070Spatrick SmallVector<IdentifierInfo *, 8> ClassNames;
151e5dd7070Spatrick SmallVector<SourceLocation, 8> ClassLocs;
152e5dd7070Spatrick SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
153e5dd7070Spatrick
154*12c85518Srobert while (true) {
155e5dd7070Spatrick MaybeSkipAttributes(tok::objc_class);
156e5dd7070Spatrick if (expectIdentifier()) {
157e5dd7070Spatrick SkipUntil(tok::semi);
158e5dd7070Spatrick return Actions.ConvertDeclToDeclGroup(nullptr);
159e5dd7070Spatrick }
160e5dd7070Spatrick ClassNames.push_back(Tok.getIdentifierInfo());
161e5dd7070Spatrick ClassLocs.push_back(Tok.getLocation());
162e5dd7070Spatrick ConsumeToken();
163e5dd7070Spatrick
164e5dd7070Spatrick // Parse the optional objc-type-parameter-list.
165e5dd7070Spatrick ObjCTypeParamList *TypeParams = nullptr;
166e5dd7070Spatrick if (Tok.is(tok::less))
167e5dd7070Spatrick TypeParams = parseObjCTypeParamList();
168e5dd7070Spatrick ClassTypeParams.push_back(TypeParams);
169e5dd7070Spatrick if (!TryConsumeToken(tok::comma))
170e5dd7070Spatrick break;
171e5dd7070Spatrick }
172e5dd7070Spatrick
173e5dd7070Spatrick // Consume the ';'.
174e5dd7070Spatrick if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
175e5dd7070Spatrick return Actions.ConvertDeclToDeclGroup(nullptr);
176e5dd7070Spatrick
177e5dd7070Spatrick return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
178e5dd7070Spatrick ClassLocs.data(),
179e5dd7070Spatrick ClassTypeParams,
180e5dd7070Spatrick ClassNames.size());
181e5dd7070Spatrick }
182e5dd7070Spatrick
CheckNestedObjCContexts(SourceLocation AtLoc)183e5dd7070Spatrick void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
184e5dd7070Spatrick {
185e5dd7070Spatrick Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
186e5dd7070Spatrick if (ock == Sema::OCK_None)
187e5dd7070Spatrick return;
188e5dd7070Spatrick
189e5dd7070Spatrick Decl *Decl = Actions.getObjCDeclContext();
190e5dd7070Spatrick if (CurParsedObjCImpl) {
191e5dd7070Spatrick CurParsedObjCImpl->finish(AtLoc);
192e5dd7070Spatrick } else {
193e5dd7070Spatrick Actions.ActOnAtEnd(getCurScope(), AtLoc);
194e5dd7070Spatrick }
195e5dd7070Spatrick Diag(AtLoc, diag::err_objc_missing_end)
196e5dd7070Spatrick << FixItHint::CreateInsertion(AtLoc, "@end\n");
197e5dd7070Spatrick if (Decl)
198e5dd7070Spatrick Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;
199e5dd7070Spatrick }
200e5dd7070Spatrick
201e5dd7070Spatrick ///
202e5dd7070Spatrick /// objc-interface:
203e5dd7070Spatrick /// objc-class-interface-attributes[opt] objc-class-interface
204e5dd7070Spatrick /// objc-category-interface
205e5dd7070Spatrick ///
206e5dd7070Spatrick /// objc-class-interface:
207e5dd7070Spatrick /// '@' 'interface' identifier objc-type-parameter-list[opt]
208e5dd7070Spatrick /// objc-superclass[opt] objc-protocol-refs[opt]
209e5dd7070Spatrick /// objc-class-instance-variables[opt]
210e5dd7070Spatrick /// objc-interface-decl-list
211e5dd7070Spatrick /// @end
212e5dd7070Spatrick ///
213e5dd7070Spatrick /// objc-category-interface:
214e5dd7070Spatrick /// '@' 'interface' identifier objc-type-parameter-list[opt]
215e5dd7070Spatrick /// '(' identifier[opt] ')' objc-protocol-refs[opt]
216e5dd7070Spatrick /// objc-interface-decl-list
217e5dd7070Spatrick /// @end
218e5dd7070Spatrick ///
219e5dd7070Spatrick /// objc-superclass:
220e5dd7070Spatrick /// ':' identifier objc-type-arguments[opt]
221e5dd7070Spatrick ///
222e5dd7070Spatrick /// objc-class-interface-attributes:
223e5dd7070Spatrick /// __attribute__((visibility("default")))
224e5dd7070Spatrick /// __attribute__((visibility("hidden")))
225e5dd7070Spatrick /// __attribute__((deprecated))
226e5dd7070Spatrick /// __attribute__((unavailable))
227e5dd7070Spatrick /// __attribute__((objc_exception)) - used by NSException on 64-bit
228e5dd7070Spatrick /// __attribute__((objc_root_class))
229e5dd7070Spatrick ///
ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)230e5dd7070Spatrick Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
231e5dd7070Spatrick ParsedAttributes &attrs) {
232e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
233e5dd7070Spatrick "ParseObjCAtInterfaceDeclaration(): Expected @interface");
234e5dd7070Spatrick CheckNestedObjCContexts(AtLoc);
235e5dd7070Spatrick ConsumeToken(); // the "interface" identifier
236e5dd7070Spatrick
237e5dd7070Spatrick // Code completion after '@interface'.
238e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
239e5dd7070Spatrick cutOffParsing();
240a9ac8606Spatrick Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
241e5dd7070Spatrick return nullptr;
242e5dd7070Spatrick }
243e5dd7070Spatrick
244e5dd7070Spatrick MaybeSkipAttributes(tok::objc_interface);
245e5dd7070Spatrick
246e5dd7070Spatrick if (expectIdentifier())
247e5dd7070Spatrick return nullptr; // missing class or category name.
248e5dd7070Spatrick
249e5dd7070Spatrick // We have a class or category name - consume it.
250e5dd7070Spatrick IdentifierInfo *nameId = Tok.getIdentifierInfo();
251e5dd7070Spatrick SourceLocation nameLoc = ConsumeToken();
252e5dd7070Spatrick
253e5dd7070Spatrick // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
254e5dd7070Spatrick // case, LAngleLoc will be valid and ProtocolIdents will capture the
255e5dd7070Spatrick // protocol references (that have not yet been resolved).
256e5dd7070Spatrick SourceLocation LAngleLoc, EndProtoLoc;
257e5dd7070Spatrick SmallVector<IdentifierLocPair, 8> ProtocolIdents;
258e5dd7070Spatrick ObjCTypeParamList *typeParameterList = nullptr;
259e5dd7070Spatrick ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
260e5dd7070Spatrick if (Tok.is(tok::less))
261e5dd7070Spatrick typeParameterList = parseObjCTypeParamListOrProtocolRefs(
262e5dd7070Spatrick typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);
263e5dd7070Spatrick
264e5dd7070Spatrick if (Tok.is(tok::l_paren) &&
265e5dd7070Spatrick !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
266e5dd7070Spatrick
267e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
268e5dd7070Spatrick T.consumeOpen();
269e5dd7070Spatrick
270e5dd7070Spatrick SourceLocation categoryLoc;
271e5dd7070Spatrick IdentifierInfo *categoryId = nullptr;
272e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
273e5dd7070Spatrick cutOffParsing();
274a9ac8606Spatrick Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
275e5dd7070Spatrick return nullptr;
276e5dd7070Spatrick }
277e5dd7070Spatrick
278e5dd7070Spatrick // For ObjC2, the category name is optional (not an error).
279e5dd7070Spatrick if (Tok.is(tok::identifier)) {
280e5dd7070Spatrick categoryId = Tok.getIdentifierInfo();
281e5dd7070Spatrick categoryLoc = ConsumeToken();
282e5dd7070Spatrick }
283e5dd7070Spatrick else if (!getLangOpts().ObjC) {
284e5dd7070Spatrick Diag(Tok, diag::err_expected)
285e5dd7070Spatrick << tok::identifier; // missing category name.
286e5dd7070Spatrick return nullptr;
287e5dd7070Spatrick }
288e5dd7070Spatrick
289e5dd7070Spatrick T.consumeClose();
290e5dd7070Spatrick if (T.getCloseLocation().isInvalid())
291e5dd7070Spatrick return nullptr;
292e5dd7070Spatrick
293e5dd7070Spatrick // Next, we need to check for any protocol references.
294e5dd7070Spatrick assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
295e5dd7070Spatrick SmallVector<Decl *, 8> ProtocolRefs;
296e5dd7070Spatrick SmallVector<SourceLocation, 8> ProtocolLocs;
297e5dd7070Spatrick if (Tok.is(tok::less) &&
298e5dd7070Spatrick ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
299e5dd7070Spatrick LAngleLoc, EndProtoLoc,
300e5dd7070Spatrick /*consumeLastToken=*/true))
301e5dd7070Spatrick return nullptr;
302e5dd7070Spatrick
303*12c85518Srobert ObjCCategoryDecl *CategoryType = Actions.ActOnStartCategoryInterface(
304e5dd7070Spatrick AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
305e5dd7070Spatrick ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
306e5dd7070Spatrick EndProtoLoc, attrs);
307e5dd7070Spatrick
308e5dd7070Spatrick if (Tok.is(tok::l_brace))
309e5dd7070Spatrick ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
310e5dd7070Spatrick
311e5dd7070Spatrick ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
312e5dd7070Spatrick
313e5dd7070Spatrick return CategoryType;
314e5dd7070Spatrick }
315e5dd7070Spatrick // Parse a class interface.
316e5dd7070Spatrick IdentifierInfo *superClassId = nullptr;
317e5dd7070Spatrick SourceLocation superClassLoc;
318e5dd7070Spatrick SourceLocation typeArgsLAngleLoc;
319e5dd7070Spatrick SmallVector<ParsedType, 4> typeArgs;
320e5dd7070Spatrick SourceLocation typeArgsRAngleLoc;
321e5dd7070Spatrick SmallVector<Decl *, 4> protocols;
322e5dd7070Spatrick SmallVector<SourceLocation, 4> protocolLocs;
323e5dd7070Spatrick if (Tok.is(tok::colon)) { // a super class is specified.
324e5dd7070Spatrick ConsumeToken();
325e5dd7070Spatrick
326e5dd7070Spatrick // Code completion of superclass names.
327e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
328e5dd7070Spatrick cutOffParsing();
329a9ac8606Spatrick Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
330e5dd7070Spatrick return nullptr;
331e5dd7070Spatrick }
332e5dd7070Spatrick
333e5dd7070Spatrick if (expectIdentifier())
334e5dd7070Spatrick return nullptr; // missing super class name.
335e5dd7070Spatrick superClassId = Tok.getIdentifierInfo();
336e5dd7070Spatrick superClassLoc = ConsumeToken();
337e5dd7070Spatrick
338e5dd7070Spatrick // Type arguments for the superclass or protocol conformances.
339e5dd7070Spatrick if (Tok.is(tok::less)) {
340e5dd7070Spatrick parseObjCTypeArgsOrProtocolQualifiers(
341e5dd7070Spatrick nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
342e5dd7070Spatrick protocols, protocolLocs, EndProtoLoc,
343e5dd7070Spatrick /*consumeLastToken=*/true,
344e5dd7070Spatrick /*warnOnIncompleteProtocols=*/true);
345e5dd7070Spatrick if (Tok.is(tok::eof))
346e5dd7070Spatrick return nullptr;
347e5dd7070Spatrick }
348e5dd7070Spatrick }
349e5dd7070Spatrick
350e5dd7070Spatrick // Next, we need to check for any protocol references.
351e5dd7070Spatrick if (LAngleLoc.isValid()) {
352e5dd7070Spatrick if (!ProtocolIdents.empty()) {
353e5dd7070Spatrick // We already parsed the protocols named when we thought we had a
354e5dd7070Spatrick // type parameter list. Translate them into actual protocol references.
355e5dd7070Spatrick for (const auto &pair : ProtocolIdents) {
356e5dd7070Spatrick protocolLocs.push_back(pair.second);
357e5dd7070Spatrick }
358e5dd7070Spatrick Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
359e5dd7070Spatrick /*ForObjCContainer=*/true,
360e5dd7070Spatrick ProtocolIdents, protocols);
361e5dd7070Spatrick }
362e5dd7070Spatrick } else if (protocols.empty() && Tok.is(tok::less) &&
363e5dd7070Spatrick ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
364e5dd7070Spatrick LAngleLoc, EndProtoLoc,
365e5dd7070Spatrick /*consumeLastToken=*/true)) {
366e5dd7070Spatrick return nullptr;
367e5dd7070Spatrick }
368e5dd7070Spatrick
369e5dd7070Spatrick if (Tok.isNot(tok::less))
370e5dd7070Spatrick Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
371e5dd7070Spatrick superClassId, superClassLoc);
372e5dd7070Spatrick
373*12c85518Srobert Sema::SkipBodyInfo SkipBody;
374*12c85518Srobert ObjCInterfaceDecl *ClsType = Actions.ActOnStartClassInterface(
375e5dd7070Spatrick getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
376e5dd7070Spatrick superClassLoc, typeArgs,
377e5dd7070Spatrick SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
378*12c85518Srobert protocols.size(), protocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
379e5dd7070Spatrick
380e5dd7070Spatrick if (Tok.is(tok::l_brace))
381e5dd7070Spatrick ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
382e5dd7070Spatrick
383e5dd7070Spatrick ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
384e5dd7070Spatrick
385*12c85518Srobert if (SkipBody.CheckSameAsPrevious) {
386*12c85518Srobert auto *PreviousDef = cast<ObjCInterfaceDecl>(SkipBody.Previous);
387*12c85518Srobert if (Actions.ActOnDuplicateODRHashDefinition(ClsType, PreviousDef)) {
388*12c85518Srobert ClsType->mergeDuplicateDefinitionWithCommon(PreviousDef->getDefinition());
389*12c85518Srobert } else {
390*12c85518Srobert ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
391*12c85518Srobert getPreprocessor().getLangOpts());
392*12c85518Srobert DiagsEmitter.diagnoseMismatch(PreviousDef, ClsType);
393*12c85518Srobert ClsType->setInvalidDecl();
394*12c85518Srobert }
395*12c85518Srobert }
396*12c85518Srobert
397e5dd7070Spatrick return ClsType;
398e5dd7070Spatrick }
399e5dd7070Spatrick
400e5dd7070Spatrick /// Add an attribute for a context-sensitive type nullability to the given
401e5dd7070Spatrick /// declarator.
addContextSensitiveTypeNullability(Parser & P,Declarator & D,NullabilityKind nullability,SourceLocation nullabilityLoc,bool & addedToDeclSpec)402e5dd7070Spatrick static void addContextSensitiveTypeNullability(Parser &P,
403e5dd7070Spatrick Declarator &D,
404e5dd7070Spatrick NullabilityKind nullability,
405e5dd7070Spatrick SourceLocation nullabilityLoc,
406e5dd7070Spatrick bool &addedToDeclSpec) {
407e5dd7070Spatrick // Create the attribute.
408e5dd7070Spatrick auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {
409e5dd7070Spatrick return Pool.create(P.getNullabilityKeyword(nullability),
410e5dd7070Spatrick SourceRange(nullabilityLoc), nullptr, SourceLocation(),
411e5dd7070Spatrick nullptr, 0, ParsedAttr::AS_ContextSensitiveKeyword);
412e5dd7070Spatrick };
413e5dd7070Spatrick
414e5dd7070Spatrick if (D.getNumTypeObjects() > 0) {
415e5dd7070Spatrick // Add the attribute to the declarator chunk nearest the declarator.
416e5dd7070Spatrick D.getTypeObject(0).getAttrs().addAtEnd(
417e5dd7070Spatrick getNullabilityAttr(D.getAttributePool()));
418e5dd7070Spatrick } else if (!addedToDeclSpec) {
419e5dd7070Spatrick // Otherwise, just put it on the declaration specifiers (if one
420e5dd7070Spatrick // isn't there already).
421e5dd7070Spatrick D.getMutableDeclSpec().getAttributes().addAtEnd(
422e5dd7070Spatrick getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));
423e5dd7070Spatrick addedToDeclSpec = true;
424e5dd7070Spatrick }
425e5dd7070Spatrick }
426e5dd7070Spatrick
427e5dd7070Spatrick /// Parse an Objective-C type parameter list, if present, or capture
428e5dd7070Spatrick /// the locations of the protocol identifiers for a list of protocol
429e5dd7070Spatrick /// references.
430e5dd7070Spatrick ///
431e5dd7070Spatrick /// objc-type-parameter-list:
432e5dd7070Spatrick /// '<' objc-type-parameter (',' objc-type-parameter)* '>'
433e5dd7070Spatrick ///
434e5dd7070Spatrick /// objc-type-parameter:
435e5dd7070Spatrick /// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
436e5dd7070Spatrick ///
437e5dd7070Spatrick /// objc-type-parameter-bound:
438e5dd7070Spatrick /// ':' type-name
439e5dd7070Spatrick ///
440e5dd7070Spatrick /// objc-type-parameter-variance:
441e5dd7070Spatrick /// '__covariant'
442e5dd7070Spatrick /// '__contravariant'
443e5dd7070Spatrick ///
444e5dd7070Spatrick /// \param lAngleLoc The location of the starting '<'.
445e5dd7070Spatrick ///
446e5dd7070Spatrick /// \param protocolIdents Will capture the list of identifiers, if the
447e5dd7070Spatrick /// angle brackets contain a list of protocol references rather than a
448e5dd7070Spatrick /// type parameter list.
449e5dd7070Spatrick ///
450e5dd7070Spatrick /// \param rAngleLoc The location of the ending '>'.
parseObjCTypeParamListOrProtocolRefs(ObjCTypeParamListScope & Scope,SourceLocation & lAngleLoc,SmallVectorImpl<IdentifierLocPair> & protocolIdents,SourceLocation & rAngleLoc,bool mayBeProtocolList)451e5dd7070Spatrick ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
452e5dd7070Spatrick ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,
453e5dd7070Spatrick SmallVectorImpl<IdentifierLocPair> &protocolIdents,
454e5dd7070Spatrick SourceLocation &rAngleLoc, bool mayBeProtocolList) {
455e5dd7070Spatrick assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
456e5dd7070Spatrick
457e5dd7070Spatrick // Within the type parameter list, don't treat '>' as an operator.
458e5dd7070Spatrick GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
459e5dd7070Spatrick
460e5dd7070Spatrick // Local function to "flush" the protocol identifiers, turning them into
461e5dd7070Spatrick // type parameters.
462e5dd7070Spatrick SmallVector<Decl *, 4> typeParams;
463e5dd7070Spatrick auto makeProtocolIdentsIntoTypeParameters = [&]() {
464e5dd7070Spatrick unsigned index = 0;
465e5dd7070Spatrick for (const auto &pair : protocolIdents) {
466e5dd7070Spatrick DeclResult typeParam = Actions.actOnObjCTypeParam(
467e5dd7070Spatrick getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
468e5dd7070Spatrick index++, pair.first, pair.second, SourceLocation(), nullptr);
469e5dd7070Spatrick if (typeParam.isUsable())
470e5dd7070Spatrick typeParams.push_back(typeParam.get());
471e5dd7070Spatrick }
472e5dd7070Spatrick
473e5dd7070Spatrick protocolIdents.clear();
474e5dd7070Spatrick mayBeProtocolList = false;
475e5dd7070Spatrick };
476e5dd7070Spatrick
477e5dd7070Spatrick bool invalid = false;
478e5dd7070Spatrick lAngleLoc = ConsumeToken();
479e5dd7070Spatrick
480e5dd7070Spatrick do {
481e5dd7070Spatrick // Parse the variance, if any.
482e5dd7070Spatrick SourceLocation varianceLoc;
483e5dd7070Spatrick ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
484e5dd7070Spatrick if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
485e5dd7070Spatrick variance = Tok.is(tok::kw___covariant)
486e5dd7070Spatrick ? ObjCTypeParamVariance::Covariant
487e5dd7070Spatrick : ObjCTypeParamVariance::Contravariant;
488e5dd7070Spatrick varianceLoc = ConsumeToken();
489e5dd7070Spatrick
490e5dd7070Spatrick // Once we've seen a variance specific , we know this is not a
491e5dd7070Spatrick // list of protocol references.
492e5dd7070Spatrick if (mayBeProtocolList) {
493e5dd7070Spatrick // Up until now, we have been queuing up parameters because they
494e5dd7070Spatrick // might be protocol references. Turn them into parameters now.
495e5dd7070Spatrick makeProtocolIdentsIntoTypeParameters();
496e5dd7070Spatrick }
497e5dd7070Spatrick }
498e5dd7070Spatrick
499e5dd7070Spatrick // Parse the identifier.
500e5dd7070Spatrick if (!Tok.is(tok::identifier)) {
501e5dd7070Spatrick // Code completion.
502e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
503e5dd7070Spatrick // FIXME: If these aren't protocol references, we'll need different
504e5dd7070Spatrick // completions.
505e5dd7070Spatrick cutOffParsing();
506a9ac8606Spatrick Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
507e5dd7070Spatrick
508e5dd7070Spatrick // FIXME: Better recovery here?.
509e5dd7070Spatrick return nullptr;
510e5dd7070Spatrick }
511e5dd7070Spatrick
512e5dd7070Spatrick Diag(Tok, diag::err_objc_expected_type_parameter);
513e5dd7070Spatrick invalid = true;
514e5dd7070Spatrick break;
515e5dd7070Spatrick }
516e5dd7070Spatrick
517e5dd7070Spatrick IdentifierInfo *paramName = Tok.getIdentifierInfo();
518e5dd7070Spatrick SourceLocation paramLoc = ConsumeToken();
519e5dd7070Spatrick
520e5dd7070Spatrick // If there is a bound, parse it.
521e5dd7070Spatrick SourceLocation colonLoc;
522e5dd7070Spatrick TypeResult boundType;
523e5dd7070Spatrick if (TryConsumeToken(tok::colon, colonLoc)) {
524e5dd7070Spatrick // Once we've seen a bound, we know this is not a list of protocol
525e5dd7070Spatrick // references.
526e5dd7070Spatrick if (mayBeProtocolList) {
527e5dd7070Spatrick // Up until now, we have been queuing up parameters because they
528e5dd7070Spatrick // might be protocol references. Turn them into parameters now.
529e5dd7070Spatrick makeProtocolIdentsIntoTypeParameters();
530e5dd7070Spatrick }
531e5dd7070Spatrick
532e5dd7070Spatrick // type-name
533e5dd7070Spatrick boundType = ParseTypeName();
534e5dd7070Spatrick if (boundType.isInvalid())
535e5dd7070Spatrick invalid = true;
536e5dd7070Spatrick } else if (mayBeProtocolList) {
537e5dd7070Spatrick // If this could still be a protocol list, just capture the identifier.
538e5dd7070Spatrick // We don't want to turn it into a parameter.
539e5dd7070Spatrick protocolIdents.push_back(std::make_pair(paramName, paramLoc));
540e5dd7070Spatrick continue;
541e5dd7070Spatrick }
542e5dd7070Spatrick
543e5dd7070Spatrick // Create the type parameter.
544e5dd7070Spatrick DeclResult typeParam = Actions.actOnObjCTypeParam(
545e5dd7070Spatrick getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
546e5dd7070Spatrick paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
547e5dd7070Spatrick if (typeParam.isUsable())
548e5dd7070Spatrick typeParams.push_back(typeParam.get());
549e5dd7070Spatrick } while (TryConsumeToken(tok::comma));
550e5dd7070Spatrick
551e5dd7070Spatrick // Parse the '>'.
552e5dd7070Spatrick if (invalid) {
553e5dd7070Spatrick SkipUntil(tok::greater, tok::at, StopBeforeMatch);
554e5dd7070Spatrick if (Tok.is(tok::greater))
555e5dd7070Spatrick ConsumeToken();
556ec727ea7Spatrick } else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc,
557e5dd7070Spatrick /*ConsumeLastToken=*/true,
558e5dd7070Spatrick /*ObjCGenericList=*/true)) {
559e5dd7070Spatrick SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
560e5dd7070Spatrick tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
561e5dd7070Spatrick tok::comma, tok::semi },
562e5dd7070Spatrick StopBeforeMatch);
563e5dd7070Spatrick if (Tok.is(tok::greater))
564e5dd7070Spatrick ConsumeToken();
565e5dd7070Spatrick }
566e5dd7070Spatrick
567e5dd7070Spatrick if (mayBeProtocolList) {
568e5dd7070Spatrick // A type parameter list must be followed by either a ':' (indicating the
569e5dd7070Spatrick // presence of a superclass) or a '(' (indicating that this is a category
570e5dd7070Spatrick // or extension). This disambiguates between an objc-type-parameter-list
571e5dd7070Spatrick // and a objc-protocol-refs.
572e5dd7070Spatrick if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
573e5dd7070Spatrick // Returning null indicates that we don't have a type parameter list.
574e5dd7070Spatrick // The results the caller needs to handle the protocol references are
575e5dd7070Spatrick // captured in the reference parameters already.
576e5dd7070Spatrick return nullptr;
577e5dd7070Spatrick }
578e5dd7070Spatrick
579e5dd7070Spatrick // We have a type parameter list that looks like a list of protocol
580e5dd7070Spatrick // references. Turn that parameter list into type parameters.
581e5dd7070Spatrick makeProtocolIdentsIntoTypeParameters();
582e5dd7070Spatrick }
583e5dd7070Spatrick
584e5dd7070Spatrick // Form the type parameter list and enter its scope.
585e5dd7070Spatrick ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
586e5dd7070Spatrick getCurScope(),
587e5dd7070Spatrick lAngleLoc,
588e5dd7070Spatrick typeParams,
589e5dd7070Spatrick rAngleLoc);
590e5dd7070Spatrick Scope.enter(list);
591e5dd7070Spatrick
592e5dd7070Spatrick // Clear out the angle locations; they're used by the caller to indicate
593e5dd7070Spatrick // whether there are any protocol references.
594e5dd7070Spatrick lAngleLoc = SourceLocation();
595e5dd7070Spatrick rAngleLoc = SourceLocation();
596e5dd7070Spatrick return invalid ? nullptr : list;
597e5dd7070Spatrick }
598e5dd7070Spatrick
599e5dd7070Spatrick /// Parse an objc-type-parameter-list.
parseObjCTypeParamList()600e5dd7070Spatrick ObjCTypeParamList *Parser::parseObjCTypeParamList() {
601e5dd7070Spatrick SourceLocation lAngleLoc;
602e5dd7070Spatrick SmallVector<IdentifierLocPair, 1> protocolIdents;
603e5dd7070Spatrick SourceLocation rAngleLoc;
604e5dd7070Spatrick
605e5dd7070Spatrick ObjCTypeParamListScope Scope(Actions, getCurScope());
606e5dd7070Spatrick return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,
607e5dd7070Spatrick rAngleLoc,
608e5dd7070Spatrick /*mayBeProtocolList=*/false);
609e5dd7070Spatrick }
610e5dd7070Spatrick
611e5dd7070Spatrick /// objc-interface-decl-list:
612e5dd7070Spatrick /// empty
613e5dd7070Spatrick /// objc-interface-decl-list objc-property-decl [OBJC2]
614e5dd7070Spatrick /// objc-interface-decl-list objc-method-requirement [OBJC2]
615e5dd7070Spatrick /// objc-interface-decl-list objc-method-proto ';'
616e5dd7070Spatrick /// objc-interface-decl-list declaration
617e5dd7070Spatrick /// objc-interface-decl-list ';'
618e5dd7070Spatrick ///
619e5dd7070Spatrick /// objc-method-requirement: [OBJC2]
620e5dd7070Spatrick /// @required
621e5dd7070Spatrick /// @optional
622e5dd7070Spatrick ///
ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,Decl * CDecl)623e5dd7070Spatrick void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
624e5dd7070Spatrick Decl *CDecl) {
625e5dd7070Spatrick SmallVector<Decl *, 32> allMethods;
626e5dd7070Spatrick SmallVector<DeclGroupPtrTy, 8> allTUVariables;
627e5dd7070Spatrick tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
628e5dd7070Spatrick
629e5dd7070Spatrick SourceRange AtEnd;
630e5dd7070Spatrick
631*12c85518Srobert while (true) {
632e5dd7070Spatrick // If this is a method prototype, parse it.
633e5dd7070Spatrick if (Tok.isOneOf(tok::minus, tok::plus)) {
634e5dd7070Spatrick if (Decl *methodPrototype =
635e5dd7070Spatrick ParseObjCMethodPrototype(MethodImplKind, false))
636e5dd7070Spatrick allMethods.push_back(methodPrototype);
637e5dd7070Spatrick // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
638e5dd7070Spatrick // method definitions.
639e5dd7070Spatrick if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
640e5dd7070Spatrick // We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
641e5dd7070Spatrick SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
642e5dd7070Spatrick if (Tok.is(tok::semi))
643e5dd7070Spatrick ConsumeToken();
644e5dd7070Spatrick }
645e5dd7070Spatrick continue;
646e5dd7070Spatrick }
647e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
648e5dd7070Spatrick Diag(Tok, diag::err_expected_minus_or_plus);
649e5dd7070Spatrick ParseObjCMethodDecl(Tok.getLocation(),
650e5dd7070Spatrick tok::minus,
651e5dd7070Spatrick MethodImplKind, false);
652e5dd7070Spatrick continue;
653e5dd7070Spatrick }
654e5dd7070Spatrick // Ignore excess semicolons.
655e5dd7070Spatrick if (Tok.is(tok::semi)) {
656e5dd7070Spatrick // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,
657e5dd7070Spatrick // to make -Wextra-semi diagnose them.
658e5dd7070Spatrick ConsumeToken();
659e5dd7070Spatrick continue;
660e5dd7070Spatrick }
661e5dd7070Spatrick
662e5dd7070Spatrick // If we got to the end of the file, exit the loop.
663e5dd7070Spatrick if (isEofOrEom())
664e5dd7070Spatrick break;
665e5dd7070Spatrick
666e5dd7070Spatrick // Code completion within an Objective-C interface.
667e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
668a9ac8606Spatrick cutOffParsing();
669e5dd7070Spatrick Actions.CodeCompleteOrdinaryName(getCurScope(),
670e5dd7070Spatrick CurParsedObjCImpl? Sema::PCC_ObjCImplementation
671e5dd7070Spatrick : Sema::PCC_ObjCInterface);
672a9ac8606Spatrick return;
673e5dd7070Spatrick }
674e5dd7070Spatrick
675e5dd7070Spatrick // If we don't have an @ directive, parse it as a function definition.
676e5dd7070Spatrick if (Tok.isNot(tok::at)) {
677e5dd7070Spatrick // The code below does not consume '}'s because it is afraid of eating the
678e5dd7070Spatrick // end of a namespace. Because of the way this code is structured, an
679e5dd7070Spatrick // erroneous r_brace would cause an infinite loop if not handled here.
680e5dd7070Spatrick if (Tok.is(tok::r_brace))
681e5dd7070Spatrick break;
682e5dd7070Spatrick
683*12c85518Srobert ParsedAttributes EmptyDeclAttrs(AttrFactory);
684*12c85518Srobert ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
685e5dd7070Spatrick
686e5dd7070Spatrick // Since we call ParseDeclarationOrFunctionDefinition() instead of
687e5dd7070Spatrick // ParseExternalDeclaration() below (so that this doesn't parse nested
688e5dd7070Spatrick // @interfaces), this needs to duplicate some code from the latter.
689e5dd7070Spatrick if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
690e5dd7070Spatrick SourceLocation DeclEnd;
691*12c85518Srobert ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
692*12c85518Srobert allTUVariables.push_back(ParseDeclaration(DeclaratorContext::File,
693*12c85518Srobert DeclEnd, EmptyDeclAttrs,
694*12c85518Srobert EmptyDeclSpecAttrs));
695e5dd7070Spatrick continue;
696e5dd7070Spatrick }
697e5dd7070Spatrick
698*12c85518Srobert allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(
699*12c85518Srobert EmptyDeclAttrs, EmptyDeclSpecAttrs));
700e5dd7070Spatrick continue;
701e5dd7070Spatrick }
702e5dd7070Spatrick
703e5dd7070Spatrick // Otherwise, we have an @ directive, eat the @.
704e5dd7070Spatrick SourceLocation AtLoc = ConsumeToken(); // the "@"
705e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
706a9ac8606Spatrick cutOffParsing();
707e5dd7070Spatrick Actions.CodeCompleteObjCAtDirective(getCurScope());
708a9ac8606Spatrick return;
709e5dd7070Spatrick }
710e5dd7070Spatrick
711e5dd7070Spatrick tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
712e5dd7070Spatrick
713e5dd7070Spatrick if (DirectiveKind == tok::objc_end) { // @end -> terminate list
714e5dd7070Spatrick AtEnd.setBegin(AtLoc);
715e5dd7070Spatrick AtEnd.setEnd(Tok.getLocation());
716e5dd7070Spatrick break;
717e5dd7070Spatrick } else if (DirectiveKind == tok::objc_not_keyword) {
718e5dd7070Spatrick Diag(Tok, diag::err_objc_unknown_at);
719e5dd7070Spatrick SkipUntil(tok::semi);
720e5dd7070Spatrick continue;
721e5dd7070Spatrick }
722e5dd7070Spatrick
723e5dd7070Spatrick // Eat the identifier.
724e5dd7070Spatrick ConsumeToken();
725e5dd7070Spatrick
726e5dd7070Spatrick switch (DirectiveKind) {
727e5dd7070Spatrick default:
728e5dd7070Spatrick // FIXME: If someone forgets an @end on a protocol, this loop will
729e5dd7070Spatrick // continue to eat up tons of stuff and spew lots of nonsense errors. It
730e5dd7070Spatrick // would probably be better to bail out if we saw an @class or @interface
731e5dd7070Spatrick // or something like that.
732e5dd7070Spatrick Diag(AtLoc, diag::err_objc_illegal_interface_qual);
733e5dd7070Spatrick // Skip until we see an '@' or '}' or ';'.
734e5dd7070Spatrick SkipUntil(tok::r_brace, tok::at, StopAtSemi);
735e5dd7070Spatrick break;
736e5dd7070Spatrick
737e5dd7070Spatrick case tok::objc_implementation:
738e5dd7070Spatrick case tok::objc_interface:
739e5dd7070Spatrick Diag(AtLoc, diag::err_objc_missing_end)
740e5dd7070Spatrick << FixItHint::CreateInsertion(AtLoc, "@end\n");
741e5dd7070Spatrick Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
742e5dd7070Spatrick << (int)Actions.getObjCContainerKind();
743e5dd7070Spatrick ConsumeToken();
744e5dd7070Spatrick break;
745e5dd7070Spatrick
746e5dd7070Spatrick case tok::objc_required:
747e5dd7070Spatrick case tok::objc_optional:
748e5dd7070Spatrick // This is only valid on protocols.
749e5dd7070Spatrick if (contextKey != tok::objc_protocol)
750e5dd7070Spatrick Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
751e5dd7070Spatrick else
752e5dd7070Spatrick MethodImplKind = DirectiveKind;
753e5dd7070Spatrick break;
754e5dd7070Spatrick
755e5dd7070Spatrick case tok::objc_property:
756e5dd7070Spatrick ObjCDeclSpec OCDS;
757e5dd7070Spatrick SourceLocation LParenLoc;
758e5dd7070Spatrick // Parse property attribute list, if any.
759e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
760e5dd7070Spatrick LParenLoc = Tok.getLocation();
761e5dd7070Spatrick ParseObjCPropertyAttribute(OCDS);
762e5dd7070Spatrick }
763e5dd7070Spatrick
764e5dd7070Spatrick bool addedToDeclSpec = false;
765e5dd7070Spatrick auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
766e5dd7070Spatrick if (FD.D.getIdentifier() == nullptr) {
767e5dd7070Spatrick Diag(AtLoc, diag::err_objc_property_requires_field_name)
768e5dd7070Spatrick << FD.D.getSourceRange();
769e5dd7070Spatrick return;
770e5dd7070Spatrick }
771e5dd7070Spatrick if (FD.BitfieldSize) {
772e5dd7070Spatrick Diag(AtLoc, diag::err_objc_property_bitfield)
773e5dd7070Spatrick << FD.D.getSourceRange();
774e5dd7070Spatrick return;
775e5dd7070Spatrick }
776e5dd7070Spatrick
777e5dd7070Spatrick // Map a nullability property attribute to a context-sensitive keyword
778e5dd7070Spatrick // attribute.
779ec727ea7Spatrick if (OCDS.getPropertyAttributes() &
780ec727ea7Spatrick ObjCPropertyAttribute::kind_nullability)
781e5dd7070Spatrick addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
782e5dd7070Spatrick OCDS.getNullabilityLoc(),
783e5dd7070Spatrick addedToDeclSpec);
784e5dd7070Spatrick
785e5dd7070Spatrick // Install the property declarator into interfaceDecl.
786e5dd7070Spatrick IdentifierInfo *SelName =
787e5dd7070Spatrick OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
788e5dd7070Spatrick
789e5dd7070Spatrick Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
790e5dd7070Spatrick IdentifierInfo *SetterName = OCDS.getSetterName();
791e5dd7070Spatrick Selector SetterSel;
792e5dd7070Spatrick if (SetterName)
793e5dd7070Spatrick SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
794e5dd7070Spatrick else
795e5dd7070Spatrick SetterSel = SelectorTable::constructSetterSelector(
796e5dd7070Spatrick PP.getIdentifierTable(), PP.getSelectorTable(),
797e5dd7070Spatrick FD.D.getIdentifier());
798e5dd7070Spatrick Decl *Property = Actions.ActOnProperty(
799e5dd7070Spatrick getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
800e5dd7070Spatrick MethodImplKind);
801e5dd7070Spatrick
802e5dd7070Spatrick FD.complete(Property);
803e5dd7070Spatrick };
804e5dd7070Spatrick
805e5dd7070Spatrick // Parse all the comma separated declarators.
806e5dd7070Spatrick ParsingDeclSpec DS(*this);
807e5dd7070Spatrick ParseStructDeclaration(DS, ObjCPropertyCallback);
808e5dd7070Spatrick
809e5dd7070Spatrick ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
810e5dd7070Spatrick break;
811e5dd7070Spatrick }
812e5dd7070Spatrick }
813e5dd7070Spatrick
814e5dd7070Spatrick // We break out of the big loop in two cases: when we see @end or when we see
815e5dd7070Spatrick // EOF. In the former case, eat the @end. In the later case, emit an error.
816e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
817a9ac8606Spatrick cutOffParsing();
818e5dd7070Spatrick Actions.CodeCompleteObjCAtDirective(getCurScope());
819a9ac8606Spatrick return;
820e5dd7070Spatrick } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
821e5dd7070Spatrick ConsumeToken(); // the "end" identifier
822e5dd7070Spatrick } else {
823e5dd7070Spatrick Diag(Tok, diag::err_objc_missing_end)
824e5dd7070Spatrick << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
825e5dd7070Spatrick Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
826e5dd7070Spatrick << (int)Actions.getObjCContainerKind();
827e5dd7070Spatrick AtEnd.setBegin(Tok.getLocation());
828e5dd7070Spatrick AtEnd.setEnd(Tok.getLocation());
829e5dd7070Spatrick }
830e5dd7070Spatrick
831e5dd7070Spatrick // Insert collected methods declarations into the @interface object.
832e5dd7070Spatrick // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
833e5dd7070Spatrick Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
834e5dd7070Spatrick }
835e5dd7070Spatrick
836e5dd7070Spatrick /// Diagnose redundant or conflicting nullability information.
diagnoseRedundantPropertyNullability(Parser & P,ObjCDeclSpec & DS,NullabilityKind nullability,SourceLocation nullabilityLoc)837e5dd7070Spatrick static void diagnoseRedundantPropertyNullability(Parser &P,
838e5dd7070Spatrick ObjCDeclSpec &DS,
839e5dd7070Spatrick NullabilityKind nullability,
840e5dd7070Spatrick SourceLocation nullabilityLoc){
841e5dd7070Spatrick if (DS.getNullability() == nullability) {
842e5dd7070Spatrick P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
843e5dd7070Spatrick << DiagNullabilityKind(nullability, true)
844e5dd7070Spatrick << SourceRange(DS.getNullabilityLoc());
845e5dd7070Spatrick return;
846e5dd7070Spatrick }
847e5dd7070Spatrick
848e5dd7070Spatrick P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
849e5dd7070Spatrick << DiagNullabilityKind(nullability, true)
850e5dd7070Spatrick << DiagNullabilityKind(DS.getNullability(), true)
851e5dd7070Spatrick << SourceRange(DS.getNullabilityLoc());
852e5dd7070Spatrick }
853e5dd7070Spatrick
854e5dd7070Spatrick /// Parse property attribute declarations.
855e5dd7070Spatrick ///
856e5dd7070Spatrick /// property-attr-decl: '(' property-attrlist ')'
857e5dd7070Spatrick /// property-attrlist:
858e5dd7070Spatrick /// property-attribute
859e5dd7070Spatrick /// property-attrlist ',' property-attribute
860e5dd7070Spatrick /// property-attribute:
861e5dd7070Spatrick /// getter '=' identifier
862e5dd7070Spatrick /// setter '=' identifier ':'
863e5dd7070Spatrick /// direct
864e5dd7070Spatrick /// readonly
865e5dd7070Spatrick /// readwrite
866e5dd7070Spatrick /// assign
867e5dd7070Spatrick /// retain
868e5dd7070Spatrick /// copy
869e5dd7070Spatrick /// nonatomic
870e5dd7070Spatrick /// atomic
871e5dd7070Spatrick /// strong
872e5dd7070Spatrick /// weak
873e5dd7070Spatrick /// unsafe_unretained
874e5dd7070Spatrick /// nonnull
875e5dd7070Spatrick /// nullable
876e5dd7070Spatrick /// null_unspecified
877e5dd7070Spatrick /// null_resettable
878e5dd7070Spatrick /// class
879e5dd7070Spatrick ///
ParseObjCPropertyAttribute(ObjCDeclSpec & DS)880e5dd7070Spatrick void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
881e5dd7070Spatrick assert(Tok.getKind() == tok::l_paren);
882e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
883e5dd7070Spatrick T.consumeOpen();
884e5dd7070Spatrick
885*12c85518Srobert while (true) {
886e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
887a9ac8606Spatrick cutOffParsing();
888e5dd7070Spatrick Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
889a9ac8606Spatrick return;
890e5dd7070Spatrick }
891e5dd7070Spatrick const IdentifierInfo *II = Tok.getIdentifierInfo();
892e5dd7070Spatrick
893e5dd7070Spatrick // If this is not an identifier at all, bail out early.
894e5dd7070Spatrick if (!II) {
895e5dd7070Spatrick T.consumeClose();
896e5dd7070Spatrick return;
897e5dd7070Spatrick }
898e5dd7070Spatrick
899e5dd7070Spatrick SourceLocation AttrName = ConsumeToken(); // consume last attribute name
900e5dd7070Spatrick
901e5dd7070Spatrick if (II->isStr("readonly"))
902ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
903e5dd7070Spatrick else if (II->isStr("assign"))
904ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
905e5dd7070Spatrick else if (II->isStr("unsafe_unretained"))
906ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
907e5dd7070Spatrick else if (II->isStr("readwrite"))
908ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
909e5dd7070Spatrick else if (II->isStr("retain"))
910ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
911e5dd7070Spatrick else if (II->isStr("strong"))
912ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
913e5dd7070Spatrick else if (II->isStr("copy"))
914ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
915e5dd7070Spatrick else if (II->isStr("nonatomic"))
916ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
917e5dd7070Spatrick else if (II->isStr("atomic"))
918ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
919e5dd7070Spatrick else if (II->isStr("weak"))
920ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
921e5dd7070Spatrick else if (II->isStr("getter") || II->isStr("setter")) {
922e5dd7070Spatrick bool IsSetter = II->getNameStart()[0] == 's';
923e5dd7070Spatrick
924e5dd7070Spatrick // getter/setter require extra treatment.
925e5dd7070Spatrick unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
926e5dd7070Spatrick diag::err_objc_expected_equal_for_getter;
927e5dd7070Spatrick
928e5dd7070Spatrick if (ExpectAndConsume(tok::equal, DiagID)) {
929e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
930e5dd7070Spatrick return;
931e5dd7070Spatrick }
932e5dd7070Spatrick
933e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
934a9ac8606Spatrick cutOffParsing();
935e5dd7070Spatrick if (IsSetter)
936e5dd7070Spatrick Actions.CodeCompleteObjCPropertySetter(getCurScope());
937e5dd7070Spatrick else
938e5dd7070Spatrick Actions.CodeCompleteObjCPropertyGetter(getCurScope());
939a9ac8606Spatrick return;
940e5dd7070Spatrick }
941e5dd7070Spatrick
942e5dd7070Spatrick SourceLocation SelLoc;
943e5dd7070Spatrick IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
944e5dd7070Spatrick
945e5dd7070Spatrick if (!SelIdent) {
946e5dd7070Spatrick Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
947e5dd7070Spatrick << IsSetter;
948e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
949e5dd7070Spatrick return;
950e5dd7070Spatrick }
951e5dd7070Spatrick
952e5dd7070Spatrick if (IsSetter) {
953ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
954e5dd7070Spatrick DS.setSetterName(SelIdent, SelLoc);
955e5dd7070Spatrick
956e5dd7070Spatrick if (ExpectAndConsume(tok::colon,
957e5dd7070Spatrick diag::err_expected_colon_after_setter_name)) {
958e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
959e5dd7070Spatrick return;
960e5dd7070Spatrick }
961e5dd7070Spatrick } else {
962ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
963e5dd7070Spatrick DS.setGetterName(SelIdent, SelLoc);
964e5dd7070Spatrick }
965e5dd7070Spatrick } else if (II->isStr("nonnull")) {
966ec727ea7Spatrick if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
967e5dd7070Spatrick diagnoseRedundantPropertyNullability(*this, DS,
968e5dd7070Spatrick NullabilityKind::NonNull,
969e5dd7070Spatrick Tok.getLocation());
970ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
971e5dd7070Spatrick DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
972e5dd7070Spatrick } else if (II->isStr("nullable")) {
973ec727ea7Spatrick if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
974e5dd7070Spatrick diagnoseRedundantPropertyNullability(*this, DS,
975e5dd7070Spatrick NullabilityKind::Nullable,
976e5dd7070Spatrick Tok.getLocation());
977ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
978e5dd7070Spatrick DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
979e5dd7070Spatrick } else if (II->isStr("null_unspecified")) {
980ec727ea7Spatrick if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
981e5dd7070Spatrick diagnoseRedundantPropertyNullability(*this, DS,
982e5dd7070Spatrick NullabilityKind::Unspecified,
983e5dd7070Spatrick Tok.getLocation());
984ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
985e5dd7070Spatrick DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
986e5dd7070Spatrick } else if (II->isStr("null_resettable")) {
987ec727ea7Spatrick if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
988e5dd7070Spatrick diagnoseRedundantPropertyNullability(*this, DS,
989e5dd7070Spatrick NullabilityKind::Unspecified,
990e5dd7070Spatrick Tok.getLocation());
991ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
992e5dd7070Spatrick DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
993e5dd7070Spatrick
994e5dd7070Spatrick // Also set the null_resettable bit.
995ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
996e5dd7070Spatrick } else if (II->isStr("class")) {
997ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_class);
998e5dd7070Spatrick } else if (II->isStr("direct")) {
999ec727ea7Spatrick DS.setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
1000e5dd7070Spatrick } else {
1001e5dd7070Spatrick Diag(AttrName, diag::err_objc_expected_property_attr) << II;
1002e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
1003e5dd7070Spatrick return;
1004e5dd7070Spatrick }
1005e5dd7070Spatrick
1006e5dd7070Spatrick if (Tok.isNot(tok::comma))
1007e5dd7070Spatrick break;
1008e5dd7070Spatrick
1009e5dd7070Spatrick ConsumeToken();
1010e5dd7070Spatrick }
1011e5dd7070Spatrick
1012e5dd7070Spatrick T.consumeClose();
1013e5dd7070Spatrick }
1014e5dd7070Spatrick
1015e5dd7070Spatrick /// objc-method-proto:
1016e5dd7070Spatrick /// objc-instance-method objc-method-decl objc-method-attributes[opt]
1017e5dd7070Spatrick /// objc-class-method objc-method-decl objc-method-attributes[opt]
1018e5dd7070Spatrick ///
1019e5dd7070Spatrick /// objc-instance-method: '-'
1020e5dd7070Spatrick /// objc-class-method: '+'
1021e5dd7070Spatrick ///
1022e5dd7070Spatrick /// objc-method-attributes: [OBJC2]
1023e5dd7070Spatrick /// __attribute__((deprecated))
1024e5dd7070Spatrick ///
ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)1025e5dd7070Spatrick Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
1026e5dd7070Spatrick bool MethodDefinition) {
1027e5dd7070Spatrick assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
1028e5dd7070Spatrick
1029e5dd7070Spatrick tok::TokenKind methodType = Tok.getKind();
1030e5dd7070Spatrick SourceLocation mLoc = ConsumeToken();
1031e5dd7070Spatrick Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
1032e5dd7070Spatrick MethodDefinition);
1033e5dd7070Spatrick // Since this rule is used for both method declarations and definitions,
1034e5dd7070Spatrick // the caller is (optionally) responsible for consuming the ';'.
1035e5dd7070Spatrick return MDecl;
1036e5dd7070Spatrick }
1037e5dd7070Spatrick
1038e5dd7070Spatrick /// objc-selector:
1039e5dd7070Spatrick /// identifier
1040e5dd7070Spatrick /// one of
1041e5dd7070Spatrick /// enum struct union if else while do for switch case default
1042e5dd7070Spatrick /// break continue return goto asm sizeof typeof __alignof
1043e5dd7070Spatrick /// unsigned long const short volatile signed restrict _Complex
1044e5dd7070Spatrick /// in out inout bycopy byref oneway int char float double void _Bool
1045e5dd7070Spatrick ///
ParseObjCSelectorPiece(SourceLocation & SelectorLoc)1046e5dd7070Spatrick IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
1047e5dd7070Spatrick
1048e5dd7070Spatrick switch (Tok.getKind()) {
1049e5dd7070Spatrick default:
1050e5dd7070Spatrick return nullptr;
1051e5dd7070Spatrick case tok::colon:
1052e5dd7070Spatrick // Empty selector piece uses the location of the ':'.
1053e5dd7070Spatrick SelectorLoc = Tok.getLocation();
1054e5dd7070Spatrick return nullptr;
1055e5dd7070Spatrick case tok::ampamp:
1056e5dd7070Spatrick case tok::ampequal:
1057e5dd7070Spatrick case tok::amp:
1058e5dd7070Spatrick case tok::pipe:
1059e5dd7070Spatrick case tok::tilde:
1060e5dd7070Spatrick case tok::exclaim:
1061e5dd7070Spatrick case tok::exclaimequal:
1062e5dd7070Spatrick case tok::pipepipe:
1063e5dd7070Spatrick case tok::pipeequal:
1064e5dd7070Spatrick case tok::caret:
1065e5dd7070Spatrick case tok::caretequal: {
1066e5dd7070Spatrick std::string ThisTok(PP.getSpelling(Tok));
1067e5dd7070Spatrick if (isLetter(ThisTok[0])) {
1068e5dd7070Spatrick IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);
1069e5dd7070Spatrick Tok.setKind(tok::identifier);
1070e5dd7070Spatrick SelectorLoc = ConsumeToken();
1071e5dd7070Spatrick return II;
1072e5dd7070Spatrick }
1073e5dd7070Spatrick return nullptr;
1074e5dd7070Spatrick }
1075e5dd7070Spatrick
1076e5dd7070Spatrick case tok::identifier:
1077e5dd7070Spatrick case tok::kw_asm:
1078e5dd7070Spatrick case tok::kw_auto:
1079e5dd7070Spatrick case tok::kw_bool:
1080e5dd7070Spatrick case tok::kw_break:
1081e5dd7070Spatrick case tok::kw_case:
1082e5dd7070Spatrick case tok::kw_catch:
1083e5dd7070Spatrick case tok::kw_char:
1084e5dd7070Spatrick case tok::kw_class:
1085e5dd7070Spatrick case tok::kw_const:
1086e5dd7070Spatrick case tok::kw_const_cast:
1087e5dd7070Spatrick case tok::kw_continue:
1088e5dd7070Spatrick case tok::kw_default:
1089e5dd7070Spatrick case tok::kw_delete:
1090e5dd7070Spatrick case tok::kw_do:
1091e5dd7070Spatrick case tok::kw_double:
1092e5dd7070Spatrick case tok::kw_dynamic_cast:
1093e5dd7070Spatrick case tok::kw_else:
1094e5dd7070Spatrick case tok::kw_enum:
1095e5dd7070Spatrick case tok::kw_explicit:
1096e5dd7070Spatrick case tok::kw_export:
1097e5dd7070Spatrick case tok::kw_extern:
1098e5dd7070Spatrick case tok::kw_false:
1099e5dd7070Spatrick case tok::kw_float:
1100e5dd7070Spatrick case tok::kw_for:
1101e5dd7070Spatrick case tok::kw_friend:
1102e5dd7070Spatrick case tok::kw_goto:
1103e5dd7070Spatrick case tok::kw_if:
1104e5dd7070Spatrick case tok::kw_inline:
1105e5dd7070Spatrick case tok::kw_int:
1106e5dd7070Spatrick case tok::kw_long:
1107e5dd7070Spatrick case tok::kw_mutable:
1108e5dd7070Spatrick case tok::kw_namespace:
1109e5dd7070Spatrick case tok::kw_new:
1110e5dd7070Spatrick case tok::kw_operator:
1111e5dd7070Spatrick case tok::kw_private:
1112e5dd7070Spatrick case tok::kw_protected:
1113e5dd7070Spatrick case tok::kw_public:
1114e5dd7070Spatrick case tok::kw_register:
1115e5dd7070Spatrick case tok::kw_reinterpret_cast:
1116e5dd7070Spatrick case tok::kw_restrict:
1117e5dd7070Spatrick case tok::kw_return:
1118e5dd7070Spatrick case tok::kw_short:
1119e5dd7070Spatrick case tok::kw_signed:
1120e5dd7070Spatrick case tok::kw_sizeof:
1121e5dd7070Spatrick case tok::kw_static:
1122e5dd7070Spatrick case tok::kw_static_cast:
1123e5dd7070Spatrick case tok::kw_struct:
1124e5dd7070Spatrick case tok::kw_switch:
1125e5dd7070Spatrick case tok::kw_template:
1126e5dd7070Spatrick case tok::kw_this:
1127e5dd7070Spatrick case tok::kw_throw:
1128e5dd7070Spatrick case tok::kw_true:
1129e5dd7070Spatrick case tok::kw_try:
1130e5dd7070Spatrick case tok::kw_typedef:
1131e5dd7070Spatrick case tok::kw_typeid:
1132e5dd7070Spatrick case tok::kw_typename:
1133e5dd7070Spatrick case tok::kw_typeof:
1134e5dd7070Spatrick case tok::kw_union:
1135e5dd7070Spatrick case tok::kw_unsigned:
1136e5dd7070Spatrick case tok::kw_using:
1137e5dd7070Spatrick case tok::kw_virtual:
1138e5dd7070Spatrick case tok::kw_void:
1139e5dd7070Spatrick case tok::kw_volatile:
1140e5dd7070Spatrick case tok::kw_wchar_t:
1141e5dd7070Spatrick case tok::kw_while:
1142e5dd7070Spatrick case tok::kw__Bool:
1143e5dd7070Spatrick case tok::kw__Complex:
1144e5dd7070Spatrick case tok::kw___alignof:
1145e5dd7070Spatrick case tok::kw___auto_type:
1146e5dd7070Spatrick IdentifierInfo *II = Tok.getIdentifierInfo();
1147e5dd7070Spatrick SelectorLoc = ConsumeToken();
1148e5dd7070Spatrick return II;
1149e5dd7070Spatrick }
1150e5dd7070Spatrick }
1151e5dd7070Spatrick
1152e5dd7070Spatrick /// objc-for-collection-in: 'in'
1153e5dd7070Spatrick ///
isTokIdentifier_in() const1154e5dd7070Spatrick bool Parser::isTokIdentifier_in() const {
1155e5dd7070Spatrick // FIXME: May have to do additional look-ahead to only allow for
1156e5dd7070Spatrick // valid tokens following an 'in'; such as an identifier, unary operators,
1157e5dd7070Spatrick // '[' etc.
1158e5dd7070Spatrick return (getLangOpts().ObjC && Tok.is(tok::identifier) &&
1159e5dd7070Spatrick Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
1160e5dd7070Spatrick }
1161e5dd7070Spatrick
1162e5dd7070Spatrick /// ParseObjCTypeQualifierList - This routine parses the objective-c's type
1163e5dd7070Spatrick /// qualifier list and builds their bitmask representation in the input
1164e5dd7070Spatrick /// argument.
1165e5dd7070Spatrick ///
1166e5dd7070Spatrick /// objc-type-qualifiers:
1167e5dd7070Spatrick /// objc-type-qualifier
1168e5dd7070Spatrick /// objc-type-qualifiers objc-type-qualifier
1169e5dd7070Spatrick ///
1170e5dd7070Spatrick /// objc-type-qualifier:
1171e5dd7070Spatrick /// 'in'
1172e5dd7070Spatrick /// 'out'
1173e5dd7070Spatrick /// 'inout'
1174e5dd7070Spatrick /// 'oneway'
1175e5dd7070Spatrick /// 'bycopy'
1176e5dd7070Spatrick /// 'byref'
1177e5dd7070Spatrick /// 'nonnull'
1178e5dd7070Spatrick /// 'nullable'
1179e5dd7070Spatrick /// 'null_unspecified'
1180e5dd7070Spatrick ///
ParseObjCTypeQualifierList(ObjCDeclSpec & DS,DeclaratorContext Context)1181e5dd7070Spatrick void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
1182e5dd7070Spatrick DeclaratorContext Context) {
1183a9ac8606Spatrick assert(Context == DeclaratorContext::ObjCParameter ||
1184a9ac8606Spatrick Context == DeclaratorContext::ObjCResult);
1185e5dd7070Spatrick
1186*12c85518Srobert while (true) {
1187e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1188a9ac8606Spatrick cutOffParsing();
1189a9ac8606Spatrick Actions.CodeCompleteObjCPassingType(
1190a9ac8606Spatrick getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);
1191a9ac8606Spatrick return;
1192e5dd7070Spatrick }
1193e5dd7070Spatrick
1194e5dd7070Spatrick if (Tok.isNot(tok::identifier))
1195e5dd7070Spatrick return;
1196e5dd7070Spatrick
1197e5dd7070Spatrick const IdentifierInfo *II = Tok.getIdentifierInfo();
1198e5dd7070Spatrick for (unsigned i = 0; i != objc_NumQuals; ++i) {
1199e5dd7070Spatrick if (II != ObjCTypeQuals[i] ||
1200e5dd7070Spatrick NextToken().is(tok::less) ||
1201e5dd7070Spatrick NextToken().is(tok::coloncolon))
1202e5dd7070Spatrick continue;
1203e5dd7070Spatrick
1204e5dd7070Spatrick ObjCDeclSpec::ObjCDeclQualifier Qual;
1205e5dd7070Spatrick NullabilityKind Nullability;
1206e5dd7070Spatrick switch (i) {
1207e5dd7070Spatrick default: llvm_unreachable("Unknown decl qualifier");
1208e5dd7070Spatrick case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
1209e5dd7070Spatrick case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
1210e5dd7070Spatrick case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
1211e5dd7070Spatrick case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
1212e5dd7070Spatrick case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
1213e5dd7070Spatrick case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
1214e5dd7070Spatrick
1215e5dd7070Spatrick case objc_nonnull:
1216e5dd7070Spatrick Qual = ObjCDeclSpec::DQ_CSNullability;
1217e5dd7070Spatrick Nullability = NullabilityKind::NonNull;
1218e5dd7070Spatrick break;
1219e5dd7070Spatrick
1220e5dd7070Spatrick case objc_nullable:
1221e5dd7070Spatrick Qual = ObjCDeclSpec::DQ_CSNullability;
1222e5dd7070Spatrick Nullability = NullabilityKind::Nullable;
1223e5dd7070Spatrick break;
1224e5dd7070Spatrick
1225e5dd7070Spatrick case objc_null_unspecified:
1226e5dd7070Spatrick Qual = ObjCDeclSpec::DQ_CSNullability;
1227e5dd7070Spatrick Nullability = NullabilityKind::Unspecified;
1228e5dd7070Spatrick break;
1229e5dd7070Spatrick }
1230e5dd7070Spatrick
1231e5dd7070Spatrick // FIXME: Diagnose redundant specifiers.
1232e5dd7070Spatrick DS.setObjCDeclQualifier(Qual);
1233e5dd7070Spatrick if (Qual == ObjCDeclSpec::DQ_CSNullability)
1234e5dd7070Spatrick DS.setNullability(Tok.getLocation(), Nullability);
1235e5dd7070Spatrick
1236e5dd7070Spatrick ConsumeToken();
1237e5dd7070Spatrick II = nullptr;
1238e5dd7070Spatrick break;
1239e5dd7070Spatrick }
1240e5dd7070Spatrick
1241e5dd7070Spatrick // If this wasn't a recognized qualifier, bail out.
1242e5dd7070Spatrick if (II) return;
1243e5dd7070Spatrick }
1244e5dd7070Spatrick }
1245e5dd7070Spatrick
1246e5dd7070Spatrick /// Take all the decl attributes out of the given list and add
1247e5dd7070Spatrick /// them to the given attribute set.
takeDeclAttributes(ParsedAttributesView & attrs,ParsedAttributesView & from)1248e5dd7070Spatrick static void takeDeclAttributes(ParsedAttributesView &attrs,
1249e5dd7070Spatrick ParsedAttributesView &from) {
1250e5dd7070Spatrick for (auto &AL : llvm::reverse(from)) {
1251e5dd7070Spatrick if (!AL.isUsedAsTypeAttr()) {
1252e5dd7070Spatrick from.remove(&AL);
1253e5dd7070Spatrick attrs.addAtEnd(&AL);
1254e5dd7070Spatrick }
1255e5dd7070Spatrick }
1256e5dd7070Spatrick }
1257e5dd7070Spatrick
1258e5dd7070Spatrick /// takeDeclAttributes - Take all the decl attributes from the given
1259e5dd7070Spatrick /// declarator and add them to the given list.
takeDeclAttributes(ParsedAttributes & attrs,Declarator & D)1260e5dd7070Spatrick static void takeDeclAttributes(ParsedAttributes &attrs,
1261e5dd7070Spatrick Declarator &D) {
1262*12c85518Srobert // This gets called only from Parser::ParseObjCTypeName(), and that should
1263*12c85518Srobert // never add declaration attributes to the Declarator.
1264*12c85518Srobert assert(D.getDeclarationAttributes().empty());
1265*12c85518Srobert
1266e5dd7070Spatrick // First, take ownership of all attributes.
1267e5dd7070Spatrick attrs.getPool().takeAllFrom(D.getAttributePool());
1268e5dd7070Spatrick attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
1269e5dd7070Spatrick
1270e5dd7070Spatrick // Now actually move the attributes over.
1271e5dd7070Spatrick takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
1272e5dd7070Spatrick takeDeclAttributes(attrs, D.getAttributes());
1273e5dd7070Spatrick for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
1274e5dd7070Spatrick takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
1275e5dd7070Spatrick }
1276e5dd7070Spatrick
1277e5dd7070Spatrick /// objc-type-name:
1278e5dd7070Spatrick /// '(' objc-type-qualifiers[opt] type-name ')'
1279e5dd7070Spatrick /// '(' objc-type-qualifiers[opt] ')'
1280e5dd7070Spatrick ///
ParseObjCTypeName(ObjCDeclSpec & DS,DeclaratorContext context,ParsedAttributes * paramAttrs)1281e5dd7070Spatrick ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
1282e5dd7070Spatrick DeclaratorContext context,
1283e5dd7070Spatrick ParsedAttributes *paramAttrs) {
1284a9ac8606Spatrick assert(context == DeclaratorContext::ObjCParameter ||
1285a9ac8606Spatrick context == DeclaratorContext::ObjCResult);
1286e5dd7070Spatrick assert((paramAttrs != nullptr) ==
1287a9ac8606Spatrick (context == DeclaratorContext::ObjCParameter));
1288e5dd7070Spatrick
1289e5dd7070Spatrick assert(Tok.is(tok::l_paren) && "expected (");
1290e5dd7070Spatrick
1291e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
1292e5dd7070Spatrick T.consumeOpen();
1293e5dd7070Spatrick
1294e5dd7070Spatrick ObjCDeclContextSwitch ObjCDC(*this);
1295e5dd7070Spatrick
1296e5dd7070Spatrick // Parse type qualifiers, in, inout, etc.
1297e5dd7070Spatrick ParseObjCTypeQualifierList(DS, context);
1298e5dd7070Spatrick SourceLocation TypeStartLoc = Tok.getLocation();
1299e5dd7070Spatrick
1300e5dd7070Spatrick ParsedType Ty;
1301e5dd7070Spatrick if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
1302e5dd7070Spatrick // Parse an abstract declarator.
1303e5dd7070Spatrick DeclSpec declSpec(AttrFactory);
1304e5dd7070Spatrick declSpec.setObjCQualifiers(&DS);
1305e5dd7070Spatrick DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
1306a9ac8606Spatrick if (context == DeclaratorContext::ObjCResult)
1307e5dd7070Spatrick dsContext = DeclSpecContext::DSC_objc_method_result;
1308e5dd7070Spatrick ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
1309*12c85518Srobert Declarator declarator(declSpec, ParsedAttributesView::none(), context);
1310e5dd7070Spatrick ParseDeclarator(declarator);
1311e5dd7070Spatrick
1312e5dd7070Spatrick // If that's not invalid, extract a type.
1313e5dd7070Spatrick if (!declarator.isInvalidType()) {
1314e5dd7070Spatrick // Map a nullability specifier to a context-sensitive keyword attribute.
1315e5dd7070Spatrick bool addedToDeclSpec = false;
1316e5dd7070Spatrick if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
1317e5dd7070Spatrick addContextSensitiveTypeNullability(*this, declarator,
1318e5dd7070Spatrick DS.getNullability(),
1319e5dd7070Spatrick DS.getNullabilityLoc(),
1320e5dd7070Spatrick addedToDeclSpec);
1321e5dd7070Spatrick
1322e5dd7070Spatrick TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
1323e5dd7070Spatrick if (!type.isInvalid())
1324e5dd7070Spatrick Ty = type.get();
1325e5dd7070Spatrick
1326e5dd7070Spatrick // If we're parsing a parameter, steal all the decl attributes
1327e5dd7070Spatrick // and add them to the decl spec.
1328a9ac8606Spatrick if (context == DeclaratorContext::ObjCParameter)
1329e5dd7070Spatrick takeDeclAttributes(*paramAttrs, declarator);
1330e5dd7070Spatrick }
1331e5dd7070Spatrick }
1332e5dd7070Spatrick
1333e5dd7070Spatrick if (Tok.is(tok::r_paren))
1334e5dd7070Spatrick T.consumeClose();
1335e5dd7070Spatrick else if (Tok.getLocation() == TypeStartLoc) {
1336e5dd7070Spatrick // If we didn't eat any tokens, then this isn't a type.
1337e5dd7070Spatrick Diag(Tok, diag::err_expected_type);
1338e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
1339e5dd7070Spatrick } else {
1340e5dd7070Spatrick // Otherwise, we found *something*, but didn't get a ')' in the right
1341e5dd7070Spatrick // place. Emit an error then return what we have as the type.
1342e5dd7070Spatrick T.consumeClose();
1343e5dd7070Spatrick }
1344e5dd7070Spatrick return Ty;
1345e5dd7070Spatrick }
1346e5dd7070Spatrick
1347e5dd7070Spatrick /// objc-method-decl:
1348e5dd7070Spatrick /// objc-selector
1349e5dd7070Spatrick /// objc-keyword-selector objc-parmlist[opt]
1350e5dd7070Spatrick /// objc-type-name objc-selector
1351e5dd7070Spatrick /// objc-type-name objc-keyword-selector objc-parmlist[opt]
1352e5dd7070Spatrick ///
1353e5dd7070Spatrick /// objc-keyword-selector:
1354e5dd7070Spatrick /// objc-keyword-decl
1355e5dd7070Spatrick /// objc-keyword-selector objc-keyword-decl
1356e5dd7070Spatrick ///
1357e5dd7070Spatrick /// objc-keyword-decl:
1358e5dd7070Spatrick /// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
1359e5dd7070Spatrick /// objc-selector ':' objc-keyword-attributes[opt] identifier
1360e5dd7070Spatrick /// ':' objc-type-name objc-keyword-attributes[opt] identifier
1361e5dd7070Spatrick /// ':' objc-keyword-attributes[opt] identifier
1362e5dd7070Spatrick ///
1363e5dd7070Spatrick /// objc-parmlist:
1364e5dd7070Spatrick /// objc-parms objc-ellipsis[opt]
1365e5dd7070Spatrick ///
1366e5dd7070Spatrick /// objc-parms:
1367e5dd7070Spatrick /// objc-parms , parameter-declaration
1368e5dd7070Spatrick ///
1369e5dd7070Spatrick /// objc-ellipsis:
1370e5dd7070Spatrick /// , ...
1371e5dd7070Spatrick ///
1372e5dd7070Spatrick /// objc-keyword-attributes: [OBJC2]
1373e5dd7070Spatrick /// __attribute__((unused))
1374e5dd7070Spatrick ///
ParseObjCMethodDecl(SourceLocation mLoc,tok::TokenKind mType,tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)1375e5dd7070Spatrick Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
1376e5dd7070Spatrick tok::TokenKind mType,
1377e5dd7070Spatrick tok::ObjCKeywordKind MethodImplKind,
1378e5dd7070Spatrick bool MethodDefinition) {
1379e5dd7070Spatrick ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
1380e5dd7070Spatrick
1381e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1382a9ac8606Spatrick cutOffParsing();
1383e5dd7070Spatrick Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
1384e5dd7070Spatrick /*ReturnType=*/nullptr);
1385e5dd7070Spatrick return nullptr;
1386e5dd7070Spatrick }
1387e5dd7070Spatrick
1388e5dd7070Spatrick // Parse the return type if present.
1389e5dd7070Spatrick ParsedType ReturnType;
1390e5dd7070Spatrick ObjCDeclSpec DSRet;
1391e5dd7070Spatrick if (Tok.is(tok::l_paren))
1392a9ac8606Spatrick ReturnType =
1393a9ac8606Spatrick ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult, nullptr);
1394e5dd7070Spatrick
1395e5dd7070Spatrick // If attributes exist before the method, parse them.
1396e5dd7070Spatrick ParsedAttributes methodAttrs(AttrFactory);
1397a9ac8606Spatrick MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1398a9ac8606Spatrick methodAttrs);
1399e5dd7070Spatrick
1400e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1401a9ac8606Spatrick cutOffParsing();
1402e5dd7070Spatrick Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
1403e5dd7070Spatrick ReturnType);
1404e5dd7070Spatrick return nullptr;
1405e5dd7070Spatrick }
1406e5dd7070Spatrick
1407e5dd7070Spatrick // Now parse the selector.
1408e5dd7070Spatrick SourceLocation selLoc;
1409e5dd7070Spatrick IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
1410e5dd7070Spatrick
1411e5dd7070Spatrick // An unnamed colon is valid.
1412e5dd7070Spatrick if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
1413e5dd7070Spatrick Diag(Tok, diag::err_expected_selector_for_method)
1414e5dd7070Spatrick << SourceRange(mLoc, Tok.getLocation());
1415e5dd7070Spatrick // Skip until we get a ; or @.
1416e5dd7070Spatrick SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
1417e5dd7070Spatrick return nullptr;
1418e5dd7070Spatrick }
1419e5dd7070Spatrick
1420e5dd7070Spatrick SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
1421e5dd7070Spatrick if (Tok.isNot(tok::colon)) {
1422e5dd7070Spatrick // If attributes exist after the method, parse them.
1423a9ac8606Spatrick MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1424a9ac8606Spatrick methodAttrs);
1425e5dd7070Spatrick
1426e5dd7070Spatrick Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
1427e5dd7070Spatrick Decl *Result = Actions.ActOnMethodDeclaration(
1428e5dd7070Spatrick getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,
1429e5dd7070Spatrick selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
1430e5dd7070Spatrick MethodImplKind, false, MethodDefinition);
1431e5dd7070Spatrick PD.complete(Result);
1432e5dd7070Spatrick return Result;
1433e5dd7070Spatrick }
1434e5dd7070Spatrick
1435e5dd7070Spatrick SmallVector<IdentifierInfo *, 12> KeyIdents;
1436e5dd7070Spatrick SmallVector<SourceLocation, 12> KeyLocs;
1437e5dd7070Spatrick SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
1438e5dd7070Spatrick ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
1439e5dd7070Spatrick Scope::FunctionDeclarationScope | Scope::DeclScope);
1440e5dd7070Spatrick
1441e5dd7070Spatrick AttributePool allParamAttrs(AttrFactory);
1442*12c85518Srobert while (true) {
1443e5dd7070Spatrick ParsedAttributes paramAttrs(AttrFactory);
1444e5dd7070Spatrick Sema::ObjCArgInfo ArgInfo;
1445e5dd7070Spatrick
1446e5dd7070Spatrick // Each iteration parses a single keyword argument.
1447e5dd7070Spatrick if (ExpectAndConsume(tok::colon))
1448e5dd7070Spatrick break;
1449e5dd7070Spatrick
1450e5dd7070Spatrick ArgInfo.Type = nullptr;
1451e5dd7070Spatrick if (Tok.is(tok::l_paren)) // Parse the argument type if present.
1452a9ac8606Spatrick ArgInfo.Type = ParseObjCTypeName(
1453a9ac8606Spatrick ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter, ¶mAttrs);
1454e5dd7070Spatrick
1455e5dd7070Spatrick // If attributes exist before the argument name, parse them.
1456e5dd7070Spatrick // Regardless, collect all the attributes we've parsed so far.
1457a9ac8606Spatrick MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1458a9ac8606Spatrick paramAttrs);
1459e5dd7070Spatrick ArgInfo.ArgAttrs = paramAttrs;
1460e5dd7070Spatrick
1461e5dd7070Spatrick // Code completion for the next piece of the selector.
1462e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1463a9ac8606Spatrick cutOffParsing();
1464e5dd7070Spatrick KeyIdents.push_back(SelIdent);
1465e5dd7070Spatrick Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
1466e5dd7070Spatrick mType == tok::minus,
1467e5dd7070Spatrick /*AtParameterName=*/true,
1468e5dd7070Spatrick ReturnType, KeyIdents);
1469e5dd7070Spatrick return nullptr;
1470e5dd7070Spatrick }
1471e5dd7070Spatrick
1472e5dd7070Spatrick if (expectIdentifier())
1473e5dd7070Spatrick break; // missing argument name.
1474e5dd7070Spatrick
1475e5dd7070Spatrick ArgInfo.Name = Tok.getIdentifierInfo();
1476e5dd7070Spatrick ArgInfo.NameLoc = Tok.getLocation();
1477e5dd7070Spatrick ConsumeToken(); // Eat the identifier.
1478e5dd7070Spatrick
1479e5dd7070Spatrick ArgInfos.push_back(ArgInfo);
1480e5dd7070Spatrick KeyIdents.push_back(SelIdent);
1481e5dd7070Spatrick KeyLocs.push_back(selLoc);
1482e5dd7070Spatrick
1483e5dd7070Spatrick // Make sure the attributes persist.
1484e5dd7070Spatrick allParamAttrs.takeAllFrom(paramAttrs.getPool());
1485e5dd7070Spatrick
1486e5dd7070Spatrick // Code completion for the next piece of the selector.
1487e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1488a9ac8606Spatrick cutOffParsing();
1489e5dd7070Spatrick Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
1490e5dd7070Spatrick mType == tok::minus,
1491e5dd7070Spatrick /*AtParameterName=*/false,
1492e5dd7070Spatrick ReturnType, KeyIdents);
1493e5dd7070Spatrick return nullptr;
1494e5dd7070Spatrick }
1495e5dd7070Spatrick
1496e5dd7070Spatrick // Check for another keyword selector.
1497e5dd7070Spatrick SelIdent = ParseObjCSelectorPiece(selLoc);
1498e5dd7070Spatrick if (!SelIdent && Tok.isNot(tok::colon))
1499e5dd7070Spatrick break;
1500e5dd7070Spatrick if (!SelIdent) {
1501e5dd7070Spatrick SourceLocation ColonLoc = Tok.getLocation();
1502e5dd7070Spatrick if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
1503e5dd7070Spatrick Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
1504e5dd7070Spatrick Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
1505e5dd7070Spatrick Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
1506e5dd7070Spatrick }
1507e5dd7070Spatrick }
1508e5dd7070Spatrick // We have a selector or a colon, continue parsing.
1509e5dd7070Spatrick }
1510e5dd7070Spatrick
1511e5dd7070Spatrick bool isVariadic = false;
1512e5dd7070Spatrick bool cStyleParamWarned = false;
1513e5dd7070Spatrick // Parse the (optional) parameter list.
1514e5dd7070Spatrick while (Tok.is(tok::comma)) {
1515e5dd7070Spatrick ConsumeToken();
1516e5dd7070Spatrick if (Tok.is(tok::ellipsis)) {
1517e5dd7070Spatrick isVariadic = true;
1518e5dd7070Spatrick ConsumeToken();
1519e5dd7070Spatrick break;
1520e5dd7070Spatrick }
1521e5dd7070Spatrick if (!cStyleParamWarned) {
1522e5dd7070Spatrick Diag(Tok, diag::warn_cstyle_param);
1523e5dd7070Spatrick cStyleParamWarned = true;
1524e5dd7070Spatrick }
1525e5dd7070Spatrick DeclSpec DS(AttrFactory);
1526e5dd7070Spatrick ParseDeclarationSpecifiers(DS);
1527e5dd7070Spatrick // Parse the declarator.
1528*12c85518Srobert Declarator ParmDecl(DS, ParsedAttributesView::none(),
1529*12c85518Srobert DeclaratorContext::Prototype);
1530e5dd7070Spatrick ParseDeclarator(ParmDecl);
1531e5dd7070Spatrick IdentifierInfo *ParmII = ParmDecl.getIdentifier();
1532e5dd7070Spatrick Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
1533e5dd7070Spatrick CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
1534e5dd7070Spatrick ParmDecl.getIdentifierLoc(),
1535e5dd7070Spatrick Param,
1536e5dd7070Spatrick nullptr));
1537e5dd7070Spatrick }
1538e5dd7070Spatrick
1539e5dd7070Spatrick // FIXME: Add support for optional parameter list...
1540e5dd7070Spatrick // If attributes exist after the method, parse them.
1541a9ac8606Spatrick MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1542a9ac8606Spatrick methodAttrs);
1543e5dd7070Spatrick
1544e5dd7070Spatrick if (KeyIdents.size() == 0)
1545e5dd7070Spatrick return nullptr;
1546e5dd7070Spatrick
1547e5dd7070Spatrick Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
1548e5dd7070Spatrick &KeyIdents[0]);
1549e5dd7070Spatrick Decl *Result = Actions.ActOnMethodDeclaration(
1550e5dd7070Spatrick getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
1551e5dd7070Spatrick Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
1552e5dd7070Spatrick MethodImplKind, isVariadic, MethodDefinition);
1553e5dd7070Spatrick
1554e5dd7070Spatrick PD.complete(Result);
1555e5dd7070Spatrick return Result;
1556e5dd7070Spatrick }
1557e5dd7070Spatrick
1558e5dd7070Spatrick /// objc-protocol-refs:
1559e5dd7070Spatrick /// '<' identifier-list '>'
1560e5dd7070Spatrick ///
1561e5dd7070Spatrick bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl * > & Protocols,SmallVectorImpl<SourceLocation> & ProtocolLocs,bool WarnOnDeclarations,bool ForObjCContainer,SourceLocation & LAngleLoc,SourceLocation & EndLoc,bool consumeLastToken)1562e5dd7070Spatrick ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
1563e5dd7070Spatrick SmallVectorImpl<SourceLocation> &ProtocolLocs,
1564e5dd7070Spatrick bool WarnOnDeclarations, bool ForObjCContainer,
1565e5dd7070Spatrick SourceLocation &LAngleLoc, SourceLocation &EndLoc,
1566e5dd7070Spatrick bool consumeLastToken) {
1567e5dd7070Spatrick assert(Tok.is(tok::less) && "expected <");
1568e5dd7070Spatrick
1569e5dd7070Spatrick LAngleLoc = ConsumeToken(); // the "<"
1570e5dd7070Spatrick
1571e5dd7070Spatrick SmallVector<IdentifierLocPair, 8> ProtocolIdents;
1572e5dd7070Spatrick
1573*12c85518Srobert while (true) {
1574e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1575e5dd7070Spatrick cutOffParsing();
1576a9ac8606Spatrick Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
1577e5dd7070Spatrick return true;
1578e5dd7070Spatrick }
1579e5dd7070Spatrick
1580e5dd7070Spatrick if (expectIdentifier()) {
1581e5dd7070Spatrick SkipUntil(tok::greater, StopAtSemi);
1582e5dd7070Spatrick return true;
1583e5dd7070Spatrick }
1584e5dd7070Spatrick ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
1585e5dd7070Spatrick Tok.getLocation()));
1586e5dd7070Spatrick ProtocolLocs.push_back(Tok.getLocation());
1587e5dd7070Spatrick ConsumeToken();
1588e5dd7070Spatrick
1589e5dd7070Spatrick if (!TryConsumeToken(tok::comma))
1590e5dd7070Spatrick break;
1591e5dd7070Spatrick }
1592e5dd7070Spatrick
1593e5dd7070Spatrick // Consume the '>'.
1594ec727ea7Spatrick if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken,
1595e5dd7070Spatrick /*ObjCGenericList=*/false))
1596e5dd7070Spatrick return true;
1597e5dd7070Spatrick
1598e5dd7070Spatrick // Convert the list of protocols identifiers into a list of protocol decls.
1599e5dd7070Spatrick Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
1600e5dd7070Spatrick ProtocolIdents, Protocols);
1601e5dd7070Spatrick return false;
1602e5dd7070Spatrick }
1603e5dd7070Spatrick
parseObjCProtocolQualifierType(SourceLocation & rAngleLoc)1604e5dd7070Spatrick TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
1605e5dd7070Spatrick assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
1606e5dd7070Spatrick assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");
1607e5dd7070Spatrick
1608e5dd7070Spatrick SourceLocation lAngleLoc;
1609e5dd7070Spatrick SmallVector<Decl *, 8> protocols;
1610e5dd7070Spatrick SmallVector<SourceLocation, 8> protocolLocs;
1611e5dd7070Spatrick (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
1612e5dd7070Spatrick lAngleLoc, rAngleLoc,
1613e5dd7070Spatrick /*consumeLastToken=*/true);
1614e5dd7070Spatrick TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
1615e5dd7070Spatrick protocols,
1616e5dd7070Spatrick protocolLocs,
1617e5dd7070Spatrick rAngleLoc);
1618e5dd7070Spatrick if (result.isUsable()) {
1619e5dd7070Spatrick Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
1620e5dd7070Spatrick << FixItHint::CreateInsertion(lAngleLoc, "id")
1621e5dd7070Spatrick << SourceRange(lAngleLoc, rAngleLoc);
1622e5dd7070Spatrick }
1623e5dd7070Spatrick
1624e5dd7070Spatrick return result;
1625e5dd7070Spatrick }
1626e5dd7070Spatrick
1627e5dd7070Spatrick /// Parse Objective-C type arguments or protocol qualifiers.
1628e5dd7070Spatrick ///
1629e5dd7070Spatrick /// objc-type-arguments:
1630e5dd7070Spatrick /// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
1631e5dd7070Spatrick ///
parseObjCTypeArgsOrProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken,bool warnOnIncompleteProtocols)1632e5dd7070Spatrick void Parser::parseObjCTypeArgsOrProtocolQualifiers(
1633e5dd7070Spatrick ParsedType baseType,
1634e5dd7070Spatrick SourceLocation &typeArgsLAngleLoc,
1635e5dd7070Spatrick SmallVectorImpl<ParsedType> &typeArgs,
1636e5dd7070Spatrick SourceLocation &typeArgsRAngleLoc,
1637e5dd7070Spatrick SourceLocation &protocolLAngleLoc,
1638e5dd7070Spatrick SmallVectorImpl<Decl *> &protocols,
1639e5dd7070Spatrick SmallVectorImpl<SourceLocation> &protocolLocs,
1640e5dd7070Spatrick SourceLocation &protocolRAngleLoc,
1641e5dd7070Spatrick bool consumeLastToken,
1642e5dd7070Spatrick bool warnOnIncompleteProtocols) {
1643e5dd7070Spatrick assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
1644e5dd7070Spatrick SourceLocation lAngleLoc = ConsumeToken();
1645e5dd7070Spatrick
1646e5dd7070Spatrick // Whether all of the elements we've parsed thus far are single
1647e5dd7070Spatrick // identifiers, which might be types or might be protocols.
1648e5dd7070Spatrick bool allSingleIdentifiers = true;
1649e5dd7070Spatrick SmallVector<IdentifierInfo *, 4> identifiers;
1650e5dd7070Spatrick SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
1651e5dd7070Spatrick
1652e5dd7070Spatrick // Parse a list of comma-separated identifiers, bailing out if we
1653e5dd7070Spatrick // see something different.
1654e5dd7070Spatrick do {
1655e5dd7070Spatrick // Parse a single identifier.
1656e5dd7070Spatrick if (Tok.is(tok::identifier) &&
1657e5dd7070Spatrick (NextToken().is(tok::comma) ||
1658e5dd7070Spatrick NextToken().is(tok::greater) ||
1659e5dd7070Spatrick NextToken().is(tok::greatergreater))) {
1660e5dd7070Spatrick identifiers.push_back(Tok.getIdentifierInfo());
1661e5dd7070Spatrick identifierLocs.push_back(ConsumeToken());
1662e5dd7070Spatrick continue;
1663e5dd7070Spatrick }
1664e5dd7070Spatrick
1665e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1666e5dd7070Spatrick // FIXME: Also include types here.
1667e5dd7070Spatrick SmallVector<IdentifierLocPair, 4> identifierLocPairs;
1668e5dd7070Spatrick for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
1669e5dd7070Spatrick identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
1670e5dd7070Spatrick identifierLocs[i]));
1671e5dd7070Spatrick }
1672e5dd7070Spatrick
1673e5dd7070Spatrick QualType BaseT = Actions.GetTypeFromParser(baseType);
1674a9ac8606Spatrick cutOffParsing();
1675e5dd7070Spatrick if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
1676e5dd7070Spatrick Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
1677e5dd7070Spatrick } else {
1678e5dd7070Spatrick Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
1679e5dd7070Spatrick }
1680e5dd7070Spatrick return;
1681e5dd7070Spatrick }
1682e5dd7070Spatrick
1683e5dd7070Spatrick allSingleIdentifiers = false;
1684e5dd7070Spatrick break;
1685e5dd7070Spatrick } while (TryConsumeToken(tok::comma));
1686e5dd7070Spatrick
1687e5dd7070Spatrick // If we parsed an identifier list, semantic analysis sorts out
1688e5dd7070Spatrick // whether it refers to protocols or to type arguments.
1689e5dd7070Spatrick if (allSingleIdentifiers) {
1690e5dd7070Spatrick // Parse the closing '>'.
1691e5dd7070Spatrick SourceLocation rAngleLoc;
1692ec727ea7Spatrick (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
1693e5dd7070Spatrick /*ObjCGenericList=*/true);
1694e5dd7070Spatrick
1695e5dd7070Spatrick // Let Sema figure out what we parsed.
1696e5dd7070Spatrick Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
1697e5dd7070Spatrick baseType,
1698e5dd7070Spatrick lAngleLoc,
1699e5dd7070Spatrick identifiers,
1700e5dd7070Spatrick identifierLocs,
1701e5dd7070Spatrick rAngleLoc,
1702e5dd7070Spatrick typeArgsLAngleLoc,
1703e5dd7070Spatrick typeArgs,
1704e5dd7070Spatrick typeArgsRAngleLoc,
1705e5dd7070Spatrick protocolLAngleLoc,
1706e5dd7070Spatrick protocols,
1707e5dd7070Spatrick protocolRAngleLoc,
1708e5dd7070Spatrick warnOnIncompleteProtocols);
1709e5dd7070Spatrick return;
1710e5dd7070Spatrick }
1711e5dd7070Spatrick
1712e5dd7070Spatrick // We parsed an identifier list but stumbled into non single identifiers, this
1713e5dd7070Spatrick // means we might (a) check that what we already parsed is a legitimate type
1714e5dd7070Spatrick // (not a protocol or unknown type) and (b) parse the remaining ones, which
1715e5dd7070Spatrick // must all be type args.
1716e5dd7070Spatrick
1717e5dd7070Spatrick // Convert the identifiers into type arguments.
1718e5dd7070Spatrick bool invalid = false;
1719e5dd7070Spatrick IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;
1720e5dd7070Spatrick SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;
1721e5dd7070Spatrick SmallVector<IdentifierInfo *, 2> unknownTypeArgs;
1722e5dd7070Spatrick SmallVector<SourceLocation, 2> unknownTypeArgsLoc;
1723e5dd7070Spatrick
1724e5dd7070Spatrick for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
1725e5dd7070Spatrick ParsedType typeArg
1726e5dd7070Spatrick = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
1727e5dd7070Spatrick if (typeArg) {
1728e5dd7070Spatrick DeclSpec DS(AttrFactory);
1729e5dd7070Spatrick const char *prevSpec = nullptr;
1730e5dd7070Spatrick unsigned diagID;
1731e5dd7070Spatrick DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
1732e5dd7070Spatrick typeArg, Actions.getASTContext().getPrintingPolicy());
1733e5dd7070Spatrick
1734e5dd7070Spatrick // Form a declarator to turn this into a type.
1735*12c85518Srobert Declarator D(DS, ParsedAttributesView::none(),
1736*12c85518Srobert DeclaratorContext::TypeName);
1737e5dd7070Spatrick TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
1738e5dd7070Spatrick if (fullTypeArg.isUsable()) {
1739e5dd7070Spatrick typeArgs.push_back(fullTypeArg.get());
1740e5dd7070Spatrick if (!foundValidTypeId) {
1741e5dd7070Spatrick foundValidTypeId = identifiers[i];
1742e5dd7070Spatrick foundValidTypeSrcLoc = identifierLocs[i];
1743e5dd7070Spatrick }
1744e5dd7070Spatrick } else {
1745e5dd7070Spatrick invalid = true;
1746e5dd7070Spatrick unknownTypeArgs.push_back(identifiers[i]);
1747e5dd7070Spatrick unknownTypeArgsLoc.push_back(identifierLocs[i]);
1748e5dd7070Spatrick }
1749e5dd7070Spatrick } else {
1750e5dd7070Spatrick invalid = true;
1751e5dd7070Spatrick if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) {
1752e5dd7070Spatrick unknownTypeArgs.push_back(identifiers[i]);
1753e5dd7070Spatrick unknownTypeArgsLoc.push_back(identifierLocs[i]);
1754e5dd7070Spatrick } else if (!foundProtocolId) {
1755e5dd7070Spatrick foundProtocolId = identifiers[i];
1756e5dd7070Spatrick foundProtocolSrcLoc = identifierLocs[i];
1757e5dd7070Spatrick }
1758e5dd7070Spatrick }
1759e5dd7070Spatrick }
1760e5dd7070Spatrick
1761e5dd7070Spatrick // Continue parsing type-names.
1762e5dd7070Spatrick do {
1763e5dd7070Spatrick Token CurTypeTok = Tok;
1764e5dd7070Spatrick TypeResult typeArg = ParseTypeName();
1765e5dd7070Spatrick
1766e5dd7070Spatrick // Consume the '...' for a pack expansion.
1767e5dd7070Spatrick SourceLocation ellipsisLoc;
1768e5dd7070Spatrick TryConsumeToken(tok::ellipsis, ellipsisLoc);
1769e5dd7070Spatrick if (typeArg.isUsable() && ellipsisLoc.isValid()) {
1770e5dd7070Spatrick typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
1771e5dd7070Spatrick }
1772e5dd7070Spatrick
1773e5dd7070Spatrick if (typeArg.isUsable()) {
1774e5dd7070Spatrick typeArgs.push_back(typeArg.get());
1775e5dd7070Spatrick if (!foundValidTypeId) {
1776e5dd7070Spatrick foundValidTypeId = CurTypeTok.getIdentifierInfo();
1777e5dd7070Spatrick foundValidTypeSrcLoc = CurTypeTok.getLocation();
1778e5dd7070Spatrick }
1779e5dd7070Spatrick } else {
1780e5dd7070Spatrick invalid = true;
1781e5dd7070Spatrick }
1782e5dd7070Spatrick } while (TryConsumeToken(tok::comma));
1783e5dd7070Spatrick
1784e5dd7070Spatrick // Diagnose the mix between type args and protocols.
1785e5dd7070Spatrick if (foundProtocolId && foundValidTypeId)
1786e5dd7070Spatrick Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
1787e5dd7070Spatrick foundValidTypeId,
1788e5dd7070Spatrick foundValidTypeSrcLoc);
1789e5dd7070Spatrick
1790e5dd7070Spatrick // Diagnose unknown arg types.
1791e5dd7070Spatrick ParsedType T;
1792e5dd7070Spatrick if (unknownTypeArgs.size())
1793e5dd7070Spatrick for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)
1794e5dd7070Spatrick Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],
1795e5dd7070Spatrick getCurScope(), nullptr, T);
1796e5dd7070Spatrick
1797e5dd7070Spatrick // Parse the closing '>'.
1798e5dd7070Spatrick SourceLocation rAngleLoc;
1799ec727ea7Spatrick (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
1800e5dd7070Spatrick /*ObjCGenericList=*/true);
1801e5dd7070Spatrick
1802e5dd7070Spatrick if (invalid) {
1803e5dd7070Spatrick typeArgs.clear();
1804e5dd7070Spatrick return;
1805e5dd7070Spatrick }
1806e5dd7070Spatrick
1807e5dd7070Spatrick // Record left/right angle locations.
1808e5dd7070Spatrick typeArgsLAngleLoc = lAngleLoc;
1809e5dd7070Spatrick typeArgsRAngleLoc = rAngleLoc;
1810e5dd7070Spatrick }
1811e5dd7070Spatrick
parseObjCTypeArgsAndProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken)1812e5dd7070Spatrick void Parser::parseObjCTypeArgsAndProtocolQualifiers(
1813e5dd7070Spatrick ParsedType baseType,
1814e5dd7070Spatrick SourceLocation &typeArgsLAngleLoc,
1815e5dd7070Spatrick SmallVectorImpl<ParsedType> &typeArgs,
1816e5dd7070Spatrick SourceLocation &typeArgsRAngleLoc,
1817e5dd7070Spatrick SourceLocation &protocolLAngleLoc,
1818e5dd7070Spatrick SmallVectorImpl<Decl *> &protocols,
1819e5dd7070Spatrick SmallVectorImpl<SourceLocation> &protocolLocs,
1820e5dd7070Spatrick SourceLocation &protocolRAngleLoc,
1821e5dd7070Spatrick bool consumeLastToken) {
1822e5dd7070Spatrick assert(Tok.is(tok::less));
1823e5dd7070Spatrick
1824e5dd7070Spatrick // Parse the first angle-bracket-delimited clause.
1825e5dd7070Spatrick parseObjCTypeArgsOrProtocolQualifiers(baseType,
1826e5dd7070Spatrick typeArgsLAngleLoc,
1827e5dd7070Spatrick typeArgs,
1828e5dd7070Spatrick typeArgsRAngleLoc,
1829e5dd7070Spatrick protocolLAngleLoc,
1830e5dd7070Spatrick protocols,
1831e5dd7070Spatrick protocolLocs,
1832e5dd7070Spatrick protocolRAngleLoc,
1833e5dd7070Spatrick consumeLastToken,
1834e5dd7070Spatrick /*warnOnIncompleteProtocols=*/false);
1835e5dd7070Spatrick if (Tok.is(tok::eof)) // Nothing else to do here...
1836e5dd7070Spatrick return;
1837e5dd7070Spatrick
1838e5dd7070Spatrick // An Objective-C object pointer followed by type arguments
1839e5dd7070Spatrick // can then be followed again by a set of protocol references, e.g.,
1840e5dd7070Spatrick // \c NSArray<NSView><NSTextDelegate>
1841e5dd7070Spatrick if ((consumeLastToken && Tok.is(tok::less)) ||
1842e5dd7070Spatrick (!consumeLastToken && NextToken().is(tok::less))) {
1843e5dd7070Spatrick // If we aren't consuming the last token, the prior '>' is still hanging
1844e5dd7070Spatrick // there. Consume it before we parse the protocol qualifiers.
1845e5dd7070Spatrick if (!consumeLastToken)
1846e5dd7070Spatrick ConsumeToken();
1847e5dd7070Spatrick
1848e5dd7070Spatrick if (!protocols.empty()) {
1849e5dd7070Spatrick SkipUntilFlags skipFlags = SkipUntilFlags();
1850e5dd7070Spatrick if (!consumeLastToken)
1851e5dd7070Spatrick skipFlags = skipFlags | StopBeforeMatch;
1852e5dd7070Spatrick Diag(Tok, diag::err_objc_type_args_after_protocols)
1853e5dd7070Spatrick << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
1854e5dd7070Spatrick SkipUntil(tok::greater, tok::greatergreater, skipFlags);
1855e5dd7070Spatrick } else {
1856e5dd7070Spatrick ParseObjCProtocolReferences(protocols, protocolLocs,
1857e5dd7070Spatrick /*WarnOnDeclarations=*/false,
1858e5dd7070Spatrick /*ForObjCContainer=*/false,
1859e5dd7070Spatrick protocolLAngleLoc, protocolRAngleLoc,
1860e5dd7070Spatrick consumeLastToken);
1861e5dd7070Spatrick }
1862e5dd7070Spatrick }
1863e5dd7070Spatrick }
1864e5dd7070Spatrick
parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,ParsedType type,bool consumeLastToken,SourceLocation & endLoc)1865e5dd7070Spatrick TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
1866e5dd7070Spatrick SourceLocation loc,
1867e5dd7070Spatrick ParsedType type,
1868e5dd7070Spatrick bool consumeLastToken,
1869e5dd7070Spatrick SourceLocation &endLoc) {
1870e5dd7070Spatrick assert(Tok.is(tok::less));
1871e5dd7070Spatrick SourceLocation typeArgsLAngleLoc;
1872e5dd7070Spatrick SmallVector<ParsedType, 4> typeArgs;
1873e5dd7070Spatrick SourceLocation typeArgsRAngleLoc;
1874e5dd7070Spatrick SourceLocation protocolLAngleLoc;
1875e5dd7070Spatrick SmallVector<Decl *, 4> protocols;
1876e5dd7070Spatrick SmallVector<SourceLocation, 4> protocolLocs;
1877e5dd7070Spatrick SourceLocation protocolRAngleLoc;
1878e5dd7070Spatrick
1879e5dd7070Spatrick // Parse type arguments and protocol qualifiers.
1880e5dd7070Spatrick parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
1881e5dd7070Spatrick typeArgsRAngleLoc, protocolLAngleLoc,
1882e5dd7070Spatrick protocols, protocolLocs,
1883e5dd7070Spatrick protocolRAngleLoc, consumeLastToken);
1884e5dd7070Spatrick
1885e5dd7070Spatrick if (Tok.is(tok::eof))
1886e5dd7070Spatrick return true; // Invalid type result.
1887e5dd7070Spatrick
1888e5dd7070Spatrick // Compute the location of the last token.
1889e5dd7070Spatrick if (consumeLastToken)
1890e5dd7070Spatrick endLoc = PrevTokLocation;
1891e5dd7070Spatrick else
1892e5dd7070Spatrick endLoc = Tok.getLocation();
1893e5dd7070Spatrick
1894e5dd7070Spatrick return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
1895e5dd7070Spatrick getCurScope(),
1896e5dd7070Spatrick loc,
1897e5dd7070Spatrick type,
1898e5dd7070Spatrick typeArgsLAngleLoc,
1899e5dd7070Spatrick typeArgs,
1900e5dd7070Spatrick typeArgsRAngleLoc,
1901e5dd7070Spatrick protocolLAngleLoc,
1902e5dd7070Spatrick protocols,
1903e5dd7070Spatrick protocolLocs,
1904e5dd7070Spatrick protocolRAngleLoc);
1905e5dd7070Spatrick }
1906e5dd7070Spatrick
HelperActionsForIvarDeclarations(ObjCContainerDecl * interfaceDecl,SourceLocation atLoc,BalancedDelimiterTracker & T,SmallVectorImpl<Decl * > & AllIvarDecls,bool RBraceMissing)1907*12c85518Srobert void Parser::HelperActionsForIvarDeclarations(
1908*12c85518Srobert ObjCContainerDecl *interfaceDecl, SourceLocation atLoc,
1909*12c85518Srobert BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls,
1910e5dd7070Spatrick bool RBraceMissing) {
1911e5dd7070Spatrick if (!RBraceMissing)
1912e5dd7070Spatrick T.consumeClose();
1913e5dd7070Spatrick
1914*12c85518Srobert assert(getObjCDeclContext() == interfaceDecl &&
1915*12c85518Srobert "Ivars should have interfaceDecl as their decl context");
1916e5dd7070Spatrick Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
1917e5dd7070Spatrick // Call ActOnFields() even if we don't have any decls. This is useful
1918e5dd7070Spatrick // for code rewriting tools that need to be aware of the empty list.
1919e5dd7070Spatrick Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,
1920e5dd7070Spatrick T.getOpenLocation(), T.getCloseLocation(),
1921e5dd7070Spatrick ParsedAttributesView());
1922e5dd7070Spatrick }
1923e5dd7070Spatrick
1924e5dd7070Spatrick /// objc-class-instance-variables:
1925e5dd7070Spatrick /// '{' objc-instance-variable-decl-list[opt] '}'
1926e5dd7070Spatrick ///
1927e5dd7070Spatrick /// objc-instance-variable-decl-list:
1928e5dd7070Spatrick /// objc-visibility-spec
1929e5dd7070Spatrick /// objc-instance-variable-decl ';'
1930e5dd7070Spatrick /// ';'
1931e5dd7070Spatrick /// objc-instance-variable-decl-list objc-visibility-spec
1932e5dd7070Spatrick /// objc-instance-variable-decl-list objc-instance-variable-decl ';'
1933e5dd7070Spatrick /// objc-instance-variable-decl-list static_assert-declaration
1934e5dd7070Spatrick /// objc-instance-variable-decl-list ';'
1935e5dd7070Spatrick ///
1936e5dd7070Spatrick /// objc-visibility-spec:
1937e5dd7070Spatrick /// @private
1938e5dd7070Spatrick /// @protected
1939e5dd7070Spatrick /// @public
1940e5dd7070Spatrick /// @package [OBJC2]
1941e5dd7070Spatrick ///
1942e5dd7070Spatrick /// objc-instance-variable-decl:
1943e5dd7070Spatrick /// struct-declaration
1944e5dd7070Spatrick ///
ParseObjCClassInstanceVariables(ObjCContainerDecl * interfaceDecl,tok::ObjCKeywordKind visibility,SourceLocation atLoc)1945*12c85518Srobert void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
1946e5dd7070Spatrick tok::ObjCKeywordKind visibility,
1947e5dd7070Spatrick SourceLocation atLoc) {
1948e5dd7070Spatrick assert(Tok.is(tok::l_brace) && "expected {");
1949e5dd7070Spatrick SmallVector<Decl *, 32> AllIvarDecls;
1950e5dd7070Spatrick
1951e5dd7070Spatrick ParseScope ClassScope(this, Scope::DeclScope | Scope::ClassScope);
1952e5dd7070Spatrick
1953e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_brace);
1954e5dd7070Spatrick T.consumeOpen();
1955e5dd7070Spatrick // While we still have something to read, read the instance variables.
1956e5dd7070Spatrick while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
1957e5dd7070Spatrick // Each iteration of this loop reads one objc-instance-variable-decl.
1958e5dd7070Spatrick
1959e5dd7070Spatrick // Check for extraneous top-level semicolon.
1960e5dd7070Spatrick if (Tok.is(tok::semi)) {
1961e5dd7070Spatrick ConsumeExtraSemi(InstanceVariableList);
1962e5dd7070Spatrick continue;
1963e5dd7070Spatrick }
1964e5dd7070Spatrick
1965e5dd7070Spatrick // Set the default visibility to private.
1966e5dd7070Spatrick if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
1967e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1968a9ac8606Spatrick cutOffParsing();
1969e5dd7070Spatrick Actions.CodeCompleteObjCAtVisibility(getCurScope());
1970a9ac8606Spatrick return;
1971e5dd7070Spatrick }
1972e5dd7070Spatrick
1973e5dd7070Spatrick switch (Tok.getObjCKeywordID()) {
1974e5dd7070Spatrick case tok::objc_private:
1975e5dd7070Spatrick case tok::objc_public:
1976e5dd7070Spatrick case tok::objc_protected:
1977e5dd7070Spatrick case tok::objc_package:
1978e5dd7070Spatrick visibility = Tok.getObjCKeywordID();
1979e5dd7070Spatrick ConsumeToken();
1980e5dd7070Spatrick continue;
1981e5dd7070Spatrick
1982e5dd7070Spatrick case tok::objc_end:
1983e5dd7070Spatrick Diag(Tok, diag::err_objc_unexpected_atend);
1984e5dd7070Spatrick Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
1985e5dd7070Spatrick Tok.setKind(tok::at);
1986e5dd7070Spatrick Tok.setLength(1);
1987e5dd7070Spatrick PP.EnterToken(Tok, /*IsReinject*/true);
1988e5dd7070Spatrick HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
1989e5dd7070Spatrick T, AllIvarDecls, true);
1990e5dd7070Spatrick return;
1991e5dd7070Spatrick
1992e5dd7070Spatrick default:
1993e5dd7070Spatrick Diag(Tok, diag::err_objc_illegal_visibility_spec);
1994e5dd7070Spatrick continue;
1995e5dd7070Spatrick }
1996e5dd7070Spatrick }
1997e5dd7070Spatrick
1998e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
1999a9ac8606Spatrick cutOffParsing();
2000e5dd7070Spatrick Actions.CodeCompleteOrdinaryName(getCurScope(),
2001e5dd7070Spatrick Sema::PCC_ObjCInstanceVariableList);
2002a9ac8606Spatrick return;
2003e5dd7070Spatrick }
2004e5dd7070Spatrick
2005e5dd7070Spatrick // This needs to duplicate a small amount of code from
2006e5dd7070Spatrick // ParseStructUnionBody() for things that should work in both
2007e5dd7070Spatrick // C struct and in Objective-C class instance variables.
2008e5dd7070Spatrick if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
2009e5dd7070Spatrick SourceLocation DeclEnd;
2010e5dd7070Spatrick ParseStaticAssertDeclaration(DeclEnd);
2011e5dd7070Spatrick continue;
2012e5dd7070Spatrick }
2013e5dd7070Spatrick
2014e5dd7070Spatrick auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
2015*12c85518Srobert assert(getObjCDeclContext() == interfaceDecl &&
2016*12c85518Srobert "Ivar should have interfaceDecl as its decl context");
2017e5dd7070Spatrick // Install the declarator into the interface decl.
2018e5dd7070Spatrick FD.D.setObjCIvar(true);
2019e5dd7070Spatrick Decl *Field = Actions.ActOnIvar(
2020e5dd7070Spatrick getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
2021e5dd7070Spatrick FD.BitfieldSize, visibility);
2022e5dd7070Spatrick if (Field)
2023e5dd7070Spatrick AllIvarDecls.push_back(Field);
2024e5dd7070Spatrick FD.complete(Field);
2025e5dd7070Spatrick };
2026e5dd7070Spatrick
2027e5dd7070Spatrick // Parse all the comma separated declarators.
2028e5dd7070Spatrick ParsingDeclSpec DS(*this);
2029e5dd7070Spatrick ParseStructDeclaration(DS, ObjCIvarCallback);
2030e5dd7070Spatrick
2031e5dd7070Spatrick if (Tok.is(tok::semi)) {
2032e5dd7070Spatrick ConsumeToken();
2033e5dd7070Spatrick } else {
2034e5dd7070Spatrick Diag(Tok, diag::err_expected_semi_decl_list);
2035e5dd7070Spatrick // Skip to end of block or statement
2036e5dd7070Spatrick SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
2037e5dd7070Spatrick }
2038e5dd7070Spatrick }
2039e5dd7070Spatrick HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
2040e5dd7070Spatrick T, AllIvarDecls, false);
2041e5dd7070Spatrick }
2042e5dd7070Spatrick
2043e5dd7070Spatrick /// objc-protocol-declaration:
2044e5dd7070Spatrick /// objc-protocol-definition
2045e5dd7070Spatrick /// objc-protocol-forward-reference
2046e5dd7070Spatrick ///
2047e5dd7070Spatrick /// objc-protocol-definition:
2048e5dd7070Spatrick /// \@protocol identifier
2049e5dd7070Spatrick /// objc-protocol-refs[opt]
2050e5dd7070Spatrick /// objc-interface-decl-list
2051e5dd7070Spatrick /// \@end
2052e5dd7070Spatrick ///
2053e5dd7070Spatrick /// objc-protocol-forward-reference:
2054e5dd7070Spatrick /// \@protocol identifier-list ';'
2055e5dd7070Spatrick ///
2056e5dd7070Spatrick /// "\@protocol identifier ;" should be resolved as "\@protocol
2057e5dd7070Spatrick /// identifier-list ;": objc-interface-decl-list may not start with a
2058e5dd7070Spatrick /// semicolon in the first alternative if objc-protocol-refs are omitted.
2059e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)2060e5dd7070Spatrick Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
2061e5dd7070Spatrick ParsedAttributes &attrs) {
2062e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
2063e5dd7070Spatrick "ParseObjCAtProtocolDeclaration(): Expected @protocol");
2064e5dd7070Spatrick ConsumeToken(); // the "protocol" identifier
2065e5dd7070Spatrick
2066e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2067e5dd7070Spatrick cutOffParsing();
2068a9ac8606Spatrick Actions.CodeCompleteObjCProtocolDecl(getCurScope());
2069e5dd7070Spatrick return nullptr;
2070e5dd7070Spatrick }
2071e5dd7070Spatrick
2072e5dd7070Spatrick MaybeSkipAttributes(tok::objc_protocol);
2073e5dd7070Spatrick
2074e5dd7070Spatrick if (expectIdentifier())
2075e5dd7070Spatrick return nullptr; // missing protocol name.
2076e5dd7070Spatrick // Save the protocol name, then consume it.
2077e5dd7070Spatrick IdentifierInfo *protocolName = Tok.getIdentifierInfo();
2078e5dd7070Spatrick SourceLocation nameLoc = ConsumeToken();
2079e5dd7070Spatrick
2080e5dd7070Spatrick if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
2081e5dd7070Spatrick IdentifierLocPair ProtoInfo(protocolName, nameLoc);
2082e5dd7070Spatrick return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo, attrs);
2083e5dd7070Spatrick }
2084e5dd7070Spatrick
2085e5dd7070Spatrick CheckNestedObjCContexts(AtLoc);
2086e5dd7070Spatrick
2087e5dd7070Spatrick if (Tok.is(tok::comma)) { // list of forward declarations.
2088e5dd7070Spatrick SmallVector<IdentifierLocPair, 8> ProtocolRefs;
2089e5dd7070Spatrick ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
2090e5dd7070Spatrick
2091e5dd7070Spatrick // Parse the list of forward declarations.
2092*12c85518Srobert while (true) {
2093e5dd7070Spatrick ConsumeToken(); // the ','
2094e5dd7070Spatrick if (expectIdentifier()) {
2095e5dd7070Spatrick SkipUntil(tok::semi);
2096e5dd7070Spatrick return nullptr;
2097e5dd7070Spatrick }
2098e5dd7070Spatrick ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
2099e5dd7070Spatrick Tok.getLocation()));
2100e5dd7070Spatrick ConsumeToken(); // the identifier
2101e5dd7070Spatrick
2102e5dd7070Spatrick if (Tok.isNot(tok::comma))
2103e5dd7070Spatrick break;
2104e5dd7070Spatrick }
2105e5dd7070Spatrick // Consume the ';'.
2106e5dd7070Spatrick if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
2107e5dd7070Spatrick return nullptr;
2108e5dd7070Spatrick
2109e5dd7070Spatrick return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs);
2110e5dd7070Spatrick }
2111e5dd7070Spatrick
2112e5dd7070Spatrick // Last, and definitely not least, parse a protocol declaration.
2113e5dd7070Spatrick SourceLocation LAngleLoc, EndProtoLoc;
2114e5dd7070Spatrick
2115e5dd7070Spatrick SmallVector<Decl *, 8> ProtocolRefs;
2116e5dd7070Spatrick SmallVector<SourceLocation, 8> ProtocolLocs;
2117e5dd7070Spatrick if (Tok.is(tok::less) &&
2118e5dd7070Spatrick ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
2119e5dd7070Spatrick LAngleLoc, EndProtoLoc,
2120e5dd7070Spatrick /*consumeLastToken=*/true))
2121e5dd7070Spatrick return nullptr;
2122e5dd7070Spatrick
2123*12c85518Srobert Sema::SkipBodyInfo SkipBody;
2124*12c85518Srobert ObjCProtocolDecl *ProtoType = Actions.ActOnStartProtocolInterface(
2125e5dd7070Spatrick AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
2126*12c85518Srobert ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
2127e5dd7070Spatrick
2128e5dd7070Spatrick ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
2129*12c85518Srobert if (SkipBody.CheckSameAsPrevious) {
2130*12c85518Srobert auto *PreviousDef = cast<ObjCProtocolDecl>(SkipBody.Previous);
2131*12c85518Srobert if (Actions.ActOnDuplicateODRHashDefinition(ProtoType, PreviousDef)) {
2132*12c85518Srobert ProtoType->mergeDuplicateDefinitionWithCommon(
2133*12c85518Srobert PreviousDef->getDefinition());
2134*12c85518Srobert } else {
2135*12c85518Srobert ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
2136*12c85518Srobert getPreprocessor().getLangOpts());
2137*12c85518Srobert DiagsEmitter.diagnoseMismatch(PreviousDef, ProtoType);
2138*12c85518Srobert }
2139*12c85518Srobert }
2140e5dd7070Spatrick return Actions.ConvertDeclToDeclGroup(ProtoType);
2141e5dd7070Spatrick }
2142e5dd7070Spatrick
2143e5dd7070Spatrick /// objc-implementation:
2144e5dd7070Spatrick /// objc-class-implementation-prologue
2145e5dd7070Spatrick /// objc-category-implementation-prologue
2146e5dd7070Spatrick ///
2147e5dd7070Spatrick /// objc-class-implementation-prologue:
2148e5dd7070Spatrick /// @implementation identifier objc-superclass[opt]
2149e5dd7070Spatrick /// objc-class-instance-variables[opt]
2150e5dd7070Spatrick ///
2151e5dd7070Spatrick /// objc-category-implementation-prologue:
2152e5dd7070Spatrick /// @implementation identifier ( identifier )
2153e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,ParsedAttributes & Attrs)2154e5dd7070Spatrick Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
2155e5dd7070Spatrick ParsedAttributes &Attrs) {
2156e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
2157e5dd7070Spatrick "ParseObjCAtImplementationDeclaration(): Expected @implementation");
2158e5dd7070Spatrick CheckNestedObjCContexts(AtLoc);
2159e5dd7070Spatrick ConsumeToken(); // the "implementation" identifier
2160e5dd7070Spatrick
2161e5dd7070Spatrick // Code completion after '@implementation'.
2162e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2163e5dd7070Spatrick cutOffParsing();
2164a9ac8606Spatrick Actions.CodeCompleteObjCImplementationDecl(getCurScope());
2165e5dd7070Spatrick return nullptr;
2166e5dd7070Spatrick }
2167e5dd7070Spatrick
2168e5dd7070Spatrick MaybeSkipAttributes(tok::objc_implementation);
2169e5dd7070Spatrick
2170e5dd7070Spatrick if (expectIdentifier())
2171e5dd7070Spatrick return nullptr; // missing class or category name.
2172e5dd7070Spatrick // We have a class or category name - consume it.
2173e5dd7070Spatrick IdentifierInfo *nameId = Tok.getIdentifierInfo();
2174e5dd7070Spatrick SourceLocation nameLoc = ConsumeToken(); // consume class or category name
2175*12c85518Srobert ObjCImplDecl *ObjCImpDecl = nullptr;
2176e5dd7070Spatrick
2177e5dd7070Spatrick // Neither a type parameter list nor a list of protocol references is
2178e5dd7070Spatrick // permitted here. Parse and diagnose them.
2179e5dd7070Spatrick if (Tok.is(tok::less)) {
2180e5dd7070Spatrick SourceLocation lAngleLoc, rAngleLoc;
2181e5dd7070Spatrick SmallVector<IdentifierLocPair, 8> protocolIdents;
2182e5dd7070Spatrick SourceLocation diagLoc = Tok.getLocation();
2183e5dd7070Spatrick ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
2184e5dd7070Spatrick if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,
2185e5dd7070Spatrick protocolIdents, rAngleLoc)) {
2186e5dd7070Spatrick Diag(diagLoc, diag::err_objc_parameterized_implementation)
2187e5dd7070Spatrick << SourceRange(diagLoc, PrevTokLocation);
2188e5dd7070Spatrick } else if (lAngleLoc.isValid()) {
2189e5dd7070Spatrick Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
2190e5dd7070Spatrick << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
2191e5dd7070Spatrick }
2192e5dd7070Spatrick }
2193e5dd7070Spatrick
2194e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
2195e5dd7070Spatrick // we have a category implementation.
2196e5dd7070Spatrick ConsumeParen();
2197e5dd7070Spatrick SourceLocation categoryLoc, rparenLoc;
2198e5dd7070Spatrick IdentifierInfo *categoryId = nullptr;
2199e5dd7070Spatrick
2200e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2201e5dd7070Spatrick cutOffParsing();
2202a9ac8606Spatrick Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
2203e5dd7070Spatrick return nullptr;
2204e5dd7070Spatrick }
2205e5dd7070Spatrick
2206e5dd7070Spatrick if (Tok.is(tok::identifier)) {
2207e5dd7070Spatrick categoryId = Tok.getIdentifierInfo();
2208e5dd7070Spatrick categoryLoc = ConsumeToken();
2209e5dd7070Spatrick } else {
2210e5dd7070Spatrick Diag(Tok, diag::err_expected)
2211e5dd7070Spatrick << tok::identifier; // missing category name.
2212e5dd7070Spatrick return nullptr;
2213e5dd7070Spatrick }
2214e5dd7070Spatrick if (Tok.isNot(tok::r_paren)) {
2215e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::r_paren;
2216e5dd7070Spatrick SkipUntil(tok::r_paren); // don't stop at ';'
2217e5dd7070Spatrick return nullptr;
2218e5dd7070Spatrick }
2219e5dd7070Spatrick rparenLoc = ConsumeParen();
2220e5dd7070Spatrick if (Tok.is(tok::less)) { // we have illegal '<' try to recover
2221e5dd7070Spatrick Diag(Tok, diag::err_unexpected_protocol_qualifier);
2222e5dd7070Spatrick SourceLocation protocolLAngleLoc, protocolRAngleLoc;
2223e5dd7070Spatrick SmallVector<Decl *, 4> protocols;
2224e5dd7070Spatrick SmallVector<SourceLocation, 4> protocolLocs;
2225e5dd7070Spatrick (void)ParseObjCProtocolReferences(protocols, protocolLocs,
2226e5dd7070Spatrick /*warnOnIncompleteProtocols=*/false,
2227e5dd7070Spatrick /*ForObjCContainer=*/false,
2228e5dd7070Spatrick protocolLAngleLoc, protocolRAngleLoc,
2229e5dd7070Spatrick /*consumeLastToken=*/true);
2230e5dd7070Spatrick }
2231e5dd7070Spatrick ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
2232e5dd7070Spatrick AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);
2233e5dd7070Spatrick
2234e5dd7070Spatrick } else {
2235e5dd7070Spatrick // We have a class implementation
2236e5dd7070Spatrick SourceLocation superClassLoc;
2237e5dd7070Spatrick IdentifierInfo *superClassId = nullptr;
2238e5dd7070Spatrick if (TryConsumeToken(tok::colon)) {
2239e5dd7070Spatrick // We have a super class
2240e5dd7070Spatrick if (expectIdentifier())
2241e5dd7070Spatrick return nullptr; // missing super class name.
2242e5dd7070Spatrick superClassId = Tok.getIdentifierInfo();
2243e5dd7070Spatrick superClassLoc = ConsumeToken(); // Consume super class name
2244e5dd7070Spatrick }
2245e5dd7070Spatrick ObjCImpDecl = Actions.ActOnStartClassImplementation(
2246e5dd7070Spatrick AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);
2247e5dd7070Spatrick
2248e5dd7070Spatrick if (Tok.is(tok::l_brace)) // we have ivars
2249e5dd7070Spatrick ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
2250e5dd7070Spatrick else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
2251e5dd7070Spatrick Diag(Tok, diag::err_unexpected_protocol_qualifier);
2252e5dd7070Spatrick
2253e5dd7070Spatrick SourceLocation protocolLAngleLoc, protocolRAngleLoc;
2254e5dd7070Spatrick SmallVector<Decl *, 4> protocols;
2255e5dd7070Spatrick SmallVector<SourceLocation, 4> protocolLocs;
2256e5dd7070Spatrick (void)ParseObjCProtocolReferences(protocols, protocolLocs,
2257e5dd7070Spatrick /*warnOnIncompleteProtocols=*/false,
2258e5dd7070Spatrick /*ForObjCContainer=*/false,
2259e5dd7070Spatrick protocolLAngleLoc, protocolRAngleLoc,
2260e5dd7070Spatrick /*consumeLastToken=*/true);
2261e5dd7070Spatrick }
2262e5dd7070Spatrick }
2263e5dd7070Spatrick assert(ObjCImpDecl);
2264e5dd7070Spatrick
2265e5dd7070Spatrick SmallVector<Decl *, 8> DeclsInGroup;
2266e5dd7070Spatrick
2267e5dd7070Spatrick {
2268e5dd7070Spatrick ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
2269e5dd7070Spatrick while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
2270*12c85518Srobert ParsedAttributes DeclAttrs(AttrFactory);
2271*12c85518Srobert MaybeParseCXX11Attributes(DeclAttrs);
2272*12c85518Srobert ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
2273*12c85518Srobert if (DeclGroupPtrTy DGP =
2274*12c85518Srobert ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs)) {
2275e5dd7070Spatrick DeclGroupRef DG = DGP.get();
2276e5dd7070Spatrick DeclsInGroup.append(DG.begin(), DG.end());
2277e5dd7070Spatrick }
2278e5dd7070Spatrick }
2279e5dd7070Spatrick }
2280e5dd7070Spatrick
2281e5dd7070Spatrick return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
2282e5dd7070Spatrick }
2283e5dd7070Spatrick
2284e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtEndDeclaration(SourceRange atEnd)2285e5dd7070Spatrick Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
2286e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_end) &&
2287e5dd7070Spatrick "ParseObjCAtEndDeclaration(): Expected @end");
2288e5dd7070Spatrick ConsumeToken(); // the "end" identifier
2289e5dd7070Spatrick if (CurParsedObjCImpl)
2290e5dd7070Spatrick CurParsedObjCImpl->finish(atEnd);
2291e5dd7070Spatrick else
2292e5dd7070Spatrick // missing @implementation
2293e5dd7070Spatrick Diag(atEnd.getBegin(), diag::err_expected_objc_container);
2294e5dd7070Spatrick return nullptr;
2295e5dd7070Spatrick }
2296e5dd7070Spatrick
~ObjCImplParsingDataRAII()2297e5dd7070Spatrick Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
2298e5dd7070Spatrick if (!Finished) {
2299e5dd7070Spatrick finish(P.Tok.getLocation());
2300e5dd7070Spatrick if (P.isEofOrEom()) {
2301e5dd7070Spatrick P.Diag(P.Tok, diag::err_objc_missing_end)
2302e5dd7070Spatrick << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
2303e5dd7070Spatrick P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)
2304e5dd7070Spatrick << Sema::OCK_Implementation;
2305e5dd7070Spatrick }
2306e5dd7070Spatrick }
2307e5dd7070Spatrick P.CurParsedObjCImpl = nullptr;
2308e5dd7070Spatrick assert(LateParsedObjCMethods.empty());
2309e5dd7070Spatrick }
2310e5dd7070Spatrick
finish(SourceRange AtEnd)2311e5dd7070Spatrick void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
2312e5dd7070Spatrick assert(!Finished);
2313e5dd7070Spatrick P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
2314e5dd7070Spatrick for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
2315e5dd7070Spatrick P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
2316e5dd7070Spatrick true/*Methods*/);
2317e5dd7070Spatrick
2318e5dd7070Spatrick P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
2319e5dd7070Spatrick
2320e5dd7070Spatrick if (HasCFunction)
2321e5dd7070Spatrick for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
2322e5dd7070Spatrick P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
2323e5dd7070Spatrick false/*c-functions*/);
2324e5dd7070Spatrick
2325e5dd7070Spatrick /// Clear and free the cached objc methods.
2326e5dd7070Spatrick for (LateParsedObjCMethodContainer::iterator
2327e5dd7070Spatrick I = LateParsedObjCMethods.begin(),
2328e5dd7070Spatrick E = LateParsedObjCMethods.end(); I != E; ++I)
2329e5dd7070Spatrick delete *I;
2330e5dd7070Spatrick LateParsedObjCMethods.clear();
2331e5dd7070Spatrick
2332e5dd7070Spatrick Finished = true;
2333e5dd7070Spatrick }
2334e5dd7070Spatrick
2335e5dd7070Spatrick /// compatibility-alias-decl:
2336e5dd7070Spatrick /// @compatibility_alias alias-name class-name ';'
2337e5dd7070Spatrick ///
ParseObjCAtAliasDeclaration(SourceLocation atLoc)2338e5dd7070Spatrick Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
2339e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
2340e5dd7070Spatrick "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
2341e5dd7070Spatrick ConsumeToken(); // consume compatibility_alias
2342e5dd7070Spatrick if (expectIdentifier())
2343e5dd7070Spatrick return nullptr;
2344e5dd7070Spatrick IdentifierInfo *aliasId = Tok.getIdentifierInfo();
2345e5dd7070Spatrick SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
2346e5dd7070Spatrick if (expectIdentifier())
2347e5dd7070Spatrick return nullptr;
2348e5dd7070Spatrick IdentifierInfo *classId = Tok.getIdentifierInfo();
2349e5dd7070Spatrick SourceLocation classLoc = ConsumeToken(); // consume class-name;
2350e5dd7070Spatrick ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
2351e5dd7070Spatrick return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
2352e5dd7070Spatrick classId, classLoc);
2353e5dd7070Spatrick }
2354e5dd7070Spatrick
2355e5dd7070Spatrick /// property-synthesis:
2356e5dd7070Spatrick /// @synthesize property-ivar-list ';'
2357e5dd7070Spatrick ///
2358e5dd7070Spatrick /// property-ivar-list:
2359e5dd7070Spatrick /// property-ivar
2360e5dd7070Spatrick /// property-ivar-list ',' property-ivar
2361e5dd7070Spatrick ///
2362e5dd7070Spatrick /// property-ivar:
2363e5dd7070Spatrick /// identifier
2364e5dd7070Spatrick /// identifier '=' identifier
2365e5dd7070Spatrick ///
ParseObjCPropertySynthesize(SourceLocation atLoc)2366e5dd7070Spatrick Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
2367e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
2368e5dd7070Spatrick "ParseObjCPropertySynthesize(): Expected '@synthesize'");
2369e5dd7070Spatrick ConsumeToken(); // consume synthesize
2370e5dd7070Spatrick
2371e5dd7070Spatrick while (true) {
2372e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2373e5dd7070Spatrick cutOffParsing();
2374a9ac8606Spatrick Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
2375e5dd7070Spatrick return nullptr;
2376e5dd7070Spatrick }
2377e5dd7070Spatrick
2378e5dd7070Spatrick if (Tok.isNot(tok::identifier)) {
2379e5dd7070Spatrick Diag(Tok, diag::err_synthesized_property_name);
2380e5dd7070Spatrick SkipUntil(tok::semi);
2381e5dd7070Spatrick return nullptr;
2382e5dd7070Spatrick }
2383e5dd7070Spatrick
2384e5dd7070Spatrick IdentifierInfo *propertyIvar = nullptr;
2385e5dd7070Spatrick IdentifierInfo *propertyId = Tok.getIdentifierInfo();
2386e5dd7070Spatrick SourceLocation propertyLoc = ConsumeToken(); // consume property name
2387e5dd7070Spatrick SourceLocation propertyIvarLoc;
2388e5dd7070Spatrick if (TryConsumeToken(tok::equal)) {
2389e5dd7070Spatrick // property '=' ivar-name
2390e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2391e5dd7070Spatrick cutOffParsing();
2392a9ac8606Spatrick Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
2393e5dd7070Spatrick return nullptr;
2394e5dd7070Spatrick }
2395e5dd7070Spatrick
2396e5dd7070Spatrick if (expectIdentifier())
2397e5dd7070Spatrick break;
2398e5dd7070Spatrick propertyIvar = Tok.getIdentifierInfo();
2399e5dd7070Spatrick propertyIvarLoc = ConsumeToken(); // consume ivar-name
2400e5dd7070Spatrick }
2401e5dd7070Spatrick Actions.ActOnPropertyImplDecl(
2402e5dd7070Spatrick getCurScope(), atLoc, propertyLoc, true,
2403e5dd7070Spatrick propertyId, propertyIvar, propertyIvarLoc,
2404e5dd7070Spatrick ObjCPropertyQueryKind::OBJC_PR_query_unknown);
2405e5dd7070Spatrick if (Tok.isNot(tok::comma))
2406e5dd7070Spatrick break;
2407e5dd7070Spatrick ConsumeToken(); // consume ','
2408e5dd7070Spatrick }
2409e5dd7070Spatrick ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
2410e5dd7070Spatrick return nullptr;
2411e5dd7070Spatrick }
2412e5dd7070Spatrick
2413e5dd7070Spatrick /// property-dynamic:
2414e5dd7070Spatrick /// @dynamic property-list
2415e5dd7070Spatrick ///
2416e5dd7070Spatrick /// property-list:
2417e5dd7070Spatrick /// identifier
2418e5dd7070Spatrick /// property-list ',' identifier
2419e5dd7070Spatrick ///
ParseObjCPropertyDynamic(SourceLocation atLoc)2420e5dd7070Spatrick Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
2421e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
2422e5dd7070Spatrick "ParseObjCPropertyDynamic(): Expected '@dynamic'");
2423e5dd7070Spatrick ConsumeToken(); // consume dynamic
2424e5dd7070Spatrick
2425e5dd7070Spatrick bool isClassProperty = false;
2426e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
2427e5dd7070Spatrick ConsumeParen();
2428e5dd7070Spatrick const IdentifierInfo *II = Tok.getIdentifierInfo();
2429e5dd7070Spatrick
2430e5dd7070Spatrick if (!II) {
2431e5dd7070Spatrick Diag(Tok, diag::err_objc_expected_property_attr) << II;
2432e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
2433e5dd7070Spatrick } else {
2434e5dd7070Spatrick SourceLocation AttrName = ConsumeToken(); // consume attribute name
2435e5dd7070Spatrick if (II->isStr("class")) {
2436e5dd7070Spatrick isClassProperty = true;
2437e5dd7070Spatrick if (Tok.isNot(tok::r_paren)) {
2438e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::r_paren;
2439e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
2440e5dd7070Spatrick } else
2441e5dd7070Spatrick ConsumeParen();
2442e5dd7070Spatrick } else {
2443e5dd7070Spatrick Diag(AttrName, diag::err_objc_expected_property_attr) << II;
2444e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
2445e5dd7070Spatrick }
2446e5dd7070Spatrick }
2447e5dd7070Spatrick }
2448e5dd7070Spatrick
2449e5dd7070Spatrick while (true) {
2450e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2451e5dd7070Spatrick cutOffParsing();
2452a9ac8606Spatrick Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
2453e5dd7070Spatrick return nullptr;
2454e5dd7070Spatrick }
2455e5dd7070Spatrick
2456e5dd7070Spatrick if (expectIdentifier()) {
2457e5dd7070Spatrick SkipUntil(tok::semi);
2458e5dd7070Spatrick return nullptr;
2459e5dd7070Spatrick }
2460e5dd7070Spatrick
2461e5dd7070Spatrick IdentifierInfo *propertyId = Tok.getIdentifierInfo();
2462e5dd7070Spatrick SourceLocation propertyLoc = ConsumeToken(); // consume property name
2463e5dd7070Spatrick Actions.ActOnPropertyImplDecl(
2464e5dd7070Spatrick getCurScope(), atLoc, propertyLoc, false,
2465e5dd7070Spatrick propertyId, nullptr, SourceLocation(),
2466e5dd7070Spatrick isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
2467e5dd7070Spatrick ObjCPropertyQueryKind::OBJC_PR_query_unknown);
2468e5dd7070Spatrick
2469e5dd7070Spatrick if (Tok.isNot(tok::comma))
2470e5dd7070Spatrick break;
2471e5dd7070Spatrick ConsumeToken(); // consume ','
2472e5dd7070Spatrick }
2473e5dd7070Spatrick ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
2474e5dd7070Spatrick return nullptr;
2475e5dd7070Spatrick }
2476e5dd7070Spatrick
2477e5dd7070Spatrick /// objc-throw-statement:
2478e5dd7070Spatrick /// throw expression[opt];
2479e5dd7070Spatrick ///
ParseObjCThrowStmt(SourceLocation atLoc)2480e5dd7070Spatrick StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
2481e5dd7070Spatrick ExprResult Res;
2482e5dd7070Spatrick ConsumeToken(); // consume throw
2483e5dd7070Spatrick if (Tok.isNot(tok::semi)) {
2484e5dd7070Spatrick Res = ParseExpression();
2485e5dd7070Spatrick if (Res.isInvalid()) {
2486e5dd7070Spatrick SkipUntil(tok::semi);
2487e5dd7070Spatrick return StmtError();
2488e5dd7070Spatrick }
2489e5dd7070Spatrick }
2490e5dd7070Spatrick // consume ';'
2491e5dd7070Spatrick ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
2492e5dd7070Spatrick return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
2493e5dd7070Spatrick }
2494e5dd7070Spatrick
2495e5dd7070Spatrick /// objc-synchronized-statement:
2496e5dd7070Spatrick /// @synchronized '(' expression ')' compound-statement
2497e5dd7070Spatrick ///
2498e5dd7070Spatrick StmtResult
ParseObjCSynchronizedStmt(SourceLocation atLoc)2499e5dd7070Spatrick Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
2500e5dd7070Spatrick ConsumeToken(); // consume synchronized
2501e5dd7070Spatrick if (Tok.isNot(tok::l_paren)) {
2502e5dd7070Spatrick Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
2503e5dd7070Spatrick return StmtError();
2504e5dd7070Spatrick }
2505e5dd7070Spatrick
2506e5dd7070Spatrick // The operand is surrounded with parentheses.
2507e5dd7070Spatrick ConsumeParen(); // '('
2508e5dd7070Spatrick ExprResult operand(ParseExpression());
2509e5dd7070Spatrick
2510e5dd7070Spatrick if (Tok.is(tok::r_paren)) {
2511e5dd7070Spatrick ConsumeParen(); // ')'
2512e5dd7070Spatrick } else {
2513e5dd7070Spatrick if (!operand.isInvalid())
2514e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::r_paren;
2515e5dd7070Spatrick
2516e5dd7070Spatrick // Skip forward until we see a left brace, but don't consume it.
2517e5dd7070Spatrick SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
2518e5dd7070Spatrick }
2519e5dd7070Spatrick
2520e5dd7070Spatrick // Require a compound statement.
2521e5dd7070Spatrick if (Tok.isNot(tok::l_brace)) {
2522e5dd7070Spatrick if (!operand.isInvalid())
2523e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::l_brace;
2524e5dd7070Spatrick return StmtError();
2525e5dd7070Spatrick }
2526e5dd7070Spatrick
2527e5dd7070Spatrick // Check the @synchronized operand now.
2528e5dd7070Spatrick if (!operand.isInvalid())
2529e5dd7070Spatrick operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
2530e5dd7070Spatrick
2531e5dd7070Spatrick // Parse the compound statement within a new scope.
2532e5dd7070Spatrick ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2533e5dd7070Spatrick StmtResult body(ParseCompoundStatementBody());
2534e5dd7070Spatrick bodyScope.Exit();
2535e5dd7070Spatrick
2536e5dd7070Spatrick // If there was a semantic or parse error earlier with the
2537e5dd7070Spatrick // operand, fail now.
2538e5dd7070Spatrick if (operand.isInvalid())
2539e5dd7070Spatrick return StmtError();
2540e5dd7070Spatrick
2541e5dd7070Spatrick if (body.isInvalid())
2542e5dd7070Spatrick body = Actions.ActOnNullStmt(Tok.getLocation());
2543e5dd7070Spatrick
2544e5dd7070Spatrick return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
2545e5dd7070Spatrick }
2546e5dd7070Spatrick
2547e5dd7070Spatrick /// objc-try-catch-statement:
2548e5dd7070Spatrick /// @try compound-statement objc-catch-list[opt]
2549e5dd7070Spatrick /// @try compound-statement objc-catch-list[opt] @finally compound-statement
2550e5dd7070Spatrick ///
2551e5dd7070Spatrick /// objc-catch-list:
2552e5dd7070Spatrick /// @catch ( parameter-declaration ) compound-statement
2553e5dd7070Spatrick /// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
2554e5dd7070Spatrick /// catch-parameter-declaration:
2555e5dd7070Spatrick /// parameter-declaration
2556e5dd7070Spatrick /// '...' [OBJC2]
2557e5dd7070Spatrick ///
ParseObjCTryStmt(SourceLocation atLoc)2558e5dd7070Spatrick StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
2559e5dd7070Spatrick bool catch_or_finally_seen = false;
2560e5dd7070Spatrick
2561e5dd7070Spatrick ConsumeToken(); // consume try
2562e5dd7070Spatrick if (Tok.isNot(tok::l_brace)) {
2563e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::l_brace;
2564e5dd7070Spatrick return StmtError();
2565e5dd7070Spatrick }
2566e5dd7070Spatrick StmtVector CatchStmts;
2567e5dd7070Spatrick StmtResult FinallyStmt;
2568e5dd7070Spatrick ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2569e5dd7070Spatrick StmtResult TryBody(ParseCompoundStatementBody());
2570e5dd7070Spatrick TryScope.Exit();
2571e5dd7070Spatrick if (TryBody.isInvalid())
2572e5dd7070Spatrick TryBody = Actions.ActOnNullStmt(Tok.getLocation());
2573e5dd7070Spatrick
2574e5dd7070Spatrick while (Tok.is(tok::at)) {
2575e5dd7070Spatrick // At this point, we need to lookahead to determine if this @ is the start
2576e5dd7070Spatrick // of an @catch or @finally. We don't want to consume the @ token if this
2577e5dd7070Spatrick // is an @try or @encode or something else.
2578e5dd7070Spatrick Token AfterAt = GetLookAheadToken(1);
2579e5dd7070Spatrick if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
2580e5dd7070Spatrick !AfterAt.isObjCAtKeyword(tok::objc_finally))
2581e5dd7070Spatrick break;
2582e5dd7070Spatrick
2583e5dd7070Spatrick SourceLocation AtCatchFinallyLoc = ConsumeToken();
2584e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_catch)) {
2585e5dd7070Spatrick Decl *FirstPart = nullptr;
2586e5dd7070Spatrick ConsumeToken(); // consume catch
2587e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
2588e5dd7070Spatrick ConsumeParen();
2589e5dd7070Spatrick ParseScope CatchScope(this, Scope::DeclScope |
2590e5dd7070Spatrick Scope::CompoundStmtScope |
2591e5dd7070Spatrick Scope::AtCatchScope);
2592e5dd7070Spatrick if (Tok.isNot(tok::ellipsis)) {
2593e5dd7070Spatrick DeclSpec DS(AttrFactory);
2594e5dd7070Spatrick ParseDeclarationSpecifiers(DS);
2595*12c85518Srobert Declarator ParmDecl(DS, ParsedAttributesView::none(),
2596*12c85518Srobert DeclaratorContext::ObjCCatch);
2597e5dd7070Spatrick ParseDeclarator(ParmDecl);
2598e5dd7070Spatrick
2599e5dd7070Spatrick // Inform the actions module about the declarator, so it
2600e5dd7070Spatrick // gets added to the current scope.
2601e5dd7070Spatrick FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
2602e5dd7070Spatrick } else
2603e5dd7070Spatrick ConsumeToken(); // consume '...'
2604e5dd7070Spatrick
2605e5dd7070Spatrick SourceLocation RParenLoc;
2606e5dd7070Spatrick
2607e5dd7070Spatrick if (Tok.is(tok::r_paren))
2608e5dd7070Spatrick RParenLoc = ConsumeParen();
2609e5dd7070Spatrick else // Skip over garbage, until we get to ')'. Eat the ')'.
2610e5dd7070Spatrick SkipUntil(tok::r_paren, StopAtSemi);
2611e5dd7070Spatrick
2612e5dd7070Spatrick StmtResult CatchBody(true);
2613e5dd7070Spatrick if (Tok.is(tok::l_brace))
2614e5dd7070Spatrick CatchBody = ParseCompoundStatementBody();
2615e5dd7070Spatrick else
2616e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::l_brace;
2617e5dd7070Spatrick if (CatchBody.isInvalid())
2618e5dd7070Spatrick CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
2619e5dd7070Spatrick
2620e5dd7070Spatrick StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
2621e5dd7070Spatrick RParenLoc,
2622e5dd7070Spatrick FirstPart,
2623e5dd7070Spatrick CatchBody.get());
2624e5dd7070Spatrick if (!Catch.isInvalid())
2625e5dd7070Spatrick CatchStmts.push_back(Catch.get());
2626e5dd7070Spatrick
2627e5dd7070Spatrick } else {
2628e5dd7070Spatrick Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
2629e5dd7070Spatrick << "@catch clause";
2630e5dd7070Spatrick return StmtError();
2631e5dd7070Spatrick }
2632e5dd7070Spatrick catch_or_finally_seen = true;
2633e5dd7070Spatrick } else {
2634e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
2635e5dd7070Spatrick ConsumeToken(); // consume finally
2636e5dd7070Spatrick ParseScope FinallyScope(this,
2637e5dd7070Spatrick Scope::DeclScope | Scope::CompoundStmtScope);
2638e5dd7070Spatrick
2639e5dd7070Spatrick bool ShouldCapture =
2640e5dd7070Spatrick getTargetInfo().getTriple().isWindowsMSVCEnvironment();
2641e5dd7070Spatrick if (ShouldCapture)
2642e5dd7070Spatrick Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),
2643e5dd7070Spatrick CR_ObjCAtFinally, 1);
2644e5dd7070Spatrick
2645e5dd7070Spatrick StmtResult FinallyBody(true);
2646e5dd7070Spatrick if (Tok.is(tok::l_brace))
2647e5dd7070Spatrick FinallyBody = ParseCompoundStatementBody();
2648e5dd7070Spatrick else
2649e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::l_brace;
2650e5dd7070Spatrick
2651e5dd7070Spatrick if (FinallyBody.isInvalid()) {
2652e5dd7070Spatrick FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
2653e5dd7070Spatrick if (ShouldCapture)
2654e5dd7070Spatrick Actions.ActOnCapturedRegionError();
2655e5dd7070Spatrick } else if (ShouldCapture) {
2656e5dd7070Spatrick FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());
2657e5dd7070Spatrick }
2658e5dd7070Spatrick
2659e5dd7070Spatrick FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
2660e5dd7070Spatrick FinallyBody.get());
2661e5dd7070Spatrick catch_or_finally_seen = true;
2662e5dd7070Spatrick break;
2663e5dd7070Spatrick }
2664e5dd7070Spatrick }
2665e5dd7070Spatrick if (!catch_or_finally_seen) {
2666e5dd7070Spatrick Diag(atLoc, diag::err_missing_catch_finally);
2667e5dd7070Spatrick return StmtError();
2668e5dd7070Spatrick }
2669e5dd7070Spatrick
2670e5dd7070Spatrick return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
2671e5dd7070Spatrick CatchStmts,
2672e5dd7070Spatrick FinallyStmt.get());
2673e5dd7070Spatrick }
2674e5dd7070Spatrick
2675e5dd7070Spatrick /// objc-autoreleasepool-statement:
2676e5dd7070Spatrick /// @autoreleasepool compound-statement
2677e5dd7070Spatrick ///
2678e5dd7070Spatrick StmtResult
ParseObjCAutoreleasePoolStmt(SourceLocation atLoc)2679e5dd7070Spatrick Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
2680e5dd7070Spatrick ConsumeToken(); // consume autoreleasepool
2681e5dd7070Spatrick if (Tok.isNot(tok::l_brace)) {
2682e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::l_brace;
2683e5dd7070Spatrick return StmtError();
2684e5dd7070Spatrick }
2685e5dd7070Spatrick // Enter a scope to hold everything within the compound stmt. Compound
2686e5dd7070Spatrick // statements can always hold declarations.
2687e5dd7070Spatrick ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2688e5dd7070Spatrick
2689e5dd7070Spatrick StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
2690e5dd7070Spatrick
2691e5dd7070Spatrick BodyScope.Exit();
2692e5dd7070Spatrick if (AutoreleasePoolBody.isInvalid())
2693e5dd7070Spatrick AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
2694e5dd7070Spatrick return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
2695e5dd7070Spatrick AutoreleasePoolBody.get());
2696e5dd7070Spatrick }
2697e5dd7070Spatrick
2698e5dd7070Spatrick /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
2699e5dd7070Spatrick /// for later parsing.
StashAwayMethodOrFunctionBodyTokens(Decl * MDecl)2700e5dd7070Spatrick void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
2701e5dd7070Spatrick if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
2702e5dd7070Spatrick trySkippingFunctionBody()) {
2703e5dd7070Spatrick Actions.ActOnSkippedFunctionBody(MDecl);
2704e5dd7070Spatrick return;
2705e5dd7070Spatrick }
2706e5dd7070Spatrick
2707e5dd7070Spatrick LexedMethod* LM = new LexedMethod(this, MDecl);
2708e5dd7070Spatrick CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
2709e5dd7070Spatrick CachedTokens &Toks = LM->Toks;
2710e5dd7070Spatrick // Begin by storing the '{' or 'try' or ':' token.
2711e5dd7070Spatrick Toks.push_back(Tok);
2712e5dd7070Spatrick if (Tok.is(tok::kw_try)) {
2713e5dd7070Spatrick ConsumeToken();
2714e5dd7070Spatrick if (Tok.is(tok::colon)) {
2715e5dd7070Spatrick Toks.push_back(Tok);
2716e5dd7070Spatrick ConsumeToken();
2717e5dd7070Spatrick while (Tok.isNot(tok::l_brace)) {
2718e5dd7070Spatrick ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
2719e5dd7070Spatrick ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
2720e5dd7070Spatrick }
2721e5dd7070Spatrick }
2722e5dd7070Spatrick Toks.push_back(Tok); // also store '{'
2723e5dd7070Spatrick }
2724e5dd7070Spatrick else if (Tok.is(tok::colon)) {
2725e5dd7070Spatrick ConsumeToken();
2726e5dd7070Spatrick // FIXME: This is wrong, due to C++11 braced initialization.
2727e5dd7070Spatrick while (Tok.isNot(tok::l_brace)) {
2728e5dd7070Spatrick ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
2729e5dd7070Spatrick ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
2730e5dd7070Spatrick }
2731e5dd7070Spatrick Toks.push_back(Tok); // also store '{'
2732e5dd7070Spatrick }
2733e5dd7070Spatrick ConsumeBrace();
2734e5dd7070Spatrick // Consume everything up to (and including) the matching right brace.
2735e5dd7070Spatrick ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
2736e5dd7070Spatrick while (Tok.is(tok::kw_catch)) {
2737e5dd7070Spatrick ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
2738e5dd7070Spatrick ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
2739e5dd7070Spatrick }
2740e5dd7070Spatrick }
2741e5dd7070Spatrick
2742e5dd7070Spatrick /// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
2743e5dd7070Spatrick ///
ParseObjCMethodDefinition()2744e5dd7070Spatrick Decl *Parser::ParseObjCMethodDefinition() {
2745e5dd7070Spatrick Decl *MDecl = ParseObjCMethodPrototype();
2746e5dd7070Spatrick
2747e5dd7070Spatrick PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),
2748e5dd7070Spatrick "parsing Objective-C method");
2749e5dd7070Spatrick
2750e5dd7070Spatrick // parse optional ';'
2751e5dd7070Spatrick if (Tok.is(tok::semi)) {
2752e5dd7070Spatrick if (CurParsedObjCImpl) {
2753e5dd7070Spatrick Diag(Tok, diag::warn_semicolon_before_method_body)
2754e5dd7070Spatrick << FixItHint::CreateRemoval(Tok.getLocation());
2755e5dd7070Spatrick }
2756e5dd7070Spatrick ConsumeToken();
2757e5dd7070Spatrick }
2758e5dd7070Spatrick
2759e5dd7070Spatrick // We should have an opening brace now.
2760e5dd7070Spatrick if (Tok.isNot(tok::l_brace)) {
2761e5dd7070Spatrick Diag(Tok, diag::err_expected_method_body);
2762e5dd7070Spatrick
2763e5dd7070Spatrick // Skip over garbage, until we get to '{'. Don't eat the '{'.
2764e5dd7070Spatrick SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
2765e5dd7070Spatrick
2766e5dd7070Spatrick // If we didn't find the '{', bail out.
2767e5dd7070Spatrick if (Tok.isNot(tok::l_brace))
2768e5dd7070Spatrick return nullptr;
2769e5dd7070Spatrick }
2770e5dd7070Spatrick
2771e5dd7070Spatrick if (!MDecl) {
2772e5dd7070Spatrick ConsumeBrace();
2773e5dd7070Spatrick SkipUntil(tok::r_brace);
2774e5dd7070Spatrick return nullptr;
2775e5dd7070Spatrick }
2776e5dd7070Spatrick
2777e5dd7070Spatrick // Allow the rest of sema to find private method decl implementations.
2778e5dd7070Spatrick Actions.AddAnyMethodToGlobalPool(MDecl);
2779e5dd7070Spatrick assert (CurParsedObjCImpl
2780e5dd7070Spatrick && "ParseObjCMethodDefinition - Method out of @implementation");
2781e5dd7070Spatrick // Consume the tokens and store them for later parsing.
2782e5dd7070Spatrick StashAwayMethodOrFunctionBodyTokens(MDecl);
2783e5dd7070Spatrick return MDecl;
2784e5dd7070Spatrick }
2785e5dd7070Spatrick
ParseObjCAtStatement(SourceLocation AtLoc,ParsedStmtContext StmtCtx)2786e5dd7070Spatrick StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
2787e5dd7070Spatrick ParsedStmtContext StmtCtx) {
2788e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
2789e5dd7070Spatrick cutOffParsing();
2790a9ac8606Spatrick Actions.CodeCompleteObjCAtStatement(getCurScope());
2791e5dd7070Spatrick return StmtError();
2792e5dd7070Spatrick }
2793e5dd7070Spatrick
2794e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_try))
2795e5dd7070Spatrick return ParseObjCTryStmt(AtLoc);
2796e5dd7070Spatrick
2797e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_throw))
2798e5dd7070Spatrick return ParseObjCThrowStmt(AtLoc);
2799e5dd7070Spatrick
2800e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_synchronized))
2801e5dd7070Spatrick return ParseObjCSynchronizedStmt(AtLoc);
2802e5dd7070Spatrick
2803e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
2804e5dd7070Spatrick return ParseObjCAutoreleasePoolStmt(AtLoc);
2805e5dd7070Spatrick
2806e5dd7070Spatrick if (Tok.isObjCAtKeyword(tok::objc_import) &&
2807e5dd7070Spatrick getLangOpts().DebuggerSupport) {
2808e5dd7070Spatrick SkipUntil(tok::semi);
2809e5dd7070Spatrick return Actions.ActOnNullStmt(Tok.getLocation());
2810e5dd7070Spatrick }
2811e5dd7070Spatrick
2812e5dd7070Spatrick ExprStatementTokLoc = AtLoc;
2813e5dd7070Spatrick ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
2814e5dd7070Spatrick if (Res.isInvalid()) {
2815e5dd7070Spatrick // If the expression is invalid, skip ahead to the next semicolon. Not
2816e5dd7070Spatrick // doing this opens us up to the possibility of infinite loops if
2817e5dd7070Spatrick // ParseExpression does not consume any tokens.
2818e5dd7070Spatrick SkipUntil(tok::semi);
2819e5dd7070Spatrick return StmtError();
2820e5dd7070Spatrick }
2821e5dd7070Spatrick
2822e5dd7070Spatrick // Otherwise, eat the semicolon.
2823e5dd7070Spatrick ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
2824e5dd7070Spatrick return handleExprStmt(Res, StmtCtx);
2825e5dd7070Spatrick }
2826e5dd7070Spatrick
ParseObjCAtExpression(SourceLocation AtLoc)2827e5dd7070Spatrick ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
2828e5dd7070Spatrick switch (Tok.getKind()) {
2829e5dd7070Spatrick case tok::code_completion:
2830e5dd7070Spatrick cutOffParsing();
2831a9ac8606Spatrick Actions.CodeCompleteObjCAtExpression(getCurScope());
2832e5dd7070Spatrick return ExprError();
2833e5dd7070Spatrick
2834e5dd7070Spatrick case tok::minus:
2835e5dd7070Spatrick case tok::plus: {
2836e5dd7070Spatrick tok::TokenKind Kind = Tok.getKind();
2837e5dd7070Spatrick SourceLocation OpLoc = ConsumeToken();
2838e5dd7070Spatrick
2839e5dd7070Spatrick if (!Tok.is(tok::numeric_constant)) {
2840e5dd7070Spatrick const char *Symbol = nullptr;
2841e5dd7070Spatrick switch (Kind) {
2842e5dd7070Spatrick case tok::minus: Symbol = "-"; break;
2843e5dd7070Spatrick case tok::plus: Symbol = "+"; break;
2844e5dd7070Spatrick default: llvm_unreachable("missing unary operator case");
2845e5dd7070Spatrick }
2846e5dd7070Spatrick Diag(Tok, diag::err_nsnumber_nonliteral_unary)
2847e5dd7070Spatrick << Symbol;
2848e5dd7070Spatrick return ExprError();
2849e5dd7070Spatrick }
2850e5dd7070Spatrick
2851e5dd7070Spatrick ExprResult Lit(Actions.ActOnNumericConstant(Tok));
2852e5dd7070Spatrick if (Lit.isInvalid()) {
2853e5dd7070Spatrick return Lit;
2854e5dd7070Spatrick }
2855e5dd7070Spatrick ConsumeToken(); // Consume the literal token.
2856e5dd7070Spatrick
2857e5dd7070Spatrick Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
2858e5dd7070Spatrick if (Lit.isInvalid())
2859e5dd7070Spatrick return Lit;
2860e5dd7070Spatrick
2861e5dd7070Spatrick return ParsePostfixExpressionSuffix(
2862e5dd7070Spatrick Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
2863e5dd7070Spatrick }
2864e5dd7070Spatrick
2865e5dd7070Spatrick case tok::string_literal: // primary-expression: string-literal
2866e5dd7070Spatrick case tok::wide_string_literal:
2867e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
2868e5dd7070Spatrick
2869e5dd7070Spatrick case tok::char_constant:
2870e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
2871e5dd7070Spatrick
2872e5dd7070Spatrick case tok::numeric_constant:
2873e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
2874e5dd7070Spatrick
2875e5dd7070Spatrick case tok::kw_true: // Objective-C++, etc.
2876e5dd7070Spatrick case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
2877e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
2878e5dd7070Spatrick case tok::kw_false: // Objective-C++, etc.
2879e5dd7070Spatrick case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
2880e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
2881e5dd7070Spatrick
2882e5dd7070Spatrick case tok::l_square:
2883e5dd7070Spatrick // Objective-C array literal
2884e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
2885e5dd7070Spatrick
2886e5dd7070Spatrick case tok::l_brace:
2887e5dd7070Spatrick // Objective-C dictionary literal
2888e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
2889e5dd7070Spatrick
2890e5dd7070Spatrick case tok::l_paren:
2891e5dd7070Spatrick // Objective-C boxed expression
2892e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
2893e5dd7070Spatrick
2894e5dd7070Spatrick default:
2895e5dd7070Spatrick if (Tok.getIdentifierInfo() == nullptr)
2896e5dd7070Spatrick return ExprError(Diag(AtLoc, diag::err_unexpected_at));
2897e5dd7070Spatrick
2898e5dd7070Spatrick switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
2899e5dd7070Spatrick case tok::objc_encode:
2900e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
2901e5dd7070Spatrick case tok::objc_protocol:
2902e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
2903e5dd7070Spatrick case tok::objc_selector:
2904e5dd7070Spatrick return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
2905e5dd7070Spatrick case tok::objc_available:
2906e5dd7070Spatrick return ParseAvailabilityCheckExpr(AtLoc);
2907e5dd7070Spatrick default: {
2908e5dd7070Spatrick const char *str = nullptr;
2909e5dd7070Spatrick // Only provide the @try/@finally/@autoreleasepool fixit when we're sure
2910e5dd7070Spatrick // that this is a proper statement where such directives could actually
2911e5dd7070Spatrick // occur.
2912e5dd7070Spatrick if (GetLookAheadToken(1).is(tok::l_brace) &&
2913e5dd7070Spatrick ExprStatementTokLoc == AtLoc) {
2914e5dd7070Spatrick char ch = Tok.getIdentifierInfo()->getNameStart()[0];
2915e5dd7070Spatrick str =
2916e5dd7070Spatrick ch == 't' ? "try"
2917e5dd7070Spatrick : (ch == 'f' ? "finally"
2918e5dd7070Spatrick : (ch == 'a' ? "autoreleasepool" : nullptr));
2919e5dd7070Spatrick }
2920e5dd7070Spatrick if (str) {
2921e5dd7070Spatrick SourceLocation kwLoc = Tok.getLocation();
2922e5dd7070Spatrick return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
2923e5dd7070Spatrick FixItHint::CreateReplacement(kwLoc, str));
2924e5dd7070Spatrick }
2925e5dd7070Spatrick else
2926e5dd7070Spatrick return ExprError(Diag(AtLoc, diag::err_unexpected_at));
2927e5dd7070Spatrick }
2928e5dd7070Spatrick }
2929e5dd7070Spatrick }
2930e5dd7070Spatrick }
2931e5dd7070Spatrick
2932e5dd7070Spatrick /// Parse the receiver of an Objective-C++ message send.
2933e5dd7070Spatrick ///
2934e5dd7070Spatrick /// This routine parses the receiver of a message send in
2935e5dd7070Spatrick /// Objective-C++ either as a type or as an expression. Note that this
2936e5dd7070Spatrick /// routine must not be called to parse a send to 'super', since it
2937e5dd7070Spatrick /// has no way to return such a result.
2938e5dd7070Spatrick ///
2939e5dd7070Spatrick /// \param IsExpr Whether the receiver was parsed as an expression.
2940e5dd7070Spatrick ///
2941e5dd7070Spatrick /// \param TypeOrExpr If the receiver was parsed as an expression (\c
2942e5dd7070Spatrick /// IsExpr is true), the parsed expression. If the receiver was parsed
2943e5dd7070Spatrick /// as a type (\c IsExpr is false), the parsed type.
2944e5dd7070Spatrick ///
2945e5dd7070Spatrick /// \returns True if an error occurred during parsing or semantic
2946e5dd7070Spatrick /// analysis, in which case the arguments do not have valid
2947e5dd7070Spatrick /// values. Otherwise, returns false for a successful parse.
2948e5dd7070Spatrick ///
2949e5dd7070Spatrick /// objc-receiver: [C++]
2950e5dd7070Spatrick /// 'super' [not parsed here]
2951e5dd7070Spatrick /// expression
2952e5dd7070Spatrick /// simple-type-specifier
2953e5dd7070Spatrick /// typename-specifier
ParseObjCXXMessageReceiver(bool & IsExpr,void * & TypeOrExpr)2954e5dd7070Spatrick bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
2955e5dd7070Spatrick InMessageExpressionRAIIObject InMessage(*this, true);
2956e5dd7070Spatrick
2957e5dd7070Spatrick if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
2958e5dd7070Spatrick tok::annot_cxxscope))
2959e5dd7070Spatrick TryAnnotateTypeOrScopeToken();
2960e5dd7070Spatrick
2961e5dd7070Spatrick if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
2962e5dd7070Spatrick // objc-receiver:
2963e5dd7070Spatrick // expression
2964e5dd7070Spatrick // Make sure any typos in the receiver are corrected or diagnosed, so that
2965e5dd7070Spatrick // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
2966e5dd7070Spatrick // only the things that are valid ObjC receivers?
2967e5dd7070Spatrick ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
2968e5dd7070Spatrick if (Receiver.isInvalid())
2969e5dd7070Spatrick return true;
2970e5dd7070Spatrick
2971e5dd7070Spatrick IsExpr = true;
2972e5dd7070Spatrick TypeOrExpr = Receiver.get();
2973e5dd7070Spatrick return false;
2974e5dd7070Spatrick }
2975e5dd7070Spatrick
2976e5dd7070Spatrick // objc-receiver:
2977e5dd7070Spatrick // typename-specifier
2978e5dd7070Spatrick // simple-type-specifier
2979e5dd7070Spatrick // expression (that starts with one of the above)
2980e5dd7070Spatrick DeclSpec DS(AttrFactory);
2981e5dd7070Spatrick ParseCXXSimpleTypeSpecifier(DS);
2982e5dd7070Spatrick
2983e5dd7070Spatrick if (Tok.is(tok::l_paren)) {
2984e5dd7070Spatrick // If we see an opening parentheses at this point, we are
2985e5dd7070Spatrick // actually parsing an expression that starts with a
2986e5dd7070Spatrick // function-style cast, e.g.,
2987e5dd7070Spatrick //
2988e5dd7070Spatrick // postfix-expression:
2989e5dd7070Spatrick // simple-type-specifier ( expression-list [opt] )
2990e5dd7070Spatrick // typename-specifier ( expression-list [opt] )
2991e5dd7070Spatrick //
2992e5dd7070Spatrick // Parse the remainder of this case, then the (optional)
2993e5dd7070Spatrick // postfix-expression suffix, followed by the (optional)
2994e5dd7070Spatrick // right-hand side of the binary expression. We have an
2995e5dd7070Spatrick // instance method.
2996e5dd7070Spatrick ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
2997e5dd7070Spatrick if (!Receiver.isInvalid())
2998e5dd7070Spatrick Receiver = ParsePostfixExpressionSuffix(Receiver.get());
2999e5dd7070Spatrick if (!Receiver.isInvalid())
3000e5dd7070Spatrick Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
3001e5dd7070Spatrick if (Receiver.isInvalid())
3002e5dd7070Spatrick return true;
3003e5dd7070Spatrick
3004e5dd7070Spatrick IsExpr = true;
3005e5dd7070Spatrick TypeOrExpr = Receiver.get();
3006e5dd7070Spatrick return false;
3007e5dd7070Spatrick }
3008e5dd7070Spatrick
3009e5dd7070Spatrick // We have a class message. Turn the simple-type-specifier or
3010e5dd7070Spatrick // typename-specifier we parsed into a type and parse the
3011e5dd7070Spatrick // remainder of the class message.
3012*12c85518Srobert Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
3013*12c85518Srobert DeclaratorContext::TypeName);
3014e5dd7070Spatrick TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
3015e5dd7070Spatrick if (Type.isInvalid())
3016e5dd7070Spatrick return true;
3017e5dd7070Spatrick
3018e5dd7070Spatrick IsExpr = false;
3019e5dd7070Spatrick TypeOrExpr = Type.get().getAsOpaquePtr();
3020e5dd7070Spatrick return false;
3021e5dd7070Spatrick }
3022e5dd7070Spatrick
3023e5dd7070Spatrick /// Determine whether the parser is currently referring to a an
3024e5dd7070Spatrick /// Objective-C message send, using a simplified heuristic to avoid overhead.
3025e5dd7070Spatrick ///
3026e5dd7070Spatrick /// This routine will only return true for a subset of valid message-send
3027e5dd7070Spatrick /// expressions.
isSimpleObjCMessageExpression()3028e5dd7070Spatrick bool Parser::isSimpleObjCMessageExpression() {
3029e5dd7070Spatrick assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&
3030e5dd7070Spatrick "Incorrect start for isSimpleObjCMessageExpression");
3031e5dd7070Spatrick return GetLookAheadToken(1).is(tok::identifier) &&
3032e5dd7070Spatrick GetLookAheadToken(2).is(tok::identifier);
3033e5dd7070Spatrick }
3034e5dd7070Spatrick
isStartOfObjCClassMessageMissingOpenBracket()3035e5dd7070Spatrick bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
3036e5dd7070Spatrick if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||
3037e5dd7070Spatrick InMessageExpression)
3038e5dd7070Spatrick return false;
3039e5dd7070Spatrick
3040ec727ea7Spatrick TypeResult Type;
3041e5dd7070Spatrick
3042e5dd7070Spatrick if (Tok.is(tok::annot_typename))
3043e5dd7070Spatrick Type = getTypeAnnotation(Tok);
3044e5dd7070Spatrick else if (Tok.is(tok::identifier))
3045e5dd7070Spatrick Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
3046e5dd7070Spatrick getCurScope());
3047e5dd7070Spatrick else
3048e5dd7070Spatrick return false;
3049e5dd7070Spatrick
3050ec727ea7Spatrick // FIXME: Should not be querying properties of types from the parser.
3051ec727ea7Spatrick if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) {
3052e5dd7070Spatrick const Token &AfterNext = GetLookAheadToken(2);
3053e5dd7070Spatrick if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
3054e5dd7070Spatrick if (Tok.is(tok::identifier))
3055e5dd7070Spatrick TryAnnotateTypeOrScopeToken();
3056e5dd7070Spatrick
3057e5dd7070Spatrick return Tok.is(tok::annot_typename);
3058e5dd7070Spatrick }
3059e5dd7070Spatrick }
3060e5dd7070Spatrick
3061e5dd7070Spatrick return false;
3062e5dd7070Spatrick }
3063e5dd7070Spatrick
3064e5dd7070Spatrick /// objc-message-expr:
3065e5dd7070Spatrick /// '[' objc-receiver objc-message-args ']'
3066e5dd7070Spatrick ///
3067e5dd7070Spatrick /// objc-receiver: [C]
3068e5dd7070Spatrick /// 'super'
3069e5dd7070Spatrick /// expression
3070e5dd7070Spatrick /// class-name
3071e5dd7070Spatrick /// type-name
3072e5dd7070Spatrick ///
ParseObjCMessageExpression()3073e5dd7070Spatrick ExprResult Parser::ParseObjCMessageExpression() {
3074e5dd7070Spatrick assert(Tok.is(tok::l_square) && "'[' expected");
3075e5dd7070Spatrick SourceLocation LBracLoc = ConsumeBracket(); // consume '['
3076e5dd7070Spatrick
3077e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3078e5dd7070Spatrick cutOffParsing();
3079a9ac8606Spatrick Actions.CodeCompleteObjCMessageReceiver(getCurScope());
3080e5dd7070Spatrick return ExprError();
3081e5dd7070Spatrick }
3082e5dd7070Spatrick
3083e5dd7070Spatrick InMessageExpressionRAIIObject InMessage(*this, true);
3084e5dd7070Spatrick
3085e5dd7070Spatrick if (getLangOpts().CPlusPlus) {
3086e5dd7070Spatrick // We completely separate the C and C++ cases because C++ requires
3087e5dd7070Spatrick // more complicated (read: slower) parsing.
3088e5dd7070Spatrick
3089e5dd7070Spatrick // Handle send to super.
3090e5dd7070Spatrick // FIXME: This doesn't benefit from the same typo-correction we
3091e5dd7070Spatrick // get in Objective-C.
3092e5dd7070Spatrick if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
3093e5dd7070Spatrick NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
3094e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
3095e5dd7070Spatrick nullptr);
3096e5dd7070Spatrick
3097e5dd7070Spatrick // Parse the receiver, which is either a type or an expression.
3098e5dd7070Spatrick bool IsExpr;
3099e5dd7070Spatrick void *TypeOrExpr = nullptr;
3100e5dd7070Spatrick if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
3101e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3102e5dd7070Spatrick return ExprError();
3103e5dd7070Spatrick }
3104e5dd7070Spatrick
3105e5dd7070Spatrick if (IsExpr)
3106e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
3107e5dd7070Spatrick static_cast<Expr *>(TypeOrExpr));
3108e5dd7070Spatrick
3109e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
3110e5dd7070Spatrick ParsedType::getFromOpaquePtr(TypeOrExpr),
3111e5dd7070Spatrick nullptr);
3112e5dd7070Spatrick }
3113e5dd7070Spatrick
3114e5dd7070Spatrick if (Tok.is(tok::identifier)) {
3115e5dd7070Spatrick IdentifierInfo *Name = Tok.getIdentifierInfo();
3116e5dd7070Spatrick SourceLocation NameLoc = Tok.getLocation();
3117e5dd7070Spatrick ParsedType ReceiverType;
3118e5dd7070Spatrick switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
3119e5dd7070Spatrick Name == Ident_super,
3120e5dd7070Spatrick NextToken().is(tok::period),
3121e5dd7070Spatrick ReceiverType)) {
3122e5dd7070Spatrick case Sema::ObjCSuperMessage:
3123e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
3124e5dd7070Spatrick nullptr);
3125e5dd7070Spatrick
3126e5dd7070Spatrick case Sema::ObjCClassMessage:
3127e5dd7070Spatrick if (!ReceiverType) {
3128e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3129e5dd7070Spatrick return ExprError();
3130e5dd7070Spatrick }
3131e5dd7070Spatrick
3132e5dd7070Spatrick ConsumeToken(); // the type name
3133e5dd7070Spatrick
3134e5dd7070Spatrick // Parse type arguments and protocol qualifiers.
3135e5dd7070Spatrick if (Tok.is(tok::less)) {
3136e5dd7070Spatrick SourceLocation NewEndLoc;
3137e5dd7070Spatrick TypeResult NewReceiverType
3138e5dd7070Spatrick = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
3139e5dd7070Spatrick /*consumeLastToken=*/true,
3140e5dd7070Spatrick NewEndLoc);
3141e5dd7070Spatrick if (!NewReceiverType.isUsable()) {
3142e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3143e5dd7070Spatrick return ExprError();
3144e5dd7070Spatrick }
3145e5dd7070Spatrick
3146e5dd7070Spatrick ReceiverType = NewReceiverType.get();
3147e5dd7070Spatrick }
3148e5dd7070Spatrick
3149e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
3150e5dd7070Spatrick ReceiverType, nullptr);
3151e5dd7070Spatrick
3152e5dd7070Spatrick case Sema::ObjCInstanceMessage:
3153e5dd7070Spatrick // Fall through to parse an expression.
3154e5dd7070Spatrick break;
3155e5dd7070Spatrick }
3156e5dd7070Spatrick }
3157e5dd7070Spatrick
3158e5dd7070Spatrick // Otherwise, an arbitrary expression can be the receiver of a send.
3159e5dd7070Spatrick ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
3160e5dd7070Spatrick if (Res.isInvalid()) {
3161e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3162e5dd7070Spatrick return Res;
3163e5dd7070Spatrick }
3164e5dd7070Spatrick
3165e5dd7070Spatrick return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
3166e5dd7070Spatrick Res.get());
3167e5dd7070Spatrick }
3168e5dd7070Spatrick
3169e5dd7070Spatrick /// Parse the remainder of an Objective-C message following the
3170e5dd7070Spatrick /// '[' objc-receiver.
3171e5dd7070Spatrick ///
3172e5dd7070Spatrick /// This routine handles sends to super, class messages (sent to a
3173e5dd7070Spatrick /// class name), and instance messages (sent to an object), and the
3174e5dd7070Spatrick /// target is represented by \p SuperLoc, \p ReceiverType, or \p
3175e5dd7070Spatrick /// ReceiverExpr, respectively. Only one of these parameters may have
3176e5dd7070Spatrick /// a valid value.
3177e5dd7070Spatrick ///
3178e5dd7070Spatrick /// \param LBracLoc The location of the opening '['.
3179e5dd7070Spatrick ///
3180e5dd7070Spatrick /// \param SuperLoc If this is a send to 'super', the location of the
3181e5dd7070Spatrick /// 'super' keyword that indicates a send to the superclass.
3182e5dd7070Spatrick ///
3183e5dd7070Spatrick /// \param ReceiverType If this is a class message, the type of the
3184e5dd7070Spatrick /// class we are sending a message to.
3185e5dd7070Spatrick ///
3186e5dd7070Spatrick /// \param ReceiverExpr If this is an instance message, the expression
3187e5dd7070Spatrick /// used to compute the receiver object.
3188e5dd7070Spatrick ///
3189e5dd7070Spatrick /// objc-message-args:
3190e5dd7070Spatrick /// objc-selector
3191e5dd7070Spatrick /// objc-keywordarg-list
3192e5dd7070Spatrick ///
3193e5dd7070Spatrick /// objc-keywordarg-list:
3194e5dd7070Spatrick /// objc-keywordarg
3195e5dd7070Spatrick /// objc-keywordarg-list objc-keywordarg
3196e5dd7070Spatrick ///
3197e5dd7070Spatrick /// objc-keywordarg:
3198e5dd7070Spatrick /// selector-name[opt] ':' objc-keywordexpr
3199e5dd7070Spatrick ///
3200e5dd7070Spatrick /// objc-keywordexpr:
3201e5dd7070Spatrick /// nonempty-expr-list
3202e5dd7070Spatrick ///
3203e5dd7070Spatrick /// nonempty-expr-list:
3204e5dd7070Spatrick /// assignment-expression
3205e5dd7070Spatrick /// nonempty-expr-list , assignment-expression
3206e5dd7070Spatrick ///
3207e5dd7070Spatrick ExprResult
ParseObjCMessageExpressionBody(SourceLocation LBracLoc,SourceLocation SuperLoc,ParsedType ReceiverType,Expr * ReceiverExpr)3208e5dd7070Spatrick Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
3209e5dd7070Spatrick SourceLocation SuperLoc,
3210e5dd7070Spatrick ParsedType ReceiverType,
3211e5dd7070Spatrick Expr *ReceiverExpr) {
3212e5dd7070Spatrick InMessageExpressionRAIIObject InMessage(*this, true);
3213e5dd7070Spatrick
3214e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3215a9ac8606Spatrick cutOffParsing();
3216e5dd7070Spatrick if (SuperLoc.isValid())
3217*12c85518Srobert Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3218*12c85518Srobert std::nullopt, false);
3219e5dd7070Spatrick else if (ReceiverType)
3220*12c85518Srobert Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3221*12c85518Srobert std::nullopt, false);
3222e5dd7070Spatrick else
3223e5dd7070Spatrick Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3224*12c85518Srobert std::nullopt, false);
3225e5dd7070Spatrick return ExprError();
3226e5dd7070Spatrick }
3227e5dd7070Spatrick
3228e5dd7070Spatrick // Parse objc-selector
3229e5dd7070Spatrick SourceLocation Loc;
3230e5dd7070Spatrick IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
3231e5dd7070Spatrick
3232e5dd7070Spatrick SmallVector<IdentifierInfo *, 12> KeyIdents;
3233e5dd7070Spatrick SmallVector<SourceLocation, 12> KeyLocs;
3234e5dd7070Spatrick ExprVector KeyExprs;
3235e5dd7070Spatrick
3236e5dd7070Spatrick if (Tok.is(tok::colon)) {
3237*12c85518Srobert while (true) {
3238e5dd7070Spatrick // Each iteration parses a single keyword argument.
3239e5dd7070Spatrick KeyIdents.push_back(selIdent);
3240e5dd7070Spatrick KeyLocs.push_back(Loc);
3241e5dd7070Spatrick
3242e5dd7070Spatrick if (ExpectAndConsume(tok::colon)) {
3243e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3244e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3245e5dd7070Spatrick // the enclosing expression.
3246e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3247e5dd7070Spatrick return ExprError();
3248e5dd7070Spatrick }
3249e5dd7070Spatrick
3250e5dd7070Spatrick /// Parse the expression after ':'
3251e5dd7070Spatrick
3252e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3253a9ac8606Spatrick cutOffParsing();
3254e5dd7070Spatrick if (SuperLoc.isValid())
3255e5dd7070Spatrick Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3256e5dd7070Spatrick KeyIdents,
3257e5dd7070Spatrick /*AtArgumentExpression=*/true);
3258e5dd7070Spatrick else if (ReceiverType)
3259e5dd7070Spatrick Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3260e5dd7070Spatrick KeyIdents,
3261e5dd7070Spatrick /*AtArgumentExpression=*/true);
3262e5dd7070Spatrick else
3263e5dd7070Spatrick Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3264e5dd7070Spatrick KeyIdents,
3265e5dd7070Spatrick /*AtArgumentExpression=*/true);
3266e5dd7070Spatrick
3267e5dd7070Spatrick return ExprError();
3268e5dd7070Spatrick }
3269e5dd7070Spatrick
3270e5dd7070Spatrick ExprResult Expr;
3271e5dd7070Spatrick if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
3272e5dd7070Spatrick Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
3273e5dd7070Spatrick Expr = ParseBraceInitializer();
3274e5dd7070Spatrick } else
3275e5dd7070Spatrick Expr = ParseAssignmentExpression();
3276e5dd7070Spatrick
3277e5dd7070Spatrick ExprResult Res(Expr);
3278e5dd7070Spatrick if (Res.isInvalid()) {
3279e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3280e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3281e5dd7070Spatrick // the enclosing expression.
3282e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3283e5dd7070Spatrick return Res;
3284e5dd7070Spatrick }
3285e5dd7070Spatrick
3286e5dd7070Spatrick // We have a valid expression.
3287e5dd7070Spatrick KeyExprs.push_back(Res.get());
3288e5dd7070Spatrick
3289e5dd7070Spatrick // Code completion after each argument.
3290e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3291a9ac8606Spatrick cutOffParsing();
3292e5dd7070Spatrick if (SuperLoc.isValid())
3293e5dd7070Spatrick Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3294e5dd7070Spatrick KeyIdents,
3295e5dd7070Spatrick /*AtArgumentExpression=*/false);
3296e5dd7070Spatrick else if (ReceiverType)
3297e5dd7070Spatrick Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3298e5dd7070Spatrick KeyIdents,
3299e5dd7070Spatrick /*AtArgumentExpression=*/false);
3300e5dd7070Spatrick else
3301e5dd7070Spatrick Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3302e5dd7070Spatrick KeyIdents,
3303e5dd7070Spatrick /*AtArgumentExpression=*/false);
3304e5dd7070Spatrick return ExprError();
3305e5dd7070Spatrick }
3306e5dd7070Spatrick
3307e5dd7070Spatrick // Check for another keyword selector.
3308e5dd7070Spatrick selIdent = ParseObjCSelectorPiece(Loc);
3309e5dd7070Spatrick if (!selIdent && Tok.isNot(tok::colon))
3310e5dd7070Spatrick break;
3311e5dd7070Spatrick // We have a selector or a colon, continue parsing.
3312e5dd7070Spatrick }
3313e5dd7070Spatrick // Parse the, optional, argument list, comma separated.
3314e5dd7070Spatrick while (Tok.is(tok::comma)) {
3315e5dd7070Spatrick SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
3316e5dd7070Spatrick /// Parse the expression after ','
3317e5dd7070Spatrick ExprResult Res(ParseAssignmentExpression());
3318e5dd7070Spatrick if (Tok.is(tok::colon))
3319e5dd7070Spatrick Res = Actions.CorrectDelayedTyposInExpr(Res);
3320e5dd7070Spatrick if (Res.isInvalid()) {
3321e5dd7070Spatrick if (Tok.is(tok::colon)) {
3322e5dd7070Spatrick Diag(commaLoc, diag::note_extra_comma_message_arg) <<
3323e5dd7070Spatrick FixItHint::CreateRemoval(commaLoc);
3324e5dd7070Spatrick }
3325e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3326e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3327e5dd7070Spatrick // the enclosing expression.
3328e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3329e5dd7070Spatrick return Res;
3330e5dd7070Spatrick }
3331e5dd7070Spatrick
3332e5dd7070Spatrick // We have a valid expression.
3333e5dd7070Spatrick KeyExprs.push_back(Res.get());
3334e5dd7070Spatrick }
3335e5dd7070Spatrick } else if (!selIdent) {
3336e5dd7070Spatrick Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
3337e5dd7070Spatrick
3338e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3339e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3340e5dd7070Spatrick // the enclosing expression.
3341e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3342e5dd7070Spatrick return ExprError();
3343e5dd7070Spatrick }
3344e5dd7070Spatrick
3345e5dd7070Spatrick if (Tok.isNot(tok::r_square)) {
3346e5dd7070Spatrick Diag(Tok, diag::err_expected)
3347e5dd7070Spatrick << (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
3348e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3349e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3350e5dd7070Spatrick // the enclosing expression.
3351e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3352e5dd7070Spatrick return ExprError();
3353e5dd7070Spatrick }
3354e5dd7070Spatrick
3355e5dd7070Spatrick SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
3356e5dd7070Spatrick
3357e5dd7070Spatrick unsigned nKeys = KeyIdents.size();
3358e5dd7070Spatrick if (nKeys == 0) {
3359e5dd7070Spatrick KeyIdents.push_back(selIdent);
3360e5dd7070Spatrick KeyLocs.push_back(Loc);
3361e5dd7070Spatrick }
3362e5dd7070Spatrick Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
3363e5dd7070Spatrick
3364e5dd7070Spatrick if (SuperLoc.isValid())
3365e5dd7070Spatrick return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
3366e5dd7070Spatrick LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3367e5dd7070Spatrick else if (ReceiverType)
3368e5dd7070Spatrick return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
3369e5dd7070Spatrick LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3370e5dd7070Spatrick return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
3371e5dd7070Spatrick LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3372e5dd7070Spatrick }
3373e5dd7070Spatrick
ParseObjCStringLiteral(SourceLocation AtLoc)3374e5dd7070Spatrick ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
3375e5dd7070Spatrick ExprResult Res(ParseStringLiteralExpression());
3376e5dd7070Spatrick if (Res.isInvalid()) return Res;
3377e5dd7070Spatrick
3378e5dd7070Spatrick // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
3379e5dd7070Spatrick // expressions. At this point, we know that the only valid thing that starts
3380e5dd7070Spatrick // with '@' is an @"".
3381e5dd7070Spatrick SmallVector<SourceLocation, 4> AtLocs;
3382e5dd7070Spatrick ExprVector AtStrings;
3383e5dd7070Spatrick AtLocs.push_back(AtLoc);
3384e5dd7070Spatrick AtStrings.push_back(Res.get());
3385e5dd7070Spatrick
3386e5dd7070Spatrick while (Tok.is(tok::at)) {
3387e5dd7070Spatrick AtLocs.push_back(ConsumeToken()); // eat the @.
3388e5dd7070Spatrick
3389e5dd7070Spatrick // Invalid unless there is a string literal.
3390e5dd7070Spatrick if (!isTokenStringLiteral())
3391e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_objc_concat_string));
3392e5dd7070Spatrick
3393e5dd7070Spatrick ExprResult Lit(ParseStringLiteralExpression());
3394e5dd7070Spatrick if (Lit.isInvalid())
3395e5dd7070Spatrick return Lit;
3396e5dd7070Spatrick
3397e5dd7070Spatrick AtStrings.push_back(Lit.get());
3398e5dd7070Spatrick }
3399e5dd7070Spatrick
3400e5dd7070Spatrick return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
3401e5dd7070Spatrick }
3402e5dd7070Spatrick
3403e5dd7070Spatrick /// ParseObjCBooleanLiteral -
3404e5dd7070Spatrick /// objc-scalar-literal : '@' boolean-keyword
3405e5dd7070Spatrick /// ;
3406e5dd7070Spatrick /// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
3407e5dd7070Spatrick /// ;
ParseObjCBooleanLiteral(SourceLocation AtLoc,bool ArgValue)3408e5dd7070Spatrick ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
3409e5dd7070Spatrick bool ArgValue) {
3410e5dd7070Spatrick SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
3411e5dd7070Spatrick return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
3412e5dd7070Spatrick }
3413e5dd7070Spatrick
3414e5dd7070Spatrick /// ParseObjCCharacterLiteral -
3415e5dd7070Spatrick /// objc-scalar-literal : '@' character-literal
3416e5dd7070Spatrick /// ;
ParseObjCCharacterLiteral(SourceLocation AtLoc)3417e5dd7070Spatrick ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
3418e5dd7070Spatrick ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
3419e5dd7070Spatrick if (Lit.isInvalid()) {
3420e5dd7070Spatrick return Lit;
3421e5dd7070Spatrick }
3422e5dd7070Spatrick ConsumeToken(); // Consume the literal token.
3423e5dd7070Spatrick return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
3424e5dd7070Spatrick }
3425e5dd7070Spatrick
3426e5dd7070Spatrick /// ParseObjCNumericLiteral -
3427e5dd7070Spatrick /// objc-scalar-literal : '@' scalar-literal
3428e5dd7070Spatrick /// ;
3429e5dd7070Spatrick /// scalar-literal : | numeric-constant /* any numeric constant. */
3430e5dd7070Spatrick /// ;
ParseObjCNumericLiteral(SourceLocation AtLoc)3431e5dd7070Spatrick ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
3432e5dd7070Spatrick ExprResult Lit(Actions.ActOnNumericConstant(Tok));
3433e5dd7070Spatrick if (Lit.isInvalid()) {
3434e5dd7070Spatrick return Lit;
3435e5dd7070Spatrick }
3436e5dd7070Spatrick ConsumeToken(); // Consume the literal token.
3437e5dd7070Spatrick return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
3438e5dd7070Spatrick }
3439e5dd7070Spatrick
3440e5dd7070Spatrick /// ParseObjCBoxedExpr -
3441e5dd7070Spatrick /// objc-box-expression:
3442e5dd7070Spatrick /// @( assignment-expression )
3443e5dd7070Spatrick ExprResult
ParseObjCBoxedExpr(SourceLocation AtLoc)3444e5dd7070Spatrick Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
3445e5dd7070Spatrick if (Tok.isNot(tok::l_paren))
3446e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
3447e5dd7070Spatrick
3448e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
3449e5dd7070Spatrick T.consumeOpen();
3450e5dd7070Spatrick ExprResult ValueExpr(ParseAssignmentExpression());
3451e5dd7070Spatrick if (T.consumeClose())
3452e5dd7070Spatrick return ExprError();
3453e5dd7070Spatrick
3454e5dd7070Spatrick if (ValueExpr.isInvalid())
3455e5dd7070Spatrick return ExprError();
3456e5dd7070Spatrick
3457e5dd7070Spatrick // Wrap the sub-expression in a parenthesized expression, to distinguish
3458e5dd7070Spatrick // a boxed expression from a literal.
3459e5dd7070Spatrick SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
3460e5dd7070Spatrick ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
3461e5dd7070Spatrick return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
3462e5dd7070Spatrick ValueExpr.get());
3463e5dd7070Spatrick }
3464e5dd7070Spatrick
ParseObjCArrayLiteral(SourceLocation AtLoc)3465e5dd7070Spatrick ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
3466e5dd7070Spatrick ExprVector ElementExprs; // array elements.
3467e5dd7070Spatrick ConsumeBracket(); // consume the l_square.
3468e5dd7070Spatrick
3469e5dd7070Spatrick bool HasInvalidEltExpr = false;
3470e5dd7070Spatrick while (Tok.isNot(tok::r_square)) {
3471e5dd7070Spatrick // Parse list of array element expressions (all must be id types).
3472e5dd7070Spatrick ExprResult Res(ParseAssignmentExpression());
3473e5dd7070Spatrick if (Res.isInvalid()) {
3474e5dd7070Spatrick // We must manually skip to a ']', otherwise the expression skipper will
3475e5dd7070Spatrick // stop at the ']' when it skips to the ';'. We want it to skip beyond
3476e5dd7070Spatrick // the enclosing expression.
3477e5dd7070Spatrick SkipUntil(tok::r_square, StopAtSemi);
3478e5dd7070Spatrick return Res;
3479e5dd7070Spatrick }
3480e5dd7070Spatrick
3481e5dd7070Spatrick Res = Actions.CorrectDelayedTyposInExpr(Res.get());
3482e5dd7070Spatrick if (Res.isInvalid())
3483e5dd7070Spatrick HasInvalidEltExpr = true;
3484e5dd7070Spatrick
3485e5dd7070Spatrick // Parse the ellipsis that indicates a pack expansion.
3486e5dd7070Spatrick if (Tok.is(tok::ellipsis))
3487e5dd7070Spatrick Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
3488e5dd7070Spatrick if (Res.isInvalid())
3489e5dd7070Spatrick HasInvalidEltExpr = true;
3490e5dd7070Spatrick
3491e5dd7070Spatrick ElementExprs.push_back(Res.get());
3492e5dd7070Spatrick
3493e5dd7070Spatrick if (Tok.is(tok::comma))
3494e5dd7070Spatrick ConsumeToken(); // Eat the ','.
3495e5dd7070Spatrick else if (Tok.isNot(tok::r_square))
3496e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
3497e5dd7070Spatrick << tok::comma);
3498e5dd7070Spatrick }
3499e5dd7070Spatrick SourceLocation EndLoc = ConsumeBracket(); // location of ']'
3500e5dd7070Spatrick
3501e5dd7070Spatrick if (HasInvalidEltExpr)
3502e5dd7070Spatrick return ExprError();
3503e5dd7070Spatrick
3504e5dd7070Spatrick MultiExprArg Args(ElementExprs);
3505e5dd7070Spatrick return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
3506e5dd7070Spatrick }
3507e5dd7070Spatrick
ParseObjCDictionaryLiteral(SourceLocation AtLoc)3508e5dd7070Spatrick ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
3509e5dd7070Spatrick SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
3510e5dd7070Spatrick ConsumeBrace(); // consume the l_square.
3511e5dd7070Spatrick bool HasInvalidEltExpr = false;
3512e5dd7070Spatrick while (Tok.isNot(tok::r_brace)) {
3513e5dd7070Spatrick // Parse the comma separated key : value expressions.
3514e5dd7070Spatrick ExprResult KeyExpr;
3515e5dd7070Spatrick {
3516e5dd7070Spatrick ColonProtectionRAIIObject X(*this);
3517e5dd7070Spatrick KeyExpr = ParseAssignmentExpression();
3518e5dd7070Spatrick if (KeyExpr.isInvalid()) {
3519e5dd7070Spatrick // We must manually skip to a '}', otherwise the expression skipper will
3520e5dd7070Spatrick // stop at the '}' when it skips to the ';'. We want it to skip beyond
3521e5dd7070Spatrick // the enclosing expression.
3522e5dd7070Spatrick SkipUntil(tok::r_brace, StopAtSemi);
3523e5dd7070Spatrick return KeyExpr;
3524e5dd7070Spatrick }
3525e5dd7070Spatrick }
3526e5dd7070Spatrick
3527e5dd7070Spatrick if (ExpectAndConsume(tok::colon)) {
3528e5dd7070Spatrick SkipUntil(tok::r_brace, StopAtSemi);
3529e5dd7070Spatrick return ExprError();
3530e5dd7070Spatrick }
3531e5dd7070Spatrick
3532e5dd7070Spatrick ExprResult ValueExpr(ParseAssignmentExpression());
3533e5dd7070Spatrick if (ValueExpr.isInvalid()) {
3534e5dd7070Spatrick // We must manually skip to a '}', otherwise the expression skipper will
3535e5dd7070Spatrick // stop at the '}' when it skips to the ';'. We want it to skip beyond
3536e5dd7070Spatrick // the enclosing expression.
3537e5dd7070Spatrick SkipUntil(tok::r_brace, StopAtSemi);
3538e5dd7070Spatrick return ValueExpr;
3539e5dd7070Spatrick }
3540e5dd7070Spatrick
3541e5dd7070Spatrick // Check the key and value for possible typos
3542e5dd7070Spatrick KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
3543e5dd7070Spatrick ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
3544e5dd7070Spatrick if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
3545e5dd7070Spatrick HasInvalidEltExpr = true;
3546e5dd7070Spatrick
3547e5dd7070Spatrick // Parse the ellipsis that designates this as a pack expansion. Do not
3548e5dd7070Spatrick // ActOnPackExpansion here, leave it to template instantiation time where
3549e5dd7070Spatrick // we can get better diagnostics.
3550e5dd7070Spatrick SourceLocation EllipsisLoc;
3551e5dd7070Spatrick if (getLangOpts().CPlusPlus)
3552e5dd7070Spatrick TryConsumeToken(tok::ellipsis, EllipsisLoc);
3553e5dd7070Spatrick
3554e5dd7070Spatrick // We have a valid expression. Collect it in a vector so we can
3555e5dd7070Spatrick // build the argument list.
3556*12c85518Srobert ObjCDictionaryElement Element = {KeyExpr.get(), ValueExpr.get(),
3557*12c85518Srobert EllipsisLoc, std::nullopt};
3558e5dd7070Spatrick Elements.push_back(Element);
3559e5dd7070Spatrick
3560e5dd7070Spatrick if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
3561e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
3562e5dd7070Spatrick << tok::comma);
3563e5dd7070Spatrick }
3564e5dd7070Spatrick SourceLocation EndLoc = ConsumeBrace();
3565e5dd7070Spatrick
3566e5dd7070Spatrick if (HasInvalidEltExpr)
3567e5dd7070Spatrick return ExprError();
3568e5dd7070Spatrick
3569e5dd7070Spatrick // Create the ObjCDictionaryLiteral.
3570e5dd7070Spatrick return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
3571e5dd7070Spatrick Elements);
3572e5dd7070Spatrick }
3573e5dd7070Spatrick
3574e5dd7070Spatrick /// objc-encode-expression:
3575e5dd7070Spatrick /// \@encode ( type-name )
3576e5dd7070Spatrick ExprResult
ParseObjCEncodeExpression(SourceLocation AtLoc)3577e5dd7070Spatrick Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
3578e5dd7070Spatrick assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
3579e5dd7070Spatrick
3580e5dd7070Spatrick SourceLocation EncLoc = ConsumeToken();
3581e5dd7070Spatrick
3582e5dd7070Spatrick if (Tok.isNot(tok::l_paren))
3583e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
3584e5dd7070Spatrick
3585e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
3586e5dd7070Spatrick T.consumeOpen();
3587e5dd7070Spatrick
3588e5dd7070Spatrick TypeResult Ty = ParseTypeName();
3589e5dd7070Spatrick
3590e5dd7070Spatrick T.consumeClose();
3591e5dd7070Spatrick
3592e5dd7070Spatrick if (Ty.isInvalid())
3593e5dd7070Spatrick return ExprError();
3594e5dd7070Spatrick
3595e5dd7070Spatrick return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
3596e5dd7070Spatrick Ty.get(), T.getCloseLocation());
3597e5dd7070Spatrick }
3598e5dd7070Spatrick
3599e5dd7070Spatrick /// objc-protocol-expression
3600e5dd7070Spatrick /// \@protocol ( protocol-name )
3601e5dd7070Spatrick ExprResult
ParseObjCProtocolExpression(SourceLocation AtLoc)3602e5dd7070Spatrick Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
3603e5dd7070Spatrick SourceLocation ProtoLoc = ConsumeToken();
3604e5dd7070Spatrick
3605e5dd7070Spatrick if (Tok.isNot(tok::l_paren))
3606e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
3607e5dd7070Spatrick
3608e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
3609e5dd7070Spatrick T.consumeOpen();
3610e5dd7070Spatrick
3611e5dd7070Spatrick if (expectIdentifier())
3612e5dd7070Spatrick return ExprError();
3613e5dd7070Spatrick
3614e5dd7070Spatrick IdentifierInfo *protocolId = Tok.getIdentifierInfo();
3615e5dd7070Spatrick SourceLocation ProtoIdLoc = ConsumeToken();
3616e5dd7070Spatrick
3617e5dd7070Spatrick T.consumeClose();
3618e5dd7070Spatrick
3619e5dd7070Spatrick return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
3620e5dd7070Spatrick T.getOpenLocation(), ProtoIdLoc,
3621e5dd7070Spatrick T.getCloseLocation());
3622e5dd7070Spatrick }
3623e5dd7070Spatrick
3624e5dd7070Spatrick /// objc-selector-expression
3625e5dd7070Spatrick /// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
ParseObjCSelectorExpression(SourceLocation AtLoc)3626e5dd7070Spatrick ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
3627e5dd7070Spatrick SourceLocation SelectorLoc = ConsumeToken();
3628e5dd7070Spatrick
3629e5dd7070Spatrick if (Tok.isNot(tok::l_paren))
3630e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
3631e5dd7070Spatrick
3632e5dd7070Spatrick SmallVector<IdentifierInfo *, 12> KeyIdents;
3633e5dd7070Spatrick SourceLocation sLoc;
3634e5dd7070Spatrick
3635e5dd7070Spatrick BalancedDelimiterTracker T(*this, tok::l_paren);
3636e5dd7070Spatrick T.consumeOpen();
3637e5dd7070Spatrick bool HasOptionalParen = Tok.is(tok::l_paren);
3638e5dd7070Spatrick if (HasOptionalParen)
3639e5dd7070Spatrick ConsumeParen();
3640e5dd7070Spatrick
3641e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3642e5dd7070Spatrick cutOffParsing();
3643a9ac8606Spatrick Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
3644e5dd7070Spatrick return ExprError();
3645e5dd7070Spatrick }
3646e5dd7070Spatrick
3647e5dd7070Spatrick IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
3648e5dd7070Spatrick if (!SelIdent && // missing selector name.
3649e5dd7070Spatrick Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
3650e5dd7070Spatrick return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
3651e5dd7070Spatrick
3652e5dd7070Spatrick KeyIdents.push_back(SelIdent);
3653e5dd7070Spatrick
3654e5dd7070Spatrick unsigned nColons = 0;
3655e5dd7070Spatrick if (Tok.isNot(tok::r_paren)) {
3656*12c85518Srobert while (true) {
3657e5dd7070Spatrick if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
3658e5dd7070Spatrick ++nColons;
3659e5dd7070Spatrick KeyIdents.push_back(nullptr);
3660e5dd7070Spatrick } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
3661e5dd7070Spatrick return ExprError();
3662e5dd7070Spatrick ++nColons;
3663e5dd7070Spatrick
3664e5dd7070Spatrick if (Tok.is(tok::r_paren))
3665e5dd7070Spatrick break;
3666e5dd7070Spatrick
3667e5dd7070Spatrick if (Tok.is(tok::code_completion)) {
3668e5dd7070Spatrick cutOffParsing();
3669a9ac8606Spatrick Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
3670e5dd7070Spatrick return ExprError();
3671e5dd7070Spatrick }
3672e5dd7070Spatrick
3673e5dd7070Spatrick // Check for another keyword selector.
3674e5dd7070Spatrick SourceLocation Loc;
3675e5dd7070Spatrick SelIdent = ParseObjCSelectorPiece(Loc);
3676e5dd7070Spatrick KeyIdents.push_back(SelIdent);
3677e5dd7070Spatrick if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
3678e5dd7070Spatrick break;
3679e5dd7070Spatrick }
3680e5dd7070Spatrick }
3681e5dd7070Spatrick if (HasOptionalParen && Tok.is(tok::r_paren))
3682e5dd7070Spatrick ConsumeParen(); // ')'
3683e5dd7070Spatrick T.consumeClose();
3684e5dd7070Spatrick Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
3685e5dd7070Spatrick return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
3686e5dd7070Spatrick T.getOpenLocation(),
3687e5dd7070Spatrick T.getCloseLocation(),
3688e5dd7070Spatrick !HasOptionalParen);
3689e5dd7070Spatrick }
3690e5dd7070Spatrick
ParseLexedObjCMethodDefs(LexedMethod & LM,bool parseMethod)3691e5dd7070Spatrick void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
3692e5dd7070Spatrick // MCDecl might be null due to error in method or c-function prototype, etc.
3693e5dd7070Spatrick Decl *MCDecl = LM.D;
3694e5dd7070Spatrick bool skip = MCDecl &&
3695e5dd7070Spatrick ((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
3696e5dd7070Spatrick (!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
3697e5dd7070Spatrick if (skip)
3698e5dd7070Spatrick return;
3699e5dd7070Spatrick
3700e5dd7070Spatrick // Save the current token position.
3701e5dd7070Spatrick SourceLocation OrigLoc = Tok.getLocation();
3702e5dd7070Spatrick
3703e5dd7070Spatrick assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
3704e5dd7070Spatrick // Store an artificial EOF token to ensure that we don't run off the end of
3705e5dd7070Spatrick // the method's body when we come to parse it.
3706e5dd7070Spatrick Token Eof;
3707e5dd7070Spatrick Eof.startToken();
3708e5dd7070Spatrick Eof.setKind(tok::eof);
3709e5dd7070Spatrick Eof.setEofData(MCDecl);
3710e5dd7070Spatrick Eof.setLocation(OrigLoc);
3711e5dd7070Spatrick LM.Toks.push_back(Eof);
3712e5dd7070Spatrick // Append the current token at the end of the new token stream so that it
3713e5dd7070Spatrick // doesn't get lost.
3714e5dd7070Spatrick LM.Toks.push_back(Tok);
3715e5dd7070Spatrick PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);
3716e5dd7070Spatrick
3717e5dd7070Spatrick // Consume the previously pushed token.
3718e5dd7070Spatrick ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
3719e5dd7070Spatrick
3720e5dd7070Spatrick assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
3721e5dd7070Spatrick "Inline objective-c method not starting with '{' or 'try' or ':'");
3722e5dd7070Spatrick // Enter a scope for the method or c-function body.
3723e5dd7070Spatrick ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
3724e5dd7070Spatrick Scope::FnScope | Scope::DeclScope |
3725e5dd7070Spatrick Scope::CompoundStmtScope);
3726e5dd7070Spatrick
3727e5dd7070Spatrick // Tell the actions module that we have entered a method or c-function definition
3728e5dd7070Spatrick // with the specified Declarator for the method/function.
3729e5dd7070Spatrick if (parseMethod)
3730e5dd7070Spatrick Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
3731e5dd7070Spatrick else
3732e5dd7070Spatrick Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
3733e5dd7070Spatrick if (Tok.is(tok::kw_try))
3734e5dd7070Spatrick ParseFunctionTryBlock(MCDecl, BodyScope);
3735e5dd7070Spatrick else {
3736e5dd7070Spatrick if (Tok.is(tok::colon))
3737e5dd7070Spatrick ParseConstructorInitializer(MCDecl);
3738e5dd7070Spatrick else
3739e5dd7070Spatrick Actions.ActOnDefaultCtorInitializers(MCDecl);
3740e5dd7070Spatrick ParseFunctionStatementBody(MCDecl, BodyScope);
3741e5dd7070Spatrick }
3742e5dd7070Spatrick
3743e5dd7070Spatrick if (Tok.getLocation() != OrigLoc) {
3744e5dd7070Spatrick // Due to parsing error, we either went over the cached tokens or
3745e5dd7070Spatrick // there are still cached tokens left. If it's the latter case skip the
3746e5dd7070Spatrick // leftover tokens.
3747e5dd7070Spatrick // Since this is an uncommon situation that should be avoided, use the
3748e5dd7070Spatrick // expensive isBeforeInTranslationUnit call.
3749e5dd7070Spatrick if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
3750e5dd7070Spatrick OrigLoc))
3751e5dd7070Spatrick while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
3752e5dd7070Spatrick ConsumeAnyToken();
3753e5dd7070Spatrick }
3754e5dd7070Spatrick // Clean up the remaining EOF token.
3755e5dd7070Spatrick ConsumeAnyToken();
3756e5dd7070Spatrick }
3757