r281358 - ObjectiveC Generics: Start using ObjCTypeParamType.

Manman Ren via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 13 10:41:05 PDT 2016


Author: mren
Date: Tue Sep 13 12:41:05 2016
New Revision: 281358

URL: http://llvm.org/viewvc/llvm-project?rev=281358&view=rev
Log:
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 <protocol>" and thus will lose
the type information in the following example:
@interface MyMutableDictionary<KeyType, ObjectType> : NSObject
- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key;
@end
MyMutableDictionary<NSString *, NSString *> *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

Modified:
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
    cfe/trunk/test/SemaObjC/kindof.m
    cfe/trunk/test/SemaObjC/parameterized_classes_subst.m

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Sep 13 12:41:05 2016
@@ -3883,6 +3883,11 @@ ASTContext::applyObjCProtocolQualifiers(
                   bool allowOnPointerType) const {
   hasError = false;
 
+  if (const ObjCTypeParamType *objT =
+      dyn_cast<ObjCTypeParamType>(type.getTypePtr())) {
+    return getObjCTypeParamType(objT->getDecl(), protocols);
+  }
+
   // Apply protocol qualifiers to ObjCObjectPointerType.
   if (allowOnPointerType) {
     if (const ObjCObjectPointerType *objPtr =

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Tue Sep 13 12:41:05 2016
@@ -1320,8 +1320,12 @@ ObjCTypeParamDecl *ObjCTypeParamDecl::Cr
                                              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,

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Sep 13 12:41:05 2016
@@ -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<TypedefType>(splitType.Ty)) {
-      if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) {
+    if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) {
+      if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(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<ObjCProtocolDecl*, 8> protocolsVec;
+          protocolsVec.append(OTPTy->qual_begin(),
+                              OTPTy->qual_end());
+          ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
+          QualType resultTy = ctx.applyObjCProtocolQualifiers(argType,
+              protocolsToApply, hasError, true/*allowOnPointerType*/);
+
+          return ctx.getQualifiedType(resultTy, splitType.Quals);
         }
 
         switch (context) {

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Sep 13 12:41:05 2016
@@ -2353,7 +2353,7 @@ static bool CheckMethodOverrideParam(Sem
   }
   if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
     return true;
-  
+
   if (!Warn)
     return false;
   unsigned DiagID = 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Sep 13 12:41:05 2016
@@ -1157,6 +1157,20 @@ TypeResult Sema::actOnObjCTypeArgsAndPro
     ResultTL = ObjCObjectPointerTL.getPointeeLoc();
   }
 
+  if (auto OTPTL = ResultTL.getAs<ObjCTypeParamTypeLoc>()) {
+    // 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<ObjCObjectTypeLoc>();
 
   // Type argument information.
@@ -5875,7 +5889,6 @@ bool Sema::checkNullabilityTypeSpecifier
   // 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
 }
 
 bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
+  if (isa<ObjCTypeParamType>(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<ObjCObjectPointerType>();
   const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp Tue Sep 13 12:41:05 2016
@@ -626,7 +626,7 @@ static bool isObjCTypeParamDependent(Qua
       : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
   public:
     IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
-    bool VisitTypedefType(const TypedefType *Type) {
+    bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) {
       if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
         Result = true;
         return false;

Modified: cfe/trunk/test/SemaObjC/kindof.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/kindof.m?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/kindof.m (original)
+++ cfe/trunk/test/SemaObjC/kindof.m Tue Sep 13 12:41:05 2016
@@ -385,7 +385,7 @@ void testNullability() {
 @end
 
 @interface NSGeneric<ObjectType> : 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<NSString*> *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<T> : NSObject
 @end

Modified: cfe/trunk/test/SemaObjC/parameterized_classes_subst.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes_subst.m?rev=281358&r1=281357&r2=281358&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes_subst.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes_subst.m Tue Sep 13 12:41:05 2016
@@ -426,3 +426,36 @@ void test_ternary_operator(NSArray<NSStr
 // warning about likely protocol/class name typos.
 // --------------------------------------------------------------------------
 typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}}
+
+// rdar://25060179
+ at interface MyMutableDictionary<KeyType, ObjectType> : NSObject
+- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \
+    // expected-note{{passing argument to parameter 'key' here}}
+ at end
+
+void bar(MyMutableDictionary<NSString *, NSString *> *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<NSCopying> *'}}
+}
+
+ at interface MyTest<K, V> : NSObject <NSCopying>
+- (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}}
+ at end
+
+ at 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}}
+}
+ at end




More information about the cfe-commits mailing list