void RuleOfTwoSoft::VisitStmt(Stmt *s) { CXXOperatorCallExpr *op = dyn_cast<CXXOperatorCallExpr>(s); if (op) { FunctionDecl *func = op->getDirectCallee(); if (func && func->getNameAsString() == "operator=") { CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(func); if (method && method->getParent()) { CXXRecordDecl *record = method->getParent(); const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (hasCopyCtor && !hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using assign operator but class " + record->getQualifiedNameAsString() + " has copy-ctor but no assign operator"; emitWarning(s->getLocStart(), msg); } } } } else if (CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(s)) { CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor(); CXXRecordDecl *record = ctorDecl->getParent(); if (ctorDecl->isCopyConstructor() && record) { const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (!hasCopyCtor && hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using copy-ctor but class " + record->getQualifiedNameAsString() + " has a trivial copy-ctor but non trivial assign operator"; emitWarning(s->getLocStart(), msg); } } } }
bool TypeUtils::classifyQualType(const CompilerInstance &ci, const VarDecl *varDecl, QualTypeClassification &classif, clang::Stmt *body) { if (!varDecl) return false; QualType qualType = TypeUtils::unrefQualType(varDecl->getType()); const Type *paramType = qualType.getTypePtrOrNull(); if (!paramType || paramType->isIncompleteType()) return false; if (isUndeducibleAuto(paramType)) return false; classif.size_of_T = ci.getASTContext().getTypeSize(qualType) / 8; classif.isBig = classif.size_of_T > 16; CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl(); classif.isNonTriviallyCopyable = recordDecl && (recordDecl->hasNonTrivialCopyConstructor() || recordDecl->hasNonTrivialDestructor()); classif.isReference = varDecl->getType()->isLValueReferenceType(); classif.isConst = qualType.isConstQualified(); if (varDecl->getType()->isRValueReferenceType()) // && ref, nothing to do here return true; if (classif.isConst && !classif.isReference) { classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable; if (classif.isBig) { classif.passBigTypeByConstRef = true; } } else if (classif.isConst && classif.isReference && !classif.isNonTriviallyCopyable && !classif.isBig) { classif.passSmallTrivialByValue = true; } else if (!classif.isConst && !classif.isReference && (classif.isBig || classif.isNonTriviallyCopyable)) { if (body && (Utils::containsNonConstMemberCall(body, varDecl) || Utils::isPassedToFunction(StmtBodyRange(body), varDecl, /*byrefonly=*/ true))) return true; classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable; if (classif.isBig) { classif.passBigTypeByConstRef = true; } } return true; }