summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse/ParseObjc.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:57:35 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:57:35 +0000
commite9d95f1ecc98ced831cace8b4b78cb7cc380f4aa (patch)
tree73962adb18c3f8c191701021f69a14b4121676e6 /clang/lib/Parse/ParseObjc.cpp
parent85f3f9513dbc88b9898d022a1a55a03d55612721 (diff)
downloadbcm5719-llvm-e9d95f1ecc98ced831cace8b4b78cb7cc380f4aa.tar.gz
bcm5719-llvm-e9d95f1ecc98ced831cace8b4b78cb7cc380f4aa.zip
Handle Objective-C type arguments.
Objective-C type arguments can be provided in angle brackets following an Objective-C interface type. Syntactically, this is the same position as one would provide protocol qualifiers (e.g., id<NSCopying>), so parse both together and let Sema sort out the ambiguous cases. This applies both when parsing types and when parsing the superclass of an Objective-C class, which can now be a specialized type (e.g., NSMutableArray<T> inherits from NSArray<T>). Check Objective-C type arguments against the type parameters of the corresponding class. Verify the length of the type argument list and that each type argument satisfies the corresponding bound. Specializations of parameterized Objective-C classes are represented in the type system as distinct types. Both specialized types (e.g., NSArray<NSString *> *) and unspecialized types (NSArray *) are represented, separately. llvm-svn: 241542
Diffstat (limited to 'clang/lib/Parse/ParseObjc.cpp')
-rw-r--r--clang/lib/Parse/ParseObjc.cpp146
1 files changed, 129 insertions, 17 deletions
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 3ef187af8d7..0e4574056b0 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
/// @end
///
/// objc-superclass:
-/// ':' identifier
+/// ':' identifier objc-type-arguments[opt]
///
/// objc-class-interface-attributes:
/// __attribute__((visibility("default")))
@@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
+ DeclSpec superClassDS(AttrFactory);
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@@ -311,18 +312,12 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
- } else if (typeParameterList) {
- // An objc-type-parameter-list is ambiguous with an objc-protocol-refs
- // in an @interface without a specified superclass, so such classes
- // are ill-formed. We have determined that we have an
- // objc-type-parameter-list but no superclass, so complain and record
- // as if we inherited from NSObject.
- SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation);
- Diag(insertLoc, diag::err_objc_parameterized_class_without_base)
- << nameId
- << FixItHint::CreateInsertion(insertLoc, " : NSObject");
- superClassId = PP.getIdentifierInfo("NSObject");
- superClassLoc = Tok.getLocation();
+
+ // Type arguments for the superclass or protocol conformances.
+ if (Tok.is(tok::less)) {
+ ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+ /*warnOnIncompleteProtocols=*/true);
+ }
}
// Next, we need to check for any protocol references.
@@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
/*ForObjCContainer=*/true,
&ProtocolIdents[0], ProtocolIdents.size(),
ProtocolRefs);
+ } else if (auto protocols = superClassDS.getProtocolQualifiers()) {
+ // We already parsed the protocols named when we thought we had a
+ // type argument list (for a specialized superclass). Treat them
+ // as actual protocol references.
+ unsigned numProtocols = superClassDS.getNumProtocolQualifiers();
+ ProtocolRefs.append(protocols, protocols + numProtocols);
+ ProtocolLocs.append(superClassDS.getProtocolLocs(),
+ superClassDS.getProtocolLocs() + numProtocols);
+ LAngleLoc = superClassDS.getProtocolLAngleLoc();
+ EndProtoLoc = superClassDS.getLocEnd();
} else if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc)) {
@@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
Decl *ClsType =
- Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
- superClassId, superClassLoc,
+ Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
+ typeParameterList, superClassId,
+ superClassLoc,
+ superClassDS.getObjCTypeArgs(),
+ superClassDS.getObjCTypeArgsRange(),
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc, attrs.getList());
@@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
SmallVector<Decl *, 8> ProtocolDecl;
SmallVector<SourceLocation, 8> ProtocolLocs;
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
- false,
- LAngleLoc, EndProtoLoc);
+ false, LAngleLoc, EndProtoLoc);
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
ProtocolLocs.data(), LAngleLoc);
if (EndProtoLoc.isValid())
@@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
return Result;
}
+/// Parse Objective-C type arguments or protocol qualifiers.
+///
+/// objc-type-arguments:
+/// '<' type-name (',' type-name)* '>'
+///
+void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
+ DeclSpec &DS,
+ 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;
+ SmallVector<SourceLocation, 4> identifierLocs;
+
+ // 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) {
+ identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
+ identifierLocs[i]));
+ }
+
+ Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(),
+ identifierLocPairs.size());
+ 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;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ /*ObjCGenericList=*/true);
+
+ // Let Sema figure out what we parsed.
+ Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
+ DS,
+ lAngleLoc,
+ identifiers,
+ identifierLocs,
+ rAngleLoc,
+ warnOnIncompleteProtocols);
+ return;
+ }
+
+ // We syntactically matched a type argument, so commit to parsing
+ // type arguments.
+ SmallVector<ParsedType, 4> typeArgs;
+
+ // Convert the identifiers into type arguments.
+ bool invalid = false;
+ for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+ ParsedType typeArg
+ = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
+ if (typeArg) {
+ typeArgs.push_back(typeArg);
+ } else {
+ invalid = true;
+ }
+ }
+
+ // Continue parsing type-names.
+ do {
+ TypeResult typeArg = ParseTypeName();
+ if (typeArg.isUsable()) {
+ typeArgs.push_back(typeArg.get());
+ } else {
+ invalid = true;
+ }
+ } while (TryConsumeToken(tok::comma));
+
+ // Parse the closing '>'.
+ SourceLocation rAngleLoc;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ /*ObjCGenericList=*/true);
+
+ if (invalid)
+ return;
+
+ // Update the DeclSpec appropriately.
+ DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+}
+
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
BalancedDelimiterTracker &T,
SmallVectorImpl<Decl *> &AllIvarDecls,
OpenPOWER on IntegriCloud