xazax.hun created this revision.
xazax.hun added reviewers: krememek, zaks.anna, jordan_rose, dcoughlin.
xazax.hun added a subscriber: cfe-commits.

This patch merged the functionality from ObjCGenericsChecker into 
DynamicTypePropagation checker.
Note that the Generics Checker can still be turned on or off individually but 
this only affects whether diagnostics are generated or not.
There is no intended functional change in this patch.

Rationale:
This is a refactoring that makes some collaboration between the 
ObjCGenericsChecker and DynamicTypePropagation checker possible.
The final goal (which will be achieved by some followup patches) is to use the 
reasoning of ObjCGenericsChecker about generics to infer dynamic type for 
objects.

Lets consider the following scenario:
id object = arrayOfStrings.firstObject;

Here the DynamicTypePropagation checker can not infer any dynamic type 
information because the static type of the arrayOfStrings.firstObject 
expression is id when arrayOfStrings is not annotated. However the generics 
checker might be able to infer an upper bound (NSString *) for the same 
expression from the usage of the symbol. 

In a follow up patch when the DynamicTypePropagation checker fails to infer the 
dynamic type for an object, we would fall back to the inference of the generics 
checker, because it may have additional information.

Impact:

When an exact type is inferred as a dynamic type (this happens when the 
allocation was visible by the analyzer), method calls on that object will be 
"devirtualized" (inlined).
When the allocation is not visible but an upper bound can be inferred, there 
will be a path split on method calls. On one path the method will be inlined 
(when a body is available) on the other, there will be no inlining. 
There are some heuristic cases, where an upper bound is treated as an exact 
type.

The expected effect of the follow up patch is that, upper bound can be inferred 
more frequently. Due to cross translation unit limits, this might not change 
the inlining behavior significantly. However there are other advantages. 
Utilizing this dynamic type information, a generic type checker could be 
implemented trivially which could catch errors like:

id object = myNSNumber;
NSString *myString = object;

Why not keep the Generics checker and the dynamic type propagation as 
completely separate checks?

One of the problem is that, right now both checkers infer type information from 
casts. In order to be able to fallback to the type inference of Generics 
checker when the type inference of dynamic type propagation failed, the 
Generics checker should assume that the dynamic type propagation is done 
already by the time its callback is invoked. Since there is no way to specify 
ordering between the checkers right now, the only way to do it correctly is to 
merge two checks into one checker.

What do you think?

http://reviews.llvm.org/D12381

Files:
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp
  test/Analysis/generics.m

Index: test/Analysis/generics.m
===================================================================
--- test/Analysis/generics.m
+++ test/Analysis/generics.m
@@ -418,7 +418,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>incompatibleTypesErased</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -528,7 +528,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>incompatibleTypesErased</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -672,7 +672,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>incompatibleTypesErased</string>
 // CHECK:   <key>issue_hash</key><string>5</string>
@@ -922,7 +922,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSString *&gt; *&apos; from &apos;NSArray&lt;NSNumber *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>crossProceduralErasedTypes</string>
 // CHECK:   <key>issue_hash</key><string>1</string>
@@ -1032,7 +1032,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>incompatibleTypesErasedReverseConversion</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -1176,7 +1176,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>incompatibleTypesErasedReverseConversion</string>
 // CHECK:   <key>issue_hash</key><string>4</string>
@@ -1286,7 +1286,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>idErasedIncompatibleTypesReverseConversion</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -1430,7 +1430,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>idErasedIncompatibleTypesReverseConversion</string>
 // CHECK:   <key>issue_hash</key><string>4</string>
@@ -1574,7 +1574,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>idErasedIncompatibleTypes</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -1684,7 +1684,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>idErasedIncompatibleTypes</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -1828,7 +1828,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>idErasedIncompatibleTypes</string>
 // CHECK:   <key>issue_hash</key><string>5</string>
@@ -2006,7 +2006,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSMutableString *&apos; from &apos;NSString *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>pathSensitiveInference</string>
 // CHECK:   <key>issue_hash</key><string>8</string>
@@ -2150,7 +2150,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;MutableArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>verifyAPIusage</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -2260,7 +2260,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSMutableString *&apos; from &apos;NSString *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>trustExplicitCasts</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -2438,7 +2438,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSNumber *&gt; *&apos; from &apos;MutableArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>subtypeOfGeneric</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -2548,7 +2548,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>genericSubtypeOfGeneric</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -2692,7 +2692,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSNumber *&gt; *&apos; from &apos;ExceptionalArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>genericSubtypeOfGeneric</string>
 // CHECK:   <key>issue_hash</key><string>5</string>
@@ -2802,7 +2802,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>genericSubtypeOfGenericReverse</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -2946,7 +2946,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSNumber *&gt; *&apos; from &apos;ExceptionalArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>genericSubtypeOfGenericReverse</string>
 // CHECK:   <key>issue_hash</key><string>5</string>
@@ -3090,7 +3090,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSMutableString *&gt; *&apos; from &apos;MutableArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>inferenceFromAPI</string>
 // CHECK:   <key>issue_hash</key><string>4</string>
@@ -3234,7 +3234,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSString *&gt; *&apos; from &apos;MutableArray&lt;NSMutableString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>inferenceFromAPI2</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -3378,7 +3378,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSString *&gt; *&apos; from &apos;MutableArray&lt;NSMutableString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>inferenceFromAPIWithLegacyTypes</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -3522,7 +3522,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSMutableString *&gt; *&apos; from &apos;MutableArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>inferenceFromAPIWithLegacyTypes2</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -3666,7 +3666,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSMutableString *&gt; *&apos; from &apos;MutableArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>inferenceFromAPIWithBuggyTypes</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -3810,7 +3810,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;MutableArray&lt;NSString *&gt; *&apos; from &apos;MutableArray&lt;NSMutableString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>InferenceFromAPIWithBuggyTypes2</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -3954,7 +3954,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>workWithProperties</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -4098,7 +4098,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>workWithProperties</string>
 // CHECK:   <key>issue_hash</key><string>4</string>
@@ -4242,7 +4242,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>workWithProperties</string>
 // CHECK:   <key>issue_hash</key><string>6</string>
@@ -4386,7 +4386,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>workWithProperties</string>
 // CHECK:   <key>issue_hash</key><string>8</string>
@@ -4564,7 +4564,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSMutableString *&apos; from &apos;NSString *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>findMethodDeclInTrackedType</string>
 // CHECK:   <key>issue_hash</key><string>4</string>
@@ -4708,7 +4708,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSMutableString *&apos; from &apos;NSString *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>findMethodDeclInTrackedType2</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -4818,7 +4818,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSString *&apos; from &apos;NSNumber *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>testAnnotatedLiterals</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -4962,7 +4962,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>trackedClassVariables</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
@@ -5106,7 +5106,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>trackedClassVariables</string>
 // CHECK:   <key>issue_hash</key><string>3</string>
@@ -5250,7 +5250,7 @@
 // CHECK:    <key>description</key><string>Incompatible pointer types assigning to &apos;NSArray&lt;NSNumber *&gt; *&apos; from &apos;NSArray&lt;NSString *&gt; *&apos;</string>
 // CHECK:    <key>category</key><string>Core Foundation/Objective-C</string>
 // CHECK:    <key>type</key><string>Generics</string>
-// CHECK:    <key>check_name</key><string>alpha.osx.cocoa.ObjCGenerics</string>
+// CHECK:    <key>check_name</key><string>core.DynamicTypePropagation</string>
 // CHECK:   <key>issue_context_kind</key><string>function</string>
 // CHECK:   <key>issue_context</key><string>nestedCollections</string>
 // CHECK:   <key>issue_hash</key><string>2</string>
Index: lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
-//=== ObjCGenericsChecker.cpp - Path sensitive checker for Generics *- C++ -*=//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker tries to find type errors that the compiler is not able to catch
-// due to the implicit conversions that were introduced for backward
-// compatibility.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-
-using namespace clang;
-using namespace ento;
-
-// ProgramState trait - a map from symbol to its specialized type.
-REGISTER_MAP_WITH_PROGRAMSTATE(TypeParamMap, SymbolRef,
-                               const ObjCObjectPointerType *)
-
-namespace {
-class ObjCGenericsChecker
-    : public Checker<check::DeadSymbols, check::PreObjCMessage,
-                     check::PostObjCMessage, check::PostStmt<CastExpr>> {
-public:
-  ProgramStateRef checkPointerEscape(ProgramStateRef State,
-                                     const InvalidatedSymbols &Escaped,
-                                     const CallEvent *Call,
-                                     PointerEscapeKind Kind) const;
-
-  void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
-  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
-  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
-  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
-
-private:
-  mutable std::unique_ptr<BugType> BT;
-  void initBugType() const {
-    if (!BT)
-      BT.reset(
-          new BugType(this, "Generics", categories::CoreFoundationObjectiveC));
-  }
-
-  class GenericsBugVisitor : public BugReporterVisitorImpl<GenericsBugVisitor> {
-  public:
-    GenericsBugVisitor(SymbolRef S) : Sym(S) {}
-    ~GenericsBugVisitor() override {}
-
-    void Profile(llvm::FoldingSetNodeID &ID) const override {
-      static int X = 0;
-      ID.AddPointer(&X);
-      ID.AddPointer(Sym);
-    }
-
-    PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
-                                   const ExplodedNode *PrevN,
-                                   BugReporterContext &BRC,
-                                   BugReport &BR) override;
-
-  private:
-    // The tracked symbol.
-    SymbolRef Sym;
-  };
-
-  void reportBug(const ObjCObjectPointerType *From,
-                 const ObjCObjectPointerType *To, ExplodedNode *N,
-                 SymbolRef Sym, CheckerContext &C,
-                 const Stmt *ReportedNode = nullptr) const {
-    initBugType();
-    SmallString<64> Buf;
-    llvm::raw_svector_ostream OS(Buf);
-    OS << "Incompatible pointer types assigning to '";
-    QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine());
-    OS << "' from '";
-    QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine());
-    OS << "'";
-    std::unique_ptr<BugReport> R(new BugReport(*BT, OS.str(), N));
-    R->markInteresting(Sym);
-    R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym));
-    if (ReportedNode)
-      R->addRange(ReportedNode->getSourceRange());
-    C.emitReport(std::move(R));
-  }
-};
-} // end anonymous namespace
-
-PathDiagnosticPiece *ObjCGenericsChecker::GenericsBugVisitor::VisitNode(
-    const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
-    BugReport &BR) {
-  ProgramStateRef state = N->getState();
-  ProgramStateRef statePrev = PrevN->getState();
-
-  const ObjCObjectPointerType *const *TrackedType =
-      state->get<TypeParamMap>(Sym);
-  const ObjCObjectPointerType *const *TrackedTypePrev =
-      statePrev->get<TypeParamMap>(Sym);
-  if (!TrackedType)
-    return nullptr;
-
-  if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
-    return nullptr;
-
-  // Retrieve the associated statement.
-  const Stmt *S = nullptr;
-  ProgramPoint ProgLoc = N->getLocation();
-  if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
-    S = SP->getStmt();
-  }
-
-  if (!S)
-    return nullptr;
-
-  const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
-
-  SmallString<64> Buf;
-  llvm::raw_svector_ostream OS(Buf);
-  OS << "Type '";
-  QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine());
-  OS << "' is inferred from ";
-
-  if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
-    OS << "explicit cast (from '";
-    QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(),
-                    Qualifiers(), OS, LangOpts, llvm::Twine());
-    OS << "' to '";
-    QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS,
-                    LangOpts, llvm::Twine());
-    OS << "')";
-  } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
-    OS << "implicit cast (from '";
-    QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(),
-                    Qualifiers(), OS, LangOpts, llvm::Twine());
-    OS << "' to '";
-    QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS,
-                    LangOpts, llvm::Twine());
-    OS << "')";
-  } else {
-    OS << "this context";
-  }
-
-  // Generate the extra diagnostic.
-  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
-                             N->getLocationContext());
-  return new PathDiagnosticEventPiece(Pos, OS.str(), true, nullptr);
-}
-
-void ObjCGenericsChecker::checkDeadSymbols(SymbolReaper &SR,
-                                           CheckerContext &C) const {
-  if (!SR.hasDeadSymbols())
-    return;
-
-  ProgramStateRef State = C.getState();
-  TypeParamMapTy TyParMap = State->get<TypeParamMap>();
-  for (TypeParamMapTy::iterator I = TyParMap.begin(), E = TyParMap.end();
-       I != E; ++I) {
-    if (SR.isDead(I->first)) {
-      State = State->remove<TypeParamMap>(I->first);
-    }
-  }
-}
-
-static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl(
-    const ObjCObjectPointerType *From, const ObjCObjectPointerType *To,
-    const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) {
-  // Checking if from and to are the same classes modulo specialization.
-  if (From->getInterfaceDecl()->getCanonicalDecl() ==
-      To->getInterfaceDecl()->getCanonicalDecl()) {
-    if (To->isSpecialized()) {
-      assert(MostInformativeCandidate->isSpecialized());
-      return MostInformativeCandidate;
-    }
-    return From;
-  }
-  const auto *SuperOfTo =
-      To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>();
-  assert(SuperOfTo);
-  QualType SuperPtrOfToQual =
-      C.getObjCObjectPointerType(QualType(SuperOfTo, 0));
-  const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>();
-  if (To->isUnspecialized())
-    return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo,
-                                              C);
-  else
-    return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo,
-                                              MostInformativeCandidate, C);
-}
-
-/// Get the most derived class if From that do not loose information about type
-/// parameters. To has to be a subclass of From. From has to be specialized.
-static const ObjCObjectPointerType *
-getMostInformativeDerivedClass(const ObjCObjectPointerType *From,
-                               const ObjCObjectPointerType *To, ASTContext &C) {
-  return getMostInformativeDerivedClassImpl(From, To, To, C);
-}
-
-static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym,
-                                     const ObjCObjectPointerType *const *Old,
-                                     const ObjCObjectPointerType *New,
-                                     ASTContext &C) {
-  if (!Old || C.canAssignObjCInterfaces(*Old, New)) {
-    State = State->set<TypeParamMap>(Sym, New);
-    return true;
-  }
-  return false;
-}
-
-void ObjCGenericsChecker::checkPostStmt(const CastExpr *CE,
-                                        CheckerContext &C) const {
-  if (CE->getCastKind() != CK_BitCast)
-    return;
-
-  QualType OriginType = CE->getSubExpr()->getType();
-  QualType DestType = CE->getType();
-
-  const auto *OrigObjectPtrType = OriginType->getAs<ObjCObjectPointerType>();
-  const auto *DestObjectPtrType = DestType->getAs<ObjCObjectPointerType>();
-
-  if (!OrigObjectPtrType || !DestObjectPtrType)
-    return;
-
-  ASTContext &ASTCtxt = C.getASTContext();
-
-  // This checker detects the subtyping relationships using the assignment
-  // rules. In order to be able to do this the kindofness must be stripped
-  // first. The checker treats every type as kindof type anyways: when the
-  // tracked type is the subtype of the static type it tries to look up the
-  // methods in the tracked type first.
-  OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
-  DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
-
-  const ObjCObjectType *OrigObjectType = OrigObjectPtrType->getObjectType();
-  const ObjCObjectType *DestObjectType = DestObjectPtrType->getObjectType();
-
-  if (OrigObjectType->isUnspecialized() && DestObjectType->isUnspecialized())
-    return;
-
-  ProgramStateRef State = C.getState();
-  SymbolRef Sym = State->getSVal(CE, C.getLocationContext()).getAsSymbol();
-  if (!Sym)
-    return;
-
-  // Check which assignments are legal.
-  bool OrigToDest =
-      ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType);
-  bool DestToOrig =
-      ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType);
-  const ObjCObjectPointerType *const *TrackedType =
-      State->get<TypeParamMap>(Sym);
-
-  // If OrigObjectType could convert to DestObjectType, this could be an
-  // implicit cast. Do not treat that cast as explicit in that case.
-  if (isa<ExplicitCastExpr>(CE) && !OrigToDest) {
-    if (DestToOrig) {
-      // Trust explicit downcasts.
-      // However a downcast may also lose information. E. g.:
-      //   MutableMap<T, U> : Map
-      // The downcast to MutableMap loses the information about the types of the
-      // Map (due to the type parameters are not being forwarded to Map), and in
-      // general there is no way to recover that information from the
-      // declaration. In order to have to most information, lets find the most
-      // derived type that has all the type parameters forwarded.
-      const ObjCObjectPointerType *WithMostInfo =
-          getMostInformativeDerivedClass(OrigObjectPtrType, DestObjectPtrType,
-                                         C.getASTContext());
-      if (storeWhenMoreInformative(State, Sym, TrackedType, WithMostInfo,
-                                   ASTCtxt))
-        C.addTransition(State);
-      return;
-    }
-    // Mismatched types. If the DestType specialized, store it. Forget the
-    // tracked type otherwise.
-    if (DestObjectPtrType->isSpecialized()) {
-      State = State->set<TypeParamMap>(Sym, DestObjectPtrType);
-      C.addTransition(State);
-    } else if (TrackedType) {
-      State = State->remove<TypeParamMap>(Sym);
-      C.addTransition(State);
-    }
-    return;
-  }
-
-  // Handle implicit casts and explicit upcasts.
-
-  if (DestObjectType->isUnspecialized()) {
-    assert(OrigObjectType->isSpecialized());
-    // In case we already have some type information for this symbol from a
-    // Specialized -> Specialized conversion, do not record the OrigType,
-    // because it might contain less type information than the tracked type.
-    if (!TrackedType) {
-      State = State->set<TypeParamMap>(Sym, OrigObjectPtrType);
-      C.addTransition(State);
-    }
-    return;
-  }
-
-  // The destination type is specialized.
-
-  // The tracked type should be the sub or super class of the static destination
-  // type. When an (implicit) upcast or a downcast happens according to static
-  // types, and there is no subtyping relationship between the tracked and the
-  // static destination types, it indicates an error.
-  if (TrackedType &&
-      !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) &&
-      !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) {
-    static CheckerProgramPointTag IllegalConv(this, "IllegalConversion");
-    ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &IllegalConv);
-    reportBug(*TrackedType, DestObjectPtrType, N, Sym, C);
-    return;
-  }
-
-  if (OrigToDest && !DestToOrig) {
-    // When upcast happens, store the type with the most information about the
-    // type parameters.
-    const ObjCObjectPointerType *WithMostInfo = getMostInformativeDerivedClass(
-        DestObjectPtrType, OrigObjectPtrType, ASTCtxt);
-    if (storeWhenMoreInformative(State, Sym, TrackedType, WithMostInfo,
-                                 ASTCtxt))
-      C.addTransition(State);
-    return;
-  }
-
-  // Downcast happens.
-
-  // Trust tracked type on unspecialized value -> specialized implicit
-  // downcasts.
-  if (storeWhenMoreInformative(State, Sym, TrackedType, DestObjectPtrType,
-                               ASTCtxt)) {
-    C.addTransition(State);
-  }
-}
-
-static const Expr *stripCastsAndSugar(const Expr *E) {
-  E = E->IgnoreParenImpCasts();
-  if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
-    E = POE->getSyntacticForm()->IgnoreParenImpCasts();
-  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
-    E = OVE->getSourceExpr()->IgnoreParenImpCasts();
-  return E;
-}
-
-// This callback is used to infer the types for Class variables. This info is
-// used later to validate messages that sent to classes. Class variables are
-// initialized with by invoking the 'class' method on a class.
-void ObjCGenericsChecker::checkPostObjCMessage(const ObjCMethodCall &M,
-                                               CheckerContext &C) const {
-  const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
-
-  SymbolRef Sym = M.getReturnValue().getAsSymbol();
-  if (!Sym)
-    return;
-
-  Selector Sel = MessageExpr->getSelector();
-  // We are only interested in cases where the class method is invoked on a
-  // class. This method is provided by the runtime and available on all classes.
-  if (MessageExpr->getReceiverKind() != ObjCMessageExpr::Class ||
-      Sel.getAsString() != "class")
-    return;
-
-  QualType ReceiverType = MessageExpr->getClassReceiver();
-  const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>();
-  QualType ReceiverClassPointerType =
-      C.getASTContext().getObjCObjectPointerType(
-          QualType(ReceiverClassType, 0));
-
-  if (!ReceiverClassType->isSpecialized())
-    return;
-  const auto *InferredType =
-      ReceiverClassPointerType->getAs<ObjCObjectPointerType>();
-  assert(InferredType);
-
-  ProgramStateRef State = C.getState();
-  State = State->set<TypeParamMap>(Sym, InferredType);
-  C.addTransition(State);
-}
-
-static bool isObjCTypeParamDependent(QualType Type) {
-  // It is illegal to typedef parameterized types inside an interface. Therfore
-  // an
-  // Objective-C type can only be dependent on a type parameter when the type
-  // parameter structurally present in the type itself.
-  class IsObjCTypeParamDependentTypeVisitor
-      : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
-  public:
-    IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
-    bool VisitTypedefType(const TypedefType *Type) {
-      if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
-        Result = true;
-        return false;
-      }
-      return true;
-    }
-    bool getResult() { return Result; }
-
-  private:
-    bool Result;
-  };
-
-  IsObjCTypeParamDependentTypeVisitor Visitor;
-  Visitor.TraverseType(Type);
-  return Visitor.getResult();
-}
-
-// A method might not be available in the interface indicated by the static
-// type. However it might be available in the tracked type. In order to properly
-// substitute the type parameters we need the declaration context of the method.
-// The more specialized the enclosing class of the method is, the more likely
-// that the parameter substitution will be successful.
-static const ObjCMethodDecl *
-findMethodDecl(const ObjCMessageExpr *MessageExpr,
-               const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) {
-  const ObjCMethodDecl *Method = nullptr;
-
-  QualType ReceiverType = MessageExpr->getReceiverType();
-  const auto *ReceiverObjectPtrType =
-      ReceiverType->getAs<ObjCObjectPointerType>();
-
-  // Do this "devirtualization" on instance and class methods only. Trust the
-  // static type on super and super class calls.
-  if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance ||
-      MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) {
-    // When the receiver type is id, Class, or some super class of the tracked
-    // type, look up the method in the tracked type, not in the receiver type.
-    // This way we preserve more information.
-    if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() ||
-        ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) {
-      const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl();
-      // The method might not be found.
-      Selector Sel = MessageExpr->getSelector();
-      Method = InterfaceDecl->lookupInstanceMethod(Sel);
-      if (!Method)
-        Method = InterfaceDecl->lookupClassMethod(Sel);
-    }
-  }
-
-  // Fallback to statick method lookup when the one based on the tracked type
-  // failed.
-  return Method ? Method : MessageExpr->getMethodDecl();
-}
-
-// When the receiver has a tracked type, use that type to validate the
-// argumments of the message expression and the return value.
-void ObjCGenericsChecker::checkPreObjCMessage(const ObjCMethodCall &M,
-                                              CheckerContext &C) const {
-  ProgramStateRef State = C.getState();
-  SymbolRef Sym = M.getReceiverSVal().getAsSymbol();
-  if (!Sym)
-    return;
-
-  const ObjCObjectPointerType *const *TrackedType =
-      State->get<TypeParamMap>(Sym);
-  if (!TrackedType)
-    return;
-
-  // Get the type arguments from tracked type and substitute type arguments
-  // before do the semantic check.
-
-  ASTContext &ASTCtxt = C.getASTContext();
-  const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
-  const ObjCMethodDecl *Method =
-      findMethodDecl(MessageExpr, *TrackedType, ASTCtxt);
-
-  // It is possible to call non-existent methods in Obj-C.
-  if (!Method)
-    return;
-
-  Optional<ArrayRef<QualType>> TypeArgs =
-      (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
-  // This case might happen when there is an unspecialized override of a
-  // specialized method.
-  if (!TypeArgs)
-    return;
-
-  for (unsigned i = 0; i < Method->param_size(); i++) {
-    const Expr *Arg = MessageExpr->getArg(i);
-    const ParmVarDecl *Param = Method->parameters()[i];
-
-    QualType OrigParamType = Param->getType();
-    if (!isObjCTypeParamDependent(OrigParamType))
-      continue;
-
-    QualType ParamType = OrigParamType.substObjCTypeArgs(
-        ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter);
-    // Check if it can be assigned
-    const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>();
-    const auto *ArgObjectPtrType =
-        stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>();
-    if (!ParamObjectPtrType || !ArgObjectPtrType)
-      continue;
-
-    // Check if we have more concrete tracked type that is not a super type of
-    // the static argument type.
-    SVal ArgSVal = M.getArgSVal(i);
-    SymbolRef ArgSym = ArgSVal.getAsSymbol();
-    if (ArgSym) {
-      const ObjCObjectPointerType *const *TrackedArgType =
-          State->get<TypeParamMap>(ArgSym);
-      if (TrackedArgType &&
-          ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) {
-        ArgObjectPtrType = *TrackedArgType;
-      }
-    }
-
-    // Warn when argument is incompatible with the parameter.
-    if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType,
-                                         ArgObjectPtrType)) {
-      static CheckerProgramPointTag Tag(this, "ArgTypeMismatch");
-      ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
-      reportBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
-      return;
-    }
-  }
-  QualType StaticResultType = Method->getReturnType();
-  // Check whether the result type was a type parameter.
-  bool IsDeclaredAsInstanceType =
-      StaticResultType == ASTCtxt.getObjCInstanceType();
-  if (!isObjCTypeParamDependent(StaticResultType) && !IsDeclaredAsInstanceType)
-    return;
-
-  QualType ResultType = Method->getReturnType().substObjCTypeArgs(
-      ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Result);
-  if (IsDeclaredAsInstanceType)
-    ResultType = QualType(*TrackedType, 0);
-
-  const Stmt *Parent =
-      C.getCurrentAnalysisDeclContext()->getParentMap().getParent(MessageExpr);
-  if (M.getMessageKind() != OCM_Message) {
-    // Properties and subscripts are not direct parents.
-    Parent =
-        C.getCurrentAnalysisDeclContext()->getParentMap().getParent(Parent);
-  }
-
-  const auto *ImplicitCast = dyn_cast_or_null<ImplicitCastExpr>(Parent);
-  if (!ImplicitCast || ImplicitCast->getCastKind() != CK_BitCast)
-    return;
-
-  const auto *ExprTypeAboveCast =
-      ImplicitCast->getType()->getAs<ObjCObjectPointerType>();
-  const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>();
-
-  if (!ExprTypeAboveCast || !ResultPtrType)
-    return;
-
-  // Only warn on unrelated types to avoid too many false positives on
-  // downcasts.
-  if (!ASTCtxt.canAssignObjCInterfaces(ExprTypeAboveCast, ResultPtrType) &&
-      !ASTCtxt.canAssignObjCInterfaces(ResultPtrType, ExprTypeAboveCast)) {
-    static CheckerProgramPointTag Tag(this, "ReturnTypeMismatch");
-    ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
-    reportBug(ResultPtrType, ExprTypeAboveCast, N, Sym, C);
-    return;
-  }
-}
-
-/// Register checker.
-void ento::registerObjCGenericsChecker(CheckerManager &mgr) {
-  mgr.registerChecker<ObjCGenericsChecker>();
-}
Index: lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -7,11 +7,23 @@
 //
 //===----------------------------------------------------------------------===//
 //
+// This file contains two checkers. One helps the static analyzer core to track
+// types, the other does type inference on Obj-C generics and report type
+// errors.
+//
+// Dynamic Type Propagation:
 // This checker defines the rules for dynamic type gathering and propagation.
 //
+// Generics Checker:
+// This checker tries to find type errors that the compiler is not able to catch
+// due to the implicit conversions that were introduced for backward
+// compatibility.
+//
 //===----------------------------------------------------------------------===//
 
 #include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
@@ -23,23 +35,74 @@
 using namespace clang;
 using namespace ento;
 
+// ProgramState trait - a map from symbol to its specialized type to trak type
+// information that is related to generics.
+REGISTER_MAP_WITH_PROGRAMSTATE(TypeParamMap, SymbolRef,
+                               const ObjCObjectPointerType *)
+
 namespace {
-class DynamicTypePropagation:
-    public Checker< check::PreCall,
-                    check::PostCall,
-                    check::PostStmt<ImplicitCastExpr>,
-                    check::PostStmt<CXXNewExpr> > {
-  const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
-                                                    CheckerContext &C) const;
-
-  /// \brief Return a better dynamic type if one can be derived from the cast.
-  const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
-                                                 CheckerContext &C) const;
+class DynamicTypePropagation
+    : public Checker<check::PreCall, check::PostCall, check::PreObjCMessage,
+                     check::PostObjCMessage, check::DeadSymbols,
+                     check::PostStmt<CastExpr>, check::PostStmt<CXXNewExpr>> {
+  mutable std::unique_ptr<BugType> BT;
+
+  void initBugType() const {
+    if (!BT)
+      BT.reset(
+          new BugType(this, "Generics", categories::CoreFoundationObjectiveC));
+  }
+
+  class GenericsBugVisitor : public BugReporterVisitorImpl<GenericsBugVisitor> {
+  public:
+    GenericsBugVisitor(SymbolRef S) : Sym(S) {}
+
+    void Profile(llvm::FoldingSetNodeID &ID) const override {
+      static int X = 0;
+      ID.AddPointer(&X);
+      ID.AddPointer(Sym);
+    }
+
+    PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+                                   const ExplodedNode *PrevN,
+                                   BugReporterContext &BRC,
+                                   BugReport &BR) override;
+
+  private:
+    // The tracked symbol.
+    SymbolRef Sym;
+  };
+
+  void reportGenericsBug(const ObjCObjectPointerType *From,
+                         const ObjCObjectPointerType *To, ExplodedNode *N,
+                         SymbolRef Sym, CheckerContext &C,
+                         const Stmt *ReportedNode = nullptr) const {
+    initBugType();
+    SmallString<64> Buf;
+    llvm::raw_svector_ostream OS(Buf);
+    OS << "Incompatible pointer types assigning to '";
+    QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine());
+    OS << "' from '";
+    QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine());
+    OS << "'";
+    std::unique_ptr<BugReport> R(new BugReport(*BT, OS.str(), N));
+    R->markInteresting(Sym);
+    R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym));
+    if (ReportedNode)
+      R->addRange(ReportedNode->getSourceRange());
+    C.emitReport(std::move(R));
+  }
+
 public:
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-  void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
   void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const;
+  void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+
+  DefaultBool CheckGenerics;
 };
 }
 
@@ -57,6 +120,98 @@
   return;
 }
 
+static const ObjCObjectType *
+getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
+                                                    CheckerContext &C) {
+  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
+    if (const ObjCObjectType *ObjTy =
+            MsgE->getClassReceiver()->getAs<ObjCObjectType>())
+      return ObjTy;
+  }
+
+  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
+    if (const ObjCObjectType *ObjTy =
+            MsgE->getSuperType()->getAs<ObjCObjectType>())
+      return ObjTy;
+  }
+
+  const Expr *RecE = MsgE->getInstanceReceiver();
+  if (!RecE)
+    return nullptr;
+
+  RecE = RecE->IgnoreParenImpCasts();
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
+    const StackFrameContext *SFCtx = C.getStackFrame();
+    // Are we calling [self alloc]? If this is self, get the type of the
+    // enclosing ObjC class.
+    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
+      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
+        if (const ObjCObjectType *ObjTy = dyn_cast<ObjCObjectType>(
+                MD->getClassInterface()->getTypeForDecl()))
+          return ObjTy;
+    }
+  }
+  return nullptr;
+}
+
+/// \brief Return a better dynamic type if one can be derived from the cast.
+///
+/// Return a better dynamic type if one can be derived from the cast.
+/// Compare the current dynamic type of the region and the new type to which we
+/// are casting. If the new type is lower in the inheritance hierarchy, pick it.
+static const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
+                                               CheckerContext &C) {
+  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
+  assert(ToR);
+
+  // Get the old and new types.
+  const ObjCObjectPointerType *NewTy =
+      CastE->getType()->getAs<ObjCObjectPointerType>();
+  if (!NewTy)
+    return nullptr;
+  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
+  if (OldDTy.isNull()) {
+    return NewTy;
+  }
+  const ObjCObjectPointerType *OldTy = OldDTy->getAs<ObjCObjectPointerType>();
+  if (!OldTy)
+    return nullptr;
+
+  // Id the old type is 'id', the new one is more precise.
+  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
+    return NewTy;
+
+  // Return new if it's a subclass of old.
+  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
+  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
+  if (ToI && FromI && FromI->isSuperClassOf(ToI))
+    return NewTy;
+
+  return nullptr;
+}
+
+/// TODO: Handle explicit casts.
+///       Handle C++ casts.
+///
+/// Precondition: the cast is between ObjCObjectPointers.
+static ExplodedNode *dynamicTypePropagationOnCasts(const CastExpr *CE,
+                                                   ProgramStateRef &State,
+                                                   CheckerContext &C) {
+  // We only track type info for regions.
+  const MemRegion *ToR = C.getSVal(CE).getAsRegion();
+  if (!ToR)
+    return C.getPredecessor();
+
+  if (isa<ExplicitCastExpr>(CE))
+    return C.getPredecessor();
+
+  if (const Type *NewTy = getBetterObjCType(CE, C)) {
+    State = State->setDynamicTypeInfo(ToR, QualType(NewTy, 0));
+    return C.addTransition(State);
+  }
+  return C.getPredecessor();
+}
+
 void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
                                           CheckerContext &C) const {
   if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
@@ -113,7 +268,7 @@
 
     ProgramStateRef State = C.getState();
     const ObjCMethodDecl *D = Msg->getDecl();
-    
+
     if (D && D->hasRelatedResultType()) {
       switch (Msg->getMethodFamily()) {
       default:
@@ -130,7 +285,7 @@
         if (!ObjTy)
           return;
         QualType DynResTy =
-                 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
+            C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
         C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
         break;
       }
@@ -173,25 +328,6 @@
   }
 }
 
-void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
-                                           CheckerContext &C) const {
-  // We only track dynamic type info for regions.
-  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
-  if (!ToR)
-    return;
-
-  switch (CastE->getCastKind()) {
-  default:
-    break;
-  case CK_BitCast:
-    // Only handle ObjCObjects for now.
-    if (const Type *NewTy = getBetterObjCType(CastE, C))
-      C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
-    break;
-  }
-  return;
-}
-
 void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
                                            CheckerContext &C) const {
   if (NewE->isArray())
@@ -201,79 +337,489 @@
   const MemRegion *MR = C.getSVal(NewE).getAsRegion();
   if (!MR)
     return;
-  
+
   C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
                                                    /*CanBeSubclass=*/false));
 }
 
-const ObjCObjectType *
-DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
-                                                    CheckerContext &C) const {
-  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
-    if (const ObjCObjectType *ObjTy
-          = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
-    return ObjTy;
-  }
 
-  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
-    if (const ObjCObjectType *ObjTy
-          = MsgE->getSuperType()->getAs<ObjCObjectType>())
-      return ObjTy;
+PathDiagnosticPiece *DynamicTypePropagation::GenericsBugVisitor::VisitNode(
+    const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
+    BugReport &BR) {
+  ProgramStateRef state = N->getState();
+  ProgramStateRef statePrev = PrevN->getState();
+
+  const ObjCObjectPointerType *const *TrackedType =
+      state->get<TypeParamMap>(Sym);
+  const ObjCObjectPointerType *const *TrackedTypePrev =
+      statePrev->get<TypeParamMap>(Sym);
+  if (!TrackedType)
+    return nullptr;
+
+  if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
+    return nullptr;
+
+  // Retrieve the associated statement.
+  const Stmt *S = nullptr;
+  ProgramPoint ProgLoc = N->getLocation();
+  if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
+    S = SP->getStmt();
   }
 
-  const Expr *RecE = MsgE->getInstanceReceiver();
-  if (!RecE)
+  if (!S)
     return nullptr;
 
-  RecE= RecE->IgnoreParenImpCasts();
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
-    const StackFrameContext *SFCtx = C.getStackFrame();
-    // Are we calling [self alloc]? If this is self, get the type of the
-    // enclosing ObjC class.
-    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
-      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
-        if (const ObjCObjectType *ObjTy =
-            dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
-          return ObjTy;
+  const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
+
+  SmallString<64> Buf;
+  llvm::raw_svector_ostream OS(Buf);
+  OS << "Type '";
+  QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine());
+  OS << "' is inferred from ";
+
+  if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
+    OS << "explicit cast (from '";
+    QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(),
+                    Qualifiers(), OS, LangOpts, llvm::Twine());
+    OS << "' to '";
+    QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS,
+                    LangOpts, llvm::Twine());
+    OS << "')";
+  } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
+    OS << "implicit cast (from '";
+    QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(),
+                    Qualifiers(), OS, LangOpts, llvm::Twine());
+    OS << "' to '";
+    QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS,
+                    LangOpts, llvm::Twine());
+    OS << "')";
+  } else {
+    OS << "this context";
+  }
+
+  // Generate the extra diagnostic.
+  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+                             N->getLocationContext());
+  return new PathDiagnosticEventPiece(Pos, OS.str(), true, nullptr);
+}
+
+// Clean up the states stored by the generics checker.
+void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR,
+                                              CheckerContext &C) const {
+  if (!SR.hasDeadSymbols())
+    return;
+
+  ProgramStateRef State = C.getState();
+  TypeParamMapTy TyParMap = State->get<TypeParamMap>();
+  for (TypeParamMapTy::iterator I = TyParMap.begin(), E = TyParMap.end();
+       I != E; ++I) {
+    if (SR.isDead(I->first)) {
+      State = State->remove<TypeParamMap>(I->first);
     }
   }
-  return nullptr;
 }
 
-// Return a better dynamic type if one can be derived from the cast.
-// Compare the current dynamic type of the region and the new type to which we
-// are casting. If the new type is lower in the inheritance hierarchy, pick it.
-const ObjCObjectPointerType *
-DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
-                                          CheckerContext &C) const {
-  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
-  assert(ToR);
+static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl(
+    const ObjCObjectPointerType *From, const ObjCObjectPointerType *To,
+    const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) {
+  // Checking if from and to are the same classes modulo specialization.
+  if (From->getInterfaceDecl()->getCanonicalDecl() ==
+      To->getInterfaceDecl()->getCanonicalDecl()) {
+    if (To->isSpecialized()) {
+      assert(MostInformativeCandidate->isSpecialized());
+      return MostInformativeCandidate;
+    }
+    return From;
+  }
+  const auto *SuperOfTo =
+      To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>();
+  assert(SuperOfTo);
+  QualType SuperPtrOfToQual =
+      C.getObjCObjectPointerType(QualType(SuperOfTo, 0));
+  const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>();
+  if (To->isUnspecialized())
+    return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo,
+                                              C);
+  else
+    return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo,
+                                              MostInformativeCandidate, C);
+}
 
-  // Get the old and new types.
-  const ObjCObjectPointerType *NewTy =
-      CastE->getType()->getAs<ObjCObjectPointerType>();
-  if (!NewTy)
-    return nullptr;
-  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
-  if (OldDTy.isNull()) {
-    return NewTy;
+/// Get the most derived class if From that do not loose information about type
+/// parameters. To has to be a subclass of From. From has to be specialized.
+static const ObjCObjectPointerType *
+getMostInformativeDerivedClass(const ObjCObjectPointerType *From,
+                               const ObjCObjectPointerType *To, ASTContext &C) {
+  return getMostInformativeDerivedClassImpl(From, To, To, C);
+}
+
+static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym,
+                                     const ObjCObjectPointerType *const *Old,
+                                     const ObjCObjectPointerType *New,
+                                     ASTContext &C) {
+  if (!Old || C.canAssignObjCInterfaces(*Old, New)) {
+    State = State->set<TypeParamMap>(Sym, New);
+    return true;
   }
-  const ObjCObjectPointerType *OldTy =
-    OldDTy->getAs<ObjCObjectPointerType>();
-  if (!OldTy)
-    return nullptr;
+  return false;
+}
 
-  // Id the old type is 'id', the new one is more precise.
-  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
-    return NewTy;
+void DynamicTypePropagation::checkPostStmt(const CastExpr *CE,
+                                           CheckerContext &C) const {
+  if (CE->getCastKind() != CK_BitCast)
+    return;
 
-  // Return new if it's a subclass of old.
-  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
-  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
-  if (ToI && FromI && FromI->isSuperClassOf(ToI))
-    return NewTy;
+  QualType OriginType = CE->getSubExpr()->getType();
+  QualType DestType = CE->getType();
 
-  return nullptr;
+  const auto *OrigObjectPtrType = OriginType->getAs<ObjCObjectPointerType>();
+  const auto *DestObjectPtrType = DestType->getAs<ObjCObjectPointerType>();
+
+  if (!OrigObjectPtrType || !DestObjectPtrType)
+    return;
+
+  ProgramStateRef State = C.getState();
+  ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C);
+
+  ASTContext &ASTCtxt = C.getASTContext();
+
+  // This checker detects the subtyping relationships using the assignment
+  // rules. In order to be able to do this the kindofness must be stripped
+  // first. The checker treats every type as kindof type anyways: when the
+  // tracked type is the subtype of the static type it tries to look up the
+  // methods in the tracked type first.
+  OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
+  DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
+
+  const ObjCObjectType *OrigObjectType = OrigObjectPtrType->getObjectType();
+  const ObjCObjectType *DestObjectType = DestObjectPtrType->getObjectType();
+
+  // TODO: erase tracked information when there is a cast to unrelated type
+  //       and everything is unspecialized statically.
+  if (OrigObjectType->isUnspecialized() && DestObjectType->isUnspecialized())
+    return;
+
+  SymbolRef Sym = State->getSVal(CE, C.getLocationContext()).getAsSymbol();
+  if (!Sym)
+    return;
+
+  // Check which assignments are legal.
+  bool OrigToDest =
+      ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType);
+  bool DestToOrig =
+      ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType);
+  const ObjCObjectPointerType *const *TrackedType =
+      State->get<TypeParamMap>(Sym);
+
+  // If OrigObjectType could convert to DestObjectType, this could be an
+  // implicit cast. Do not treat that cast as explicit in that case.
+  if (isa<ExplicitCastExpr>(CE) && !OrigToDest) {
+    if (DestToOrig) {
+      // Trust explicit downcasts.
+      // However a downcast may also lose information. E. g.:
+      //   MutableMap<T, U> : Map
+      // The downcast to MutableMap loses the information about the types of the
+      // Map (due to the type parameters are not being forwarded to Map), and in
+      // general there is no way to recover that information from the
+      // declaration. In order to have to most information, lets find the most
+      // derived type that has all the type parameters forwarded.
+      const ObjCObjectPointerType *WithMostInfo =
+          getMostInformativeDerivedClass(OrigObjectPtrType, DestObjectPtrType,
+                                         C.getASTContext());
+      if (storeWhenMoreInformative(State, Sym, TrackedType, WithMostInfo,
+                                   ASTCtxt))
+        C.addTransition(State, AfterTypeProp);
+      return;
+    }
+    // Mismatched types. If the DestType specialized, store it. Forget the
+    // tracked type otherwise.
+    if (DestObjectPtrType->isSpecialized()) {
+      State = State->set<TypeParamMap>(Sym, DestObjectPtrType);
+      C.addTransition(State, AfterTypeProp);
+    } else if (TrackedType) {
+      State = State->remove<TypeParamMap>(Sym);
+      C.addTransition(State, AfterTypeProp);
+    }
+    return;
+  }
+
+  // Handle implicit casts and explicit upcasts.
+
+  if (DestObjectType->isUnspecialized()) {
+    assert(OrigObjectType->isSpecialized());
+    // In case we already have some type information for this symbol from a
+    // Specialized -> Specialized conversion, do not record the OrigType,
+    // because it might contain less type information than the tracked type.
+    if (!TrackedType) {
+      State = State->set<TypeParamMap>(Sym, OrigObjectPtrType);
+      C.addTransition(State, AfterTypeProp);
+    }
+    return;
+  }
+
+  // The destination type is specialized.
+
+  // The tracked type should be the sub or super class of the static destination
+  // type. When an (implicit) upcast or a downcast happens according to static
+  // types, and there is no subtyping relationship between the tracked and the
+  // static destination types, it indicates an error.
+  if (TrackedType &&
+      !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) &&
+      !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) {
+    static CheckerProgramPointTag IllegalConv(this, "IllegalConversion");
+    ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv);
+    reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C);
+    return;
+  }
+
+  if (OrigToDest && !DestToOrig) {
+    // When upcast happens, store the type with the most information about the
+    // type parameters.
+    const ObjCObjectPointerType *WithMostInfo = getMostInformativeDerivedClass(
+        DestObjectPtrType, OrigObjectPtrType, ASTCtxt);
+    if (storeWhenMoreInformative(State, Sym, TrackedType, WithMostInfo,
+                                 ASTCtxt))
+      C.addTransition(State, AfterTypeProp);
+    return;
+  }
+
+  // Downcast happens.
+
+  // Trust tracked type on unspecialized value -> specialized implicit
+  // downcasts.
+  if (storeWhenMoreInformative(State, Sym, TrackedType, DestObjectPtrType,
+                               ASTCtxt)) {
+    C.addTransition(State, AfterTypeProp);
+  }
+}
+
+static const Expr *stripCastsAndSugar(const Expr *E) {
+  E = E->IgnoreParenImpCasts();
+  if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+    E = POE->getSyntacticForm()->IgnoreParenImpCasts();
+  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+    E = OVE->getSourceExpr()->IgnoreParenImpCasts();
+  return E;
+}
+
+// This callback is used to infer the types for Class variables. This info is
+// used later to validate messages that sent to classes. Class variables are
+// initialized with by invoking the 'class' method on a class.
+void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
+                                                  CheckerContext &C) const {
+  const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
+
+  SymbolRef Sym = M.getReturnValue().getAsSymbol();
+  if (!Sym)
+    return;
+
+  Selector Sel = MessageExpr->getSelector();
+  // We are only interested in cases where the class method is invoked on a
+  // class. This method is provided by the runtime and available on all classes.
+  if (MessageExpr->getReceiverKind() != ObjCMessageExpr::Class ||
+      Sel.getAsString() != "class")
+    return;
+
+  QualType ReceiverType = MessageExpr->getClassReceiver();
+  const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>();
+  QualType ReceiverClassPointerType =
+      C.getASTContext().getObjCObjectPointerType(
+          QualType(ReceiverClassType, 0));
+
+  if (!ReceiverClassType->isSpecialized())
+    return;
+  const auto *InferredType =
+      ReceiverClassPointerType->getAs<ObjCObjectPointerType>();
+  assert(InferredType);
+
+  ProgramStateRef State = C.getState();
+  State = State->set<TypeParamMap>(Sym, InferredType);
+  C.addTransition(State);
+}
+
+static bool isObjCTypeParamDependent(QualType Type) {
+  // It is illegal to typedef parameterized types inside an interface. Therfore
+  // an
+  // Objective-C type can only be dependent on a type parameter when the type
+  // parameter structurally present in the type itself.
+  class IsObjCTypeParamDependentTypeVisitor
+      : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
+  public:
+    IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
+    bool VisitTypedefType(const TypedefType *Type) {
+      if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
+        Result = true;
+        return false;
+      }
+      return true;
+    }
+    bool getResult() { return Result; }
+
+  private:
+    bool Result;
+  };
+
+  IsObjCTypeParamDependentTypeVisitor Visitor;
+  Visitor.TraverseType(Type);
+  return Visitor.getResult();
+}
+
+// A method might not be available in the interface indicated by the static
+// type. However it might be available in the tracked type. In order to properly
+// substitute the type parameters we need the declaration context of the method.
+// The more specialized the enclosing class of the method is, the more likely
+// that the parameter substitution will be successful.
+static const ObjCMethodDecl *
+findMethodDecl(const ObjCMessageExpr *MessageExpr,
+               const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) {
+  const ObjCMethodDecl *Method = nullptr;
+
+  QualType ReceiverType = MessageExpr->getReceiverType();
+  const auto *ReceiverObjectPtrType =
+      ReceiverType->getAs<ObjCObjectPointerType>();
+
+  // Do this "devirtualization" on instance and class methods only. Trust the
+  // static type on super and super class calls.
+  if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance ||
+      MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) {
+    // When the receiver type is id, Class, or some super class of the tracked
+    // type, look up the method in the tracked type, not in the receiver type.
+    // This way we preserve more information.
+    if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() ||
+        ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) {
+      const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl();
+      // The method might not be found.
+      Selector Sel = MessageExpr->getSelector();
+      Method = InterfaceDecl->lookupInstanceMethod(Sel);
+      if (!Method)
+        Method = InterfaceDecl->lookupClassMethod(Sel);
+    }
+  }
+
+  // Fallback to statick method lookup when the one based on the tracked type
+  // failed.
+  return Method ? Method : MessageExpr->getMethodDecl();
+}
+
+// When the receiver has a tracked type, use that type to validate the
+// argumments of the message expression and the return value.
+void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M,
+                                                 CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SymbolRef Sym = M.getReceiverSVal().getAsSymbol();
+  if (!Sym)
+    return;
+
+  const ObjCObjectPointerType *const *TrackedType =
+      State->get<TypeParamMap>(Sym);
+  if (!TrackedType)
+    return;
+
+  // Get the type arguments from tracked type and substitute type arguments
+  // before do the semantic check.
+
+  ASTContext &ASTCtxt = C.getASTContext();
+  const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
+  const ObjCMethodDecl *Method =
+      findMethodDecl(MessageExpr, *TrackedType, ASTCtxt);
+
+  // It is possible to call non-existent methods in Obj-C.
+  if (!Method)
+    return;
+
+  Optional<ArrayRef<QualType>> TypeArgs =
+      (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
+  // This case might happen when there is an unspecialized override of a
+  // specialized method.
+  if (!TypeArgs)
+    return;
+
+  for (unsigned i = 0; i < Method->param_size(); i++) {
+    const Expr *Arg = MessageExpr->getArg(i);
+    const ParmVarDecl *Param = Method->parameters()[i];
+
+    QualType OrigParamType = Param->getType();
+    if (!isObjCTypeParamDependent(OrigParamType))
+      continue;
+
+    QualType ParamType = OrigParamType.substObjCTypeArgs(
+        ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter);
+    // Check if it can be assigned
+    const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>();
+    const auto *ArgObjectPtrType =
+        stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>();
+    if (!ParamObjectPtrType || !ArgObjectPtrType)
+      continue;
+
+    // Check if we have more concrete tracked type that is not a super type of
+    // the static argument type.
+    SVal ArgSVal = M.getArgSVal(i);
+    SymbolRef ArgSym = ArgSVal.getAsSymbol();
+    if (ArgSym) {
+      const ObjCObjectPointerType *const *TrackedArgType =
+          State->get<TypeParamMap>(ArgSym);
+      if (TrackedArgType &&
+          ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) {
+        ArgObjectPtrType = *TrackedArgType;
+      }
+    }
+
+    // Warn when argument is incompatible with the parameter.
+    if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType,
+                                         ArgObjectPtrType)) {
+      static CheckerProgramPointTag Tag(this, "ArgTypeMismatch");
+      ExplodedNode *N = C.addTransition(State, &Tag);
+      reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
+      return;
+    }
+  }
+  QualType StaticResultType = Method->getReturnType();
+  // Check whether the result type was a type parameter.
+  bool IsDeclaredAsInstanceType =
+      StaticResultType == ASTCtxt.getObjCInstanceType();
+  if (!isObjCTypeParamDependent(StaticResultType) && !IsDeclaredAsInstanceType)
+    return;
+
+  QualType ResultType = Method->getReturnType().substObjCTypeArgs(
+      ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Result);
+  if (IsDeclaredAsInstanceType)
+    ResultType = QualType(*TrackedType, 0);
+
+  const Stmt *Parent =
+      C.getCurrentAnalysisDeclContext()->getParentMap().getParent(MessageExpr);
+  if (M.getMessageKind() != OCM_Message) {
+    // Properties and subscripts are not direct parents.
+    Parent =
+        C.getCurrentAnalysisDeclContext()->getParentMap().getParent(Parent);
+  }
+
+  const auto *ImplicitCast = dyn_cast_or_null<ImplicitCastExpr>(Parent);
+  if (!ImplicitCast || ImplicitCast->getCastKind() != CK_BitCast)
+    return;
+
+  const auto *ExprTypeAboveCast =
+      ImplicitCast->getType()->getAs<ObjCObjectPointerType>();
+  const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>();
+
+  if (!ExprTypeAboveCast || !ResultPtrType)
+    return;
+
+  // Only warn on unrelated types to avoid too many false positives on
+  // downcasts.
+  if (!ASTCtxt.canAssignObjCInterfaces(ExprTypeAboveCast, ResultPtrType) &&
+      !ASTCtxt.canAssignObjCInterfaces(ResultPtrType, ExprTypeAboveCast)) {
+    static CheckerProgramPointTag Tag(this, "ReturnTypeMismatch");
+    ExplodedNode *N = C.addTransition(State, &Tag);
+    reportGenericsBug(ResultPtrType, ExprTypeAboveCast, N, Sym, C);
+    return;
+  }
+}
+
+/// Register checkers.
+void ento::registerObjCGenericsChecker(CheckerManager &mgr) {
+  DynamicTypePropagation *checker =
+      mgr.registerChecker<DynamicTypePropagation>();
+  checker->CheckGenerics = true;
 }
 
 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td
+++ lib/StaticAnalyzer/Checkers/Checkers.td
@@ -454,7 +454,7 @@
 
 def ObjCGenericsChecker : Checker<"ObjCGenerics">,
   HelpText<"Check for incorrect usages of parameterized types.">,
-  DescFile<"ObjCGenericsChecker.cpp">;
+  DescFile<"DynamicTypePropagation.cpp">;
 
 def NonLocalizedStringChecker : Checker<"NonLocalizedStringChecker">,
   HelpText<"Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings">,
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -52,7 +52,6 @@
   ObjCAtSyncChecker.cpp
   ObjCContainersASTChecker.cpp
   ObjCContainersChecker.cpp
-  ObjCGenericsChecker.cpp
   ObjCMissingSuperCallChecker.cpp
   ObjCSelfInitChecker.cpp
   ObjCUnusedIVarsChecker.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to