2008-01-08 03:49:32 +08:00
|
|
|
//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Objective-C portions of the Parser interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2015-06-20 02:14:38 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2018-03-23 08:07:18 +08:00
|
|
|
#include "clang/AST/PrettyDeclStackTrace.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2017-03-23 23:11:07 +08:00
|
|
|
#include "clang/Parse/RAIIObjectsForParser.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
|
|
|
#include "clang/Sema/Scope.h"
|
2006-11-05 10:08:13 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-09-18 03:15:26 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2016-02-13 06:53:10 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2013-04-04 01:36:11 +08:00
|
|
|
/// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
|
2013-04-04 08:15:10 +08:00
|
|
|
void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
|
2013-04-04 01:36:11 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
2013-04-04 08:15:10 +08:00
|
|
|
if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
|
|
|
|
Diag(Tok, diag::err_objc_postfix_attribute_hint)
|
|
|
|
<< (Kind == tok::objc_protocol);
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_objc_postfix_attribute);
|
2013-04-04 01:36:11 +08:00
|
|
|
ParseGNUAttributes(attrs);
|
|
|
|
}
|
|
|
|
}
|
2006-11-05 10:08:13 +08:00
|
|
|
|
2008-12-09 05:53:24 +08:00
|
|
|
/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
|
2006-11-05 10:08:13 +08:00
|
|
|
/// external-declaration: [C99 6.9]
|
|
|
|
/// [OBJC] objc-class-definition
|
2007-10-30 05:39:29 +08:00
|
|
|
/// [OBJC] objc-class-declaration
|
|
|
|
/// [OBJC] objc-alias-declaration
|
|
|
|
/// [OBJC] objc-protocol-definition
|
|
|
|
/// [OBJC] objc-method-definition
|
|
|
|
/// [OBJC] '@' 'end'
|
2018-02-12 21:38:25 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
|
2006-11-05 10:08:13 +08:00
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-12-07 17:27:33 +08:00
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
|
|
|
|
Decl *SingleDecl = nullptr;
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_class:
|
|
|
|
return ParseObjCAtClassDeclaration(AtLoc);
|
2018-02-12 21:38:25 +08:00
|
|
|
case tok::objc_interface:
|
|
|
|
SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, Attrs);
|
2011-08-28 04:50:59 +08:00
|
|
|
break;
|
2018-02-12 21:38:25 +08:00
|
|
|
case tok::objc_protocol:
|
|
|
|
return ParseObjCAtProtocolDeclaration(AtLoc, Attrs);
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_implementation:
|
2019-04-12 01:55:30 +08:00
|
|
|
return ParseObjCAtImplementationDeclaration(AtLoc, Attrs);
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_end:
|
2011-09-01 01:37:55 +08:00
|
|
|
return ParseObjCAtEndDeclaration(AtLoc);
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_compatibility_alias:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
|
|
|
|
break;
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_synthesize:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCPropertySynthesize(AtLoc);
|
|
|
|
break;
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_dynamic:
|
2011-08-28 04:50:59 +08:00
|
|
|
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
|
|
|
|
break;
|
2012-12-12 06:11:52 +08:00
|
|
|
case tok::objc_import:
|
2017-11-21 17:42:42 +08:00
|
|
|
if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {
|
|
|
|
SingleDecl = ParseModuleImport(AtLoc);
|
|
|
|
break;
|
|
|
|
}
|
2017-01-21 04:03:00 +08:00
|
|
|
Diag(AtLoc, diag::err_atimport);
|
2014-03-27 06:02:43 +08:00
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(nullptr);
|
2008-08-23 10:02:23 +08:00
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
SingleDecl = nullptr;
|
2011-08-28 04:50:59 +08:00
|
|
|
break;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2011-08-28 04:50:59 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(SingleDecl);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
/// Class to handle popping type parameters when leaving the scope.
|
|
|
|
class Parser::ObjCTypeParamListScope {
|
|
|
|
Sema &Actions;
|
|
|
|
Scope *S;
|
|
|
|
ObjCTypeParamList *Params;
|
2016-02-13 06:53:10 +08:00
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
public:
|
|
|
|
ObjCTypeParamListScope(Sema &Actions, Scope *S)
|
|
|
|
: Actions(Actions), S(S), Params(nullptr) {}
|
2016-02-13 06:53:10 +08:00
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
~ObjCTypeParamListScope() {
|
|
|
|
leave();
|
|
|
|
}
|
2016-02-13 06:53:10 +08:00
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
void enter(ObjCTypeParamList *P) {
|
|
|
|
assert(!Params);
|
|
|
|
Params = P;
|
|
|
|
}
|
2016-02-13 06:53:10 +08:00
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
void leave() {
|
|
|
|
if (Params)
|
|
|
|
Actions.popObjCTypeParamList(S, Params);
|
|
|
|
Params = nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-class-declaration:
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
|
|
|
|
///
|
|
|
|
/// objc-class-forward-decl:
|
|
|
|
/// identifier objc-type-parameter-list[opt]
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2011-08-28 04:50:59 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken(); // the identifier "class"
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 8> ClassNames;
|
|
|
|
SmallVector<SourceLocation, 8> ClassLocs;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
while (1) {
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_class);
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier()) {
|
2006-11-05 10:08:13 +08:00
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(nullptr);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
ClassNames.push_back(Tok.getIdentifierInfo());
|
2009-11-18 07:12:20 +08:00
|
|
|
ClassLocs.push_back(Tok.getLocation());
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
// Parse the optional objc-type-parameter-list.
|
|
|
|
ObjCTypeParamList *TypeParams = nullptr;
|
2015-11-03 09:19:56 +08:00
|
|
|
if (Tok.is(tok::less))
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
TypeParams = parseObjCTypeParamList();
|
|
|
|
ClassTypeParams.push_back(TypeParams);
|
2014-01-01 11:08:43 +08:00
|
|
|
if (!TryConsumeToken(tok::comma))
|
2006-11-05 10:08:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-05 10:08:13 +08:00
|
|
|
// Consume the ';'.
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
|
2014-05-21 14:02:52 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(nullptr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-18 07:12:20 +08:00
|
|
|
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
|
|
|
|
ClassLocs.data(),
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ClassTypeParams,
|
2009-11-18 07:12:20 +08:00
|
|
|
ClassNames.size());
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2011-12-06 17:25:23 +08:00
|
|
|
void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
|
|
|
|
{
|
|
|
|
Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
|
|
|
|
if (ock == Sema::OCK_None)
|
|
|
|
return;
|
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
Decl *Decl = Actions.getObjCDeclContext();
|
|
|
|
if (CurParsedObjCImpl) {
|
|
|
|
CurParsedObjCImpl->finish(AtLoc);
|
|
|
|
} else {
|
|
|
|
Actions.ActOnAtEnd(getCurScope(), AtLoc);
|
|
|
|
}
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
|
|
|
|
if (Decl)
|
2018-08-10 05:08:08 +08:00
|
|
|
Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;
|
2011-12-06 17:25:23 +08:00
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-interface:
|
|
|
|
/// objc-class-interface-attributes[opt] objc-class-interface
|
|
|
|
/// objc-category-interface
|
|
|
|
///
|
|
|
|
/// objc-class-interface:
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
|
|
|
/// objc-superclass[opt] objc-protocol-refs[opt]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-class-instance-variables[opt]
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-category-interface:
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
|
|
|
/// '(' identifier[opt] ')' objc-protocol-refs[opt]
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-superclass:
|
2015-07-07 11:57:35 +08:00
|
|
|
/// ':' identifier objc-type-arguments[opt]
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-class-interface-attributes:
|
|
|
|
/// __attribute__((visibility("default")))
|
|
|
|
/// __attribute__((visibility("hidden")))
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
/// __attribute__((unavailable))
|
|
|
|
/// __attribute__((objc_exception)) - used by NSException on 64-bit
|
2012-04-07 02:12:22 +08:00
|
|
|
/// __attribute__((objc_root_class))
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2011-12-06 17:25:23 +08:00
|
|
|
Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
2010-12-24 10:08:15 +08:00
|
|
|
ParsedAttributes &attrs) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
|
2007-08-21 05:31:48 +08:00
|
|
|
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
|
2011-12-06 17:25:23 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
2007-08-21 05:31:48 +08:00
|
|
|
ConsumeToken(); // the "interface" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 00:26:39 +08:00
|
|
|
// Code completion after '@interface'.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_interface);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return nullptr; // missing class or category name.
|
2009-11-17 02:57:01 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
// We have a class or category name - consume it.
|
2007-08-23 06:17:26 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-08-21 05:31:48 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
|
|
|
// Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
|
|
|
|
// case, LAngleLoc will be valid and ProtocolIdents will capture the
|
|
|
|
// protocol references (that have not yet been resolved).
|
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
|
|
|
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
|
|
|
ObjCTypeParamList *typeParameterList = nullptr;
|
2015-11-03 09:19:56 +08:00
|
|
|
ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
|
|
|
|
if (Tok.is(tok::less))
|
|
|
|
typeParameterList = parseObjCTypeParamListOrProtocolRefs(
|
|
|
|
typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::l_paren) &&
|
2010-04-27 05:18:08 +08:00
|
|
|
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
|
|
|
SourceLocation categoryLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *categoryId = nullptr;
|
2009-11-19 03:08:43 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 03:08:43 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-08-24 03:56:30 +08:00
|
|
|
// For ObjC2, the category name is optional (not an error).
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
2010-04-03 07:15:40 +08:00
|
|
|
}
|
2018-10-31 04:31:30 +08:00
|
|
|
else if (!getLangOpts().ObjC) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected)
|
|
|
|
<< tok::identifier; // missing category name.
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid())
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-04-27 05:18:08 +08:00
|
|
|
// Next, we need to check for any protocol references.
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolRefs;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2010-04-27 05:18:08 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
2015-04-20 04:15:55 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
|
2015-07-07 11:58:14 +08:00
|
|
|
LAngleLoc, EndProtoLoc,
|
|
|
|
/*consumeLastToken=*/true))
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-04-03 07:15:40 +08:00
|
|
|
|
2017-03-23 19:44:25 +08:00
|
|
|
Decl *CategoryType = Actions.ActOnStartCategoryInterface(
|
|
|
|
AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
|
|
|
|
ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
|
2018-07-13 05:09:05 +08:00
|
|
|
EndProtoLoc, attrs);
|
2017-03-23 19:44:25 +08:00
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2011-12-06 17:25:23 +08:00
|
|
|
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
2010-04-27 05:18:08 +08:00
|
|
|
return CategoryType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
// Parse a class interface.
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *superClassId = nullptr;
|
2007-08-21 05:31:48 +08:00
|
|
|
SourceLocation superClassLoc;
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation typeArgsLAngleLoc;
|
|
|
|
SmallVector<ParsedType, 4> typeArgs;
|
|
|
|
SourceLocation typeArgsRAngleLoc;
|
|
|
|
SmallVector<Decl *, 4> protocols;
|
|
|
|
SmallVector<SourceLocation, 4> protocolLocs;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) { // a super class is specified.
|
2007-08-21 05:31:48 +08:00
|
|
|
ConsumeToken();
|
2009-11-19 00:26:39 +08:00
|
|
|
|
|
|
|
// Code completion of superclass names.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return nullptr; // missing super class name.
|
2007-08-21 05:31:48 +08:00
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken();
|
2015-07-07 11:57:35 +08:00
|
|
|
|
|
|
|
// Type arguments for the superclass or protocol conformances.
|
|
|
|
if (Tok.is(tok::less)) {
|
2016-01-16 07:43:34 +08:00
|
|
|
parseObjCTypeArgsOrProtocolQualifiers(
|
|
|
|
nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
|
|
|
|
protocols, protocolLocs, EndProtoLoc,
|
|
|
|
/*consumeLastToken=*/true,
|
|
|
|
/*warnOnIncompleteProtocols=*/true);
|
2016-09-14 04:04:35 +08:00
|
|
|
if (Tok.is(tok::eof))
|
|
|
|
return nullptr;
|
2015-07-07 11:57:35 +08:00
|
|
|
}
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2016-09-14 04:04:35 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
// Next, we need to check for any protocol references.
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (LAngleLoc.isValid()) {
|
2015-07-07 11:58:14 +08:00
|
|
|
if (!ProtocolIdents.empty()) {
|
|
|
|
// We already parsed the protocols named when we thought we had a
|
|
|
|
// type parameter list. Translate them into actual protocol references.
|
|
|
|
for (const auto &pair : ProtocolIdents) {
|
|
|
|
protocolLocs.push_back(pair.second);
|
|
|
|
}
|
|
|
|
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
|
|
|
|
/*ForObjCContainer=*/true,
|
2015-10-22 12:59:56 +08:00
|
|
|
ProtocolIdents, protocols);
|
2015-07-07 11:58:14 +08:00
|
|
|
}
|
|
|
|
} else if (protocols.empty() && Tok.is(tok::less) &&
|
|
|
|
ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
|
|
|
|
LAngleLoc, EndProtoLoc,
|
|
|
|
/*consumeLastToken=*/true)) {
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-09-26 03:36:32 +08:00
|
|
|
if (Tok.isNot(tok::less))
|
2016-11-09 10:47:07 +08:00
|
|
|
Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
|
|
|
|
superClassId, superClassLoc);
|
2018-07-13 05:09:05 +08:00
|
|
|
|
|
|
|
Decl *ClsType = Actions.ActOnStartClassInterface(
|
|
|
|
getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
|
|
|
|
superClassLoc, typeArgs,
|
|
|
|
SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
|
|
|
|
protocols.size(), protocolLocs.data(), EndProtoLoc, attrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2011-12-06 17:25:23 +08:00
|
|
|
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
|
2007-08-21 05:31:48 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
2010-04-27 05:18:08 +08:00
|
|
|
return ClsType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
2015-06-20 02:14:38 +08:00
|
|
|
/// Add an attribute for a context-sensitive type nullability to the given
|
|
|
|
/// declarator.
|
|
|
|
static void addContextSensitiveTypeNullability(Parser &P,
|
|
|
|
Declarator &D,
|
|
|
|
NullabilityKind nullability,
|
|
|
|
SourceLocation nullabilityLoc,
|
|
|
|
bool &addedToDeclSpec) {
|
|
|
|
// Create the attribute.
|
2018-07-13 23:07:47 +08:00
|
|
|
auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {
|
2018-07-04 04:30:34 +08:00
|
|
|
return Pool.create(P.getNullabilityKeyword(nullability),
|
|
|
|
SourceRange(nullabilityLoc), nullptr, SourceLocation(),
|
2018-07-13 23:07:47 +08:00
|
|
|
nullptr, 0, ParsedAttr::AS_ContextSensitiveKeyword);
|
2015-06-20 02:14:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
if (D.getNumTypeObjects() > 0) {
|
|
|
|
// Add the attribute to the declarator chunk nearest the declarator.
|
2018-08-03 09:21:16 +08:00
|
|
|
D.getTypeObject(0).getAttrs().addAtEnd(
|
2018-07-13 05:09:05 +08:00
|
|
|
getNullabilityAttr(D.getAttributePool()));
|
2015-06-20 02:14:38 +08:00
|
|
|
} else if (!addedToDeclSpec) {
|
|
|
|
// Otherwise, just put it on the declaration specifiers (if one
|
|
|
|
// isn't there already).
|
2018-08-03 09:21:16 +08:00
|
|
|
D.getMutableDeclSpec().getAttributes().addAtEnd(
|
2018-07-13 05:09:05 +08:00
|
|
|
getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));
|
2015-06-20 02:14:38 +08:00
|
|
|
addedToDeclSpec = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// Parse an Objective-C type parameter list, if present, or capture
|
|
|
|
/// the locations of the protocol identifiers for a list of protocol
|
|
|
|
/// references.
|
|
|
|
///
|
|
|
|
/// objc-type-parameter-list:
|
|
|
|
/// '<' objc-type-parameter (',' objc-type-parameter)* '>'
|
|
|
|
///
|
|
|
|
/// objc-type-parameter:
|
2015-07-07 11:58:54 +08:00
|
|
|
/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
///
|
|
|
|
/// objc-type-parameter-bound:
|
|
|
|
/// ':' type-name
|
|
|
|
///
|
2015-07-07 11:58:54 +08:00
|
|
|
/// objc-type-parameter-variance:
|
|
|
|
/// '__covariant'
|
|
|
|
/// '__contravariant'
|
|
|
|
///
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// \param lAngleLoc The location of the starting '<'.
|
|
|
|
///
|
|
|
|
/// \param protocolIdents Will capture the list of identifiers, if the
|
|
|
|
/// angle brackets contain a list of protocol references rather than a
|
|
|
|
/// type parameter list.
|
|
|
|
///
|
|
|
|
/// \param rAngleLoc The location of the ending '>'.
|
|
|
|
ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
|
2015-11-03 09:19:56 +08:00
|
|
|
ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,
|
|
|
|
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
|
|
|
SourceLocation &rAngleLoc, bool mayBeProtocolList) {
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
|
|
|
|
|
|
|
|
// Within the type parameter list, don't treat '>' as an operator.
|
|
|
|
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
|
|
|
|
|
|
|
// Local function to "flush" the protocol identifiers, turning them into
|
|
|
|
// type parameters.
|
|
|
|
SmallVector<Decl *, 4> typeParams;
|
|
|
|
auto makeProtocolIdentsIntoTypeParameters = [&]() {
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
unsigned index = 0;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
for (const auto &pair : protocolIdents) {
|
2015-07-07 11:58:54 +08:00
|
|
|
DeclResult typeParam = Actions.actOnObjCTypeParam(
|
2016-01-16 07:43:34 +08:00
|
|
|
getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
|
|
|
|
index++, pair.first, pair.second, SourceLocation(), nullptr);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (typeParam.isUsable())
|
|
|
|
typeParams.push_back(typeParam.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
protocolIdents.clear();
|
|
|
|
mayBeProtocolList = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool invalid = false;
|
|
|
|
lAngleLoc = ConsumeToken();
|
2015-07-07 11:58:54 +08:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
do {
|
2015-07-07 11:58:54 +08:00
|
|
|
// Parse the variance, if any.
|
|
|
|
SourceLocation varianceLoc;
|
|
|
|
ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
|
|
|
|
if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
|
|
|
|
variance = Tok.is(tok::kw___covariant)
|
|
|
|
? ObjCTypeParamVariance::Covariant
|
|
|
|
: ObjCTypeParamVariance::Contravariant;
|
|
|
|
varianceLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Once we've seen a variance specific , we know this is not a
|
|
|
|
// list of protocol references.
|
|
|
|
if (mayBeProtocolList) {
|
|
|
|
// Up until now, we have been queuing up parameters because they
|
|
|
|
// might be protocol references. Turn them into parameters now.
|
|
|
|
makeProtocolIdentsIntoTypeParameters();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
// Parse the identifier.
|
|
|
|
if (!Tok.is(tok::identifier)) {
|
|
|
|
// Code completion.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
// FIXME: If these aren't protocol references, we'll need different
|
|
|
|
// completions.
|
2015-12-25 07:58:11 +08:00
|
|
|
Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
|
|
|
|
// FIXME: Better recovery here?.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Diag(Tok, diag::err_objc_expected_type_parameter);
|
|
|
|
invalid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *paramName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation paramLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// If there is a bound, parse it.
|
|
|
|
SourceLocation colonLoc;
|
|
|
|
TypeResult boundType;
|
|
|
|
if (TryConsumeToken(tok::colon, colonLoc)) {
|
|
|
|
// Once we've seen a bound, we know this is not a list of protocol
|
|
|
|
// references.
|
|
|
|
if (mayBeProtocolList) {
|
|
|
|
// Up until now, we have been queuing up parameters because they
|
|
|
|
// might be protocol references. Turn them into parameters now.
|
|
|
|
makeProtocolIdentsIntoTypeParameters();
|
|
|
|
}
|
|
|
|
|
|
|
|
// type-name
|
|
|
|
boundType = ParseTypeName();
|
|
|
|
if (boundType.isInvalid())
|
|
|
|
invalid = true;
|
|
|
|
} else if (mayBeProtocolList) {
|
|
|
|
// If this could still be a protocol list, just capture the identifier.
|
|
|
|
// We don't want to turn it into a parameter.
|
|
|
|
protocolIdents.push_back(std::make_pair(paramName, paramLoc));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the type parameter.
|
2016-01-16 07:43:34 +08:00
|
|
|
DeclResult typeParam = Actions.actOnObjCTypeParam(
|
|
|
|
getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
|
|
|
|
paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (typeParam.isUsable())
|
|
|
|
typeParams.push_back(typeParam.get());
|
|
|
|
} while (TryConsumeToken(tok::comma));
|
|
|
|
|
|
|
|
// Parse the '>'.
|
|
|
|
if (invalid) {
|
|
|
|
SkipUntil(tok::greater, tok::at, StopBeforeMatch);
|
|
|
|
if (Tok.is(tok::greater))
|
|
|
|
ConsumeToken();
|
|
|
|
} else if (ParseGreaterThanInTemplateList(rAngleLoc,
|
|
|
|
/*ConsumeLastToken=*/true,
|
|
|
|
/*ObjCGenericList=*/true)) {
|
|
|
|
Diag(lAngleLoc, diag::note_matching) << "'<'";
|
|
|
|
SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
|
|
|
|
tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
|
|
|
|
tok::comma, tok::semi },
|
|
|
|
StopBeforeMatch);
|
|
|
|
if (Tok.is(tok::greater))
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mayBeProtocolList) {
|
|
|
|
// A type parameter list must be followed by either a ':' (indicating the
|
|
|
|
// presence of a superclass) or a '(' (indicating that this is a category
|
|
|
|
// or extension). This disambiguates between an objc-type-parameter-list
|
|
|
|
// and a objc-protocol-refs.
|
|
|
|
if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
|
|
|
|
// Returning null indicates that we don't have a type parameter list.
|
|
|
|
// The results the caller needs to handle the protocol references are
|
|
|
|
// captured in the reference parameters already.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a type parameter list that looks like a list of protocol
|
|
|
|
// references. Turn that parameter list into type parameters.
|
|
|
|
makeProtocolIdentsIntoTypeParameters();
|
|
|
|
}
|
|
|
|
|
2015-11-03 09:19:56 +08:00
|
|
|
// Form the type parameter list and enter its scope.
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
|
|
|
|
getCurScope(),
|
|
|
|
lAngleLoc,
|
|
|
|
typeParams,
|
|
|
|
rAngleLoc);
|
2015-11-03 09:19:56 +08:00
|
|
|
Scope.enter(list);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
|
|
|
// Clear out the angle locations; they're used by the caller to indicate
|
|
|
|
// whether there are any protocol references.
|
|
|
|
lAngleLoc = SourceLocation();
|
|
|
|
rAngleLoc = SourceLocation();
|
2015-12-16 14:25:38 +08:00
|
|
|
return invalid ? nullptr : list;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Parse an objc-type-parameter-list.
|
|
|
|
ObjCTypeParamList *Parser::parseObjCTypeParamList() {
|
|
|
|
SourceLocation lAngleLoc;
|
|
|
|
SmallVector<IdentifierLocPair, 1> protocolIdents;
|
|
|
|
SourceLocation rAngleLoc;
|
2015-11-03 09:19:56 +08:00
|
|
|
|
|
|
|
ObjCTypeParamListScope Scope(Actions, getCurScope());
|
|
|
|
return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,
|
|
|
|
rAngleLoc,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/*mayBeProtocolList=*/false);
|
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list:
|
|
|
|
/// empty
|
|
|
|
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-interface-decl-list objc-method-requirement [OBJC2]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-interface-decl-list objc-method-proto ';'
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list declaration
|
|
|
|
/// objc-interface-decl-list ';'
|
|
|
|
///
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-method-requirement: [OBJC2]
|
|
|
|
/// @required
|
|
|
|
/// @optional
|
|
|
|
///
|
2018-07-31 03:24:48 +08:00
|
|
|
void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
|
2011-08-23 05:44:58 +08:00
|
|
|
Decl *CDecl) {
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> allMethods;
|
|
|
|
SmallVector<DeclGroupPtrTy, 8> allTUVariables;
|
2007-09-18 08:25:23 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-07 09:20:12 +08:00
|
|
|
SourceRange AtEnd;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
while (1) {
|
2008-10-20 13:46:22 +08:00
|
|
|
// If this is a method prototype, parse it.
|
2015-06-18 18:59:26 +08:00
|
|
|
if (Tok.isOneOf(tok::minus, tok::plus)) {
|
2012-07-27 01:32:28 +08:00
|
|
|
if (Decl *methodPrototype =
|
|
|
|
ParseObjCMethodPrototype(MethodImplKind, false))
|
|
|
|
allMethods.push_back(methodPrototype);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
|
|
|
|
// method definitions.
|
2011-12-17 12:13:22 +08:00
|
|
|
if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
|
|
|
|
// We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
|
2011-12-17 12:13:22 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-04-03 07:15:40 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected_minus_or_plus);
|
2018-07-31 03:24:48 +08:00
|
|
|
ParseObjCMethodDecl(Tok.getLocation(),
|
|
|
|
tok::minus,
|
2011-03-13 02:54:30 +08:00
|
|
|
MethodImplKind, false);
|
2010-04-03 07:15:40 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-10-20 13:46:22 +08:00
|
|
|
// Ignore excess semicolons.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2019-03-14 22:18:56 +08:00
|
|
|
// FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,
|
|
|
|
// to make -Wextra-semi diagnose them.
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken();
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// If we got to the end of the file, exit the loop.
|
2013-11-23 12:06:09 +08:00
|
|
|
if (isEofOrEom())
|
2007-09-11 04:33:04 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-14 05:24:21 +08:00
|
|
|
// Code completion within an Objective-C interface.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(),
|
2012-02-08 00:50:53 +08:00
|
|
|
CurParsedObjCImpl? Sema::PCC_ObjCImplementation
|
2010-08-27 07:41:50 +08:00
|
|
|
: Sema::PCC_ObjCInterface);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:24:21 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// If we don't have an @ directive, parse it as a function definition.
|
|
|
|
if (Tok.isNot(tok::at)) {
|
2009-01-09 12:34:13 +08:00
|
|
|
// The code below does not consume '}'s because it is afraid of eating the
|
|
|
|
// end of a namespace. Because of the way this code is structured, an
|
|
|
|
// erroneous r_brace would cause an infinite loop if not handled here.
|
|
|
|
if (Tok.is(tok::r_brace))
|
|
|
|
break;
|
2019-03-14 22:18:56 +08:00
|
|
|
|
2012-06-23 13:07:58 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2019-03-14 22:18:56 +08:00
|
|
|
|
|
|
|
// Since we call ParseDeclarationOrFunctionDefinition() instead of
|
|
|
|
// ParseExternalDeclaration() below (so that this doesn't parse nested
|
|
|
|
// @interfaces), this needs to duplicate some code from the latter.
|
|
|
|
if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
|
|
|
|
SourceLocation DeclEnd;
|
|
|
|
allTUVariables.push_back(
|
|
|
|
ParseDeclaration(DeclaratorContext::FileContext, DeclEnd, attrs));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Otherwise, we have an @ directive, eat the @.
|
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-12-07 17:27:33 +08:00
|
|
|
}
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
|
2010-01-07 09:20:12 +08:00
|
|
|
AtEnd.setBegin(AtLoc);
|
|
|
|
AtEnd.setEnd(Tok.getLocation());
|
2008-10-20 13:46:22 +08:00
|
|
|
break;
|
2010-03-16 14:04:47 +08:00
|
|
|
} else if (DirectiveKind == tok::objc_not_keyword) {
|
|
|
|
Diag(Tok, diag::err_objc_unknown_at);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
continue;
|
2008-10-20 14:10:06 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
switch (DirectiveKind) {
|
|
|
|
default:
|
2008-10-20 14:10:06 +08:00
|
|
|
// FIXME: If someone forgets an @end on a protocol, this loop will
|
|
|
|
// continue to eat up tons of stuff and spew lots of nonsense errors. It
|
|
|
|
// would probably be better to bail out if we saw an @class or @interface
|
|
|
|
// or something like that.
|
2008-10-20 15:22:18 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_illegal_interface_qual);
|
2008-10-20 14:10:06 +08:00
|
|
|
// Skip until we see an '@' or '}' or ';'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, tok::at, StopAtSemi);
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-11-02 08:44:43 +08:00
|
|
|
case tok::objc_implementation:
|
2010-11-10 04:38:00 +08:00
|
|
|
case tok::objc_interface:
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
|
2018-08-10 05:08:08 +08:00
|
|
|
Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
|
|
|
|
<< (int)Actions.getObjCContainerKind();
|
2010-11-02 08:44:43 +08:00
|
|
|
ConsumeToken();
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
case tok::objc_required:
|
|
|
|
case tok::objc_optional:
|
|
|
|
// This is only valid on protocols.
|
2008-10-20 13:46:22 +08:00
|
|
|
if (contextKey != tok::objc_protocol)
|
2008-10-20 14:10:06 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
|
2008-10-20 13:57:40 +08:00
|
|
|
else
|
2008-10-20 14:10:06 +08:00
|
|
|
MethodImplKind = DirectiveKind;
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
case tok::objc_property:
|
2008-10-20 13:46:22 +08:00
|
|
|
ObjCDeclSpec OCDS;
|
2012-03-01 06:18:55 +08:00
|
|
|
SourceLocation LParenLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
// Parse property attribute list, if any.
|
2012-03-01 06:18:55 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
LParenLoc = Tok.getLocation();
|
2011-08-22 23:54:49 +08:00
|
|
|
ParseObjCPropertyAttribute(OCDS);
|
2012-03-01 06:18:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-06-20 02:14:38 +08:00
|
|
|
bool addedToDeclSpec = false;
|
2014-09-03 19:06:10 +08:00
|
|
|
auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
|
|
|
|
if (FD.D.getIdentifier() == nullptr) {
|
|
|
|
Diag(AtLoc, diag::err_objc_property_requires_field_name)
|
|
|
|
<< FD.D.getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (FD.BitfieldSize) {
|
|
|
|
Diag(AtLoc, diag::err_objc_property_bitfield)
|
|
|
|
<< FD.D.getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-20 02:14:38 +08:00
|
|
|
// Map a nullability property attribute to a context-sensitive keyword
|
|
|
|
// attribute.
|
|
|
|
if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
|
|
|
|
addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
|
|
|
|
OCDS.getNullabilityLoc(),
|
|
|
|
addedToDeclSpec);
|
|
|
|
|
2014-09-03 19:06:10 +08:00
|
|
|
// Install the property declarator into interfaceDecl.
|
|
|
|
IdentifierInfo *SelName =
|
|
|
|
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
|
|
|
|
|
|
|
|
Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
|
|
|
|
IdentifierInfo *SetterName = OCDS.getSetterName();
|
|
|
|
Selector SetterSel;
|
|
|
|
if (SetterName)
|
|
|
|
SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
|
|
|
|
else
|
|
|
|
SetterSel = SelectorTable::constructSetterSelector(
|
|
|
|
PP.getIdentifierTable(), PP.getSelectorTable(),
|
|
|
|
FD.D.getIdentifier());
|
|
|
|
Decl *Property = Actions.ActOnProperty(
|
|
|
|
getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
|
2015-12-11 07:02:09 +08:00
|
|
|
MethodImplKind);
|
2014-09-03 19:06:10 +08:00
|
|
|
|
|
|
|
FD.complete(Property);
|
|
|
|
};
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Parse all the comma separated declarators.
|
2012-08-09 07:04:35 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2014-09-03 19:06:10 +08:00
|
|
|
ParseStructDeclaration(DS, ObjCPropertyCallback);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-26 09:53:26 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2007-09-06 07:30:30 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2008-10-20 14:10:06 +08:00
|
|
|
|
|
|
|
// We break out of the big loop in two cases: when we see @end or when we see
|
|
|
|
// EOF. In the former case, eat the @end. In the later case, emit an error.
|
2009-12-07 17:27:33 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCAtDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2011-12-06 17:25:23 +08:00
|
|
|
} else if (Tok.isObjCAtKeyword(tok::objc_end)) {
|
2008-10-20 14:10:06 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2011-12-06 17:25:23 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
|
2018-08-10 05:08:08 +08:00
|
|
|
Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
|
|
|
|
<< (int)Actions.getObjCContainerKind();
|
2011-12-06 17:25:23 +08:00
|
|
|
AtEnd.setBegin(Tok.getLocation());
|
|
|
|
AtEnd.setEnd(Tok.getLocation());
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
// Insert collected methods declarations into the @interface object.
|
2008-10-20 14:10:06 +08:00
|
|
|
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
|
2013-07-16 23:33:19 +08:00
|
|
|
Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2015-06-20 02:14:38 +08:00
|
|
|
/// Diagnose redundant or conflicting nullability information.
|
|
|
|
static void diagnoseRedundantPropertyNullability(Parser &P,
|
|
|
|
ObjCDeclSpec &DS,
|
|
|
|
NullabilityKind nullability,
|
|
|
|
SourceLocation nullabilityLoc){
|
|
|
|
if (DS.getNullability() == nullability) {
|
|
|
|
P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
|
2015-06-25 06:02:08 +08:00
|
|
|
<< DiagNullabilityKind(nullability, true)
|
2015-06-20 02:14:38 +08:00
|
|
|
<< SourceRange(DS.getNullabilityLoc());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
|
2015-06-25 06:02:08 +08:00
|
|
|
<< DiagNullabilityKind(nullability, true)
|
|
|
|
<< DiagNullabilityKind(DS.getNullability(), true)
|
2015-06-20 02:14:38 +08:00
|
|
|
<< SourceRange(DS.getNullabilityLoc());
|
|
|
|
}
|
|
|
|
|
2007-09-01 00:11:31 +08:00
|
|
|
/// Parse property attribute declarations.
|
|
|
|
///
|
|
|
|
/// property-attr-decl: '(' property-attrlist ')'
|
|
|
|
/// property-attrlist:
|
|
|
|
/// property-attribute
|
|
|
|
/// property-attrlist ',' property-attribute
|
|
|
|
/// property-attribute:
|
|
|
|
/// getter '=' identifier
|
|
|
|
/// setter '=' identifier ':'
|
Implement __attribute__((objc_direct)), __attribute__((objc_direct_members))
__attribute__((objc_direct)) is an attribute on methods declaration, and
__attribute__((objc_direct_members)) on implementation, categories or
extensions.
A `direct` property specifier is added (@property(direct) type name)
These attributes / specifiers cause the method to have no associated
Objective-C metadata (for the property or the method itself), and the
calling convention to be a direct C function call.
The symbol for the method has enforced hidden visibility and such direct
calls are hence unreachable cross image. An explicit C function must be
made if so desired to wrap them.
The implicit `self` and `_cmd` arguments are preserved, however to
maintain compatibility with the usual `objc_msgSend` semantics,
3 fundamental precautions are taken:
1) for instance methods, `self` is nil-checked. On arm64 backends this
typically adds a single instruction (cbz x0, <closest-ret>) to the
codegen, for the vast majority of the cases when the return type is a
scalar.
2) for class methods, because the class may not be realized/initialized
yet, a call to `[self self]` is emitted. When the proper deployment
target is used, this is optimized to `objc_opt_self(self)`.
However, long term we might want to emit something better that the
optimizer can reason about. When inlining kicks in, these calls
aren't optimized away as the optimizer has no idea that a single call
is really necessary.
3) the calling convention for the `_cmd` argument is changed: the caller
leaves the second argument to the call undefined, and the selector is
loaded inside the body when it's referenced only.
As far as error reporting goes, the compiler refuses:
- making any overloads direct,
- making an overload of a direct method,
- implementations marked as direct when the declaration in the
interface isn't (the other way around is allowed, as the direct
attribute is inherited from the declaration),
- marking methods required for protocol conformance as direct,
- messaging an unqualified `id` with a direct method,
- forming any @selector() expression with only direct selectors.
As warnings:
- any inconsistency of direct-related calling convention when
@selector() or messaging is used,
- forming any @selector() expression with a possibly direct selector.
Lastly an `objc_direct_members` attribute is added that can decorate
`@implementation` blocks and causes methods only declared there (and in
no `@interface`) to be automatically direct. When decorating an
`@interface` then all methods and properties declared in this block are
marked direct.
Radar-ID: rdar://problem/2684889
Differential Revision: https://reviews.llvm.org/D69991
Reviewed-By: John McCall
2019-11-08 15:14:58 +08:00
|
|
|
/// direct
|
2007-09-01 00:11:31 +08:00
|
|
|
/// readonly
|
|
|
|
/// readwrite
|
|
|
|
/// assign
|
|
|
|
/// retain
|
|
|
|
/// copy
|
|
|
|
/// nonatomic
|
2011-06-16 07:02:42 +08:00
|
|
|
/// atomic
|
|
|
|
/// strong
|
|
|
|
/// weak
|
|
|
|
/// unsafe_unretained
|
2015-06-20 02:14:38 +08:00
|
|
|
/// nonnull
|
|
|
|
/// nullable
|
|
|
|
/// null_unspecified
|
2015-06-20 02:14:46 +08:00
|
|
|
/// null_resettable
|
2016-01-27 02:52:43 +08:00
|
|
|
/// class
|
2007-09-01 00:11:31 +08:00
|
|
|
///
|
2011-08-22 23:54:49 +08:00
|
|
|
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
|
2008-10-20 15:24:39 +08:00
|
|
|
assert(Tok.getKind() == tok::l_paren);
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:15:22 +08:00
|
|
|
while (1) {
|
2009-10-09 05:55:05 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-10-09 05:55:05 +08:00
|
|
|
}
|
2007-09-01 00:11:31 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:22:18 +08:00
|
|
|
// If this is not an identifier at all, bail out early.
|
2014-05-21 14:02:52 +08:00
|
|
|
if (!II) {
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-10-20 15:22:18 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
SourceLocation AttrName = ConsumeToken(); // consume last attribute name
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-20 12:42:34 +08:00
|
|
|
if (II->isStr("readonly"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("assign"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("unsafe_unretained"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("readwrite"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("retain"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("strong"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("copy"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("nonatomic"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
|
2011-06-11 08:45:12 +08:00
|
|
|
else if (II->isStr("atomic"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
|
2011-06-16 07:02:42 +08:00
|
|
|
else if (II->isStr("weak"))
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("getter") || II->isStr("setter")) {
|
2010-10-03 01:45:21 +08:00
|
|
|
bool IsSetter = II->getNameStart()[0] == 's';
|
|
|
|
|
2008-10-20 15:39:53 +08:00
|
|
|
// getter/setter require extra treatment.
|
2010-10-03 01:45:21 +08:00
|
|
|
unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
|
2015-11-15 02:16:02 +08:00
|
|
|
diag::err_objc_expected_equal_for_getter;
|
2010-10-03 01:45:21 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::equal, DiagID)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:00:43 +08:00
|
|
|
return;
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 15:41:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-10-03 01:45:21 +08:00
|
|
|
if (IsSetter)
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertySetter(getCurScope());
|
2009-11-19 15:41:15 +08:00
|
|
|
else
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyGetter(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-11-19 15:41:15 +08:00
|
|
|
}
|
|
|
|
|
2010-10-03 01:45:21 +08:00
|
|
|
SourceLocation SelLoc;
|
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
|
|
|
|
|
|
|
|
if (!SelIdent) {
|
|
|
|
Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
|
|
|
|
<< IsSetter;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:24:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-03 01:45:21 +08:00
|
|
|
if (IsSetter) {
|
2008-10-20 15:24:39 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
|
2017-03-17 02:25:40 +08:00
|
|
|
DS.setSetterName(SelIdent, SelLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::colon,
|
|
|
|
diag::err_expected_colon_after_setter_name)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:24:39 +08:00
|
|
|
return;
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2008-10-20 15:24:39 +08:00
|
|
|
} else {
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
|
2017-03-17 02:25:40 +08:00
|
|
|
DS.setGetterName(SelIdent, SelLoc);
|
2008-10-20 15:24:39 +08:00
|
|
|
}
|
2015-06-20 02:14:38 +08:00
|
|
|
} else if (II->isStr("nonnull")) {
|
|
|
|
if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
|
|
|
|
diagnoseRedundantPropertyNullability(*this, DS,
|
|
|
|
NullabilityKind::NonNull,
|
|
|
|
Tok.getLocation());
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
|
|
|
|
DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
|
|
|
|
} else if (II->isStr("nullable")) {
|
|
|
|
if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
|
|
|
|
diagnoseRedundantPropertyNullability(*this, DS,
|
|
|
|
NullabilityKind::Nullable,
|
|
|
|
Tok.getLocation());
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
|
|
|
|
DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
|
|
|
|
} else if (II->isStr("null_unspecified")) {
|
|
|
|
if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
|
|
|
|
diagnoseRedundantPropertyNullability(*this, DS,
|
|
|
|
NullabilityKind::Unspecified,
|
|
|
|
Tok.getLocation());
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
|
|
|
|
DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
|
2015-06-20 02:14:46 +08:00
|
|
|
} else if (II->isStr("null_resettable")) {
|
|
|
|
if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
|
|
|
|
diagnoseRedundantPropertyNullability(*this, DS,
|
|
|
|
NullabilityKind::Unspecified,
|
|
|
|
Tok.getLocation());
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
|
|
|
|
DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
|
|
|
|
|
|
|
|
// Also set the null_resettable bit.
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
|
2016-01-27 02:52:43 +08:00
|
|
|
} else if (II->isStr("class")) {
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class);
|
Implement __attribute__((objc_direct)), __attribute__((objc_direct_members))
__attribute__((objc_direct)) is an attribute on methods declaration, and
__attribute__((objc_direct_members)) on implementation, categories or
extensions.
A `direct` property specifier is added (@property(direct) type name)
These attributes / specifiers cause the method to have no associated
Objective-C metadata (for the property or the method itself), and the
calling convention to be a direct C function call.
The symbol for the method has enforced hidden visibility and such direct
calls are hence unreachable cross image. An explicit C function must be
made if so desired to wrap them.
The implicit `self` and `_cmd` arguments are preserved, however to
maintain compatibility with the usual `objc_msgSend` semantics,
3 fundamental precautions are taken:
1) for instance methods, `self` is nil-checked. On arm64 backends this
typically adds a single instruction (cbz x0, <closest-ret>) to the
codegen, for the vast majority of the cases when the return type is a
scalar.
2) for class methods, because the class may not be realized/initialized
yet, a call to `[self self]` is emitted. When the proper deployment
target is used, this is optimized to `objc_opt_self(self)`.
However, long term we might want to emit something better that the
optimizer can reason about. When inlining kicks in, these calls
aren't optimized away as the optimizer has no idea that a single call
is really necessary.
3) the calling convention for the `_cmd` argument is changed: the caller
leaves the second argument to the call undefined, and the selector is
loaded inside the body when it's referenced only.
As far as error reporting goes, the compiler refuses:
- making any overloads direct,
- making an overload of a direct method,
- implementations marked as direct when the declaration in the
interface isn't (the other way around is allowed, as the direct
attribute is inherited from the declaration),
- marking methods required for protocol conformance as direct,
- messaging an unqualified `id` with a direct method,
- forming any @selector() expression with only direct selectors.
As warnings:
- any inconsistency of direct-related calling convention when
@selector() or messaging is used,
- forming any @selector() expression with a possibly direct selector.
Lastly an `objc_direct_members` attribute is added that can decorate
`@implementation` blocks and causes methods only declared there (and in
no `@interface`) to be automatically direct. When decorating an
`@interface` then all methods and properties declared in this block are
marked direct.
Radar-ID: rdar://problem/2684889
Differential Revision: https://reviews.llvm.org/D69991
Reviewed-By: John McCall
2019-11-08 15:14:58 +08:00
|
|
|
} else if (II->isStr("direct")) {
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_direct);
|
2008-10-20 15:39:53 +08:00
|
|
|
} else {
|
2008-11-19 15:49:38 +08:00
|
|
|
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-20 15:15:22 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
ConsumeToken();
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-proto:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-instance-method objc-method-decl objc-method-attributes[opt]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-class-method objc-method-decl objc-method-attributes[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-method: '-'
|
|
|
|
/// objc-class-method: '+'
|
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-method-attributes: [OBJC2]
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
///
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
|
2011-03-13 02:54:30 +08:00
|
|
|
bool MethodDefinition) {
|
2015-06-18 18:59:26 +08:00
|
|
|
assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
tok::TokenKind methodType = Tok.getKind();
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation mLoc = ConsumeToken();
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
|
2011-03-13 02:54:30 +08:00
|
|
|
MethodDefinition);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Since this rule is used for both method declarations and definitions,
|
2007-09-11 04:51:04 +08:00
|
|
|
// the caller is (optionally) responsible for consuming the ';'.
|
2007-09-06 07:30:30 +08:00
|
|
|
return MDecl;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-selector:
|
|
|
|
/// identifier
|
|
|
|
/// one of
|
|
|
|
/// enum struct union if else while do for switch case default
|
|
|
|
/// break continue return goto asm sizeof typeof __alignof
|
|
|
|
/// unsigned long const short volatile signed restrict _Complex
|
|
|
|
/// in out inout bycopy byref oneway int char float double void _Bool
|
|
|
|
///
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
|
2010-09-03 09:26:16 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default:
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2017-07-13 18:50:21 +08:00
|
|
|
case tok::colon:
|
|
|
|
// Empty selector piece uses the location of the ':'.
|
|
|
|
SelectorLoc = Tok.getLocation();
|
|
|
|
return nullptr;
|
2010-09-04 01:33:04 +08:00
|
|
|
case tok::ampamp:
|
|
|
|
case tok::ampequal:
|
|
|
|
case tok::amp:
|
|
|
|
case tok::pipe:
|
|
|
|
case tok::tilde:
|
|
|
|
case tok::exclaim:
|
|
|
|
case tok::exclaimequal:
|
|
|
|
case tok::pipepipe:
|
|
|
|
case tok::pipeequal:
|
|
|
|
case tok::caret:
|
|
|
|
case tok::caretequal: {
|
2010-09-04 02:01:09 +08:00
|
|
|
std::string ThisTok(PP.getSpelling(Tok));
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isLetter(ThisTok[0])) {
|
2016-11-03 20:25:51 +08:00
|
|
|
IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);
|
2010-09-04 01:33:04 +08:00
|
|
|
Tok.setKind(tok::identifier);
|
|
|
|
SelectorLoc = ConsumeToken();
|
|
|
|
return II;
|
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-09-04 01:33:04 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::identifier:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_asm:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw_auto:
|
2007-11-15 13:25:19 +08:00
|
|
|
case tok::kw_bool:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_break:
|
|
|
|
case tok::kw_case:
|
|
|
|
case tok::kw_catch:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_const_cast:
|
|
|
|
case tok::kw_continue:
|
|
|
|
case tok::kw_default:
|
|
|
|
case tok::kw_delete:
|
|
|
|
case tok::kw_do:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_dynamic_cast:
|
|
|
|
case tok::kw_else:
|
|
|
|
case tok::kw_enum:
|
|
|
|
case tok::kw_explicit:
|
|
|
|
case tok::kw_export:
|
|
|
|
case tok::kw_extern:
|
|
|
|
case tok::kw_false:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_friend:
|
|
|
|
case tok::kw_goto:
|
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_inline:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_mutable:
|
|
|
|
case tok::kw_namespace:
|
|
|
|
case tok::kw_new:
|
|
|
|
case tok::kw_operator:
|
|
|
|
case tok::kw_private:
|
|
|
|
case tok::kw_protected:
|
|
|
|
case tok::kw_public:
|
|
|
|
case tok::kw_register:
|
|
|
|
case tok::kw_reinterpret_cast:
|
|
|
|
case tok::kw_restrict:
|
|
|
|
case tok::kw_return:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_sizeof:
|
|
|
|
case tok::kw_static:
|
|
|
|
case tok::kw_static_cast:
|
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_switch:
|
|
|
|
case tok::kw_template:
|
|
|
|
case tok::kw_this:
|
|
|
|
case tok::kw_throw:
|
|
|
|
case tok::kw_true:
|
|
|
|
case tok::kw_try:
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_typeid:
|
|
|
|
case tok::kw_typename:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
case tok::kw_union:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_using:
|
|
|
|
case tok::kw_virtual:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
case tok::kw_while:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Complex:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw___alignof:
|
2015-11-11 10:02:15 +08:00
|
|
|
case tok::kw___auto_type:
|
2007-10-07 10:00:24 +08:00
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
2007-10-11 08:55:41 +08:00
|
|
|
SelectorLoc = ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
return II;
|
2007-09-28 03:52:15 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-01-03 06:54:34 +08:00
|
|
|
/// objc-for-collection-in: 'in'
|
|
|
|
///
|
2008-01-05 07:04:08 +08:00
|
|
|
bool Parser::isTokIdentifier_in() const {
|
2008-01-04 01:55:25 +08:00
|
|
|
// FIXME: May have to do additional look-ahead to only allow for
|
|
|
|
// valid tokens following an 'in'; such as an identifier, unary operators,
|
|
|
|
// '[' etc.
|
2018-10-31 04:31:30 +08:00
|
|
|
return (getLangOpts().ObjC && Tok.is(tok::identifier) &&
|
2008-08-23 10:02:23 +08:00
|
|
|
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
|
2008-01-03 06:54:34 +08:00
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
/// ParseObjCTypeQualifierList - This routine parses the objective-c's type
|
2007-12-12 14:56:32 +08:00
|
|
|
/// qualifier list and builds their bitmask representation in the input
|
|
|
|
/// argument.
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-type-qualifiers:
|
|
|
|
/// objc-type-qualifier
|
|
|
|
/// objc-type-qualifiers objc-type-qualifier
|
|
|
|
///
|
2015-06-20 02:14:38 +08:00
|
|
|
/// objc-type-qualifier:
|
|
|
|
/// 'in'
|
|
|
|
/// 'out'
|
|
|
|
/// 'inout'
|
|
|
|
/// 'oneway'
|
|
|
|
/// 'bycopy'
|
|
|
|
/// 'byref'
|
|
|
|
/// 'nonnull'
|
|
|
|
/// 'nullable'
|
|
|
|
/// 'null_unspecified'
|
|
|
|
///
|
2011-03-09 03:17:54 +08:00
|
|
|
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclaratorContext Context) {
|
|
|
|
assert(Context == DeclaratorContext::ObjCParameterContext ||
|
|
|
|
Context == DeclaratorContext::ObjCResultContext);
|
2011-10-01 17:56:14 +08:00
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
while (1) {
|
2010-08-24 09:06:58 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCPassingType(getCurScope(), DS,
|
2017-12-29 13:41:00 +08:00
|
|
|
Context == DeclaratorContext::ObjCParameterContext);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-24 09:06:58 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2007-12-12 14:56:32 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
for (unsigned i = 0; i != objc_NumQuals; ++i) {
|
2015-06-20 02:14:38 +08:00
|
|
|
if (II != ObjCTypeQuals[i] ||
|
|
|
|
NextToken().is(tok::less) ||
|
|
|
|
NextToken().is(tok::coloncolon))
|
2007-12-12 14:56:32 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec::ObjCDeclQualifier Qual;
|
2015-06-20 02:14:38 +08:00
|
|
|
NullabilityKind Nullability;
|
2007-12-12 14:56:32 +08:00
|
|
|
switch (i) {
|
2011-09-23 13:06:16 +08:00
|
|
|
default: llvm_unreachable("Unknown decl qualifier");
|
2008-01-08 03:49:32 +08:00
|
|
|
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
|
|
|
|
case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
|
|
|
|
case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
|
|
|
|
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
|
|
|
|
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
|
|
|
|
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
|
2015-06-20 02:14:38 +08:00
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
case objc_nonnull:
|
2015-06-20 02:14:38 +08:00
|
|
|
Qual = ObjCDeclSpec::DQ_CSNullability;
|
|
|
|
Nullability = NullabilityKind::NonNull;
|
|
|
|
break;
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
case objc_nullable:
|
2015-06-20 02:14:38 +08:00
|
|
|
Qual = ObjCDeclSpec::DQ_CSNullability;
|
|
|
|
Nullability = NullabilityKind::Nullable;
|
|
|
|
break;
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
case objc_null_unspecified:
|
2015-06-20 02:14:38 +08:00
|
|
|
Qual = ObjCDeclSpec::DQ_CSNullability;
|
|
|
|
Nullability = NullabilityKind::Unspecified;
|
|
|
|
break;
|
2007-12-12 14:56:32 +08:00
|
|
|
}
|
2015-06-20 02:14:38 +08:00
|
|
|
|
|
|
|
// FIXME: Diagnose redundant specifiers.
|
2008-01-08 03:49:32 +08:00
|
|
|
DS.setObjCDeclQualifier(Qual);
|
2015-06-20 02:14:38 +08:00
|
|
|
if (Qual == ObjCDeclSpec::DQ_CSNullability)
|
|
|
|
DS.setNullability(Tok.getLocation(), Nullability);
|
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
ConsumeToken();
|
2014-05-21 14:02:52 +08:00
|
|
|
II = nullptr;
|
2007-12-12 14:56:32 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
// If this wasn't a recognized qualifier, bail out.
|
|
|
|
if (II) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-01 17:56:14 +08:00
|
|
|
/// Take all the decl attributes out of the given list and add
|
|
|
|
/// them to the given attribute set.
|
2018-07-13 05:09:05 +08:00
|
|
|
static void takeDeclAttributes(ParsedAttributesView &attrs,
|
|
|
|
ParsedAttributesView &from) {
|
|
|
|
for (auto &AL : llvm::reverse(from)) {
|
|
|
|
if (!AL.isUsedAsTypeAttr()) {
|
|
|
|
from.remove(&AL);
|
2018-08-03 09:21:16 +08:00
|
|
|
attrs.addAtEnd(&AL);
|
2011-10-01 17:56:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takeDeclAttributes - Take all the decl attributes from the given
|
|
|
|
/// declarator and add them to the given list.
|
|
|
|
static void takeDeclAttributes(ParsedAttributes &attrs,
|
|
|
|
Declarator &D) {
|
|
|
|
// First, take ownership of all attributes.
|
|
|
|
attrs.getPool().takeAllFrom(D.getAttributePool());
|
|
|
|
attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
|
|
|
|
|
|
|
|
// Now actually move the attributes over.
|
2018-07-13 05:09:05 +08:00
|
|
|
takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
|
2011-10-01 17:56:14 +08:00
|
|
|
takeDeclAttributes(attrs, D.getAttributes());
|
|
|
|
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
|
2018-07-13 05:09:05 +08:00
|
|
|
takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
|
2011-10-01 17:56:14 +08:00
|
|
|
}
|
|
|
|
|
2007-12-12 14:56:32 +08:00
|
|
|
/// objc-type-name:
|
|
|
|
/// '(' objc-type-qualifiers[opt] type-name ')'
|
|
|
|
/// '(' objc-type-qualifiers[opt] ')'
|
|
|
|
///
|
2018-07-31 03:24:48 +08:00
|
|
|
ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclaratorContext context,
|
2011-10-01 17:56:14 +08:00
|
|
|
ParsedAttributes *paramAttrs) {
|
2017-12-29 13:41:00 +08:00
|
|
|
assert(context == DeclaratorContext::ObjCParameterContext ||
|
|
|
|
context == DeclaratorContext::ObjCResultContext);
|
2014-05-21 14:02:52 +08:00
|
|
|
assert((paramAttrs != nullptr) ==
|
2017-12-29 13:41:00 +08:00
|
|
|
(context == DeclaratorContext::ObjCParameterContext));
|
2011-10-01 17:56:14 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_paren) && "expected (");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2011-08-23 01:59:19 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
|
|
|
|
2007-11-01 05:59:43 +08:00
|
|
|
// Parse type qualifiers, in, inout, etc.
|
2011-10-01 17:56:14 +08:00
|
|
|
ParseObjCTypeQualifierList(DS, context);
|
2019-06-27 07:39:23 +08:00
|
|
|
SourceLocation TypeStartLoc = Tok.getLocation();
|
2007-08-23 07:18:22 +08:00
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType Ty;
|
2015-06-20 07:18:00 +08:00
|
|
|
if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
|
2011-10-01 17:56:14 +08:00
|
|
|
// Parse an abstract declarator.
|
|
|
|
DeclSpec declSpec(AttrFactory);
|
|
|
|
declSpec.setObjCQualifiers(&DS);
|
2017-12-31 08:06:40 +08:00
|
|
|
DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
|
2017-12-29 13:41:00 +08:00
|
|
|
if (context == DeclaratorContext::ObjCResultContext)
|
2017-12-31 08:06:40 +08:00
|
|
|
dsContext = DeclSpecContext::DSC_objc_method_result;
|
2015-06-20 07:18:00 +08:00
|
|
|
ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
|
2011-10-01 17:56:14 +08:00
|
|
|
Declarator declarator(declSpec, context);
|
|
|
|
ParseDeclarator(declarator);
|
|
|
|
|
|
|
|
// If that's not invalid, extract a type.
|
|
|
|
if (!declarator.isInvalidType()) {
|
2015-06-20 02:14:38 +08:00
|
|
|
// Map a nullability specifier to a context-sensitive keyword attribute.
|
|
|
|
bool addedToDeclSpec = false;
|
|
|
|
if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
|
|
|
|
addContextSensitiveTypeNullability(*this, declarator,
|
|
|
|
DS.getNullability(),
|
|
|
|
DS.getNullabilityLoc(),
|
|
|
|
addedToDeclSpec);
|
|
|
|
|
2011-10-01 17:56:14 +08:00
|
|
|
TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
|
|
|
|
if (!type.isInvalid())
|
|
|
|
Ty = type.get();
|
|
|
|
|
|
|
|
// If we're parsing a parameter, steal all the decl attributes
|
|
|
|
// and add them to the decl spec.
|
2017-12-29 13:41:00 +08:00
|
|
|
if (context == DeclaratorContext::ObjCParameterContext)
|
2011-10-01 17:56:14 +08:00
|
|
|
takeDeclAttributes(*paramAttrs, declarator);
|
|
|
|
}
|
2009-02-19 01:45:20 +08:00
|
|
|
}
|
2011-09-08 09:46:34 +08:00
|
|
|
|
2008-10-22 11:52:06 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-10-22 11:52:06 +08:00
|
|
|
else if (Tok.getLocation() == TypeStartLoc) {
|
2008-08-23 09:48:03 +08:00
|
|
|
// If we didn't eat any tokens, then this isn't a type.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_type);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-10-22 11:52:06 +08:00
|
|
|
} else {
|
|
|
|
// Otherwise, we found *something*, but didn't get a ')' in the right
|
|
|
|
// place. Emit an error then return what we have as the type.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
return Ty;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-method-decl:
|
|
|
|
/// objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-type-name objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-type-name objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-keyword-selector:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-keyword-decl
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-keyword-selector objc-keyword-decl
|
|
|
|
///
|
|
|
|
/// objc-keyword-decl:
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// objc-selector ':' objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-keyword-attributes[opt] identifier
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parmlist:
|
|
|
|
/// objc-parms objc-ellipsis[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parms:
|
|
|
|
/// objc-parms , parameter-declaration
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-ellipsis:
|
2007-08-23 00:35:03 +08:00
|
|
|
/// , ...
|
|
|
|
///
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-keyword-attributes: [OBJC2]
|
|
|
|
/// __attribute__((unused))
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
2010-08-24 02:23:48 +08:00
|
|
|
tok::TokenKind mType,
|
2011-03-13 02:54:30 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind,
|
|
|
|
bool MethodDefinition) {
|
2012-05-07 14:16:41 +08:00
|
|
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
2009-11-04 10:18:39 +08:00
|
|
|
|
2010-04-07 08:21:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2016-01-16 07:43:34 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
|
|
|
|
/*ReturnType=*/nullptr);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-04-07 08:21:17 +08:00
|
|
|
}
|
|
|
|
|
2008-08-23 09:48:03 +08:00
|
|
|
// Parse the return type if present.
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReturnType;
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec DSRet;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren))
|
2017-12-29 13:41:00 +08:00
|
|
|
ReturnType = ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResultContext,
|
2014-05-21 14:02:52 +08:00
|
|
|
nullptr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-19 07:05:16 +08:00
|
|
|
// If attributes exist before the method, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes methodAttrs(AttrFactory);
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2018-02-12 21:38:25 +08:00
|
|
|
MaybeParseCXX11Attributes(methodAttrs);
|
2010-02-19 07:05:16 +08:00
|
|
|
|
2010-04-07 08:21:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
|
2011-08-22 23:54:49 +08:00
|
|
|
ReturnType);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-04-07 08:21:17 +08:00
|
|
|
}
|
|
|
|
|
2010-02-19 07:05:16 +08:00
|
|
|
// Now parse the selector.
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation selLoc;
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
|
2008-08-23 09:48:03 +08:00
|
|
|
|
2009-02-12 04:43:13 +08:00
|
|
|
// An unnamed colon is valid.
|
|
|
|
if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_selector_for_method)
|
|
|
|
<< SourceRange(mLoc, Tok.getLocation());
|
2012-07-27 01:32:28 +08:00
|
|
|
// Skip until we get a ; or @.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2008-08-23 09:48:03 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2018-02-12 21:38:25 +08:00
|
|
|
MaybeParseCXX11Attributes(methodAttrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *Result = Actions.ActOnMethodDeclaration(
|
|
|
|
getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,
|
|
|
|
selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
|
|
|
|
MethodImplKind, false, MethodDefinition);
|
2009-11-04 10:18:39 +08:00
|
|
|
PD.complete(Result);
|
|
|
|
return Result;
|
2007-10-07 10:00:24 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2011-10-03 14:36:36 +08:00
|
|
|
SmallVector<SourceLocation, 12> KeyLocs;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
|
2013-01-29 06:42:45 +08:00
|
|
|
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
|
|
|
Scope::FunctionDeclarationScope | Scope::DeclScope);
|
2011-03-24 19:26:52 +08:00
|
|
|
|
|
|
|
AttributePool allParamAttrs(AttrFactory);
|
2007-10-07 10:00:24 +08:00
|
|
|
while (1) {
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes paramAttrs(AttrFactory);
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::ObjCArgInfo ArgInfo;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Each iteration parses a single keyword argument.
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::colon))
|
2007-10-07 10:00:24 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2016-01-16 07:43:34 +08:00
|
|
|
ArgInfo.Type = nullptr;
|
2009-04-12 02:57:04 +08:00
|
|
|
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
|
2011-10-01 17:56:14 +08:00
|
|
|
ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec,
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclaratorContext::ObjCParameterContext,
|
2011-10-01 17:56:14 +08:00
|
|
|
¶mAttrs);
|
2009-04-12 02:57:04 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist before the argument name, parse them.
|
2011-10-01 17:56:14 +08:00
|
|
|
// Regardless, collect all the attributes we've parsed so far.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(paramAttrs);
|
2018-02-12 21:38:25 +08:00
|
|
|
MaybeParseCXX11Attributes(paramAttrs);
|
2018-07-13 05:09:05 +08:00
|
|
|
ArgInfo.ArgAttrs = paramAttrs;
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2010-07-09 07:37:41 +08:00
|
|
|
// Code completion for the next piece of the selector.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
KeyIdents.push_back(SelIdent);
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
|
2010-07-09 07:37:41 +08:00
|
|
|
mType == tok::minus,
|
|
|
|
/*AtParameterName=*/true,
|
2013-06-16 11:47:57 +08:00
|
|
|
ReturnType, KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-07-09 07:37:41 +08:00
|
|
|
}
|
2017-04-11 23:01:53 +08:00
|
|
|
|
|
|
|
if (expectIdentifier())
|
|
|
|
break; // missing argument name.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 02:57:04 +08:00
|
|
|
ArgInfo.Name = Tok.getIdentifierInfo();
|
|
|
|
ArgInfo.NameLoc = Tok.getLocation();
|
2007-10-07 10:00:24 +08:00
|
|
|
ConsumeToken(); // Eat the identifier.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 02:57:04 +08:00
|
|
|
ArgInfos.push_back(ArgInfo);
|
|
|
|
KeyIdents.push_back(SelIdent);
|
2011-10-03 14:36:36 +08:00
|
|
|
KeyLocs.push_back(selLoc);
|
2009-04-12 02:57:04 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
// Make sure the attributes persist.
|
|
|
|
allParamAttrs.takeAllFrom(paramAttrs.getPool());
|
|
|
|
|
2010-07-09 07:20:03 +08:00
|
|
|
// Code completion for the next piece of the selector.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
|
2010-07-09 07:20:03 +08:00
|
|
|
mType == tok::minus,
|
2010-07-09 07:37:41 +08:00
|
|
|
/*AtParameterName=*/false,
|
2013-06-16 11:47:57 +08:00
|
|
|
ReturnType, KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-07-09 07:20:03 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Check for another keyword selector.
|
2011-10-03 14:36:36 +08:00
|
|
|
SelIdent = ParseObjCSelectorPiece(selLoc);
|
2012-09-13 00:50:35 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon))
|
|
|
|
break;
|
2012-09-18 07:09:59 +08:00
|
|
|
if (!SelIdent) {
|
2012-09-18 03:15:26 +08:00
|
|
|
SourceLocation ColonLoc = Tok.getLocation();
|
|
|
|
if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
|
2012-09-18 07:09:59 +08:00
|
|
|
Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
|
|
|
|
Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
|
|
|
|
Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
|
2012-09-18 03:15:26 +08:00
|
|
|
}
|
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-15 20:35:21 +08:00
|
|
|
bool isVariadic = false;
|
2012-06-22 02:43:08 +08:00
|
|
|
bool cStyleParamWarned = false;
|
2007-10-07 10:00:24 +08:00
|
|
|
// Parse the (optional) parameter list.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::ellipsis)) {
|
2007-11-15 20:35:21 +08:00
|
|
|
isVariadic = true;
|
2007-08-23 02:35:33 +08:00
|
|
|
ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
break;
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2012-06-22 02:43:08 +08:00
|
|
|
if (!cStyleParamWarned) {
|
|
|
|
Diag(Tok, diag::warn_cstyle_param);
|
|
|
|
cStyleParamWarned = true;
|
|
|
|
}
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2018-04-26 08:42:40 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2009-09-09 23:08:12 +08:00
|
|
|
// Parse the declarator.
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator ParmDecl(DS, DeclaratorContext::PrototypeContext);
|
2007-10-07 10:00:24 +08:00
|
|
|
ParseDeclarator(ParmDecl);
|
2010-04-08 08:30:06 +08:00
|
|
|
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
|
2010-04-08 08:30:06 +08:00
|
|
|
CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
2018-07-31 03:24:48 +08:00
|
|
|
ParmDecl.getIdentifierLoc(),
|
2010-04-08 08:30:06 +08:00
|
|
|
Param,
|
2014-05-21 14:02:52 +08:00
|
|
|
nullptr));
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-12 08:21:25 +08:00
|
|
|
// FIXME: Add support for optional parameter list...
|
2007-09-11 04:33:04 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC)
|
2011-03-24 19:26:52 +08:00
|
|
|
MaybeParseGNUAttributes(methodAttrs);
|
2018-02-12 21:38:25 +08:00
|
|
|
MaybeParseCXX11Attributes(methodAttrs);
|
|
|
|
|
2011-08-22 23:54:49 +08:00
|
|
|
if (KeyIdents.size() == 0)
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
|
|
|
|
&KeyIdents[0]);
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *Result = Actions.ActOnMethodDeclaration(
|
|
|
|
getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
|
|
|
|
Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
|
|
|
|
MethodImplKind, isVariadic, MethodDefinition);
|
|
|
|
|
2009-11-04 10:18:39 +08:00
|
|
|
PD.complete(Result);
|
|
|
|
return Result;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
/// objc-protocol-refs:
|
|
|
|
/// '<' identifier-list '>'
|
|
|
|
///
|
|
|
|
bool Parser::
|
2011-07-23 18:55:15 +08:00
|
|
|
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
|
|
|
|
SmallVectorImpl<SourceLocation> &ProtocolLocs,
|
2015-04-20 04:15:55 +08:00
|
|
|
bool WarnOnDeclarations, bool ForObjCContainer,
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation &LAngleLoc, SourceLocation &EndLoc,
|
|
|
|
bool consumeLastToken) {
|
2008-07-26 12:03:38 +08:00
|
|
|
assert(Tok.is(tok::less) && "expected <");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-30 03:41:44 +08:00
|
|
|
LAngleLoc = ConsumeToken(); // the "<"
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
while (1) {
|
2009-11-18 12:19:12 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2015-12-25 07:58:11 +08:00
|
|
|
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return true;
|
2009-11-18 12:19:12 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::greater, StopAtSemi);
|
2008-07-26 12:03:38 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
2009-09-30 03:41:44 +08:00
|
|
|
ProtocolLocs.push_back(Tok.getLocation());
|
2008-07-26 12:03:38 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (!TryConsumeToken(tok::comma))
|
2008-07-26 12:03:38 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
// Consume the '>'.
|
2015-07-07 11:58:14 +08:00
|
|
|
if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/*ObjCGenericList=*/false))
|
2008-07-26 12:03:38 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
// Convert the list of protocols identifiers into a list of protocol decls.
|
2015-04-20 04:15:55 +08:00
|
|
|
Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
|
2015-10-22 12:59:56 +08:00
|
|
|
ProtocolIdents, Protocols);
|
2008-07-26 12:03:38 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
|
2010-10-22 07:17:00 +08:00
|
|
|
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
|
2018-10-31 04:31:30 +08:00
|
|
|
assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");
|
2015-07-07 11:58:14 +08:00
|
|
|
|
|
|
|
SourceLocation lAngleLoc;
|
|
|
|
SmallVector<Decl *, 8> protocols;
|
|
|
|
SmallVector<SourceLocation, 8> protocolLocs;
|
|
|
|
(void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
|
|
|
|
lAngleLoc, rAngleLoc,
|
|
|
|
/*consumeLastToken=*/true);
|
|
|
|
TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
|
|
|
|
protocols,
|
|
|
|
protocolLocs,
|
|
|
|
rAngleLoc);
|
|
|
|
if (result.isUsable()) {
|
|
|
|
Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
|
|
|
|
<< FixItHint::CreateInsertion(lAngleLoc, "id")
|
|
|
|
<< SourceRange(lAngleLoc, rAngleLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2010-10-22 07:17:00 +08:00
|
|
|
}
|
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
/// Parse Objective-C type arguments or protocol qualifiers.
|
|
|
|
///
|
|
|
|
/// objc-type-arguments:
|
2015-07-07 11:58:14 +08:00
|
|
|
/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
|
|
|
|
///
|
|
|
|
void Parser::parseObjCTypeArgsOrProtocolQualifiers(
|
Warn when an intended Objective-C specialization was actually a useless protocol qualification.
Warn in cases where one has provided redundant protocol qualification
that might be a typo for a specialization, e.g., NSArray<NSObject>,
which is pointless (NSArray declares that it conforms to NSObject) and
is likely to be a typo for NSArray<NSObject *>, i.e., an array of
NSObject pointers. This warning is very narrow, only applying when the
base type being qualified is parameterized, has the same number of
parameters as their are protocols listed, all of the names can also
refer to types (including Objective-C class types, of course), and at
least one of those types is an Objective-C class (making this a typo
for a missing '*'). The limitations are partly for performance reasons
(we don't want to do redundant name lookup unless we really need to),
and because we want the warning to apply in very limited cases to
limit false positives.
Part of rdar://problem/6294649.
llvm-svn: 241547
2015-07-07 11:58:28 +08:00
|
|
|
ParsedType baseType,
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation &typeArgsLAngleLoc,
|
|
|
|
SmallVectorImpl<ParsedType> &typeArgs,
|
|
|
|
SourceLocation &typeArgsRAngleLoc,
|
|
|
|
SourceLocation &protocolLAngleLoc,
|
|
|
|
SmallVectorImpl<Decl *> &protocols,
|
|
|
|
SmallVectorImpl<SourceLocation> &protocolLocs,
|
|
|
|
SourceLocation &protocolRAngleLoc,
|
|
|
|
bool consumeLastToken,
|
2015-07-07 11:57:35 +08:00
|
|
|
bool warnOnIncompleteProtocols) {
|
|
|
|
assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
|
|
|
|
SourceLocation lAngleLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Whether all of the elements we've parsed thus far are single
|
|
|
|
// identifiers, which might be types or might be protocols.
|
|
|
|
bool allSingleIdentifiers = true;
|
|
|
|
SmallVector<IdentifierInfo *, 4> identifiers;
|
2015-07-07 11:58:14 +08:00
|
|
|
SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
|
2015-07-07 11:57:35 +08:00
|
|
|
|
|
|
|
// Parse a list of comma-separated identifiers, bailing out if we
|
|
|
|
// see something different.
|
|
|
|
do {
|
|
|
|
// Parse a single identifier.
|
|
|
|
if (Tok.is(tok::identifier) &&
|
|
|
|
(NextToken().is(tok::comma) ||
|
|
|
|
NextToken().is(tok::greater) ||
|
|
|
|
NextToken().is(tok::greatergreater))) {
|
|
|
|
identifiers.push_back(Tok.getIdentifierInfo());
|
|
|
|
identifierLocs.push_back(ConsumeToken());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
// FIXME: Also include types here.
|
|
|
|
SmallVector<IdentifierLocPair, 4> identifierLocPairs;
|
|
|
|
for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
|
2018-07-31 03:24:48 +08:00
|
|
|
identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
|
2015-07-07 11:57:35 +08:00
|
|
|
identifierLocs[i]));
|
|
|
|
}
|
|
|
|
|
2015-07-07 14:20:36 +08:00
|
|
|
QualType BaseT = Actions.GetTypeFromParser(baseType);
|
|
|
|
if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
|
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
|
|
|
|
} else {
|
2015-12-25 07:58:11 +08:00
|
|
|
Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
|
2015-07-07 14:20:36 +08:00
|
|
|
}
|
2015-07-07 11:57:35 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
allSingleIdentifiers = false;
|
|
|
|
break;
|
|
|
|
} while (TryConsumeToken(tok::comma));
|
|
|
|
|
|
|
|
// If we parsed an identifier list, semantic analysis sorts out
|
|
|
|
// whether it refers to protocols or to type arguments.
|
|
|
|
if (allSingleIdentifiers) {
|
|
|
|
// Parse the closing '>'.
|
|
|
|
SourceLocation rAngleLoc;
|
2015-07-07 11:58:14 +08:00
|
|
|
(void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
|
2015-07-07 11:57:35 +08:00
|
|
|
/*ObjCGenericList=*/true);
|
|
|
|
|
|
|
|
// Let Sema figure out what we parsed.
|
|
|
|
Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
|
Warn when an intended Objective-C specialization was actually a useless protocol qualification.
Warn in cases where one has provided redundant protocol qualification
that might be a typo for a specialization, e.g., NSArray<NSObject>,
which is pointless (NSArray declares that it conforms to NSObject) and
is likely to be a typo for NSArray<NSObject *>, i.e., an array of
NSObject pointers. This warning is very narrow, only applying when the
base type being qualified is parameterized, has the same number of
parameters as their are protocols listed, all of the names can also
refer to types (including Objective-C class types, of course), and at
least one of those types is an Objective-C class (making this a typo
for a missing '*'). The limitations are partly for performance reasons
(we don't want to do redundant name lookup unless we really need to),
and because we want the warning to apply in very limited cases to
limit false positives.
Part of rdar://problem/6294649.
llvm-svn: 241547
2015-07-07 11:58:28 +08:00
|
|
|
baseType,
|
2015-07-07 11:57:35 +08:00
|
|
|
lAngleLoc,
|
|
|
|
identifiers,
|
|
|
|
identifierLocs,
|
|
|
|
rAngleLoc,
|
2015-07-07 11:58:14 +08:00
|
|
|
typeArgsLAngleLoc,
|
|
|
|
typeArgs,
|
|
|
|
typeArgsRAngleLoc,
|
|
|
|
protocolLAngleLoc,
|
|
|
|
protocols,
|
|
|
|
protocolRAngleLoc,
|
2015-07-07 11:57:35 +08:00
|
|
|
warnOnIncompleteProtocols);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-14 04:59:07 +08:00
|
|
|
// We parsed an identifier list but stumbled into non single identifiers, this
|
|
|
|
// means we might (a) check that what we already parsed is a legitimate type
|
|
|
|
// (not a protocol or unknown type) and (b) parse the remaining ones, which
|
|
|
|
// must all be type args.
|
2015-07-07 11:57:35 +08:00
|
|
|
|
|
|
|
// Convert the identifiers into type arguments.
|
|
|
|
bool invalid = false;
|
2016-04-14 04:59:07 +08:00
|
|
|
IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;
|
|
|
|
SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;
|
|
|
|
SmallVector<IdentifierInfo *, 2> unknownTypeArgs;
|
|
|
|
SmallVector<SourceLocation, 2> unknownTypeArgsLoc;
|
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
|
|
|
|
ParsedType typeArg
|
|
|
|
= Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
|
|
|
|
if (typeArg) {
|
2015-07-07 11:58:14 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
const char *prevSpec = nullptr;
|
|
|
|
unsigned diagID;
|
2018-01-02 02:23:28 +08:00
|
|
|
DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
|
|
|
|
typeArg, Actions.getASTContext().getPrintingPolicy());
|
2015-07-07 11:58:14 +08:00
|
|
|
|
|
|
|
// Form a declarator to turn this into a type.
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator D(DS, DeclaratorContext::TypeNameContext);
|
2015-07-07 11:58:14 +08:00
|
|
|
TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
|
2016-04-14 04:59:07 +08:00
|
|
|
if (fullTypeArg.isUsable()) {
|
2015-07-07 11:58:14 +08:00
|
|
|
typeArgs.push_back(fullTypeArg.get());
|
2016-04-14 04:59:07 +08:00
|
|
|
if (!foundValidTypeId) {
|
|
|
|
foundValidTypeId = identifiers[i];
|
|
|
|
foundValidTypeSrcLoc = identifierLocs[i];
|
|
|
|
}
|
|
|
|
} else {
|
2015-07-07 11:58:14 +08:00
|
|
|
invalid = true;
|
2016-04-14 04:59:07 +08:00
|
|
|
unknownTypeArgs.push_back(identifiers[i]);
|
|
|
|
unknownTypeArgsLoc.push_back(identifierLocs[i]);
|
|
|
|
}
|
2015-07-07 11:57:35 +08:00
|
|
|
} else {
|
|
|
|
invalid = true;
|
2016-04-14 04:59:07 +08:00
|
|
|
if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) {
|
|
|
|
unknownTypeArgs.push_back(identifiers[i]);
|
|
|
|
unknownTypeArgsLoc.push_back(identifierLocs[i]);
|
|
|
|
} else if (!foundProtocolId) {
|
|
|
|
foundProtocolId = identifiers[i];
|
|
|
|
foundProtocolSrcLoc = identifierLocs[i];
|
|
|
|
}
|
2015-07-07 11:57:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Continue parsing type-names.
|
|
|
|
do {
|
2016-04-14 04:59:07 +08:00
|
|
|
Token CurTypeTok = Tok;
|
2015-07-07 11:57:35 +08:00
|
|
|
TypeResult typeArg = ParseTypeName();
|
2015-07-07 11:58:14 +08:00
|
|
|
|
|
|
|
// Consume the '...' for a pack expansion.
|
|
|
|
SourceLocation ellipsisLoc;
|
|
|
|
TryConsumeToken(tok::ellipsis, ellipsisLoc);
|
|
|
|
if (typeArg.isUsable() && ellipsisLoc.isValid()) {
|
|
|
|
typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
|
|
|
|
}
|
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
if (typeArg.isUsable()) {
|
|
|
|
typeArgs.push_back(typeArg.get());
|
2016-04-14 04:59:07 +08:00
|
|
|
if (!foundValidTypeId) {
|
|
|
|
foundValidTypeId = CurTypeTok.getIdentifierInfo();
|
|
|
|
foundValidTypeSrcLoc = CurTypeTok.getLocation();
|
|
|
|
}
|
2015-07-07 11:57:35 +08:00
|
|
|
} else {
|
|
|
|
invalid = true;
|
|
|
|
}
|
|
|
|
} while (TryConsumeToken(tok::comma));
|
|
|
|
|
2016-04-14 04:59:07 +08:00
|
|
|
// Diagnose the mix between type args and protocols.
|
|
|
|
if (foundProtocolId && foundValidTypeId)
|
|
|
|
Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
|
|
|
|
foundValidTypeId,
|
|
|
|
foundValidTypeSrcLoc);
|
|
|
|
|
|
|
|
// Diagnose unknown arg types.
|
|
|
|
ParsedType T;
|
|
|
|
if (unknownTypeArgs.size())
|
|
|
|
for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)
|
|
|
|
Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],
|
|
|
|
getCurScope(), nullptr, T);
|
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
// Parse the closing '>'.
|
|
|
|
SourceLocation rAngleLoc;
|
2015-07-07 11:58:14 +08:00
|
|
|
(void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
|
2015-07-07 11:57:35 +08:00
|
|
|
/*ObjCGenericList=*/true);
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
if (invalid) {
|
|
|
|
typeArgs.clear();
|
2015-07-07 11:57:35 +08:00
|
|
|
return;
|
2015-07-07 11:58:14 +08:00
|
|
|
}
|
2015-07-07 11:57:35 +08:00
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
// Record left/right angle locations.
|
|
|
|
typeArgsLAngleLoc = lAngleLoc;
|
|
|
|
typeArgsRAngleLoc = rAngleLoc;
|
2015-07-07 11:57:35 +08:00
|
|
|
}
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
void Parser::parseObjCTypeArgsAndProtocolQualifiers(
|
Warn when an intended Objective-C specialization was actually a useless protocol qualification.
Warn in cases where one has provided redundant protocol qualification
that might be a typo for a specialization, e.g., NSArray<NSObject>,
which is pointless (NSArray declares that it conforms to NSObject) and
is likely to be a typo for NSArray<NSObject *>, i.e., an array of
NSObject pointers. This warning is very narrow, only applying when the
base type being qualified is parameterized, has the same number of
parameters as their are protocols listed, all of the names can also
refer to types (including Objective-C class types, of course), and at
least one of those types is an Objective-C class (making this a typo
for a missing '*'). The limitations are partly for performance reasons
(we don't want to do redundant name lookup unless we really need to),
and because we want the warning to apply in very limited cases to
limit false positives.
Part of rdar://problem/6294649.
llvm-svn: 241547
2015-07-07 11:58:28 +08:00
|
|
|
ParsedType baseType,
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation &typeArgsLAngleLoc,
|
|
|
|
SmallVectorImpl<ParsedType> &typeArgs,
|
|
|
|
SourceLocation &typeArgsRAngleLoc,
|
|
|
|
SourceLocation &protocolLAngleLoc,
|
|
|
|
SmallVectorImpl<Decl *> &protocols,
|
|
|
|
SmallVectorImpl<SourceLocation> &protocolLocs,
|
|
|
|
SourceLocation &protocolRAngleLoc,
|
|
|
|
bool consumeLastToken) {
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
assert(Tok.is(tok::less));
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
// Parse the first angle-bracket-delimited clause.
|
Warn when an intended Objective-C specialization was actually a useless protocol qualification.
Warn in cases where one has provided redundant protocol qualification
that might be a typo for a specialization, e.g., NSArray<NSObject>,
which is pointless (NSArray declares that it conforms to NSObject) and
is likely to be a typo for NSArray<NSObject *>, i.e., an array of
NSObject pointers. This warning is very narrow, only applying when the
base type being qualified is parameterized, has the same number of
parameters as their are protocols listed, all of the names can also
refer to types (including Objective-C class types, of course), and at
least one of those types is an Objective-C class (making this a typo
for a missing '*'). The limitations are partly for performance reasons
(we don't want to do redundant name lookup unless we really need to),
and because we want the warning to apply in very limited cases to
limit false positives.
Part of rdar://problem/6294649.
llvm-svn: 241547
2015-07-07 11:58:28 +08:00
|
|
|
parseObjCTypeArgsOrProtocolQualifiers(baseType,
|
|
|
|
typeArgsLAngleLoc,
|
2015-07-07 11:58:14 +08:00
|
|
|
typeArgs,
|
|
|
|
typeArgsRAngleLoc,
|
|
|
|
protocolLAngleLoc,
|
|
|
|
protocols,
|
|
|
|
protocolLocs,
|
|
|
|
protocolRAngleLoc,
|
|
|
|
consumeLastToken,
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
/*warnOnIncompleteProtocols=*/false);
|
2016-09-14 04:04:35 +08:00
|
|
|
if (Tok.is(tok::eof)) // Nothing else to do here...
|
|
|
|
return;
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
|
|
|
|
// An Objective-C object pointer followed by type arguments
|
|
|
|
// can then be followed again by a set of protocol references, e.g.,
|
|
|
|
// \c NSArray<NSView><NSTextDelegate>
|
2015-07-07 11:58:14 +08:00
|
|
|
if ((consumeLastToken && Tok.is(tok::less)) ||
|
|
|
|
(!consumeLastToken && NextToken().is(tok::less))) {
|
|
|
|
// If we aren't consuming the last token, the prior '>' is still hanging
|
|
|
|
// there. Consume it before we parse the protocol qualifiers.
|
|
|
|
if (!consumeLastToken)
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
if (!protocols.empty()) {
|
|
|
|
SkipUntilFlags skipFlags = SkipUntilFlags();
|
|
|
|
if (!consumeLastToken)
|
|
|
|
skipFlags = skipFlags | StopBeforeMatch;
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
Diag(Tok, diag::err_objc_type_args_after_protocols)
|
2015-07-07 11:58:14 +08:00
|
|
|
<< SourceRange(protocolLAngleLoc, protocolRAngleLoc);
|
|
|
|
SkipUntil(tok::greater, tok::greatergreater, skipFlags);
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
} else {
|
2018-07-31 03:24:48 +08:00
|
|
|
ParseObjCProtocolReferences(protocols, protocolLocs,
|
2015-07-07 11:58:14 +08:00
|
|
|
/*WarnOnDeclarations=*/false,
|
|
|
|
/*ForObjCContainer=*/false,
|
2018-07-31 03:24:48 +08:00
|
|
|
protocolLAngleLoc, protocolRAngleLoc,
|
2015-07-07 11:58:14 +08:00
|
|
|
consumeLastToken);
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
|
|
|
|
SourceLocation loc,
|
|
|
|
ParsedType type,
|
|
|
|
bool consumeLastToken,
|
|
|
|
SourceLocation &endLoc) {
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
assert(Tok.is(tok::less));
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation typeArgsLAngleLoc;
|
|
|
|
SmallVector<ParsedType, 4> typeArgs;
|
|
|
|
SourceLocation typeArgsRAngleLoc;
|
|
|
|
SourceLocation protocolLAngleLoc;
|
|
|
|
SmallVector<Decl *, 4> protocols;
|
|
|
|
SmallVector<SourceLocation, 4> protocolLocs;
|
|
|
|
SourceLocation protocolRAngleLoc;
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
|
|
|
|
// Parse type arguments and protocol qualifiers.
|
Warn when an intended Objective-C specialization was actually a useless protocol qualification.
Warn in cases where one has provided redundant protocol qualification
that might be a typo for a specialization, e.g., NSArray<NSObject>,
which is pointless (NSArray declares that it conforms to NSObject) and
is likely to be a typo for NSArray<NSObject *>, i.e., an array of
NSObject pointers. This warning is very narrow, only applying when the
base type being qualified is parameterized, has the same number of
parameters as their are protocols listed, all of the names can also
refer to types (including Objective-C class types, of course), and at
least one of those types is an Objective-C class (making this a typo
for a missing '*'). The limitations are partly for performance reasons
(we don't want to do redundant name lookup unless we really need to),
and because we want the warning to apply in very limited cases to
limit false positives.
Part of rdar://problem/6294649.
llvm-svn: 241547
2015-07-07 11:58:28 +08:00
|
|
|
parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
|
2015-07-07 11:58:14 +08:00
|
|
|
typeArgsRAngleLoc, protocolLAngleLoc,
|
|
|
|
protocols, protocolLocs,
|
|
|
|
protocolRAngleLoc, consumeLastToken);
|
|
|
|
|
2016-09-14 04:04:35 +08:00
|
|
|
if (Tok.is(tok::eof))
|
|
|
|
return true; // Invalid type result.
|
|
|
|
|
2015-07-07 11:58:14 +08:00
|
|
|
// Compute the location of the last token.
|
|
|
|
if (consumeLastToken)
|
|
|
|
endLoc = PrevTokLocation;
|
|
|
|
else
|
|
|
|
endLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
|
|
|
|
getCurScope(),
|
|
|
|
loc,
|
|
|
|
type,
|
|
|
|
typeArgsLAngleLoc,
|
|
|
|
typeArgs,
|
|
|
|
typeArgsRAngleLoc,
|
|
|
|
protocolLAngleLoc,
|
|
|
|
protocols,
|
|
|
|
protocolLocs,
|
|
|
|
protocolRAngleLoc);
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
}
|
|
|
|
|
2013-03-21 02:09:33 +08:00
|
|
|
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
|
|
|
BalancedDelimiterTracker &T,
|
|
|
|
SmallVectorImpl<Decl *> &AllIvarDecls,
|
|
|
|
bool RBraceMissing) {
|
|
|
|
if (!RBraceMissing)
|
|
|
|
T.consumeClose();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-03-21 02:09:33 +08:00
|
|
|
Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
|
|
|
|
Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
|
|
|
|
Actions.ActOnObjCContainerFinishDefinition();
|
|
|
|
// Call ActOnFields() even if we don't have any decls. This is useful
|
|
|
|
// for code rewriting tools that need to be aware of the empty list.
|
2018-07-13 05:09:05 +08:00
|
|
|
Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,
|
|
|
|
T.getOpenLocation(), T.getCloseLocation(),
|
|
|
|
ParsedAttributesView());
|
2013-03-21 02:09:33 +08:00
|
|
|
}
|
2010-10-22 07:17:00 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-class-instance-variables:
|
|
|
|
/// '{' objc-instance-variable-decl-list[opt] '}'
|
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl-list:
|
|
|
|
/// objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl ';'
|
|
|
|
/// ';'
|
|
|
|
/// objc-instance-variable-decl-list objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
|
2019-03-14 22:18:56 +08:00
|
|
|
/// objc-instance-variable-decl-list static_assert-declaration
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-instance-variable-decl-list ';'
|
|
|
|
///
|
|
|
|
/// objc-visibility-spec:
|
|
|
|
/// @private
|
|
|
|
/// @protected
|
|
|
|
/// @public
|
2007-08-22 05:17:12 +08:00
|
|
|
/// @package [OBJC2]
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl:
|
2009-09-09 23:08:12 +08:00
|
|
|
/// struct-declaration
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
|
2010-02-23 07:04:20 +08:00
|
|
|
tok::ObjCKeywordKind visibility,
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation atLoc) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_brace) && "expected {");
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> AllIvarDecls;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-01-13 02:45:55 +08:00
|
|
|
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
|
2011-10-07 07:23:20 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
T.consumeOpen();
|
2007-08-22 05:17:12 +08:00
|
|
|
// While we still have something to read, read the instance variables.
|
2013-11-23 12:06:09 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
|
2007-08-22 05:17:12 +08:00
|
|
|
// Each iteration of this loop reads one objc-instance-variable-decl.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
// Check for extraneous top-level semicolon.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2012-05-17 03:04:59 +08:00
|
|
|
ConsumeExtraSemi(InstanceVariableList);
|
2007-08-22 05:17:12 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
// Set the default visibility to private.
|
2014-01-01 11:08:43 +08:00
|
|
|
if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
|
2010-01-14 05:54:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtVisibility(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:54:15 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2007-08-22 05:17:12 +08:00
|
|
|
case tok::objc_private:
|
|
|
|
case tok::objc_public:
|
|
|
|
case tok::objc_protected:
|
|
|
|
case tok::objc_package:
|
2007-08-24 02:16:40 +08:00
|
|
|
visibility = Tok.getObjCKeywordID();
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
continue;
|
2013-03-21 02:45:49 +08:00
|
|
|
|
|
|
|
case tok::objc_end:
|
|
|
|
Diag(Tok, diag::err_objc_unexpected_atend);
|
2013-03-21 02:09:33 +08:00
|
|
|
Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
|
|
|
|
Tok.setKind(tok::at);
|
|
|
|
Tok.setLength(1);
|
2019-05-17 17:32:05 +08:00
|
|
|
PP.EnterToken(Tok, /*IsReinject*/true);
|
2013-03-21 02:09:33 +08:00
|
|
|
HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
|
|
|
|
T, AllIvarDecls, true);
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-03-21 02:45:49 +08:00
|
|
|
default:
|
|
|
|
Diag(Tok, diag::err_objc_illegal_visibility_spec);
|
|
|
|
continue;
|
2007-08-22 05:17:12 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-14 05:54:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(),
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::PCC_ObjCInstanceVariableList);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-01-14 05:54:15 +08:00
|
|
|
}
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2019-03-14 22:18:56 +08:00
|
|
|
// This needs to duplicate a small amount of code from
|
|
|
|
// ParseStructUnionBody() for things that should work in both
|
|
|
|
// C struct and in Objective-C class instance variables.
|
|
|
|
if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
|
|
|
|
SourceLocation DeclEnd;
|
|
|
|
ParseStaticAssertDeclaration(DeclEnd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-03 19:06:10 +08:00
|
|
|
auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
|
|
|
|
Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
|
|
|
|
// Install the declarator into the interface decl.
|
2015-06-20 02:25:57 +08:00
|
|
|
FD.D.setObjCIvar(true);
|
2014-09-03 19:06:10 +08:00
|
|
|
Decl *Field = Actions.ActOnIvar(
|
|
|
|
getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
|
|
|
|
FD.BitfieldSize, visibility);
|
|
|
|
Actions.ActOnObjCContainerFinishDefinition();
|
|
|
|
if (Field)
|
|
|
|
AllIvarDecls.push_back(Field);
|
|
|
|
FD.complete(Field);
|
|
|
|
};
|
|
|
|
|
2008-04-10 14:46:29 +08:00
|
|
|
// Parse all the comma separated declarators.
|
2012-08-09 07:04:35 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2014-09-03 19:06:10 +08:00
|
|
|
ParseStructDeclaration(DS, ObjCIvarCallback);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2007-08-22 05:17:12 +08:00
|
|
|
}
|
|
|
|
}
|
2013-03-21 02:09:33 +08:00
|
|
|
HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
|
|
|
|
T, AllIvarDecls, false);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-21 05:31:48 +08:00
|
|
|
|
|
|
|
/// objc-protocol-declaration:
|
|
|
|
/// objc-protocol-definition
|
|
|
|
/// objc-protocol-forward-reference
|
|
|
|
///
|
|
|
|
/// objc-protocol-definition:
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-protocol-refs[opt]
|
|
|
|
/// objc-interface-decl-list
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@end
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-protocol-forward-reference:
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol identifier-list ';'
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
2012-06-11 14:19:40 +08:00
|
|
|
/// "\@protocol identifier ;" should be resolved as "\@protocol
|
2007-09-07 05:24:23 +08:00
|
|
|
/// identifier-list ;": objc-interface-decl-list may not start with a
|
2007-08-21 05:31:48 +08:00
|
|
|
/// semicolon in the first alternative if objc-protocol-refs are omitted.
|
2018-07-31 03:24:48 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
2012-01-02 05:23:57 +08:00
|
|
|
Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
|
|
|
|
ParsedAttributes &attrs) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
|
2007-08-23 06:17:26 +08:00
|
|
|
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
|
|
|
|
ConsumeToken(); // the "protocol" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-18 12:49:41 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-11-18 12:49:41 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_protocol);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return nullptr; // missing protocol name.
|
2007-08-23 06:17:26 +08:00
|
|
|
// Save the protocol name, then consume it.
|
|
|
|
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
|
2008-07-22 06:17:28 +08:00
|
|
|
IdentifierLocPair ProtoInfo(protocolName, nameLoc);
|
2018-07-13 05:09:05 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo, attrs);
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-12-08 17:58:43 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::comma)) { // list of forward declarations.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierLocPair, 8> ProtocolRefs;
|
2008-07-22 06:17:28 +08:00
|
|
|
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Parse the list of forward declarations.
|
|
|
|
while (1) {
|
|
|
|
ConsumeToken(); // the ','
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier()) {
|
2007-08-23 06:17:26 +08:00
|
|
|
SkipUntil(tok::semi);
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2008-07-22 06:17:28 +08:00
|
|
|
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken(); // the identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-08-23 06:17:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Consume the ';'.
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2018-07-13 05:09:05 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs);
|
2008-07-22 06:17:28 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Last, and definitely not least, parse a protocol declaration.
|
2009-09-30 03:41:44 +08:00
|
|
|
SourceLocation LAngleLoc, EndProtoLoc;
|
2008-07-22 06:17:28 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> ProtocolRefs;
|
|
|
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
2008-07-22 06:17:28 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
2015-04-20 04:15:55 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
|
2015-07-07 11:58:14 +08:00
|
|
|
LAngleLoc, EndProtoLoc,
|
|
|
|
/*consumeLastToken=*/true))
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *ProtoType = Actions.ActOnStartProtocolInterface(
|
|
|
|
AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
|
|
|
|
ProtocolLocs.data(), EndProtoLoc, attrs);
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2011-08-23 05:44:58 +08:00
|
|
|
ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
|
2012-01-02 05:23:57 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(ProtoType);
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-implementation:
|
|
|
|
/// objc-class-implementation-prologue
|
|
|
|
/// objc-category-implementation-prologue
|
|
|
|
///
|
|
|
|
/// objc-class-implementation-prologue:
|
|
|
|
/// @implementation identifier objc-superclass[opt]
|
|
|
|
/// objc-class-instance-variables[opt]
|
|
|
|
///
|
|
|
|
/// objc-category-implementation-prologue:
|
|
|
|
/// @implementation identifier ( identifier )
|
2012-02-08 00:50:53 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
2019-04-12 01:55:30 +08:00
|
|
|
Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
|
|
|
|
ParsedAttributes &Attrs) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
|
|
|
|
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
|
2011-12-06 17:25:23 +08:00
|
|
|
CheckNestedObjCContexts(AtLoc);
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken(); // the "implementation" identifier
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 00:26:39 +08:00
|
|
|
// Code completion after '@implementation'.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-11-19 00:26:39 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 08:15:10 +08:00
|
|
|
MaybeSkipAttributes(tok::objc_implementation);
|
2013-04-04 01:36:11 +08:00
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return nullptr; // missing class or category name.
|
2007-09-01 08:26:16 +08:00
|
|
|
// We have a class or category name - consume it.
|
2007-09-26 02:38:09 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-09-01 08:26:16 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
2014-05-21 14:02:52 +08:00
|
|
|
Decl *ObjCImpDecl = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
// Neither a type parameter list nor a list of protocol references is
|
|
|
|
// permitted here. Parse and diagnose them.
|
|
|
|
if (Tok.is(tok::less)) {
|
|
|
|
SourceLocation lAngleLoc, rAngleLoc;
|
|
|
|
SmallVector<IdentifierLocPair, 8> protocolIdents;
|
|
|
|
SourceLocation diagLoc = Tok.getLocation();
|
2015-11-03 09:19:56 +08:00
|
|
|
ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
|
|
|
|
if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,
|
|
|
|
protocolIdents, rAngleLoc)) {
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
Diag(diagLoc, diag::err_objc_parameterized_implementation)
|
|
|
|
<< SourceRange(diagLoc, PrevTokLocation);
|
|
|
|
} else if (lAngleLoc.isValid()) {
|
|
|
|
Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
|
|
|
|
<< FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// we have a category implementation.
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeParen();
|
2007-09-01 08:26:16 +08:00
|
|
|
SourceLocation categoryLoc, rparenLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *categoryId = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 03:08:43 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-11-19 03:08:43 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
|
|
|
} else {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected)
|
|
|
|
<< tok::identifier; // missing category name.
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren); // don't stop at ';'
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
2013-05-18 01:58:11 +08:00
|
|
|
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
|
|
|
|
Diag(Tok, diag::err_unexpected_protocol_qualifier);
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation protocolLAngleLoc, protocolRAngleLoc;
|
|
|
|
SmallVector<Decl *, 4> protocols;
|
|
|
|
SmallVector<SourceLocation, 4> protocolLocs;
|
2018-07-31 03:24:48 +08:00
|
|
|
(void)ParseObjCProtocolReferences(protocols, protocolLocs,
|
2015-07-07 11:58:14 +08:00
|
|
|
/*warnOnIncompleteProtocols=*/false,
|
|
|
|
/*ForObjCContainer=*/false,
|
|
|
|
protocolLAngleLoc, protocolRAngleLoc,
|
|
|
|
/*consumeLastToken=*/true);
|
2013-05-18 01:58:11 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
|
2019-04-12 01:55:30 +08:00
|
|
|
AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
} else {
|
|
|
|
// We have a class implementation
|
|
|
|
SourceLocation superClassLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *superClassId = nullptr;
|
2014-01-01 11:08:43 +08:00
|
|
|
if (TryConsumeToken(tok::colon)) {
|
2012-02-08 00:50:53 +08:00
|
|
|
// We have a super class
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return nullptr; // missing super class name.
|
2012-02-08 00:50:53 +08:00
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken(); // Consume super class name
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
ObjCImpDecl = Actions.ActOnStartClassImplementation(
|
2019-04-12 01:55:30 +08:00
|
|
|
AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
if (Tok.is(tok::l_brace)) // we have ivars
|
|
|
|
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
|
2013-04-25 07:23:47 +08:00
|
|
|
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
|
|
|
|
Diag(Tok, diag::err_unexpected_protocol_qualifier);
|
2015-07-07 11:58:14 +08:00
|
|
|
|
|
|
|
SourceLocation protocolLAngleLoc, protocolRAngleLoc;
|
|
|
|
SmallVector<Decl *, 4> protocols;
|
|
|
|
SmallVector<SourceLocation, 4> protocolLocs;
|
2018-07-31 03:24:48 +08:00
|
|
|
(void)ParseObjCProtocolReferences(protocols, protocolLocs,
|
2015-07-07 11:58:14 +08:00
|
|
|
/*warnOnIncompleteProtocols=*/false,
|
|
|
|
/*ForObjCContainer=*/false,
|
|
|
|
protocolLAngleLoc, protocolRAngleLoc,
|
|
|
|
/*consumeLastToken=*/true);
|
2013-04-25 07:23:47 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
assert(ObjCImpDecl);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
SmallVector<Decl *, 8> DeclsInGroup;
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
{
|
|
|
|
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
|
2013-11-23 12:06:09 +08:00
|
|
|
while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
|
2012-02-08 00:50:53 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2012-02-08 00:50:53 +08:00
|
|
|
if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
|
|
|
|
DeclGroupRef DG = DGP.get();
|
|
|
|
DeclsInGroup.append(DG.begin(), DG.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-24 05:11:20 +08:00
|
|
|
return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-10-30 05:38:07 +08:00
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
Parser::DeclGroupPtrTy
|
|
|
|
Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
|
|
|
|
"ParseObjCAtEndDeclaration(): Expected @end");
|
|
|
|
ConsumeToken(); // the "end" identifier
|
2012-02-08 00:50:53 +08:00
|
|
|
if (CurParsedObjCImpl)
|
|
|
|
CurParsedObjCImpl->finish(atEnd);
|
2011-09-01 06:24:06 +08:00
|
|
|
else
|
2010-01-07 09:20:12 +08:00
|
|
|
// missing @implementation
|
2011-12-06 17:25:23 +08:00
|
|
|
Diag(atEnd.getBegin(), diag::err_expected_objc_container);
|
2016-01-16 07:43:25 +08:00
|
|
|
return nullptr;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-09-05 03:26:51 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
|
|
|
|
if (!Finished) {
|
|
|
|
finish(P.Tok.getLocation());
|
2013-11-23 12:06:09 +08:00
|
|
|
if (P.isEofOrEom()) {
|
2012-02-08 00:50:53 +08:00
|
|
|
P.Diag(P.Tok, diag::err_objc_missing_end)
|
|
|
|
<< FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
|
2018-08-10 05:08:08 +08:00
|
|
|
P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)
|
2012-02-08 00:50:53 +08:00
|
|
|
<< Sema::OCK_Implementation;
|
|
|
|
}
|
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
P.CurParsedObjCImpl = nullptr;
|
2012-02-08 00:50:53 +08:00
|
|
|
assert(LateParsedObjCMethods.empty());
|
|
|
|
}
|
2011-12-06 17:25:23 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
|
|
|
|
assert(!Finished);
|
2017-07-03 18:12:24 +08:00
|
|
|
P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
|
2012-02-08 00:50:53 +08:00
|
|
|
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
2018-07-31 03:24:48 +08:00
|
|
|
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
2012-07-03 07:37:09 +08:00
|
|
|
true/*Methods*/);
|
2011-12-06 17:25:23 +08:00
|
|
|
|
2012-02-08 00:50:53 +08:00
|
|
|
P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
|
2009-11-17 02:57:01 +08:00
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
if (HasCFunction)
|
|
|
|
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
2018-07-31 03:24:48 +08:00
|
|
|
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
2012-07-03 07:37:09 +08:00
|
|
|
false/*c-functions*/);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Clear and free the cached objc methods.
|
2011-11-29 16:14:54 +08:00
|
|
|
for (LateParsedObjCMethodContainer::iterator
|
|
|
|
I = LateParsedObjCMethods.begin(),
|
|
|
|
E = LateParsedObjCMethods.end(); I != E; ++I)
|
|
|
|
delete *I;
|
|
|
|
LateParsedObjCMethods.clear();
|
2012-02-08 00:50:53 +08:00
|
|
|
|
|
|
|
Finished = true;
|
2011-11-29 16:14:54 +08:00
|
|
|
}
|
|
|
|
|
2007-09-05 03:26:51 +08:00
|
|
|
/// compatibility-alias-decl:
|
|
|
|
/// @compatibility_alias alias-name class-name ';'
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
|
2007-09-05 03:26:51 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
|
|
|
|
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
|
|
|
|
ConsumeToken(); // consume compatibility_alias
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *classId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation classLoc = ConsumeToken(); // consume class-name;
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
|
2012-08-09 07:32:13 +08:00
|
|
|
return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
|
|
|
|
classId, classLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
/// property-synthesis:
|
|
|
|
/// @synthesize property-ivar-list ';'
|
|
|
|
///
|
|
|
|
/// property-ivar-list:
|
|
|
|
/// property-ivar
|
|
|
|
/// property-ivar-list ',' property-ivar
|
|
|
|
///
|
|
|
|
/// property-ivar:
|
|
|
|
/// identifier
|
|
|
|
/// identifier '=' identifier
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
|
2013-04-29 23:35:35 +08:00
|
|
|
"ParseObjCPropertySynthesize(): Expected '@synthesize'");
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeToken(); // consume synthesize
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-19 03:45:45 +08:00
|
|
|
while (true) {
|
2009-11-19 06:32:06 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 06:32:06 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-11-19 03:45:45 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_synthesized_property_name);
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 03:45:45 +08:00
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
|
|
|
|
IdentifierInfo *propertyIvar = nullptr;
|
2008-04-18 08:19:30 +08:00
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
2010-11-17 09:03:52 +08:00
|
|
|
SourceLocation propertyIvarLoc;
|
2014-01-01 11:08:43 +08:00
|
|
|
if (TryConsumeToken(tok::equal)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// property '=' ivar-name
|
2009-11-19 06:32:06 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 06:32:06 +08:00
|
|
|
}
|
2017-04-11 23:01:53 +08:00
|
|
|
|
|
|
|
if (expectIdentifier())
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
2008-04-18 08:19:30 +08:00
|
|
|
propertyIvar = Tok.getIdentifierInfo();
|
2010-11-17 09:03:52 +08:00
|
|
|
propertyIvarLoc = ConsumeToken(); // consume ivar-name
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2016-01-29 02:49:28 +08:00
|
|
|
Actions.ActOnPropertyImplDecl(
|
|
|
|
getCurScope(), atLoc, propertyLoc, true,
|
|
|
|
propertyId, propertyIvar, propertyIvarLoc,
|
|
|
|
ObjCPropertyQueryKind::OBJC_PR_query_unknown);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// property-dynamic:
|
|
|
|
/// @dynamic property-list
|
|
|
|
///
|
|
|
|
/// property-list:
|
|
|
|
/// identifier
|
|
|
|
/// property-list ',' identifier
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
|
2007-09-01 08:26:16 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
|
|
|
|
"ParseObjCPropertyDynamic(): Expected '@dynamic'");
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeToken(); // consume dynamic
|
2016-01-30 03:05:57 +08:00
|
|
|
|
|
|
|
bool isClassProperty = false;
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
ConsumeParen();
|
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
|
|
|
|
if (!II) {
|
|
|
|
Diag(Tok, diag::err_objc_expected_property_attr) << II;
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
} else {
|
|
|
|
SourceLocation AttrName = ConsumeToken(); // consume attribute name
|
|
|
|
if (II->isStr("class")) {
|
|
|
|
isClassProperty = true;
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
} else
|
|
|
|
ConsumeParen();
|
|
|
|
} else {
|
|
|
|
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-19 06:56:13 +08:00
|
|
|
while (true) {
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-08-22 23:54:49 +08:00
|
|
|
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 06:56:13 +08:00
|
|
|
}
|
2017-04-11 23:01:53 +08:00
|
|
|
|
|
|
|
if (expectIdentifier()) {
|
2009-11-19 06:56:13 +08:00
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-11-19 06:56:13 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-04-22 05:05:54 +08:00
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
2016-01-29 02:49:28 +08:00
|
|
|
Actions.ActOnPropertyImplDecl(
|
|
|
|
getCurScope(), atLoc, propertyLoc, false,
|
|
|
|
propertyId, nullptr, SourceLocation(),
|
2016-01-30 03:05:57 +08:00
|
|
|
isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
|
2016-01-29 02:49:28 +08:00
|
|
|
ObjCPropertyQueryKind::OBJC_PR_query_unknown);
|
2008-04-22 05:05:54 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
/// objc-throw-statement:
|
|
|
|
/// throw expression[opt];
|
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
|
|
|
|
ExprResult Res;
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume throw
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2007-11-07 10:00:49 +08:00
|
|
|
Res = ParseExpression();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2007-09-20 03:14:32 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
}
|
2010-04-21 05:21:51 +08:00
|
|
|
// consume ';'
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
|
2008-01-30 02:21:32 +08:00
|
|
|
/// objc-synchronized-statement:
|
2008-01-31 01:38:29 +08:00
|
|
|
/// @synchronized '(' expression ')' compound-statement
|
2008-01-30 02:21:32 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
|
2008-01-30 03:14:59 +08:00
|
|
|
ConsumeToken(); // consume synchronized
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// The operand is surrounded with parentheses.
|
2008-01-30 03:14:59 +08:00
|
|
|
ConsumeParen(); // '('
|
2011-07-28 05:50:02 +08:00
|
|
|
ExprResult operand(ParseExpression());
|
|
|
|
|
|
|
|
if (Tok.is(tok::r_paren)) {
|
|
|
|
ConsumeParen(); // ')'
|
|
|
|
} else {
|
|
|
|
if (!operand.isInvalid())
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// Skip forward until we see a left brace, but don't consume it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// Require a compound statement.
|
2008-01-31 01:38:29 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2011-07-28 05:50:02 +08:00
|
|
|
if (!operand.isInvalid())
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-31 01:38:29 +08:00
|
|
|
}
|
2008-06-05 04:36:13 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
// Check the @synchronized operand now.
|
|
|
|
if (!operand.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
|
2011-07-28 05:50:02 +08:00
|
|
|
|
|
|
|
// Parse the compound statement within a new scope.
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
|
2011-07-28 05:50:02 +08:00
|
|
|
StmtResult body(ParseCompoundStatementBody());
|
|
|
|
bodyScope.Exit();
|
|
|
|
|
|
|
|
// If there was a semantic or parse error earlier with the
|
|
|
|
// operand, fail now.
|
|
|
|
if (operand.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (body.isInvalid())
|
|
|
|
body = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
|
2008-01-30 02:21:32 +08:00
|
|
|
}
|
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
/// objc-try-catch-statement:
|
|
|
|
/// @try compound-statement objc-catch-list[opt]
|
|
|
|
/// @try compound-statement objc-catch-list[opt] @finally compound-statement
|
|
|
|
///
|
|
|
|
/// objc-catch-list:
|
|
|
|
/// @catch ( parameter-declaration ) compound-statement
|
|
|
|
/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
|
|
|
|
/// catch-parameter-declaration:
|
|
|
|
/// parameter-declaration
|
|
|
|
/// '...' [OBJC2]
|
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
2007-09-20 03:14:32 +08:00
|
|
|
bool catch_or_finally_seen = false;
|
2008-12-12 04:12:42 +08:00
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume try
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2012-08-24 06:51:59 +08:00
|
|
|
StmtVector CatchStmts;
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FinallyStmt;
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult TryBody(ParseCompoundStatementBody());
|
2008-12-10 14:34:36 +08:00
|
|
|
TryScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (TryBody.isInvalid())
|
2007-11-02 23:39:31 +08:00
|
|
|
TryBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-11-26 06:21:31 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
2008-03-10 14:06:04 +08:00
|
|
|
// At this point, we need to lookahead to determine if this @ is the start
|
|
|
|
// of an @catch or @finally. We don't want to consume the @ token if this
|
|
|
|
// is an @try or @encode or something else.
|
|
|
|
Token AfterAt = GetLookAheadToken(1);
|
|
|
|
if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
|
|
|
|
!AfterAt.isObjCAtKeyword(tok::objc_finally))
|
|
|
|
break;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-02 08:18:53 +08:00
|
|
|
SourceLocation AtCatchFinallyLoc = ConsumeToken();
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_catch)) {
|
2014-05-21 14:02:52 +08:00
|
|
|
Decl *FirstPart = nullptr;
|
2007-11-02 07:59:59 +08:00
|
|
|
ConsumeToken(); // consume catch
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeParen();
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope CatchScope(this, Scope::DeclScope |
|
|
|
|
Scope::CompoundStmtScope |
|
|
|
|
Scope::AtCatchScope);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::ellipsis)) {
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2018-04-26 08:42:40 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator ParmDecl(DS, DeclaratorContext::ObjCCatchContext);
|
2009-03-04 03:52:17 +08:00
|
|
|
ParseDeclarator(ParmDecl);
|
|
|
|
|
2010-04-24 07:01:43 +08:00
|
|
|
// Inform the actions module about the declarator, so it
|
2009-03-04 03:52:17 +08:00
|
|
|
// gets added to the current scope.
|
2010-07-03 01:43:08 +08:00
|
|
|
FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
|
2008-02-06 05:27:35 +08:00
|
|
|
} else
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume '...'
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-08 06:56:58 +08:00
|
|
|
SourceLocation RParenLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-08 06:56:58 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
RParenLoc = ConsumeParen();
|
|
|
|
else // Skip over garbage, until we get to ')'. Eat the ')'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2009-04-08 06:56:58 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult CatchBody(true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
CatchBody = ParseCompoundStatementBody();
|
|
|
|
else
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2008-12-09 21:15:23 +08:00
|
|
|
if (CatchBody.isInvalid())
|
2007-11-02 07:59:59 +08:00
|
|
|
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
RParenLoc,
|
|
|
|
FirstPart,
|
2014-05-29 18:55:11 +08:00
|
|
|
CatchBody.get());
|
2010-04-24 06:50:49 +08:00
|
|
|
if (!Catch.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
CatchStmts.push_back(Catch.get());
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-02-06 05:27:35 +08:00
|
|
|
} else {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
|
|
|
|
<< "@catch clause";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
catch_or_finally_seen = true;
|
2008-03-10 14:06:04 +08:00
|
|
|
} else {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
|
2008-02-06 05:27:35 +08:00
|
|
|
ConsumeToken(); // consume finally
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope FinallyScope(this,
|
|
|
|
Scope::DeclScope | Scope::CompoundStmtScope);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
Reapply "[Parse] Use CapturedStmt for @finally on MSVC"
This reapplies r334224 and adds explicit triples to some tests to fix
them on Windows (where otherwise they would have run with the default
windows-msvc triple, which I'm changing the behavior for).
Original commit message:
The body of a `@finally` needs to be executed on both exceptional and
non-exceptional paths. On landingpad platforms, this is straightforward:
the `@finally` body is emitted as a normal (non-exceptional) cleanup,
and then a catch-all is emitted which branches to that cleanup (the
cleanup has code to conditionally re-throw based on a flag which is set
by the catch-all).
Unfortunately, we can't use the same approach for MSVC exceptions, where
the catch-all will be emitted as a catchpad. We can't just branch to the
cleanup from within the catchpad, since we can only exit it via a
catchret, at which point the exception is destroyed and we can't
rethrow. We could potentially emit the finally body inside the catchpad
and have the normal cleanup path somehow branch into it, but that would
require some new IR construct that could branch into a catchpad.
Instead, after discussing it with Reid Kleckner, we decided that
frontend outlining was the best approach, similar to how SEH `__finally`
works today. We decided to use CapturedStmt (which was also suggested by
Reid) rather than CaptureFinder (which is what `__finally` uses) since
the latter doesn't handle a lot of cases we care about, e.g. self
accesses, property accesses, block captures, etc. Extending
CaptureFinder to handle those additional cases proved unwieldy, whereas
CapturedStmt already took care of all of those. In theory `__finally`
could also be moved over to CapturedStmt, which would remove some
existing limitations (e.g. the inability to capture this), although
CaptureFinder would still be needed for SEH filters.
The one case supported by `@finally` but not CapturedStmt (or
CaptureFinder for that matter) is arbitrary control flow out of the
`@finally`, e.g. having a return statement inside a `@finally`. We can
add that support as a follow-up, but in practice we've found it to be
used very rarely anyway.
Differential Revision: https://reviews.llvm.org/D47564
llvm-svn: 334251
2018-06-08 08:30:00 +08:00
|
|
|
bool ShouldCapture =
|
|
|
|
getTargetInfo().getTriple().isWindowsMSVCEnvironment();
|
|
|
|
if (ShouldCapture)
|
|
|
|
Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),
|
|
|
|
CR_ObjCAtFinally, 1);
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FinallyBody(true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
FinallyBody = ParseCompoundStatementBody();
|
|
|
|
else
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
Reapply "[Parse] Use CapturedStmt for @finally on MSVC"
This reapplies r334224 and adds explicit triples to some tests to fix
them on Windows (where otherwise they would have run with the default
windows-msvc triple, which I'm changing the behavior for).
Original commit message:
The body of a `@finally` needs to be executed on both exceptional and
non-exceptional paths. On landingpad platforms, this is straightforward:
the `@finally` body is emitted as a normal (non-exceptional) cleanup,
and then a catch-all is emitted which branches to that cleanup (the
cleanup has code to conditionally re-throw based on a flag which is set
by the catch-all).
Unfortunately, we can't use the same approach for MSVC exceptions, where
the catch-all will be emitted as a catchpad. We can't just branch to the
cleanup from within the catchpad, since we can only exit it via a
catchret, at which point the exception is destroyed and we can't
rethrow. We could potentially emit the finally body inside the catchpad
and have the normal cleanup path somehow branch into it, but that would
require some new IR construct that could branch into a catchpad.
Instead, after discussing it with Reid Kleckner, we decided that
frontend outlining was the best approach, similar to how SEH `__finally`
works today. We decided to use CapturedStmt (which was also suggested by
Reid) rather than CaptureFinder (which is what `__finally` uses) since
the latter doesn't handle a lot of cases we care about, e.g. self
accesses, property accesses, block captures, etc. Extending
CaptureFinder to handle those additional cases proved unwieldy, whereas
CapturedStmt already took care of all of those. In theory `__finally`
could also be moved over to CapturedStmt, which would remove some
existing limitations (e.g. the inability to capture this), although
CaptureFinder would still be needed for SEH filters.
The one case supported by `@finally` but not CapturedStmt (or
CaptureFinder for that matter) is arbitrary control flow out of the
`@finally`, e.g. having a return statement inside a `@finally`. We can
add that support as a follow-up, but in practice we've found it to be
used very rarely anyway.
Differential Revision: https://reviews.llvm.org/D47564
llvm-svn: 334251
2018-06-08 08:30:00 +08:00
|
|
|
|
|
|
|
if (FinallyBody.isInvalid()) {
|
2007-11-02 08:18:53 +08:00
|
|
|
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
|
Reapply "[Parse] Use CapturedStmt for @finally on MSVC"
This reapplies r334224 and adds explicit triples to some tests to fix
them on Windows (where otherwise they would have run with the default
windows-msvc triple, which I'm changing the behavior for).
Original commit message:
The body of a `@finally` needs to be executed on both exceptional and
non-exceptional paths. On landingpad platforms, this is straightforward:
the `@finally` body is emitted as a normal (non-exceptional) cleanup,
and then a catch-all is emitted which branches to that cleanup (the
cleanup has code to conditionally re-throw based on a flag which is set
by the catch-all).
Unfortunately, we can't use the same approach for MSVC exceptions, where
the catch-all will be emitted as a catchpad. We can't just branch to the
cleanup from within the catchpad, since we can only exit it via a
catchret, at which point the exception is destroyed and we can't
rethrow. We could potentially emit the finally body inside the catchpad
and have the normal cleanup path somehow branch into it, but that would
require some new IR construct that could branch into a catchpad.
Instead, after discussing it with Reid Kleckner, we decided that
frontend outlining was the best approach, similar to how SEH `__finally`
works today. We decided to use CapturedStmt (which was also suggested by
Reid) rather than CaptureFinder (which is what `__finally` uses) since
the latter doesn't handle a lot of cases we care about, e.g. self
accesses, property accesses, block captures, etc. Extending
CaptureFinder to handle those additional cases proved unwieldy, whereas
CapturedStmt already took care of all of those. In theory `__finally`
could also be moved over to CapturedStmt, which would remove some
existing limitations (e.g. the inability to capture this), although
CaptureFinder would still be needed for SEH filters.
The one case supported by `@finally` but not CapturedStmt (or
CaptureFinder for that matter) is arbitrary control flow out of the
`@finally`, e.g. having a return statement inside a `@finally`. We can
add that support as a follow-up, but in practice we've found it to be
used very rarely anyway.
Differential Revision: https://reviews.llvm.org/D47564
llvm-svn: 334251
2018-06-08 08:30:00 +08:00
|
|
|
if (ShouldCapture)
|
|
|
|
Actions.ActOnCapturedRegionError();
|
|
|
|
} else if (ShouldCapture) {
|
|
|
|
FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());
|
|
|
|
}
|
|
|
|
|
2008-12-09 21:15:23 +08:00
|
|
|
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
FinallyBody.get());
|
2007-09-20 03:14:32 +08:00
|
|
|
catch_or_finally_seen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
if (!catch_or_finally_seen) {
|
2007-09-20 03:14:32 +08:00
|
|
|
Diag(atLoc, diag::err_missing_catch_finally);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
|
2012-08-24 05:35:17 +08:00
|
|
|
CatchStmts,
|
2014-05-29 18:55:11 +08:00
|
|
|
FinallyStmt.get());
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
/// objc-autoreleasepool-statement:
|
|
|
|
/// @autoreleasepool compound-statement
|
|
|
|
///
|
|
|
|
StmtResult
|
|
|
|
Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
|
|
|
|
ConsumeToken(); // consume autoreleasepool
|
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2011-06-16 07:02:42 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
// Enter a scope to hold everything within the compound stmt. Compound
|
|
|
|
// statements can always hold declarations.
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
|
|
|
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
|
|
|
|
|
|
|
|
BodyScope.Exit();
|
|
|
|
if (AutoreleasePoolBody.isInvalid())
|
|
|
|
AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2018-07-31 03:24:48 +08:00
|
|
|
return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
AutoreleasePoolBody.get());
|
2011-06-16 07:02:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
|
2012-07-03 07:37:09 +08:00
|
|
|
/// for later parsing.
|
|
|
|
void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
|
2016-06-17 05:40:06 +08:00
|
|
|
if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
|
|
|
|
trySkippingFunctionBody()) {
|
|
|
|
Actions.ActOnSkippedFunctionBody(MDecl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
LexedMethod* LM = new LexedMethod(this, MDecl);
|
|
|
|
CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
|
|
|
|
CachedTokens &Toks = LM->Toks;
|
2012-08-11 05:15:06 +08:00
|
|
|
// Begin by storing the '{' or 'try' or ':' token.
|
2012-07-03 07:37:09 +08:00
|
|
|
Toks.push_back(Tok);
|
2012-08-11 02:10:56 +08:00
|
|
|
if (Tok.is(tok::kw_try)) {
|
|
|
|
ConsumeToken();
|
2012-08-11 04:34:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
Toks.push_back(Tok);
|
|
|
|
ConsumeToken();
|
|
|
|
while (Tok.isNot(tok::l_brace)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
|
|
|
}
|
2012-08-11 05:15:06 +08:00
|
|
|
Toks.push_back(Tok); // also store '{'
|
|
|
|
}
|
|
|
|
else if (Tok.is(tok::colon)) {
|
|
|
|
ConsumeToken();
|
2015-08-21 11:04:33 +08:00
|
|
|
// FIXME: This is wrong, due to C++11 braced initialization.
|
2012-08-11 05:15:06 +08:00
|
|
|
while (Tok.isNot(tok::l_brace)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
2012-08-11 02:10:56 +08:00
|
|
|
Toks.push_back(Tok); // also store '{'
|
|
|
|
}
|
2012-07-03 07:37:09 +08:00
|
|
|
ConsumeBrace();
|
|
|
|
// Consume everything up to (and including) the matching right brace.
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
2012-08-11 02:10:56 +08:00
|
|
|
while (Tok.is(tok::kw_catch)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
2012-07-03 07:37:09 +08:00
|
|
|
}
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
|
2007-09-01 08:26:16 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseObjCMethodDefinition() {
|
2011-08-22 23:54:49 +08:00
|
|
|
Decl *MDecl = ParseObjCMethodPrototype();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2018-03-23 08:07:18 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),
|
2010-08-27 07:41:50 +08:00
|
|
|
"parsing Objective-C method");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
// parse optional ';'
|
2009-10-21 00:39:13 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2012-02-08 00:50:53 +08:00
|
|
|
if (CurParsedObjCImpl) {
|
2009-11-11 06:55:49 +08:00
|
|
|
Diag(Tok, diag::warn_semicolon_before_method_body)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
2009-11-11 06:55:49 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken();
|
2009-10-21 00:39:13 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// We should have an opening brace now.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-03-01 05:48:07 +08:00
|
|
|
Diag(Tok, diag::err_expected_method_body);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// If we didn't find the '{', bail out.
|
|
|
|
if (Tok.isNot(tok::l_brace))
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2012-02-08 00:50:53 +08:00
|
|
|
|
|
|
|
if (!MDecl) {
|
|
|
|
ConsumeBrace();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2012-02-08 00:50:53 +08:00
|
|
|
}
|
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
// Allow the rest of sema to find private method decl implementations.
|
2012-02-08 00:50:53 +08:00
|
|
|
Actions.AddAnyMethodToGlobalPool(MDecl);
|
2018-07-31 03:24:48 +08:00
|
|
|
assert (CurParsedObjCImpl
|
2012-08-10 01:15:00 +08:00
|
|
|
&& "ParseObjCMethodDefinition - Method out of @implementation");
|
|
|
|
// Consume the tokens and store them for later parsing.
|
|
|
|
StashAwayMethodOrFunctionBodyTokens(MDecl);
|
2007-11-14 07:01:27 +08:00
|
|
|
return MDecl;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
|
|
|
|
ParsedStmtContext StmtCtx) {
|
2009-12-07 17:51:25 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtStatement(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2009-12-07 17:51:25 +08:00
|
|
|
return StmtError();
|
2009-12-08 00:33:19 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-12-08 00:33:19 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_try))
|
2008-03-10 14:06:04 +08:00
|
|
|
return ParseObjCTryStmt(AtLoc);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-12-08 00:33:19 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_throw))
|
2008-02-06 05:27:35 +08:00
|
|
|
return ParseObjCThrowStmt(AtLoc);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-12-08 00:33:19 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_synchronized))
|
2008-02-06 05:27:35 +08:00
|
|
|
return ParseObjCSynchronizedStmt(AtLoc);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
|
|
|
|
return ParseObjCAutoreleasePoolStmt(AtLoc);
|
2014-12-10 07:47:56 +08:00
|
|
|
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_import) &&
|
|
|
|
getLangOpts().DebuggerSupport) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return Actions.ActOnNullStmt(Tok.getLocation());
|
|
|
|
}
|
|
|
|
|
2016-12-01 20:14:38 +08:00
|
|
|
ExprStatementTokLoc = AtLoc;
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-02-06 05:27:35 +08:00
|
|
|
// If the expression is invalid, skip ahead to the next semicolon. Not
|
|
|
|
// doing this opens us up to the possibility of infinite loops if
|
|
|
|
// ParseExpression does not consume any tokens.
|
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-02-06 05:27:35 +08:00
|
|
|
// Otherwise, eat the semicolon.
|
2010-09-07 23:23:11 +08:00
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
|
2019-02-15 08:27:53 +08:00
|
|
|
return handleExprStmt(Res, StmtCtx);
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
2007-08-22 01:43:55 +08:00
|
|
|
switch (Tok.getKind()) {
|
2009-12-07 17:51:25 +08:00
|
|
|
case tok::code_completion:
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCAtExpression(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2009-12-07 17:51:25 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::minus:
|
|
|
|
case tok::plus: {
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
SourceLocation OpLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (!Tok.is(tok::numeric_constant)) {
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *Symbol = nullptr;
|
2012-03-07 04:05:56 +08:00
|
|
|
switch (Kind) {
|
|
|
|
case tok::minus: Symbol = "-"; break;
|
|
|
|
case tok::plus: Symbol = "+"; break;
|
|
|
|
default: llvm_unreachable("missing unary operator case");
|
|
|
|
}
|
|
|
|
Diag(Tok, diag::err_nsnumber_nonliteral_unary)
|
|
|
|
<< Symbol;
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2012-03-07 04:05:56 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
|
2012-03-07 04:05:56 +08:00
|
|
|
if (Lit.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
return ParsePostfixExpressionSuffix(
|
2014-05-29 18:55:11 +08:00
|
|
|
Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
case tok::string_literal: // primary-expression: string-literal
|
|
|
|
case tok::wide_string_literal:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
case tok::char_constant:
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::numeric_constant:
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
|
|
|
|
|
|
|
|
case tok::kw_true: // Objective-C++, etc.
|
|
|
|
case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
|
|
|
|
case tok::kw_false: // Objective-C++, etc.
|
|
|
|
case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::l_square:
|
|
|
|
// Objective-C array literal
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::l_brace:
|
|
|
|
// Objective-C dictionary literal
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
case tok::l_paren:
|
|
|
|
// Objective-C boxed expression
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
default:
|
2014-05-21 14:02:52 +08:00
|
|
|
if (Tok.getIdentifierInfo() == nullptr)
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
|
|
|
|
case tok::objc_encode:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_protocol:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_selector:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
|
2016-07-16 08:35:23 +08:00
|
|
|
case tok::objc_available:
|
|
|
|
return ParseAvailabilityCheckExpr(AtLoc);
|
2012-07-10 04:00:35 +08:00
|
|
|
default: {
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *str = nullptr;
|
2016-12-01 20:14:38 +08:00
|
|
|
// Only provide the @try/@finally/@autoreleasepool fixit when we're sure
|
|
|
|
// that this is a proper statement where such directives could actually
|
|
|
|
// occur.
|
|
|
|
if (GetLookAheadToken(1).is(tok::l_brace) &&
|
|
|
|
ExprStatementTokLoc == AtLoc) {
|
2012-07-10 04:00:35 +08:00
|
|
|
char ch = Tok.getIdentifierInfo()->getNameStart()[0];
|
2018-07-31 03:24:48 +08:00
|
|
|
str =
|
|
|
|
ch == 't' ? "try"
|
|
|
|
: (ch == 'f' ? "finally"
|
2014-05-21 14:02:52 +08:00
|
|
|
: (ch == 'a' ? "autoreleasepool" : nullptr));
|
2012-07-10 04:00:35 +08:00
|
|
|
}
|
|
|
|
if (str) {
|
|
|
|
SourceLocation kwLoc = Tok.getLocation();
|
2018-07-31 03:24:48 +08:00
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
|
2012-07-10 04:00:35 +08:00
|
|
|
FixItHint::CreateReplacement(kwLoc, str));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
|
|
|
}
|
2008-08-05 14:19:09 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse the receiver of an Objective-C++ message send.
|
2010-04-22 06:36:40 +08:00
|
|
|
///
|
|
|
|
/// This routine parses the receiver of a message send in
|
|
|
|
/// Objective-C++ either as a type or as an expression. Note that this
|
|
|
|
/// routine must not be called to parse a send to 'super', since it
|
|
|
|
/// has no way to return such a result.
|
2018-07-31 03:24:48 +08:00
|
|
|
///
|
2010-04-22 06:36:40 +08:00
|
|
|
/// \param IsExpr Whether the receiver was parsed as an expression.
|
|
|
|
///
|
|
|
|
/// \param TypeOrExpr If the receiver was parsed as an expression (\c
|
|
|
|
/// IsExpr is true), the parsed expression. If the receiver was parsed
|
|
|
|
/// as a type (\c IsExpr is false), the parsed type.
|
|
|
|
///
|
|
|
|
/// \returns True if an error occurred during parsing or semantic
|
|
|
|
/// analysis, in which case the arguments do not have valid
|
|
|
|
/// values. Otherwise, returns false for a successful parse.
|
|
|
|
///
|
|
|
|
/// objc-receiver: [C++]
|
|
|
|
/// 'super' [not parsed here]
|
|
|
|
/// expression
|
|
|
|
/// simple-type-specifier
|
|
|
|
/// typename-specifier
|
|
|
|
bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
|
|
|
|
tok::annot_cxxscope))
|
2010-04-22 06:36:40 +08:00
|
|
|
TryAnnotateTypeOrScopeToken();
|
|
|
|
|
2012-06-16 07:45:51 +08:00
|
|
|
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
|
2010-04-22 06:36:40 +08:00
|
|
|
// objc-receiver:
|
|
|
|
// expression
|
2014-11-21 06:06:40 +08:00
|
|
|
// Make sure any typos in the receiver are corrected or diagnosed, so that
|
|
|
|
// proper recovery can happen. FIXME: Perhaps filter the corrected expr to
|
|
|
|
// only the things that are valid ObjC receivers?
|
|
|
|
ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Receiver.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = true;
|
2014-05-29 18:55:11 +08:00
|
|
|
TypeOrExpr = Receiver.get();
|
2010-04-22 06:36:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// objc-receiver:
|
|
|
|
// typename-specifier
|
|
|
|
// simple-type-specifier
|
|
|
|
// expression (that starts with one of the above)
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2010-04-22 06:36:40 +08:00
|
|
|
ParseCXXSimpleTypeSpecifier(DS);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
// If we see an opening parentheses at this point, we are
|
|
|
|
// actually parsing an expression that starts with a
|
|
|
|
// function-style cast, e.g.,
|
|
|
|
//
|
|
|
|
// postfix-expression:
|
|
|
|
// simple-type-specifier ( expression-list [opt] )
|
|
|
|
// typename-specifier ( expression-list [opt] )
|
|
|
|
//
|
|
|
|
// Parse the remainder of this case, then the (optional)
|
|
|
|
// postfix-expression suffix, followed by the (optional)
|
|
|
|
// right-hand side of the binary expression. We have an
|
|
|
|
// instance method.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (!Receiver.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
Receiver = ParsePostfixExpressionSuffix(Receiver.get());
|
2010-04-22 06:36:40 +08:00
|
|
|
if (!Receiver.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Receiver.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = true;
|
2014-05-29 18:55:11 +08:00
|
|
|
TypeOrExpr = Receiver.get();
|
2010-04-22 06:36:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-04-22 06:36:40 +08:00
|
|
|
// We have a class message. Turn the simple-type-specifier or
|
|
|
|
// typename-specifier we parsed into a type and parse the
|
|
|
|
// remainder of the class message.
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
|
2010-07-03 01:43:08 +08:00
|
|
|
TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
2010-04-22 06:36:40 +08:00
|
|
|
if (Type.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
IsExpr = false;
|
2010-08-24 13:47:05 +08:00
|
|
|
TypeOrExpr = Type.get().getAsOpaquePtr();
|
2010-04-22 06:36:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether the parser is currently referring to a an
|
2010-05-31 22:40:22 +08:00
|
|
|
/// Objective-C message send, using a simplified heuristic to avoid overhead.
|
|
|
|
///
|
|
|
|
/// This routine will only return true for a subset of valid message-send
|
|
|
|
/// expressions.
|
|
|
|
bool Parser::isSimpleObjCMessageExpression() {
|
2018-10-31 04:31:30 +08:00
|
|
|
assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&
|
2010-05-31 22:40:22 +08:00
|
|
|
"Incorrect start for isSimpleObjCMessageExpression");
|
|
|
|
return GetLookAheadToken(1).is(tok::identifier) &&
|
|
|
|
GetLookAheadToken(2).is(tok::identifier);
|
|
|
|
}
|
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
|
2018-10-31 04:31:30 +08:00
|
|
|
if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||
|
2010-09-16 09:51:54 +08:00
|
|
|
InMessageExpression)
|
|
|
|
return false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
ParsedType Type;
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
if (Tok.is(tok::annot_typename))
|
2010-09-16 09:51:54 +08:00
|
|
|
Type = getTypeAnnotation(Tok);
|
|
|
|
else if (Tok.is(tok::identifier))
|
2018-07-31 03:24:48 +08:00
|
|
|
Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
|
2010-09-16 09:51:54 +08:00
|
|
|
getCurScope());
|
|
|
|
else
|
|
|
|
return false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
|
|
|
|
const Token &AfterNext = GetLookAheadToken(2);
|
2015-06-18 18:59:26 +08:00
|
|
|
if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
|
2010-09-16 09:51:54 +08:00
|
|
|
if (Tok.is(tok::identifier))
|
|
|
|
TryAnnotateTypeOrScopeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
return Tok.is(tok::annot_typename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-message-expr:
|
2007-09-06 03:52:07 +08:00
|
|
|
/// '[' objc-receiver objc-message-args ']'
|
|
|
|
///
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// objc-receiver: [C]
|
2010-04-11 16:28:14 +08:00
|
|
|
/// 'super'
|
2007-09-06 03:52:07 +08:00
|
|
|
/// expression
|
|
|
|
/// class-name
|
|
|
|
/// type-name
|
2010-04-22 06:36:40 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCMessageExpression() {
|
2008-01-26 02:59:06 +08:00
|
|
|
assert(Tok.is(tok::l_square) && "'[' expected");
|
|
|
|
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
|
|
|
|
|
2010-05-28 07:06:34 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-05-28 07:06:34 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2010-04-22 06:36:40 +08:00
|
|
|
// We completely separate the C and C++ cases because C++ requires
|
2018-07-31 03:24:48 +08:00
|
|
|
// more complicated (read: slower) parsing.
|
|
|
|
|
|
|
|
// Handle send to super.
|
2010-04-22 06:36:40 +08:00
|
|
|
// FIXME: This doesn't benefit from the same typo-correction we
|
|
|
|
// get in Objective-C.
|
|
|
|
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
|
2010-07-03 01:43:08 +08:00
|
|
|
NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
|
2016-01-16 07:43:34 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
|
|
|
|
nullptr);
|
2010-04-22 06:36:40 +08:00
|
|
|
|
|
|
|
// Parse the receiver, which is either a type or an expression.
|
|
|
|
bool IsExpr;
|
2014-05-21 14:02:52 +08:00
|
|
|
void *TypeOrExpr = nullptr;
|
2010-04-22 06:36:40 +08:00
|
|
|
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2010-04-22 06:36:40 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsExpr)
|
2016-01-16 07:43:34 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
|
|
|
|
static_cast<Expr *>(TypeOrExpr));
|
2010-04-22 06:36:40 +08:00
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType::getFromOpaquePtr(TypeOrExpr),
|
2014-05-21 14:02:52 +08:00
|
|
|
nullptr);
|
2010-06-01 02:18:22 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-06-01 02:18:22 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2010-04-14 10:22:16 +08:00
|
|
|
IdentifierInfo *Name = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation NameLoc = Tok.getLocation();
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReceiverType;
|
2010-07-03 01:43:08 +08:00
|
|
|
switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
|
2010-04-14 10:22:16 +08:00
|
|
|
Name == Ident_super,
|
2010-04-22 04:38:13 +08:00
|
|
|
NextToken().is(tok::period),
|
|
|
|
ReceiverType)) {
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCSuperMessage:
|
2016-01-16 07:43:34 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
|
|
|
|
nullptr);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCClassMessage:
|
2010-04-22 04:38:13 +08:00
|
|
|
if (!ReceiverType) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2010-04-22 04:38:13 +08:00
|
|
|
ConsumeToken(); // the type name
|
|
|
|
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
// Parse type arguments and protocol qualifiers.
|
|
|
|
if (Tok.is(tok::less)) {
|
2015-07-07 11:58:14 +08:00
|
|
|
SourceLocation NewEndLoc;
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
TypeResult NewReceiverType
|
2015-07-07 11:58:14 +08:00
|
|
|
= parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
|
|
|
|
/*consumeLastToken=*/true,
|
|
|
|
NewEndLoc);
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
if (!NewReceiverType.isUsable()) {
|
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
ReceiverType = NewReceiverType.get();
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
2014-05-21 14:02:52 +08:00
|
|
|
ReceiverType, nullptr);
|
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
case Sema::ObjCInstanceMessage:
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
// Fall through to parse an expression.
|
2010-04-14 10:22:16 +08:00
|
|
|
break;
|
2009-04-09 03:50:10 +08:00
|
|
|
}
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-04-11 16:28:14 +08:00
|
|
|
// Otherwise, an arbitrary expression can be the receiver of a send.
|
2014-11-22 02:48:04 +08:00
|
|
|
ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2016-01-16 07:43:34 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
|
|
|
|
Res.get());
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse the remainder of an Objective-C message following the
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// '[' objc-receiver.
|
|
|
|
///
|
|
|
|
/// This routine handles sends to super, class messages (sent to a
|
|
|
|
/// class name), and instance messages (sent to an object), and the
|
|
|
|
/// target is represented by \p SuperLoc, \p ReceiverType, or \p
|
|
|
|
/// ReceiverExpr, respectively. Only one of these parameters may have
|
|
|
|
/// a valid value.
|
|
|
|
///
|
|
|
|
/// \param LBracLoc The location of the opening '['.
|
|
|
|
///
|
|
|
|
/// \param SuperLoc If this is a send to 'super', the location of the
|
|
|
|
/// 'super' keyword that indicates a send to the superclass.
|
|
|
|
///
|
|
|
|
/// \param ReceiverType If this is a class message, the type of the
|
|
|
|
/// class we are sending a message to.
|
|
|
|
///
|
|
|
|
/// \param ReceiverExpr If this is an instance message, the expression
|
|
|
|
/// used to compute the receiver object.
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2007-09-06 03:52:07 +08:00
|
|
|
/// objc-message-args:
|
|
|
|
/// objc-selector
|
|
|
|
/// objc-keywordarg-list
|
|
|
|
///
|
|
|
|
/// objc-keywordarg-list:
|
|
|
|
/// objc-keywordarg
|
|
|
|
/// objc-keywordarg-list objc-keywordarg
|
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// objc-keywordarg:
|
2007-09-06 03:52:07 +08:00
|
|
|
/// selector-name[opt] ':' objc-keywordexpr
|
|
|
|
///
|
|
|
|
/// objc-keywordexpr:
|
|
|
|
/// nonempty-expr-list
|
|
|
|
///
|
|
|
|
/// nonempty-expr-list:
|
|
|
|
/// assignment-expression
|
|
|
|
/// nonempty-expr-list , assignment-expression
|
2008-12-13 23:32:12 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-01-26 02:59:06 +08:00
|
|
|
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
SourceLocation SuperLoc,
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReceiverType,
|
2014-10-30 13:30:05 +08:00
|
|
|
Expr *ReceiverExpr) {
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
|
|
|
|
2009-11-07 10:08:14 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
|
2010-09-21 07:34:21 +08:00
|
|
|
false);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
|
2010-09-21 07:34:21 +08:00
|
|
|
false);
|
2009-11-07 10:08:14 +08:00
|
|
|
else
|
2010-08-24 07:25:46 +08:00
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
None, false);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return ExprError();
|
2009-11-07 10:08:14 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-09-06 07:08:20 +08:00
|
|
|
// Parse objc-selector
|
2007-10-11 08:55:41 +08:00
|
|
|
SourceLocation Loc;
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2011-10-03 14:36:17 +08:00
|
|
|
SmallVector<SourceLocation, 12> KeyLocs;
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector KeyExprs;
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
while (1) {
|
|
|
|
// Each iteration parses a single keyword argument.
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
KeyIdents.push_back(selIdent);
|
2011-10-03 14:36:17 +08:00
|
|
|
KeyLocs.push_back(Loc);
|
2007-09-18 04:25:27 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::colon)) {
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Parse the expression after ':'
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-21 07:34:21 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
if (SuperLoc.isValid())
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/true);
|
2010-09-21 07:34:21 +08:00
|
|
|
else if (ReceiverType)
|
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/true);
|
2010-09-21 07:34:21 +08:00
|
|
|
else
|
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/true);
|
2010-09-21 07:34:21 +08:00
|
|
|
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-09-21 07:34:21 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-04-19 07:43:21 +08:00
|
|
|
ExprResult Expr;
|
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
Expr = ParseBraceInitializer();
|
|
|
|
} else
|
|
|
|
Expr = ParseAssignmentExpression();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-04-19 07:43:21 +08:00
|
|
|
ExprResult Res(Expr);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2007-09-18 04:25:27 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// We have a valid expression.
|
2014-05-29 18:55:11 +08:00
|
|
|
KeyExprs.push_back(Res.get());
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-11-19 09:08:35 +08:00
|
|
|
// Code completion after each argument.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2018-07-31 03:24:48 +08:00
|
|
|
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/false);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/false);
|
2009-11-19 09:08:35 +08:00
|
|
|
else
|
2010-08-24 07:25:46 +08:00
|
|
|
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
|
2013-06-16 11:47:57 +08:00
|
|
|
KeyIdents,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*AtArgumentExpression=*/false);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-09-21 07:34:21 +08:00
|
|
|
return ExprError();
|
2009-11-19 09:08:35 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// Check for another keyword selector.
|
2009-04-12 02:13:45 +08:00
|
|
|
selIdent = ParseObjCSelectorPiece(Loc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (!selIdent && Tok.isNot(tok::colon))
|
2007-09-06 07:08:20 +08:00
|
|
|
break;
|
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
|
|
|
// Parse the, optional, argument list, comma separated.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2012-05-22 06:43:44 +08:00
|
|
|
SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Parse the expression after ','
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseAssignmentExpression());
|
2014-11-22 02:48:04 +08:00
|
|
|
if (Tok.is(tok::colon))
|
|
|
|
Res = Actions.CorrectDelayedTyposInExpr(Res);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2012-05-22 06:43:44 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
Diag(commaLoc, diag::note_extra_comma_message_arg) <<
|
|
|
|
FixItHint::CreateRemoval(commaLoc);
|
|
|
|
}
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2007-11-15 21:05:42 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-15 21:05:42 +08:00
|
|
|
// We have a valid expression.
|
2014-05-29 18:55:11 +08:00
|
|
|
KeyExprs.push_back(Res.get());
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
|
|
|
} else if (!selIdent) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_square)) {
|
2013-12-31 07:29:50 +08:00
|
|
|
Diag(Tok, diag::err_expected)
|
|
|
|
<< (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2008-01-26 02:59:06 +08:00
|
|
|
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-06 02:42:47 +08:00
|
|
|
unsigned nKeys = KeyIdents.size();
|
2011-10-03 14:36:17 +08:00
|
|
|
if (nKeys == 0) {
|
2007-10-07 10:00:24 +08:00
|
|
|
KeyIdents.push_back(selIdent);
|
2011-10-03 14:36:17 +08:00
|
|
|
KeyLocs.push_back(Loc);
|
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
|
2008-12-13 23:32:12 +08:00
|
|
|
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
if (SuperLoc.isValid())
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
else if (ReceiverType)
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
|
2012-08-24 06:51:59 +08:00
|
|
|
LBracLoc, KeyLocs, RBracLoc, KeyExprs);
|
2007-09-06 03:52:07 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Res(ParseStringLiteralExpression());
|
2012-08-24 05:35:17 +08:00
|
|
|
if (Res.isInvalid()) return Res;
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
|
|
|
|
// expressions. At this point, we know that the only valid thing that starts
|
|
|
|
// with '@' is an @"".
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<SourceLocation, 4> AtLocs;
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector AtStrings;
|
2007-12-12 09:04:12 +08:00
|
|
|
AtLocs.push_back(AtLoc);
|
2014-05-29 18:55:11 +08:00
|
|
|
AtStrings.push_back(Res.get());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
|
|
|
AtLocs.push_back(ConsumeToken()); // eat the @.
|
|
|
|
|
2008-12-10 04:22:58 +08:00
|
|
|
// Invalid unless there is a string literal.
|
2009-02-18 13:56:09 +08:00
|
|
|
if (!isTokenStringLiteral())
|
|
|
|
return ExprError(Diag(Tok, diag::err_objc_concat_string));
|
2007-12-12 09:04:12 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Lit(ParseStringLiteralExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Lit.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
AtStrings.push_back(Lit.get());
|
2007-12-12 09:04:12 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2015-12-25 07:58:11 +08:00
|
|
|
return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
2007-08-22 23:14:15 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
/// ParseObjCBooleanLiteral -
|
|
|
|
/// objc-scalar-literal : '@' boolean-keyword
|
|
|
|
/// ;
|
|
|
|
/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
|
|
|
|
/// ;
|
2018-07-31 03:24:48 +08:00
|
|
|
ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
|
2012-03-07 04:05:56 +08:00
|
|
|
bool ArgValue) {
|
|
|
|
SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
|
|
|
|
return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObjCCharacterLiteral -
|
|
|
|
/// objc-scalar-literal : '@' character-literal
|
|
|
|
/// ;
|
|
|
|
ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObjCNumericLiteral -
|
|
|
|
/// objc-scalar-literal : '@' scalar-literal
|
|
|
|
/// ;
|
|
|
|
/// scalar-literal : | numeric-constant /* any numeric constant. */
|
|
|
|
/// ;
|
|
|
|
ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
|
|
|
|
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
|
|
|
|
if (Lit.isInvalid()) {
|
2012-08-24 05:35:17 +08:00
|
|
|
return Lit;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2012-03-07 08:14:40 +08:00
|
|
|
ConsumeToken(); // Consume the literal token.
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
/// ParseObjCBoxedExpr -
|
|
|
|
/// objc-box-expression:
|
|
|
|
/// @( assignment-expression )
|
|
|
|
ExprResult
|
|
|
|
Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
|
|
|
|
if (Tok.isNot(tok::l_paren))
|
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
|
|
|
|
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
ExprResult ValueExpr(ParseAssignmentExpression());
|
|
|
|
if (T.consumeClose())
|
|
|
|
return ExprError();
|
2012-05-11 04:02:36 +08:00
|
|
|
|
|
|
|
if (ValueExpr.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2012-04-19 08:25:12 +08:00
|
|
|
// Wrap the sub-expression in a parenthesized expression, to distinguish
|
|
|
|
// a boxed expression from a literal.
|
|
|
|
SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
|
2014-05-29 18:55:11 +08:00
|
|
|
ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
|
2014-05-29 18:55:11 +08:00
|
|
|
ValueExpr.get());
|
2012-04-19 08:25:12 +08:00
|
|
|
}
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ElementExprs; // array elements.
|
2012-03-07 04:05:56 +08:00
|
|
|
ConsumeBracket(); // consume the l_square.
|
|
|
|
|
2016-07-20 04:21:18 +08:00
|
|
|
bool HasInvalidEltExpr = false;
|
2012-03-07 04:05:56 +08:00
|
|
|
while (Tok.isNot(tok::r_square)) {
|
|
|
|
// Parse list of array element expressions (all must be id types).
|
|
|
|
ExprResult Res(ParseAssignmentExpression());
|
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
|
|
|
|
2016-07-20 04:21:18 +08:00
|
|
|
Res = Actions.CorrectDelayedTyposInExpr(Res.get());
|
|
|
|
if (Res.isInvalid())
|
|
|
|
HasInvalidEltExpr = true;
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
// Parse the ellipsis that indicates a pack expansion.
|
|
|
|
if (Tok.is(tok::ellipsis))
|
2018-07-31 03:24:48 +08:00
|
|
|
Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
|
2012-03-07 04:05:56 +08:00
|
|
|
if (Res.isInvalid())
|
2016-07-20 04:21:18 +08:00
|
|
|
HasInvalidEltExpr = true;
|
2012-03-07 04:05:56 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
ElementExprs.push_back(Res.get());
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken(); // Eat the ','.
|
|
|
|
else if (Tok.isNot(tok::r_square))
|
2013-12-24 17:48:30 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
|
|
|
|
<< tok::comma);
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
|
2016-07-20 04:21:18 +08:00
|
|
|
|
|
|
|
if (HasInvalidEltExpr)
|
|
|
|
return ExprError();
|
|
|
|
|
2012-08-24 06:51:59 +08:00
|
|
|
MultiExprArg Args(ElementExprs);
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
|
|
|
|
SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
|
|
|
|
ConsumeBrace(); // consume the l_square.
|
2016-07-20 04:21:18 +08:00
|
|
|
bool HasInvalidEltExpr = false;
|
2012-03-07 04:05:56 +08:00
|
|
|
while (Tok.isNot(tok::r_brace)) {
|
|
|
|
// Parse the comma separated key : value expressions.
|
|
|
|
ExprResult KeyExpr;
|
|
|
|
{
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
KeyExpr = ParseAssignmentExpression();
|
|
|
|
if (KeyExpr.isInvalid()) {
|
|
|
|
// We must manually skip to a '}', otherwise the expression skipper will
|
|
|
|
// stop at the '}' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return KeyExpr;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::colon)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2013-04-19 03:37:43 +08:00
|
|
|
return ExprError();
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
ExprResult ValueExpr(ParseAssignmentExpression());
|
|
|
|
if (ValueExpr.isInvalid()) {
|
|
|
|
// We must manually skip to a '}', otherwise the expression skipper will
|
|
|
|
// stop at the '}' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return ValueExpr;
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2016-07-20 04:21:18 +08:00
|
|
|
// Check the key and value for possible typos
|
|
|
|
KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
|
|
|
|
ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
|
|
|
|
if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
|
|
|
|
HasInvalidEltExpr = true;
|
|
|
|
|
|
|
|
// Parse the ellipsis that designates this as a pack expansion. Do not
|
|
|
|
// ActOnPackExpansion here, leave it to template instantiation time where
|
|
|
|
// we can get better diagnostics.
|
2012-03-07 04:05:56 +08:00
|
|
|
SourceLocation EllipsisLoc;
|
2013-12-24 17:48:30 +08:00
|
|
|
if (getLangOpts().CPlusPlus)
|
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
// We have a valid expression. Collect it in a vector so we can
|
|
|
|
// build the argument list.
|
2018-07-31 03:24:48 +08:00
|
|
|
ObjCDictionaryElement Element = {
|
|
|
|
KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
|
2012-03-07 04:05:56 +08:00
|
|
|
};
|
|
|
|
Elements.push_back(Element);
|
2014-01-01 11:08:43 +08:00
|
|
|
|
|
|
|
if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
|
2013-12-24 17:48:30 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
|
|
|
|
<< tok::comma);
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
SourceLocation EndLoc = ConsumeBrace();
|
2016-07-20 04:21:18 +08:00
|
|
|
|
|
|
|
if (HasInvalidEltExpr)
|
|
|
|
return ExprError();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
// Create the ObjCDictionaryLiteral.
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
|
2015-12-25 07:58:15 +08:00
|
|
|
Elements);
|
2012-03-07 04:05:56 +08:00
|
|
|
}
|
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
/// objc-encode-expression:
|
2012-09-13 01:01:48 +08:00
|
|
|
/// \@encode ( type-name )
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
SourceLocation EncLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
if (Ty.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
|
|
|
|
Ty.get(), T.getCloseLocation());
|
2007-08-22 23:14:15 +08:00
|
|
|
}
|
2007-08-23 23:25:28 +08:00
|
|
|
|
|
|
|
/// objc-protocol-expression
|
2012-06-11 14:19:40 +08:00
|
|
|
/// \@protocol ( protocol-name )
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
|
2007-08-23 23:25:28 +08:00
|
|
|
SourceLocation ProtoLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2017-04-11 23:01:53 +08:00
|
|
|
if (expectIdentifier())
|
|
|
|
return ExprError();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-18 00:58:11 +08:00
|
|
|
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
|
2012-05-16 08:50:02 +08:00
|
|
|
SourceLocation ProtoIdLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-08-23 23:25:28 +08:00
|
|
|
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
|
|
|
|
T.getOpenLocation(), ProtoIdLoc,
|
|
|
|
T.getCloseLocation());
|
2007-08-23 23:25:28 +08:00
|
|
|
}
|
2007-10-16 07:39:13 +08:00
|
|
|
|
|
|
|
/// objc-selector-expression
|
2014-06-25 01:02:19 +08:00
|
|
|
/// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
|
2013-01-23 02:35:43 +08:00
|
|
|
ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation SelectorLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation sLoc;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2014-06-25 01:02:19 +08:00
|
|
|
bool HasOptionalParen = Tok.is(tok::l_paren);
|
|
|
|
if (HasOptionalParen)
|
|
|
|
ConsumeParen();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-26 23:07:07 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-08-26 23:07:07 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-04-12 02:13:45 +08:00
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
|
2010-08-28 06:32:41 +08:00
|
|
|
if (!SelIdent && // missing selector name.
|
|
|
|
Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
|
2013-12-24 17:48:30 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-12-06 06:21:29 +08:00
|
|
|
unsigned nColons = 0;
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-10-16 07:39:13 +08:00
|
|
|
while (1) {
|
2014-01-01 11:08:43 +08:00
|
|
|
if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
|
2010-08-28 06:32:41 +08:00
|
|
|
++nColons;
|
2014-05-21 14:02:52 +08:00
|
|
|
KeyIdents.push_back(nullptr);
|
2014-01-01 11:08:43 +08:00
|
|
|
} else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
|
|
|
|
return ExprError();
|
2010-08-28 06:32:41 +08:00
|
|
|
++nColons;
|
2014-01-01 11:08:43 +08:00
|
|
|
|
2007-10-16 07:39:13 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-26 23:07:07 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2013-06-16 11:47:57 +08:00
|
|
|
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-08-26 23:07:07 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2007-10-16 07:39:13 +08:00
|
|
|
// Check for another keyword selector.
|
|
|
|
SourceLocation Loc;
|
2009-04-12 02:13:45 +08:00
|
|
|
SelIdent = ParseObjCSelectorPiece(Loc);
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2011-03-27 02:11:38 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
|
2007-10-16 07:39:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-12-06 06:21:29 +08:00
|
|
|
}
|
2014-06-25 01:02:19 +08:00
|
|
|
if (HasOptionalParen && Tok.is(tok::r_paren))
|
|
|
|
ConsumeParen(); // ')'
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-12-06 06:21:29 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
|
2012-12-31 08:28:03 +08:00
|
|
|
return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
|
|
|
|
T.getOpenLocation(),
|
2014-06-25 01:02:19 +08:00
|
|
|
T.getCloseLocation(),
|
|
|
|
!HasOptionalParen);
|
2016-02-13 06:53:10 +08:00
|
|
|
}
|
2011-09-01 01:37:55 +08:00
|
|
|
|
2012-07-03 07:37:09 +08:00
|
|
|
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
|
|
|
// MCDecl might be null due to error in method or c-function prototype, etc.
|
|
|
|
Decl *MCDecl = LM.D;
|
2018-07-31 03:24:48 +08:00
|
|
|
bool skip = MCDecl &&
|
2012-07-03 07:37:09 +08:00
|
|
|
((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
|
|
|
|
(!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
|
|
|
|
if (skip)
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-17 12:13:18 +08:00
|
|
|
// Save the current token position.
|
|
|
|
SourceLocation OrigLoc = Tok.getLocation();
|
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
|
2017-06-20 01:53:21 +08:00
|
|
|
// Store an artificial EOF token to ensure that we don't run off the end of
|
|
|
|
// the method's body when we come to parse it.
|
|
|
|
Token Eof;
|
|
|
|
Eof.startToken();
|
|
|
|
Eof.setKind(tok::eof);
|
|
|
|
Eof.setEofData(MCDecl);
|
|
|
|
Eof.setLocation(OrigLoc);
|
|
|
|
LM.Toks.push_back(Eof);
|
2011-09-01 01:37:55 +08:00
|
|
|
// Append the current token at the end of the new token stream so that it
|
|
|
|
// doesn't get lost.
|
|
|
|
LM.Toks.push_back(Tok);
|
2019-05-17 17:32:05 +08:00
|
|
|
PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);
|
2016-02-10 02:52:09 +08:00
|
|
|
|
2011-09-01 01:37:55 +08:00
|
|
|
// Consume the previously pushed token.
|
2013-03-28 07:58:17 +08:00
|
|
|
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
|
2015-06-18 18:59:26 +08:00
|
|
|
"Inline objective-c method not starting with '{' or 'try' or ':'");
|
2013-12-06 00:25:25 +08:00
|
|
|
// Enter a scope for the method or c-function body.
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
|
|
|
|
Scope::FnScope | Scope::DeclScope |
|
|
|
|
Scope::CompoundStmtScope);
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
// Tell the actions module that we have entered a method or c-function definition
|
2012-07-03 07:37:09 +08:00
|
|
|
// with the specified Declarator for the method/function.
|
2012-08-09 07:41:08 +08:00
|
|
|
if (parseMethod)
|
|
|
|
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
|
|
|
|
else
|
|
|
|
Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
|
2012-08-11 02:10:56 +08:00
|
|
|
if (Tok.is(tok::kw_try))
|
2014-03-24 04:28:07 +08:00
|
|
|
ParseFunctionTryBlock(MCDecl, BodyScope);
|
2012-08-11 05:15:06 +08:00
|
|
|
else {
|
|
|
|
if (Tok.is(tok::colon))
|
|
|
|
ParseConstructorInitializer(MCDecl);
|
2016-04-19 02:19:45 +08:00
|
|
|
else
|
|
|
|
Actions.ActOnDefaultCtorInitializers(MCDecl);
|
2014-03-24 04:28:07 +08:00
|
|
|
ParseFunctionStatementBody(MCDecl, BodyScope);
|
2012-08-11 05:15:06 +08:00
|
|
|
}
|
2017-06-20 01:53:21 +08:00
|
|
|
|
2011-12-17 12:13:18 +08:00
|
|
|
if (Tok.getLocation() != OrigLoc) {
|
|
|
|
// Due to parsing error, we either went over the cached tokens or
|
|
|
|
// there are still cached tokens left. If it's the latter case skip the
|
|
|
|
// leftover tokens.
|
|
|
|
// Since this is an uncommon situation that should be avoided, use the
|
|
|
|
// expensive isBeforeInTranslationUnit call.
|
|
|
|
if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
|
|
|
|
OrigLoc))
|
|
|
|
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
|
|
|
|
ConsumeAnyToken();
|
|
|
|
}
|
2017-06-20 01:53:21 +08:00
|
|
|
// Clean up the remaining EOF token.
|
|
|
|
ConsumeAnyToken();
|
2011-09-01 01:37:55 +08:00
|
|
|
}
|