File indexing completed on 2024-05-12 05:40:59

0001 /*
0002     SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com
0003     SPDX-FileContributor: SĂ©rgio Martins <sergio.martins@kdab.com>
0004 
0005     SPDX-FileCopyrightText: 2015 Sergio Martins <smartins@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "range-loop-reference.h"
0011 #include "ClazyContext.h"
0012 #include "FixItUtils.h"
0013 #include "PreProcessorVisitor.h"
0014 #include "QtUtils.h"
0015 #include "StringUtils.h"
0016 #include "TypeUtils.h"
0017 
0018 #include <clang/AST/Expr.h>
0019 #include <clang/AST/Stmt.h>
0020 #include <clang/AST/StmtCXX.h>
0021 #include <clang/AST/Type.h>
0022 #include <llvm/Support/Casting.h>
0023 
0024 class ClazyContext;
0025 
0026 using namespace clang;
0027 
0028 RangeLoopReference::RangeLoopReference(const std::string &name, ClazyContext *context)
0029     : CheckBase(name, context, Option_CanIgnoreIncludes)
0030 {
0031     context->enablePreprocessorVisitor();
0032 }
0033 
0034 void RangeLoopReference::VisitStmt(clang::Stmt *stmt)
0035 {
0036     if (auto *rangeLoop = dyn_cast<CXXForRangeStmt>(stmt)) {
0037         processForRangeLoop(rangeLoop);
0038     }
0039 }
0040 
0041 void RangeLoopReference::processForRangeLoop(CXXForRangeStmt *rangeLoop)
0042 {
0043     Expr *containerExpr = rangeLoop->getRangeInit();
0044     if (!containerExpr) {
0045         return;
0046     }
0047 
0048     QualType qt = containerExpr->getType();
0049     const Type *t = qt.getTypePtrOrNull();
0050     if (!t || !t->isRecordType()) {
0051         return;
0052     }
0053 
0054     clazy::QualTypeClassification classif;
0055     auto *varDecl = rangeLoop->getLoopVariable();
0056     bool success = varDecl && clazy::classifyQualType(m_context, varDecl->getType(), varDecl, /*by-ref*/ classif, rangeLoop);
0057     if (!success) {
0058         return;
0059     }
0060 
0061     if (classif.passNonTriviallyCopyableByConstRef) {
0062         std::string msg;
0063         const std::string paramStr = clazy::simpleTypeName(varDecl->getType(), lo());
0064         msg = "Missing reference in range-for with non trivial type (" + paramStr + ')';
0065 
0066         std::vector<FixItHint> fixits;
0067         const bool isConst = varDecl->getType().isConstQualified();
0068 
0069         if (!isConst) {
0070             SourceLocation start = varDecl->getBeginLoc();
0071             fixits.push_back(clazy::createInsertion(start, "const "));
0072         }
0073 
0074         SourceLocation end = varDecl->getLocation();
0075         fixits.push_back(clazy::createInsertion(end, "&"));
0076 
0077         // We ignore classif.passSmallTrivialByValue because it doesn't matter, the compiler is able
0078         // to optimize it, generating the same assembly, regardless of pass by value.
0079         emitWarning(varDecl->getBeginLoc(), msg, fixits);
0080     }
0081 }