diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index b8e43325da04c..a418c82f5a017 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -626,7 +626,7 @@ static bool isObjCTypeParamDependent(QualType Type) { : 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; @@ -727,6 +727,37 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, if (!Method) return; + // If the method is declared on a class that has a non-invariant + // type parameter, don't warn about parameter mismatches after performing + // substitution. This prevents warning when the programmer has purposely + // casted the receiver to a super type or unspecialized type but the analyzer + // has a more precise tracked type than the programmer intends at the call + // site. + // + // For example, consider NSArray (which has a covariant type parameter) + // and NSMutableArray (a subclass of NSArray where the type parameter is + // invariant): + // NSMutableArray *a = [[NSMutableArray<NSString *> alloc] init; + // + // [a containsObject:number]; // Safe: -containsObject is defined on NSArray. + // NSArray<NSObject *> *other = [a arrayByAddingObject:number] // Safe + // + // [a addObject:number] // Unsafe: -addObject: is defined on NSMutableArray + // + + const ObjCInterfaceDecl *Interface = Method->getClassInterface(); + if (!Interface) + return; + + ObjCTypeParamList *TypeParams = Interface->getTypeParamList(); + if (!TypeParams) + return; + + for (ObjCTypeParamDecl *TypeParam : *TypeParams) { + if (TypeParam->getVariance() != ObjCTypeParamVariance::Invariant) + return; + } + Optional<ArrayRef<QualType>> TypeArgs = (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); // This case might happen when there is an unspecialized override of a @@ -909,12 +940,7 @@ PathDiagnosticPiece *DynamicTypePropagation::GenericsBugVisitor::VisitNode( 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 Stmt *S = PathDiagnosticLocation::getStmt(N); if (!S) return nullptr; |
