Skip to content

Commit

Permalink
Fix #12546 new check: suggest to return const reference from "getter"…
Browse files Browse the repository at this point in the history
… member function (#6256)
  • Loading branch information
chrchr-github authored Apr 10, 2024
1 parent b7f208f commit 4f8f7cc
Show file tree
Hide file tree
Showing 20 changed files with 135 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ $(libcppdir)/checkboost.o: lib/checkboost.cpp lib/check.h lib/checkboost.h lib/c
$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp

$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp

$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
Expand Down
6 changes: 3 additions & 3 deletions gui/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,23 @@ class Application {
* @brief Get application name.
* @return Application name.
*/
QString getName() const {
const QString& getName() const {
return mName;
}

/**
* @brief Get application path.
* @return Application path.
*/
QString getPath() const {
const QString& getPath() const {
return mPath;
}

/**
* @brief Get application command line parameters.
* @return Application command line parameters.
*/
QString getParameters() const {
const QString& getParameters() const {
return mParameters;
}

Expand Down
4 changes: 2 additions & 2 deletions gui/checkstatistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class CheckStatistics : public QObject {
*/
unsigned getCount(const QString &tool, ShowTypes::ShowType type) const;

std::set<std::string> getActiveCheckers() const {
const std::set<std::string>& getActiveCheckers() const {
return mActiveCheckers;
}

Expand All @@ -82,7 +82,7 @@ class CheckStatistics : public QObject {
void setCheckersReport(QString report) {
mCheckersReport = std::move(report);
}
QString getCheckersReport() const {
const QString& getCheckersReport() const {
return mCheckersReport;
}

Expand Down
2 changes: 1 addition & 1 deletion gui/codeeditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class CodeEditor : public QPlainTextEdit {
mFileName = fileName;
}

QString getFileName() const {
const QString& getFileName() const {
return mFileName;
}

Expand Down
2 changes: 1 addition & 1 deletion gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1751,7 +1751,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const bool check
Settings::terminate(false);

QFileInfo inf(projectFile->getFilename());
const QString rootpath = projectFile->getRootPath();
const QString& rootpath = projectFile->getRootPath();

QDir::setCurrent(inf.absolutePath());

Expand Down
2 changes: 1 addition & 1 deletion gui/printablereport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void PrintableReport::writeError(const ErrorItem &error)
mFormattedReport += "\n";
}

QString PrintableReport::getFormattedReportText() const
const QString& PrintableReport::getFormattedReportText() const
{
return mFormattedReport;
}
Expand Down
2 changes: 1 addition & 1 deletion gui/printablereport.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class PrintableReport : public Report {
/**
* @brief Returns the formatted report.
*/
QString getFormattedReportText() const;
const QString& getFormattedReportText() const;

private:

Expand Down
30 changes: 15 additions & 15 deletions gui/projectfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ class ProjectFile : public QObject {
* @brief Get project root path.
* @return project root path.
*/
QString getRootPath() const {
const QString& getRootPath() const {
return mRootPath;
}

QString getBuildDir() const {
const QString& getBuildDir() const {
return mBuildDir;
}

QString getImportProject() const {
const QString& getImportProject() const {
return mImportProject;
}

Expand Down Expand Up @@ -119,15 +119,15 @@ class ProjectFile : public QObject {
* @brief Get list of defines.
* @return list of defines.
*/
QStringList getDefines() const {
const QStringList& getDefines() const {
return mDefines;
}

/**
* @brief Get list of undefines.
* @return list of undefines.
*/
QStringList getUndefines() const {
const QStringList& getUndefines() const {
return mUndefines;
}

Expand All @@ -151,27 +151,27 @@ class ProjectFile : public QObject {
* @brief Get list of paths to exclude from the check.
* @return list of paths.
*/
QStringList getVsConfigurations() const {
const QStringList& getVsConfigurations() const {
return mVsConfigurations;
}

/**
* @brief Get list libraries.
* @return list of libraries.
*/
QStringList getLibraries() const {
const QStringList& getLibraries() const {
return mLibraries;
}

/**
* @brief Get platform.
* @return Current platform. If it ends with .xml then it is a file. Otherwise it must match one of the return values from @sa cppcheck::Platform::toString() ("win32A", "unix32", ..)
*/
QString getPlatform() const {
const QString& getPlatform() const {
return mPlatform;
}

QString getProjectName() const {
const QString& getProjectName() const {
return mProjectName;
}

Expand All @@ -183,7 +183,7 @@ class ProjectFile : public QObject {
* @brief Get "raw" suppressions.
* @return list of suppressions.
*/
QList<SuppressionList::Suppression> getSuppressions() const {
const QList<SuppressionList::Suppression>& getSuppressions() const {
return mSuppressions;
}

Expand All @@ -197,7 +197,7 @@ class ProjectFile : public QObject {
* @brief Get list addons.
* @return list of addons.
*/
QStringList getAddons() const {
const QStringList& getAddons() const {
return mAddons;
}

Expand Down Expand Up @@ -230,7 +230,7 @@ class ProjectFile : public QObject {
mClangTidy = c;
}

QStringList getTags() const {
const QStringList& getTags() const {
return mTags;
}

Expand All @@ -254,7 +254,7 @@ class ProjectFile : public QObject {
* @brief Get filename for the project file.
* @return file name.
*/
QString getFilename() const {
const QString& getFilename() const {
return mFilename;
}

Expand Down Expand Up @@ -367,7 +367,7 @@ class ProjectFile : public QObject {
}

/** @brief Get list of coding standards (checked by Cppcheck Premium). */
QStringList getCodingStandards() const {
const QStringList& getCodingStandards() const {
return mCodingStandards;
}

Expand Down Expand Up @@ -414,7 +414,7 @@ class ProjectFile : public QObject {
SafeChecks safeChecks;

/** Check unknown function return values */
QStringList getCheckUnknownFunctionReturn() const {
const QStringList& getCheckUnknownFunctionReturn() const {
return mCheckUnknownFunctionReturn;
}
/*
Expand Down
2 changes: 1 addition & 1 deletion gui/projectfiledialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class ProjectFileDialog : public QDialog {
* @brief Return suppressions from the dialog control.
* @return List of suppressions.
*/
QList<SuppressionList::Suppression> getSuppressions() const {
const QList<SuppressionList::Suppression>& getSuppressions() const {
return mSuppressions;
}

Expand Down
2 changes: 1 addition & 1 deletion gui/resultstree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,7 @@ void ResultsTree::setCheckDirectory(const QString &dir)
}


QString ResultsTree::getCheckDirectory()
const QString& ResultsTree::getCheckDirectory()
{
return mCheckPath;
}
Expand Down
2 changes: 1 addition & 1 deletion gui/resultstree.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class ResultsTree : public QTreeView {
* @return Directory containing source files
*/

QString getCheckDirectory();
const QString& getCheckDirectory();

/**
* @brief Check if there are any visible results in view.
Expand Down
2 changes: 1 addition & 1 deletion gui/translationhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ bool TranslationHandler::setLanguage(const QString &code)
return true;
}

QString TranslationHandler::getCurrentLanguage() const
const QString& TranslationHandler::getCurrentLanguage() const
{
return mCurrentLanguage;
}
Expand Down
4 changes: 2 additions & 2 deletions gui/translationhandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TranslationHandler : QObject {
* @return List of available translations.
*
*/
QList<TranslationInfo> getTranslations() const {
const QList<TranslationInfo>& getTranslations() const {
return mTranslations;
}

Expand All @@ -86,7 +86,7 @@ class TranslationHandler : QObject {
* @return ISO 639 language code for current translation.
*
*/
QString getCurrentLanguage() const;
const QString& getCurrentLanguage() const;

/**
* @brief Get translation suggestion for the system.
Expand Down
49 changes: 49 additions & 0 deletions lib/checkclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "tokenize.h"
#include "tokenlist.h"
#include "utils.h"
#include "valueflow.h"

#include <algorithm>
#include <cctype>
Expand Down Expand Up @@ -3303,6 +3304,54 @@ void CheckClass::checkUselessOverride()
}
}

static const Variable* getSingleReturnVar(const Scope* scope) {
if (!scope)
return nullptr;
const Token* const start = scope->bodyStart->next();
const Token* const end = Token::findsimplematch(start, ";", 1, scope->bodyEnd);
if (!end || end->next() != scope->bodyEnd)
return nullptr;
if (!start->astOperand1() || start->str() != "return")
return nullptr;
return start->astOperand1()->variable();
}

void CheckClass::checkReturnByReference()
{
if (!mSettings->severity.isEnabled(Severity::performance) && !mSettings->isPremiumEnabled("returnByReference"))
return;

logChecker("CheckClass::checkReturnByReference"); // performance

for (const Scope* classScope : mSymbolDatabase->classAndStructScopes) {
for (const Function& func : classScope->functionList) {
if (Function::returnsPointer(&func) || Function::returnsReference(&func) || Function::returnsStandardType(&func))
continue;
if (const Variable* var = getSingleReturnVar(func.functionScope)) {
if (!var->valueType())
continue;
const bool isContainer = var->valueType()->type == ValueType::Type::CONTAINER && var->valueType()->container;
const bool isView = isContainer && var->valueType()->container->view;
bool warn = isContainer && !isView;
if (!warn && !isView) {
const std::size_t size = ValueFlow::getSizeOf(*var->valueType(), *mSettings);
if (size > 2 * mSettings->platform.sizeof_pointer)
warn = true;
}
if (warn)
returnByReferenceError(&func, var);
}
}
}
}

void CheckClass::returnByReferenceError(const Function* func, const Variable* var)
{
const Token* tok = func ? func->tokenDef : nullptr;
const std::string message = "Function '" + (func ? func->name() : "func") + "()' should return member '" + (var ? var->name() : "var") + "' by const reference.";
reportError(tok, Severity::performance, "returnByReference", message);
}

void CheckClass::checkThisUseAfterFree()
{
if (!mSettings->severity.isEnabled(Severity::warning))
Expand Down
9 changes: 8 additions & 1 deletion lib/checkclass.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class CPPCHECKLIB CheckClass : public Check {
checkClass.checkCopyCtorAndEqOperator();
checkClass.checkOverride();
checkClass.checkUselessOverride();
checkClass.checkReturnByReference();
checkClass.checkThisUseAfterFree();
checkClass.checkUnsafeClassRefMember();
}
Expand Down Expand Up @@ -157,6 +158,9 @@ class CPPCHECKLIB CheckClass : public Check {
/** @brief Check that the overriden function is not identical to the base function */
void checkUselessOverride();

/** @brief Check that large members are returned by reference from getter function */
void checkReturnByReference();

/** @brief When "self pointer" is destroyed, 'this' might become invalid. */
void checkThisUseAfterFree();

Expand Down Expand Up @@ -208,6 +212,7 @@ class CPPCHECKLIB CheckClass : public Check {
void copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor);
void overrideError(const Function *funcInBase, const Function *funcInDerived);
void uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode = false);
void returnByReferenceError(const Function *func, const Variable* var);
void thisUseAfterFree(const Token *self, const Token *free, const Token *use);
void unsafeClassRefMemberError(const Token *tok, const std::string &varname);
void checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase);
Expand Down Expand Up @@ -246,9 +251,11 @@ class CPPCHECKLIB CheckClass : public Check {
c.selfInitializationError(nullptr, "var");
c.duplInheritedMembersError(nullptr, nullptr, "class", "class", "variable", false, false);
c.copyCtorAndEqOperatorError(nullptr, "class", false, false);
c.overrideError(nullptr, nullptr);
c.uselessOverrideError(nullptr, nullptr);
c.returnByReferenceError(nullptr, nullptr);
c.pureVirtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f");
c.virtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f");
c.overrideError(nullptr, nullptr);
c.thisUseAfterFree(nullptr, nullptr, nullptr);
c.unsafeClassRefMemberError(nullptr, "UnsafeClass::var");
}
Expand Down
22 changes: 11 additions & 11 deletions lib/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,17 @@ class CPPCHECKLIB Platform {
nonneg int long_long_bit; /// bits in long long

/** size of standard types */
nonneg int sizeof_bool;
nonneg int sizeof_short;
nonneg int sizeof_int;
nonneg int sizeof_long;
nonneg int sizeof_long_long;
nonneg int sizeof_float;
nonneg int sizeof_double;
nonneg int sizeof_long_double;
nonneg int sizeof_wchar_t;
nonneg int sizeof_size_t;
nonneg int sizeof_pointer;
std::size_t sizeof_bool;
std::size_t sizeof_short;
std::size_t sizeof_int;
std::size_t sizeof_long;
std::size_t sizeof_long_long;
std::size_t sizeof_float;
std::size_t sizeof_double;
std::size_t sizeof_long_double;
std::size_t sizeof_wchar_t;
std::size_t sizeof_size_t;
std::size_t sizeof_pointer;

char defaultSign; // unsigned:'u', signed:'s', unknown:'\0'

Expand Down
Loading

0 comments on commit 4f8f7cc

Please sign in to comment.