Re-apply "ObjectiveC Generics: Start using ObjCTypeParamType." (#48)

This re-applies Manman's c7c63c5b9, reverted in 7c090455.

rdar://problem/24619481
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index f75adef..d83fad3 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3883,6 +3883,11 @@
                   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 =
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d023433..43bec8b 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -1330,8 +1330,12 @@
                                              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 556d225..4aa0756 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1081,13 +1081,24 @@
 
     // 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) {
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index fb69c14..f3918e6 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -2365,7 +2365,7 @@
   }
   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 43434cd..a304c4f 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1157,6 +1157,20 @@
     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.
@@ -6069,6 +6083,13 @@
 }
 
 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() 
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 301a5ce..a418c82 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -626,7 +626,7 @@
       : 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;
diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m
index 63ba18f..9d758d3 100644
--- a/test/SemaObjC/kindof.m
+++ b/test/SemaObjC/kindof.m
@@ -385,7 +385,7 @@
 @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 @@
 }
 @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
diff --git a/test/SemaObjC/parameterized_classes_subst.m b/test/SemaObjC/parameterized_classes_subst.m
index f90ee90..da2d56f 100644
--- a/test/SemaObjC/parameterized_classes_subst.m
+++ b/test/SemaObjC/parameterized_classes_subst.m
@@ -426,3 +426,36 @@
 // 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
+@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}}
+@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> *'}}
+}
+
+@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}}
+@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