Skip to content

Commit c40a10d

Browse files
committed
[analyzer] ObjCGenerics: Warn only on mismatch for invariant type parameters
On a method call, the ObjCGenerics checker uses the type tracked by DynamicTypePropagation for the receiver to to infer substituted parmeter types for the called methods and warns when the argument type does not match the parameter. Unfortunately, using the tracked type can result in false positives when the receiver has a non-invariant type parameter and has been intentionally upcast. For example, becaue NSArray's type parameter is covaraint, the following code is perfectly safe: NSArray<NSString *> *allStrings = ... NSDate *date = ...; NSArray<NSObject *> *allObjects = allStrings; NSArray<NSObject *> *moreObjects = [allObjects arrayByAddingObject:date]; but the checker currently warns that the date parameter is not an NSString *. To avoid this kind of false positive, the checker will now only warn when the class defining the called method has only invariant type parameters. rdar://problem/28803951 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@288677 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 96d53fe commit c40a10d

File tree

2 files changed

+6262
-6179
lines changed

2 files changed

+6262
-6179
lines changed

lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,37 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M,
727727
if (!Method)
728728
return;
729729

730+
// If the method is declared on a class that has a non-invariant
731+
// type parameter, don't warn about parameter mismatches after performing
732+
// substitution. This prevents warning when the programmer has purposely
733+
// casted the receiver to a super type or unspecialized type but the analyzer
734+
// has a more precise tracked type than the programmer intends at the call
735+
// site.
736+
//
737+
// For example, consider NSArray (which has a covariant type parameter)
738+
// and NSMutableArray (a subclass of NSArray where the type parameter is
739+
// invariant):
740+
// NSMutableArray *a = [[NSMutableArray<NSString *> alloc] init;
741+
//
742+
// [a containsObject:number]; // Safe: -containsObject is defined on NSArray.
743+
// NSArray<NSObject *> *other = [a arrayByAddingObject:number] // Safe
744+
//
745+
// [a addObject:number] // Unsafe: -addObject: is defined on NSMutableArray
746+
//
747+
748+
const ObjCInterfaceDecl *Interface = Method->getClassInterface();
749+
if (!Interface)
750+
return;
751+
752+
ObjCTypeParamList *TypeParams = Interface->getTypeParamList();
753+
if (!TypeParams)
754+
return;
755+
756+
for (ObjCTypeParamDecl *TypeParam : *TypeParams) {
757+
if (TypeParam->getVariance() != ObjCTypeParamVariance::Invariant)
758+
return;
759+
}
760+
730761
Optional<ArrayRef<QualType>> TypeArgs =
731762
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
732763
// This case might happen when there is an unspecialized override of a

0 commit comments

Comments
 (0)