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