in src/checks/manuallevel/qt6-qhash-signature.cpp [87:181]
void Qt6QHashSignature::VisitStmt(clang::Stmt *stmt)
{
auto *declRefExpr = dyn_cast<DeclRefExpr>(stmt);
if (!declRefExpr) {
return;
}
// checking if we're dealing with a qhash function
std::string name = declRefExpr->getNameInfo().getAsString();
if (!isInterestingFunction(name)) {
return;
}
VarDecl *varDecl = m_context->lastDecl ? dyn_cast<VarDecl>(m_context->lastDecl) : nullptr;
FieldDecl *fieldDecl = m_context->lastDecl ? dyn_cast<FieldDecl>(m_context->lastDecl) : nullptr;
FunctionDecl *funcDecl = m_context->lastDecl ? dyn_cast<FunctionDecl>(m_context->lastFunctionDecl) : nullptr;
if (!varDecl && !fieldDecl && !funcDecl) {
return;
}
// need to check if this stmt is part of a return stmt, if it is, it's the lastFunctionDecl that is of interest
// loop over the parent until I find a return statement.
Stmt *parent = clazy::parent(m_context->parentMap, stmt);
bool isPartReturnStmt = false;
if (parent) {
while (parent) {
Stmt *ancester = clazy::parent(m_context->parentMap, parent);
if (!ancester) {
break;
}
auto *returnStmt = dyn_cast<ReturnStmt>(ancester);
if (returnStmt) {
isPartReturnStmt = true;
break;
}
parent = ancester;
}
}
// if the stmt is part of a return statement but there is no last functionDecl, it's a problem...
if (isPartReturnStmt && !funcDecl) {
return;
}
std::string message;
std::string declType;
SourceRange fixitRange;
SourceLocation warningLocation;
if (funcDecl && isPartReturnStmt) {
// if the return correspond to a qHash function, we are not interested
// the qHash function is taken care of during the VisitDecl
if (isInterestingFunction(funcDecl->getNameAsString())) {
return;
}
declType = funcDecl->getReturnType().getAsString();
fixitRange = funcDecl->getReturnTypeSourceRange();
warningLocation = funcDecl->getBeginLoc();
} else if (varDecl) {
declType = varDecl->getType().getAsString();
fixitRange = varDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange();
warningLocation = varDecl->getBeginLoc();
} else if (fieldDecl) {
declType = fieldDecl->getType().getAsString();
fixitRange = fieldDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange();
warningLocation = fieldDecl->getBeginLoc();
}
std::string qhashReturnType = declRefExpr->getDecl()->getAsFunction()->getReturnType().getAsString();
if (declType == "size_t" && qhashReturnType == "size_t") {
return;
}
std::vector<FixItHint> fixits;
// if the type of the variable is correct, but the qHash is not returning the right type
// just emit warning...
if (declType == "size_t" && qhashReturnType != "size_t") {
message = name + " should return size_t";
emitWarning(declRefExpr->getBeginLoc(), message, fixits);
return;
}
fixits.push_back(FixItHint::CreateReplacement(fixitRange, "size_t"));
if (qhashReturnType != "size_t") {
message = name + " should return size_t";
} else {
message = name + " returns size_t";
}
emitWarning(warningLocation, message, fixits);
return;
}