Bug 1170388 - Restrict the static analysis error given about raw pointers to refcounted objects inside a lambda, to the case where the raw pointer is captured. r=ehsan

--HG--
extra : rebase_source : 28cd2aa684abf505edbcdbc449c8cf056d3b0ee6
extra : source : 28c2862d29b8a2cb0d03cf38430f17abc269225b
This commit is contained in:
Botond Ballo 2015-06-03 16:51:36 -04:00
parent cc64bd1ee4
commit 63b921afe7
2 changed files with 93 additions and 24 deletions

View File

@ -599,6 +599,33 @@ AST_MATCHER(QualType, isRefCounted) {
return isClassRefCounted(Node);
}
#if CLANG_VERSION_FULL < 304
/// The 'equalsBoundeNode' matcher was added in clang 3.4.
/// Since infra runs clang 3.3, we polyfill it here.
AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
std::string, ID) {
BoundNodesTree bindings = Builder->build();
bool haveMatchingResult = false;
struct Visitor : public BoundNodesTree::Visitor {
const NodeType &Node;
std::string ID;
bool &haveMatchingResult;
Visitor(const NodeType &Node, const std::string &ID, bool &haveMatchingResult)
: Node(Node), ID(ID), haveMatchingResult(haveMatchingResult) {}
void visitMatch(const BoundNodes &BoundNodesView) override {
if (BoundNodesView.getNodeAs<NodeType>(ID) == &Node) {
haveMatchingResult = true;
}
}
};
Visitor visitor(Node, ID, haveMatchingResult);
bindings.visitMatches(&visitor);
return haveMatchingResult;
}
#endif
}
}
@ -704,8 +731,14 @@ DiagnosticsMatcher::DiagnosticsMatcher()
).bind("node"),
&noAddRefReleaseOnReturnChecker);
// Match declrefs with type "pointer to object of ref-counted type" inside a
// lambda, where the declaration they reference is not inside the lambda.
// This excludes arguments and local variables, leaving only captured
// variables.
astMatcher.addMatcher(lambdaExpr(
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted())))).bind("node"))
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted()))),
to(decl().bind("decl"))).bind("declref")),
unless(hasDescendant(decl(equalsBoundNode("decl"))))
),
&refCountedInsideLambdaChecker);
@ -917,14 +950,14 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
const MatchFinder::MatchResult &Result) {
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be used inside a lambda");
DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be captured by a lambda");
unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Note, "Please consider using a smart pointer");
const DeclRefExpr *node = Result.Nodes.getNodeAs<DeclRefExpr>("node");
const DeclRefExpr *declref = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
Diag.Report(node->getLocStart(), errorID) << node->getFoundDecl() <<
node->getType()->getPointeeType();
Diag.Report(node->getLocStart(), noteID);
Diag.Report(declref->getLocStart(), errorID) << declref->getFoundDecl() <<
declref->getType()->getPointeeType();
Diag.Report(declref->getLocStart(), noteID);
}
void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(

View File

@ -19,40 +19,76 @@ void take(...);
void foo() {
R* ptr;
SmartPtr<R> sp;
take([&]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([&](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([&]() {
take([&](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([&]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([&](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([&]() {
take([&](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
take([=]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([=](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([=]() {
take([=](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([=]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([=](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([=]() {
take([=](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
take([ptr]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([ptr](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([sp]() {
take([sp](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([ptr]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([ptr](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([sp]() {
take([sp](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
}