Bug 1410472 - clang-plugin follows the LLVM coding style for real r=mystor
MozReview-Commit-ID: AXrQEjWzxvg
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
RefCountedMap RefCountedClasses;
|
||||
|
||||
void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) {
|
||||
void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
// We want to reject any code which captures a pointer to an object of a
|
||||
// refcounted type, and then lets that value escape. As a primitive analysis,
|
||||
// we reject any occurances of the lambda as a template parameter to a class
|
||||
@@ -15,36 +15,35 @@ void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) {
|
||||
// in a return value (either from lambdas, or in c++14, auto functions).
|
||||
//
|
||||
// We check these lambdas' capture lists for raw pointers to refcounted types.
|
||||
AstMatcher->addMatcher(functionDecl(returns(recordType(hasDeclaration(
|
||||
cxxRecordDecl(isLambdaDecl()).bind("decl"))))),
|
||||
this);
|
||||
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"), this);
|
||||
AstMatcher->addMatcher(
|
||||
functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(
|
||||
isLambdaDecl()).bind("decl"))))),
|
||||
this);
|
||||
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"),
|
||||
this);
|
||||
AstMatcher->addMatcher(
|
||||
classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
|
||||
recordType(hasDeclaration(cxxRecordDecl(
|
||||
isLambdaDecl()).bind("decl")))))),
|
||||
classTemplateSpecializationDecl(
|
||||
hasAnyTemplateArgument(refersToType(recordType(
|
||||
hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))),
|
||||
this);
|
||||
}
|
||||
|
||||
void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc,
|
||||
StringRef Name,
|
||||
QualType Type) {
|
||||
diag(Loc, "Refcounted variable '%0' of type %1 cannot be captured by a lambda",
|
||||
DiagnosticIDs::Error) << Name << Type;
|
||||
diag(Loc, "Please consider using a smart pointer",
|
||||
DiagnosticIDs::Note);
|
||||
diag(Loc,
|
||||
"Refcounted variable '%0' of type %1 cannot be captured by a lambda",
|
||||
DiagnosticIDs::Error)
|
||||
<< Name << Type;
|
||||
diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Note);
|
||||
}
|
||||
|
||||
void RefCountedInsideLambdaChecker::check(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
static DenseSet<const CXXRecordDecl*> CheckedDecls;
|
||||
static DenseSet<const CXXRecordDecl *> CheckedDecls;
|
||||
|
||||
const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
|
||||
|
||||
if (const LambdaExpr *OuterLambda =
|
||||
Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
|
||||
Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
|
||||
const CXXMethodDecl *OpCall = OuterLambda->getCallOperator();
|
||||
QualType ReturnTy = OpCall->getReturnType();
|
||||
if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) {
|
||||
@@ -64,19 +63,20 @@ void RefCountedInsideLambdaChecker::check(
|
||||
|
||||
bool StrongRefToThisCaptured = false;
|
||||
|
||||
for (const LambdaCapture& Capture : Lambda->captures()) {
|
||||
for (const LambdaCapture &Capture : Lambda->captures()) {
|
||||
// Check if any of the captures are ByRef. If they are, we have nothing to
|
||||
// report, as it's OK to capture raw pointers to refcounted objects so long as
|
||||
// the Lambda doesn't escape the current scope, which is required by ByRef
|
||||
// captures already.
|
||||
// report, as it's OK to capture raw pointers to refcounted objects so long
|
||||
// as the Lambda doesn't escape the current scope, which is required by
|
||||
// ByRef captures already.
|
||||
if (Capture.getCaptureKind() == LCK_ByRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this capture is byvalue, and captures a strong reference to this.
|
||||
// XXX: Do we want to make sure that this type which we are capturing is a "Smart Pointer" somehow?
|
||||
if (!StrongRefToThisCaptured &&
|
||||
Capture.capturesVariable() &&
|
||||
// Check if this capture is byvalue, and captures a strong reference to
|
||||
// this.
|
||||
// XXX: Do we want to make sure that this type which we are capturing is a
|
||||
// "Smart Pointer" somehow?
|
||||
if (!StrongRefToThisCaptured && Capture.capturesVariable() &&
|
||||
Capture.getCaptureKind() == LCK_ByCopy) {
|
||||
const VarDecl *Var = Capture.getCapturedVar();
|
||||
if (Var->hasInit()) {
|
||||
@@ -103,13 +103,15 @@ void RefCountedInsideLambdaChecker::check(
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can go through and produce errors for any captured variables or this pointers.
|
||||
for (const LambdaCapture& Capture : Lambda->captures()) {
|
||||
// Now we can go through and produce errors for any captured variables or this
|
||||
// pointers.
|
||||
for (const LambdaCapture &Capture : Lambda->captures()) {
|
||||
if (Capture.capturesVariable()) {
|
||||
QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
|
||||
|
||||
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
|
||||
emitDiagnostics(Capture.getLocation(), Capture.getCapturedVar()->getName(), Pointee);
|
||||
emitDiagnostics(Capture.getLocation(),
|
||||
Capture.getCapturedVar()->getName(), Pointee);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -125,12 +127,12 @@ void RefCountedInsideLambdaChecker::check(
|
||||
// captured implicitly when the LambdaCaptureDefault was LCD_ByRef, as that
|
||||
// expresses the intent that the lambda won't leave the enclosing scope.
|
||||
bool ImplicitByRefDefaultedCapture =
|
||||
Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
|
||||
if (Capture.capturesThis() &&
|
||||
!ImplicitByRefDefaultedCapture &&
|
||||
Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
|
||||
if (Capture.capturesThis() && !ImplicitByRefDefaultedCapture &&
|
||||
!StrongRefToThisCaptured) {
|
||||
ThisVisitor V(*this);
|
||||
bool NotAborted = V.TraverseDecl(const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
|
||||
bool NotAborted = V.TraverseDecl(
|
||||
const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
|
||||
if (!NotAborted) {
|
||||
return;
|
||||
}
|
||||
@@ -138,7 +140,8 @@ void RefCountedInsideLambdaChecker::check(
|
||||
}
|
||||
}
|
||||
|
||||
bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(CXXThisExpr *This) {
|
||||
bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(
|
||||
CXXThisExpr *This) {
|
||||
QualType Pointee = This->getType()->getPointeeType();
|
||||
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
|
||||
Checker.emitDiagnostics(This->getLocStart(), "this", Pointee);
|
||||
|
||||
Reference in New Issue
Block a user