From: Manman Ren Date: Tue, 13 Sep 2016 17:41:05 +0000 (+0000) Subject: ObjectiveC Generics: Start using ObjCTypeParamType. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1286300e382671aaf0680870ca41c06cc1ea53a4;p=clang ObjectiveC Generics: Start using ObjCTypeParamType. For ObjC type parameter, we used to have TypedefType that is canonicalized to id or the bound type. We can't represent "T " and thus will lose the type information in the following example: @interface MyMutableDictionary : NSObject - (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType )key; @end MyMutableDictionary *stringsByString; NSNumber *n1, *n2; stringsByString[n1] = n2; --> no warning on type mismatch of the key. To fix the problem, we introduce a new type ObjCTypeParamType that supports a list of protocol qualifiers. We create ObjCTypeParamType for ObjCTypeParamDecl when we create ObjCTypeParamDecl. We also substitute ObjCTypeParamType instead of TypedefType on an ObjCTypeParamDecl. rdar://24619481 rdar://25060179 Differential Revision: http://reviews.llvm.org/D23080 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@281358 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2ea0f516ea..9e801b5d7a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3883,6 +3883,11 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, bool allowOnPointerType) const { hasError = false; + if (const ObjCTypeParamType *objT = + dyn_cast(type.getTypePtr())) { + return getObjCTypeParamType(objT->getDecl(), protocols); + } + // Apply protocol qualifiers to ObjCObjectPointerType. if (allowOnPointerType) { if (const ObjCObjectPointerType *objPtr = diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index d2701211be..47e032a2e5 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -1320,8 +1320,12 @@ ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, IdentifierInfo *name, SourceLocation colonLoc, TypeSourceInfo *boundInfo) { - return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index, - nameLoc, name, colonLoc, boundInfo); + auto *TPDecl = + new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index, + nameLoc, name, colonLoc, boundInfo); + QualType TPType = ctx.getObjCTypeParamType(TPDecl, {}); + TPDecl->setTypeForDecl(TPType.getTypePtr()); + return TPDecl; } ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 556d225612..4aa07568dc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1081,13 +1081,24 @@ QualType QualType::substObjCTypeArgs( // Replace an Objective-C type parameter reference with the corresponding // type argument. - if (const auto *typedefTy = dyn_cast(splitType.Ty)) { - if (auto *typeParam = dyn_cast(typedefTy->getDecl())) { + if (const auto *OTPTy = dyn_cast(splitType.Ty)) { + if (auto *typeParam = dyn_cast(OTPTy->getDecl())) { // If we have type arguments, use them. if (!typeArgs.empty()) { - // FIXME: Introduce SubstObjCTypeParamType ? QualType argType = typeArgs[typeParam->getIndex()]; - return ctx.getQualifiedType(argType, splitType.Quals); + if (OTPTy->qual_empty()) + return ctx.getQualifiedType(argType, splitType.Quals); + + // Apply protocol lists if exists. + bool hasError; + SmallVector protocolsVec; + protocolsVec.append(OTPTy->qual_begin(), + OTPTy->qual_end()); + ArrayRef protocolsToApply = protocolsVec; + QualType resultTy = ctx.applyObjCProtocolQualifiers(argType, + protocolsToApply, hasError, true/*allowOnPointerType*/); + + return ctx.getQualifiedType(resultTy, splitType.Quals); } switch (context) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 3237cd0052..a1d795d6d7 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2353,7 +2353,7 @@ static bool CheckMethodOverrideParam(Sema &S, } if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) return true; - + if (!Warn) return false; unsigned DiagID = diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9ce7f95e55..1619483f08 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1157,6 +1157,20 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( ResultTL = ObjCObjectPointerTL.getPointeeLoc(); } + if (auto OTPTL = ResultTL.getAs()) { + // Protocol qualifier information. + if (OTPTL.getNumProtocols() > 0) { + assert(OTPTL.getNumProtocols() == Protocols.size()); + OTPTL.setProtocolLAngleLoc(ProtocolLAngleLoc); + OTPTL.setProtocolRAngleLoc(ProtocolRAngleLoc); + for (unsigned i = 0, n = Protocols.size(); i != n; ++i) + OTPTL.setProtocolLoc(i, ProtocolLocs[i]); + } + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); + } + auto ObjCObjectTL = ResultTL.castAs(); // Type argument information. @@ -5875,7 +5889,6 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, // For the context-sensitive keywords/Objective-C property // attributes, require that the type be a single-level pointer. if (isContextSensitive) { - // Make sure that the pointee isn't itself a pointer type. QualType pointeeType = desugared->getPointeeType(); if (pointeeType->isAnyPointerType() || pointeeType->isObjCObjectPointerType() || @@ -5899,6 +5912,13 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, } bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { + if (isa(type)) { + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, type); + return false; + } + // Find out if it's an Objective-C object or object pointer type; const ObjCObjectPointerType *ptrType = type->getAs(); const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a8f2f3a4a5..ec2153cc82 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -626,7 +626,7 @@ static bool isObjCTypeParamDependent(QualType Type) { : public RecursiveASTVisitor { public: IsObjCTypeParamDependentTypeVisitor() : Result(false) {} - bool VisitTypedefType(const TypedefType *Type) { + bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) { if (isa(Type->getDecl())) { Result = true; return false; diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m index 63ba18fe89..9d758d3cfb 100644 --- a/test/SemaObjC/kindof.m +++ b/test/SemaObjC/kindof.m @@ -385,7 +385,7 @@ void testNullability() { @end @interface NSGeneric : NSObject -- (void)test:(__kindof ObjectType)T; +- (void)test:(__kindof ObjectType)T; // expected-note{{passing argument to parameter 'T' here}} - (void)mapUsingBlock:(id (^)(__kindof ObjectType))block; @end @implementation NSGeneric @@ -395,6 +395,14 @@ void testNullability() { } @end +void testGeneric(NSGeneric *generic) { + NSObject *NSObject_obj; + // Assign from NSObject_obj to __kindof NSString*. + [generic test:NSObject_obj]; // expected-warning{{incompatible pointer types sending 'NSObject *' to parameter of type '__kindof NSString *'}} + NSString *NSString_str; + [generic test:NSString_str]; +} + // Check that clang doesn't crash when a type parameter is illegal. @interface Array1 : NSObject @end diff --git a/test/SemaObjC/parameterized_classes_subst.m b/test/SemaObjC/parameterized_classes_subst.m index f90ee90935..da2d56f11b 100644 --- a/test/SemaObjC/parameterized_classes_subst.m +++ b/test/SemaObjC/parameterized_classes_subst.m @@ -426,3 +426,36 @@ void test_ternary_operator(NSArray *stringArray, // warning about likely protocol/class name typos. // -------------------------------------------------------------------------- typedef NSArray ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} + +// rdar://25060179 +@interface MyMutableDictionary : NSObject +- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType )key; // expected-note{{passing argument to parameter 'obj' here}} \ + // expected-note{{passing argument to parameter 'key' here}} +@end + +void bar(MyMutableDictionary *stringsByString, + NSNumber *n1, NSNumber *n2) { + // We warn here when the key types do not match. + stringsByString[n1] = n2; // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \ + // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} +} + +@interface MyTest : NSObject +- (V)test:(K)key; +- (V)test2:(K)key; // expected-note{{previous definition is here}} +- (void)mapUsingBlock:(id (^)(V))block; +- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}} +@end + +@implementation MyTest +- (id)test:(id)key { + return key; +} +- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}} + return 0; +} +- (void)mapUsingBlock:(id (^)(id))block { +} +- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}} +} +@end