Index: lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -776,31 +776,27 @@ const LocationContext *LCtx = C.getLocationContext(); - // Process OSDynamicCast: should just return the first argument. - // For now, tresting the cast as a no-op, and disregarding the case where - // the output becomes null due to the type mismatch. - if (FD->getNameAsString() == "safeMetaCast") { - state = state->BindExpr(CE, LCtx, - state->getSVal(CE->getArg(0), LCtx)); - C.addTransition(state); - return true; - } - // See if it's one of the specific functions we know how to eval. if (!SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation)) return false; // Bind the return value. - SVal RetVal = state->getSVal(CE->getArg(0), LCtx); - if (RetVal.isUnknown() || - (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { + // For now, all the functions which we can evaluate and which take + // at least one argument are identities. + if (CE->getNumArgs() >= 1) { + SVal RetVal = state->getSVal(CE->getArg(0), LCtx); + // If the receiver is unknown or the function has // 'rc_ownership_trusted_implementation' annotate attribute, conjure a // return value. - SValBuilder &SVB = C.getSValBuilder(); - RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); + if (RetVal.isUnknown() || + (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { + SValBuilder &SVB = C.getSValBuilder(); + RetVal = + SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); + } + state = state->BindExpr(CE, LCtx, RetVal, false); } - state = state->BindExpr(CE, LCtx, RetVal, false); C.addTransition(state); return true; Index: lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -102,9 +102,6 @@ return getPersistentStopSummary(); } - // [PR 3337] Use 'getAs' to strip away any typedefs on the - // function's type. - const FunctionType *FT = FD->getType()->getAs(); const IdentifierInfo *II = FD->getIdentifier(); if (!II) return getDefaultSummary(); @@ -115,7 +112,8 @@ // down below. FName = FName.substr(FName.find_first_not_of('_')); - // Inspect the result type. + // Inspect the result type. Strip away any typedefs. + const auto *FT = FD->getType()->getAs(); QualType RetTy = FT->getReturnType(); std::string RetTyName = RetTy.getAsString(); @@ -506,12 +504,6 @@ bool RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD, bool &hasTrustedImplementationAnnotation) { - // For now, we're only handling the functions that return aliases of their - // arguments: CFRetain (and its families). - // Eventually we should add other functions we can model entirely, - // such as CFRelease, which don't invalidate their arguments or globals. - if (CE->getNumArgs() != 1) - return false; IdentifierInfo *II = FD->getIdentifier(); if (!II) @@ -533,6 +525,13 @@ return isRetain(FD, FName) || isAutorelease(FD, FName) || isMakeCollectable(FName); + // Process OSDynamicCast: should just return the first argument. + // For now, treating the cast as a no-op, and disregarding the case where + // the output becomes null due to the type mismatch. + if (TrackOSObjects && FName == "safeMetaCast") { + return true; + } + const FunctionDecl* FDD = FD->getDefinition(); if (FDD && isTrustedReferenceCountImplementation(FDD)) { hasTrustedImplementationAnnotation = true; @@ -540,6 +539,12 @@ } } + if (const auto *MD = dyn_cast(FD)) { + const CXXRecordDecl *Parent = MD->getParent(); + if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) + return FName == "release" || FName == "retain"; + } + return false; } Index: test/Analysis/osobject-retain-release.cpp =================================================================== --- test/Analysis/osobject-retain-release.cpp +++ test/Analysis/osobject-retain-release.cpp @@ -9,7 +9,7 @@ struct OSObject { virtual void retain(); - virtual void release(); + virtual void release() {}; virtual ~OSObject(){} static OSObject *generateObject(int);