void FunctionArgsByRef::VisitDecl(Decl *decl) { FunctionDecl *functionDecl = dyn_cast<FunctionDecl>(decl); if (functionDecl == nullptr || !functionDecl->hasBody() || shouldIgnoreFunction(functionDecl->getNameAsString()) || !functionDecl->isThisDeclarationADefinition()) return; Stmt *body = functionDecl->getBody(); for (auto it = functionDecl->param_begin(), end = functionDecl->param_end(); it != end; ++it) { const ParmVarDecl *param = *it; QualType paramQt = param->getType(); const Type *paramType = paramQt.getTypePtrOrNull(); if (paramType == nullptr || paramType->isDependentType()) continue; const int size_of_T = m_ci.getASTContext().getTypeSize(paramQt) / 8; const bool isSmall = size_of_T <= 16; // TODO: What about arm ? CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl(); const bool isUserNonTrivial = recordDecl && (recordDecl->hasUserDeclaredCopyConstructor() || recordDecl->hasUserDeclaredDestructor()); const bool isReference = paramType->isLValueReferenceType(); const bool isConst = paramQt.isConstQualified(); if (recordDecl && shouldIgnoreClass(recordDecl->getQualifiedNameAsString())) continue; std::string error; if (isConst && !isReference) { if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } else if (isConst && isReference && !isUserNonTrivial && isSmall) { //error += "Don't use by-ref on small trivial type"; } else if (!isConst && !isReference && (!isSmall || isUserNonTrivial)) { if (Utils::containsNonConstMemberCall(body, param) || Utils::containsCallByRef(body, param)) continue; if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } if (!error.empty()) { emitWarning(param->getLocStart(), error.c_str()); } } }
bool isCppFunctionDeclaration(DeclContext *context) { FunctionDecl *decl = dyn_cast<FunctionDecl>(context); return isa<CXXRecordDecl>(context) || (decl && !decl->hasBody()); }