in src/checks/level1/foreach.cpp [41:121]
void Foreach::VisitStmt(clang::Stmt *stmt)
{
const PreProcessorVisitor *preProcessorVisitor = m_context->preprocessorVisitor;
if (!preProcessorVisitor || preProcessorVisitor->qtVersion() >= 50900) {
// Disabled since 5.9 because the Q_FOREACH internals changed.
// Not worth fixing it because range-loop is recommended
return;
}
auto *forStm = dyn_cast<ForStmt>(stmt);
if (forStm) {
m_lastForStmt = forStm;
return;
}
if (!m_lastForStmt) {
return;
}
auto *constructExpr = dyn_cast<CXXConstructExpr>(stmt);
if (!constructExpr || constructExpr->getNumArgs() < 1) {
return;
}
const CXXConstructorDecl *constructorDecl = constructExpr->getConstructor();
if (!constructorDecl || clazy::name(constructorDecl) != "QForeachContainer") {
return;
}
std::vector<DeclRefExpr *> declRefExprs;
clazy::getChilds<DeclRefExpr>(constructExpr, declRefExprs);
if (declRefExprs.empty()) {
return;
}
// Get the container value declaration
DeclRefExpr *declRefExpr = declRefExprs.front();
auto *valueDecl = dyn_cast<ValueDecl>(declRefExpr->getDecl());
if (!valueDecl) {
return;
}
QualType containerQualType = constructExpr->getArg(0)->getType();
const Type *containerType = containerQualType.getTypePtrOrNull();
CXXRecordDecl *const containerRecord = containerType ? containerType->getAsCXXRecordDecl() : nullptr;
if (!containerRecord) {
return;
}
auto *rootBaseClass = Utils::rootBaseClass(containerRecord);
StringRef containerClassName = clazy::name(rootBaseClass);
const bool isQtContainer = clazy::isQtIterableClass(containerClassName);
if (containerClassName.empty()) {
emitWarning(stmt->getBeginLoc(), "internal error, couldn't get class name of foreach container, please report a bug");
return;
}
if (!isQtContainer) {
emitWarning(stmt->getBeginLoc(), "foreach with STL container causes deep-copy (" + rootBaseClass->getQualifiedNameAsString() + ')');
return;
} else if (containerClassName == "QVarLengthArray") {
emitWarning(stmt->getBeginLoc(), "foreach with QVarLengthArray causes deep-copy");
return;
}
checkBigTypeMissingRef();
if (isa<MaterializeTemporaryExpr>(constructExpr->getArg(0))) { // Nothing else to check
return;
}
// const containers are fine
if (valueDecl->getType().isConstQualified()) {
return;
}
// Now look inside the for statement for detachments
if (containsDetachments(m_lastForStmt, valueDecl)) {
emitWarning(stmt->getBeginLoc(), "foreach container detached");
}
}