mirror of https://github.com/microsoft/clang.git
[analyzer] Extend ObjCAutoreleaseWriteChecker to catch block declarations with autoreleasing variables
Differential Revision: https://reviews.llvm.org/D46984 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332546 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9a64e8cc61
commit
08472b552c
|
@ -115,14 +115,16 @@ static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR,
|
|||
QualType Ty = PVD->getType();
|
||||
if (Ty->getPointeeType().getObjCLifetime() != Qualifiers::OCL_Autoreleasing)
|
||||
return;
|
||||
const char *WarningMsg = "Write to";
|
||||
const char *ActionMsg = "Write to";
|
||||
const auto *MarkedStmt = Match.getNodeAs<Expr>(ProblematicWriteBind);
|
||||
bool IsCapture = false;
|
||||
|
||||
// Prefer to warn on write, but if not available, warn on capture.
|
||||
if (!MarkedStmt) {
|
||||
MarkedStmt = Match.getNodeAs<Expr>(CapturedBind);
|
||||
assert(MarkedStmt);
|
||||
WarningMsg = "Capture of";
|
||||
ActionMsg = "Capture of";
|
||||
IsCapture = true;
|
||||
}
|
||||
|
||||
SourceRange Range = MarkedStmt->getSourceRange();
|
||||
|
@ -130,12 +132,14 @@ static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR,
|
|||
MarkedStmt, BR.getSourceManager(), ADC);
|
||||
bool IsMethod = Match.getNodeAs<ObjCMethodDecl>(IsMethodBind) != nullptr;
|
||||
const char *Name = IsMethod ? "method" : "function";
|
||||
|
||||
BR.EmitBasicReport(
|
||||
ADC->getDecl(), Checker,
|
||||
/*Name=*/(llvm::Twine(WarningMsg)
|
||||
/*Name=*/(llvm::Twine(ActionMsg)
|
||||
+ " autoreleasing out parameter inside autorelease pool").str(),
|
||||
/*Category=*/"Memory",
|
||||
(llvm::Twine(WarningMsg) + " autoreleasing out parameter inside " +
|
||||
(llvm::Twine(ActionMsg) + " autoreleasing out parameter " +
|
||||
(IsCapture ? "'" + PVD->getName() + "'" + " " : "") + "inside " +
|
||||
"autorelease pool that may exit before " + Name + " returns; consider "
|
||||
"writing first to a strong local variable declared outside of the block")
|
||||
.str(),
|
||||
|
@ -153,7 +157,7 @@ void ObjCAutoreleaseWriteChecker::checkASTCodeBody(const Decl *D,
|
|||
.bind(ParamBind);
|
||||
|
||||
auto ReferencedParamM =
|
||||
declRefExpr(to(parmVarDecl(DoublePointerParamM)));
|
||||
declRefExpr(to(parmVarDecl(DoublePointerParamM))).bind(CapturedBind);
|
||||
|
||||
// Write into a binded object, e.g. *ParamBind = X.
|
||||
auto WritesIntoM = binaryOperator(
|
||||
|
@ -169,7 +173,7 @@ void ObjCAutoreleaseWriteChecker::checkASTCodeBody(const Decl *D,
|
|||
ignoringParenImpCasts(ReferencedParamM));
|
||||
auto CapturedInParamM = stmt(anyOf(
|
||||
callExpr(ArgumentCaptureM),
|
||||
objcMessageExpr(ArgumentCaptureM))).bind(CapturedBind);
|
||||
objcMessageExpr(ArgumentCaptureM)));
|
||||
|
||||
// WritesIntoM happens inside a block passed as an argument.
|
||||
auto WritesOrCapturesInBlockM = hasAnyArgument(allOf(
|
||||
|
@ -192,7 +196,8 @@ void ObjCAutoreleaseWriteChecker::checkASTCodeBody(const Decl *D,
|
|||
|
||||
auto MatcherM = decl(anyOf(
|
||||
objcMethodDecl(HasParamAndWritesInMarkedFuncM).bind(IsMethodBind),
|
||||
functionDecl(HasParamAndWritesInMarkedFuncM)));
|
||||
functionDecl(HasParamAndWritesInMarkedFuncM),
|
||||
blockDecl(HasParamAndWritesInMarkedFuncM)));
|
||||
|
||||
auto Matches = match(MatcherM, *D, AM.getASTContext());
|
||||
for (BoundNodes Match : Matches)
|
||||
|
|
|
@ -265,5 +265,17 @@ void multipleErrors(NSError *__autoreleasing* error, NSDictionary *a) {
|
|||
}];
|
||||
}
|
||||
|
||||
typedef void (^errBlock)(NSError *__autoreleasing *error);
|
||||
|
||||
extern void expectError(errBlock);
|
||||
|
||||
void captureAutoreleasingVarFromBlock(NSDictionary *dict) {
|
||||
expectError(^(NSError *__autoreleasing *err) {
|
||||
[dict enumerateKeysAndObjectsUsingBlock:^{
|
||||
writeIntoError(err); // expected-warning{{Capture of autoreleasing out parameter 'err'}}
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue