diff --git a/checks.json b/checks.json index d0cb465..43ffae4 100644 --- a/checks.json +++ b/checks.json @@ -1,546 +1,556 @@ { "available_categories" : ["readability", "qt4", "containers", "qstring", "cpp", "bug", "performance", "deprecation", "qml"], "checks" : [ { "name" : "qt-keywords", "level" : -1, "fixits" : [ { "name" : "qt-keywords" } ] }, { "name" : "inefficient-qlist", "level" : -1, "categories" : ["containers", "performance"], "visits_decls" : true }, { "name" : "isempty-vs-count", "class_name" : "IsEmptyVSCount", "level" : -1, "categories" : ["readability"], "visits_stmts" : true }, { "name" : "qstring-varargs", "level" : -1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "qt4-qstring-from-array", "class_name" : "Qt4QStringFromArray", "level" : -1, "categories" : ["qt4", "qstring"], "fixits" : [ { "name" : "qt4-qstring-from-array" } ], "visits_stmts" : true }, { "name" : "tr-non-literal", "level" : -1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "container-inside-loop", "level" : -1, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "qhash-with-char-pointer-key", "level" : -1, "categories" : ["cpp", "bug"], "visits_decls" : true }, { "name" : "connect-by-name", "level" : 0, "categories" : ["bug", "readability"], "visits_decls" : true }, { "name" : "connect-non-signal", "minimum_qt_version" : 50700, "level" : 0, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "wrong-qevent-cast", "level" : 0, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "lambda-in-connect", "level" : 0, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "lambda-unique-connection", "level" : 0, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "qdatetime-utc", "class_name" : "QDateTimeUtc", "level" : 0, "categories" : ["performance"], "fixits" : [ { "name" : "qdatetime-utc" } ], "visits_stmts" : true }, { "name" : "qgetenv", "class_name" : "QGetEnv", "level" : 0, "minimum_qt_version" : 50500, "categories" : ["performance"], "fixits" : [ { "name" : "qgetenv" } ], "visits_stmts" : true }, { "name" : "qstring-insensitive-allocation", "level" : 0, "categories" : ["performance", "qstring"], "visits_stmts" : true }, { "name" : "fully-qualified-moc-types", "class_name" : "FullyQualifiedMocTypes", "level" : 0, "categories" : ["bug", "qml"], "visits_decls" : true }, { "name" : "qvariant-template-instantiation", "level" : 0, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "unused-non-trivial-variable", "level" : 0, "categories" : ["readability"], "visits_stmts" : true }, { "name" : "connect-not-normalized", "level" : 0, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "mutable-container-key", "level" : 0, "categories" : ["containers", "bug"], "visits_decls" : true }, { "name" : "qenums", "level" : 0, "minimum_qt_version" : 50500, "categories" : ["deprecation"] }, { "name" : "qmap-with-pointer-key", "level" : 0, "categories" : ["containers", "performance"], "visits_decls" : true }, { "name" : "qstring-ref", "class_name" : "StringRefCandidates", "level" : 0, "categories" : ["performance", "qstring"], "fixits" : [ { "name" : "missing-qstringref" } ], "visits_stmts" : true }, { "name" : "strict-iterators", "level" : 0, "categories" : ["containers", "performance", "bug"], "visits_stmts" : true }, { "name" : "writing-to-temporary", "level" : 0, "categories" : ["bug"], "options" : [ { "name" : "widen-criteria" } ], "visits_stmts" : true }, { "name" : "container-anti-pattern", "level" : 0, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "qcolor-from-literal", "level" : 0, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "qfileinfo-exists", "class_name" : "QFileInfoExists", "level" : 0, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "qstring-arg", "level" : 0, "categories" : ["performance", "qstring"], "options" : [ { "name" : "fillChar-overloads" } ], "visits_stmts" : true }, { "name" : "qt-macros", "class_name" : "QtMacros", "level" : 0, "categories" : ["bug"] }, { "name" : "temporary-iterator", "level" : 0, "categories" : ["containers", "bug"], "visits_stmts" : true }, { "name" : "wrong-qglobalstatic", "class_name" : "WrongQGlobalStatic", "level" : 0, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "auto-unexpected-qstringbuilder", "class_name" : "AutoUnexpectedQStringBuilder", "level" : 1, "categories" : ["bug", "qstring"], "visits_decls" : true, "visits_stmts" : true, "fixits" : [ { "name" : "auto-unexpected-qstringbuilder" } ] }, { "name" : "connect-3arg-lambda", "level" : 1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "const-signal-or-slot", "level" : 1, "categories" : ["readability", "bug"], "visits_decls" : true, "visits_stmts" : true }, { "name" : "detaching-temporary", "level" : 1, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "foreach", "level" : 1, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "incorrect-emit", "level" : 1, "categories" : ["readability"], "visits_stmts" : true }, { "name" : "inefficient-qlist-soft", "level" : 1, "categories" : ["containers", "performance"], "visits_decls" : true }, { "name" : "install-event-filter", "level" : 1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "non-pod-global-static", "level" : 1, "categories" : ["performance"], "visits_stmts" : true }, { "name" : "post-event", "level" : 1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "qdeleteall", "class_name" : "QDeleteAll", "level" : 1, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "qlatin1string-non-ascii", "level" : 1, "categories" : ["bug", "qstring"], "visits_stmts" : true }, { "name" : "qproperty-without-notify", "level" : 1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "qstring-left", "level" : 1, "categories" : ["bug", "performance", "qstring"], "visits_stmts" : true }, { "name" : "range-loop", "level" : 1, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "returning-data-from-temporary", "level" : 1, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "rule-of-two-soft", "level" : 1, "categories" : ["cpp", "bug"], "visits_stmts" : true }, { "name" : "child-event-qobject-cast", "level" : 1, "categories" : ["bug"], "visits_decls" : true }, { "name" : "virtual-signal", "level" : 1, "categories" : ["bug", "readability"], "visits_decls" : true }, { "name" : "overridden-signal", "level" : 1, "categories" : ["bug", "readability"], "visits_decls" : true }, { "name" : "qhash-namespace", "level" : 1, "categories" : ["bug"], "visits_decls" : true }, { "name" : "skipped-base-method", "level" : 1, "categories" : ["bug", "cpp"], "visits_stmts" : true }, { "name" : "unneeded-cast", "level" : -1, "categories" : ["cpp", "readability"], "options" : [ { "name" : "prefer-dynamic-cast-over-qobject" } ], "visits_stmts" : true }, { "name" : "ctor-missing-parent-argument", "level" : 2, "categories" : ["bug"], "visits_decls" : true }, { "name" : "base-class-event", "level" : 2, "categories" : ["bug"], "visits_decls" : true }, { "name" : "copyable-polymorphic", "level" : 2, "categories" : ["cpp", "bug"], "visits_decls" : true }, { "name" : "function-args-by-ref", "level" : 2, "categories" : ["cpp", "performance"], + "options" : [ + { + "name" : "warn-for-overridden-methods" + } + ], "visits_decls" : true, "visits_stmts" : true }, { "name" : "function-args-by-value", "level" : 2, "categories" : ["cpp", "performance"], + "options" : [ + { + "name" : "warn-for-overridden-methods" + } + ], "visits_decls" : true, "visits_stmts" : true }, { "name" : "global-const-char-pointer", "level" : 2, "categories" : ["cpp", "performance"], "visits_decls" : true }, { "name" : "implicit-casts", "level" : 2, "categories" : ["cpp", "bug"], "options" : [ { "name" : "bool-to-int" } ], "visits_stmts" : true }, { "name" : "missing-qobject-macro", "level" : 2, "categories" : ["bug"], "visits_decls" : true }, { "name" : "missing-typeinfo", "class_name" : "MissingTypeInfo", "level" : 2, "categories" : ["containers", "performance"], "visits_decls" : true }, { "name" : "old-style-connect", "level" : 2, "minimum_qt_version" : 50500, "ifndef" : "NO_STD_REGEX", "categories" : ["performance"], "fixits" : [ { "name" : "old-style-connect" } ], "visits_stmts" : true }, { "name" : "qstring-allocations", "level" : 2, "minimum_qt_version" : 50000, "categories" : ["performance", "qstring"], "fixits" : [ { "name" : "qlatin1string-allocations" }, { "name" : "fromLatin1_fromUtf8-allocations" }, { "name" : "fromCharPtrAllocations" } ], "options" : [ { "name" : "no-msvc-compat" } ], "visits_stmts" : true }, { "name" : "returning-void-expression", "level" : 2, "categories" : ["readability", "cpp"], "visits_stmts" : true }, { "name" : "rule-of-three", "level" : 2, "categories" : ["cpp", "bug"], "visits_decls" : true }, { "name" : "virtual-call-ctor", "level" : 2, "categories" : ["cpp", "bug"], "visits_decls" : true }, { "name" : "static-pmf", "level" : 2, "categories" : ["bug"], "visits_decls" : true }, { "name" : "assert-with-side-effects", "level" : 3, "categories" : ["bug"], "visits_stmts" : true }, { "name" : "detaching-member", "level" : 3, "categories" : ["containers", "performance"], "visits_stmts" : true }, { "name" : "thread-with-slots", "level" : 3, "categories" : ["bug"], "visits_decls" : true, "visits_stmts" : true }, { "name" : "reserve-candidates", "level" : 3, "categories" : ["containers"], "visits_stmts" : true } ] } diff --git a/src/checks/level2/function-args-by-ref.cpp b/src/checks/level2/function-args-by-ref.cpp index 3a8b2be..9c7a478 100644 --- a/src/checks/level2/function-args-by-ref.cpp +++ b/src/checks/level2/function-args-by-ref.cpp @@ -1,169 +1,170 @@ /* This file is part of the clazy static checker. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Sérgio Martins Copyright (C) 2015 Sergio Martins This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "function-args-by-ref.h" #include "Utils.h" #include "FixItUtils.h" #include "TypeUtils.h" #include "ClazyContext.h" #include "StringUtils.h" #include #include using namespace clang; using namespace std; enum Fixit { FixitNone = 0, FixitAll = 0x1 // More granularity isn't needed I guess }; static bool shouldIgnoreClass(CXXRecordDecl *record) { if (!record) return false; if (Utils::isSharedPointer(record)) return true; static const vector ignoreList = {"QDebug", // Too many warnings "QGenericReturnArgument", "QColor", // TODO: Remove in Qt6 "QStringRef", // TODO: Remove in Qt6 "QList::const_iterator", // TODO: Remove in Qt6 "QJsonArray::const_iterator", // TODO: Remove in Qt6 "QList::const_iterator", // TODO: Remove in Qt6 "QtMetaTypePrivate::QSequentialIterableImpl", "QtMetaTypePrivate::QAssociativeIterableImpl", "QVariantComparisonHelper", "QHashDummyValue", "QCharRef", "QString::Null" }; return clazy::contains(ignoreList, record->getQualifiedNameAsString()); } static bool shouldIgnoreOperator(FunctionDecl *function) { // Too many warnings in operator<< static const vector ignoreList = { "operator<<" }; return clazy::contains(ignoreList, clazy::name(function)); } static bool shouldIgnoreFunction(clang::FunctionDecl *function) { static const vector qualifiedIgnoreList = {"QDBusMessage::createErrorReply", // Fixed in Qt6 "QMenu::exec", // Fixed in Qt6 "QTextFrame::iterator", // Fixed in Qt6 "QGraphicsWidget::addActions", // Fixed in Qt6 "QListWidget::mimeData", // Fixed in Qt6 "QTableWidget::mimeData", // Fixed in Qt6 "QTreeWidget::mimeData", // Fixed in Qt6 "QWidget::addActions", // Fixed in Qt6 "QSslCertificate::verify", // Fixed in Qt6 "QSslConfiguration::setAllowedNextProtocols" // Fixed in Qt6 }; return clazy::contains(qualifiedIgnoreList, function->getQualifiedNameAsString()); } FunctionArgsByRef::FunctionArgsByRef(const std::string &name, ClazyContext *context) : CheckBase(name, context, Option_CanIgnoreIncludes) { } static std::string warningMsgForSmallType(int sizeOf, const std::string &typeName) { std::string sizeStr = std::to_string(sizeOf); return "Missing reference on large type (sizeof " + typeName + " is " + sizeStr + " bytes)"; } void FunctionArgsByRef::processFunction(FunctionDecl *func) { if (!func || !func->isThisDeclarationADefinition() || func->isDeleted() || shouldIgnoreOperator(func)) return; if (m_context->isQtDeveloper() && shouldIgnoreFunction(func)) return; - if (Utils::methodOverrides(dyn_cast(func))) { + const bool warnForOverriddenMethods = isOptionSet("warn-for-overridden-methods"); + if (!warnForOverriddenMethods && Utils::methodOverrides(dyn_cast(func))) { // When overriding you can't change the signature. You should fix the base classes first return; } Stmt *body = func->getBody(); int i = -1; for (auto param : Utils::functionParameters(func)) { i++; QualType paramQt = TypeUtils::unrefQualType(param->getType()); const Type *paramType = paramQt.getTypePtrOrNull(); if (!paramType || paramType->isIncompleteType() || paramType->isDependentType()) continue; if (shouldIgnoreClass(paramType->getAsCXXRecordDecl())) continue; TypeUtils::QualTypeClassification classif; bool success = TypeUtils::classifyQualType(m_context, param, classif, body); if (!success) continue; vector ctorInits = Utils::ctorInitializer(dyn_cast(func), param); if (Utils::ctorInitializerContainsMove(ctorInits)) continue; if (classif.passBigTypeByConstRef || classif.passNonTriviallyCopyableByConstRef) { string error; std::vector fixits; const string paramStr = param->getType().getAsString(); if (classif.passBigTypeByConstRef) { error = warningMsgForSmallType(classif.size_of_T, paramStr); } else if (classif.passNonTriviallyCopyableByConstRef) { error = "Missing reference on non-trivial type (" + paramStr + ')'; } emitWarning(param->getLocStart(), error.c_str(), fixits); } } } void FunctionArgsByRef::VisitDecl(Decl *decl) { processFunction(dyn_cast(decl)); } void FunctionArgsByRef::VisitStmt(Stmt *stmt) { if (auto lambda = dyn_cast(stmt)) { if (!shouldIgnoreFile(stmt->getLocStart())) processFunction(lambda->getCallOperator()); } } clang::FixItHint FunctionArgsByRef::fixit(const ParmVarDecl *, TypeUtils::QualTypeClassification) { FixItHint fixit; return fixit; } diff --git a/src/checks/level2/function-args-by-value.cpp b/src/checks/level2/function-args-by-value.cpp index 050caf0..cd5707b 100644 --- a/src/checks/level2/function-args-by-value.cpp +++ b/src/checks/level2/function-args-by-value.cpp @@ -1,209 +1,210 @@ /* This file is part of the clazy static checker. Copyright (C) 2016-2018 Sergio Martins This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "function-args-by-value.h" #include "Utils.h" #include "StringUtils.h" #include "TypeUtils.h" #include "FixItUtils.h" #include "ClazyContext.h" #include #include using namespace clang; using namespace std; enum Fixit { FixitNone = 0, FixitAll = 0x1 // More granularity isn't needed I guess }; // TODO, go over all these static bool shouldIgnoreClass(CXXRecordDecl *record) { if (!record) return false; if (Utils::isSharedPointer(record)) return true; static const vector ignoreList = {"QDebug", // Too many warnings "QGenericReturnArgument", "QColor", // TODO: Remove in Qt6 "QStringRef", // TODO: Remove in Qt6 "QList::const_iterator", // TODO: Remove in Qt6 "QJsonArray::const_iterator", // TODO: Remove in Qt6 "QList::const_iterator", // TODO: Remove in Qt6 "QtMetaTypePrivate::QSequentialIterableImpl", "QtMetaTypePrivate::QAssociativeIterableImpl", "QVariantComparisonHelper", "QHashDummyValue", "QCharRef", "QString::Null" }; return clazy::contains(ignoreList, record->getQualifiedNameAsString()); } static bool shouldIgnoreOperator(FunctionDecl *function) { // Too many warnings in operator<< static const vector ignoreList = { "operator<<" }; return clazy::contains(ignoreList, clazy::name(function)); } static bool shouldIgnoreFunction(clang::FunctionDecl *function) { static const vector qualifiedIgnoreList = {"QDBusMessage::createErrorReply", // Fixed in Qt6 "QMenu::exec", // Fixed in Qt6 "QTextFrame::iterator", // Fixed in Qt6 "QGraphicsWidget::addActions", // Fixed in Qt6 "QListWidget::mimeData", // Fixed in Qt6 "QTableWidget::mimeData", // Fixed in Qt6 "QTreeWidget::mimeData", // Fixed in Qt6 "QWidget::addActions", // Fixed in Qt6 "QSslCertificate::verify", // Fixed in Qt6 "QSslConfiguration::setAllowedNextProtocols" // Fixed in Qt6 }; return clazy::contains(qualifiedIgnoreList, function->getQualifiedNameAsString()); } FunctionArgsByValue::FunctionArgsByValue(const std::string &name, ClazyContext *context) : CheckBase(name, context, Option_CanIgnoreIncludes) { } void FunctionArgsByValue::VisitDecl(Decl *decl) { processFunction(dyn_cast(decl)); } void FunctionArgsByValue::VisitStmt(Stmt *stmt) { if (auto lambda = dyn_cast(stmt)) processFunction(lambda->getCallOperator()); } void FunctionArgsByValue::processFunction(FunctionDecl *func) { if (!func || !func->isThisDeclarationADefinition() || func->isDeleted()) return; auto ctor = dyn_cast(func); if (ctor && ctor->isCopyConstructor()) return; // copy-ctor must take by ref - if (Utils::methodOverrides(dyn_cast(func))) { + const bool warnForOverriddenMethods = isOptionSet("warn-for-overridden-methods"); + if (!warnForOverriddenMethods && Utils::methodOverrides(dyn_cast(func))) { // When overriding you can't change the signature. You should fix the base classes first return; } if (shouldIgnoreOperator(func)) return; if (m_context->isQtDeveloper() && shouldIgnoreFunction(func)) return; Stmt *body = func->getBody(); int i = -1; for (auto param : Utils::functionParameters(func)) { i++; QualType paramQt = TypeUtils::unrefQualType(param->getType()); const Type *paramType = paramQt.getTypePtrOrNull(); if (!paramType || paramType->isIncompleteType() || paramType->isDependentType()) continue; if (shouldIgnoreClass(paramType->getAsCXXRecordDecl())) continue; TypeUtils::QualTypeClassification classif; bool success = TypeUtils::classifyQualType(m_context, param, classif, body); if (!success) continue; if (classif.passSmallTrivialByValue) { if (ctor) { // Implements fix for Bug #379342 vector initializers = Utils::ctorInitializer(ctor, param); bool found_by_ref_member_init = false; for (auto initializer : initializers) { if (!initializer->isMemberInitializer()) continue; // skip base class initializer FieldDecl *field = initializer->getMember(); if (!field) continue; QualType type = field->getType(); if (type.isNull() || type->isReferenceType()) { found_by_ref_member_init = true; break; } } if (found_by_ref_member_init) continue; } std::vector fixits; auto method = dyn_cast(func); const bool isVirtualMethod = method && method->isVirtual(); - if (!isVirtualMethod && isFixitEnabled(FixitAll)) { // Don't try to fix virtual methods, as build can fail + if ((!isVirtualMethod || warnForOverriddenMethods) && isFixitEnabled(FixitAll)) { // Don't try to fix virtual methods, as build can fail for (auto redecl : func->redecls()) { // Fix in both header and .cpp auto fdecl = dyn_cast(redecl); const ParmVarDecl *param = fdecl->getParamDecl(i); fixits.push_back(fixit(fdecl, param, classif)); } } const string paramStr = param->getType().getAsString(); string error = "Pass small and trivially-copyable type by value (" + paramStr + ')'; emitWarning(param->getLocStart(), error.c_str(), fixits); } } } FixItHint FunctionArgsByValue::fixit(FunctionDecl *func, const ParmVarDecl *param, TypeUtils::QualTypeClassification) { QualType qt = TypeUtils::unrefQualType(param->getType()); qt.removeLocalConst(); const string typeName = qt.getAsString(PrintingPolicy(lo())); string replacement = typeName + ' ' + string(param->getName()); SourceLocation startLoc = param->getLocStart(); SourceLocation endLoc = param->getLocEnd(); const int numRedeclarations = std::distance(func->redecls_begin(), func->redecls_end()); const bool definitionIsAlsoDeclaration = numRedeclarations == 1; const bool isDeclarationButNotDefinition = !func->doesThisDeclarationHaveABody(); if (param->hasDefaultArg() && (isDeclarationButNotDefinition || definitionIsAlsoDeclaration)) { endLoc = param->getDefaultArg()->getLocStart().getLocWithOffset(-1); replacement += " ="; } if (!startLoc.isValid() || !endLoc.isValid()) { llvm::errs() << "Internal error could not apply fixit " << startLoc.printToString(sm()) << ';' << endLoc.printToString(sm()) << "\n"; return {}; } return clazy::createReplacement({ startLoc, endLoc }, replacement); } diff --git a/tests/function-args-by-ref/config.json b/tests/function-args-by-ref/config.json index 03f7284..173569d 100644 --- a/tests/function-args-by-ref/config.json +++ b/tests/function-args-by-ref/config.json @@ -1,13 +1,17 @@ { "tests" : [ { "filename" : "main.cpp" }, { "filename" : "lambdas.cpp" }, { "filename" : "sharedptrs.cpp" + }, + { + "filename" : "warn-for-overridden-methods.cpp", + "env" : { "CLAZY_EXTRA_OPTIONS" : "function-args-by-ref-warn-for-overridden-methods" } } ] } diff --git a/tests/function-args-by-ref/warn-for-overridden-methods.cpp b/tests/function-args-by-ref/warn-for-overridden-methods.cpp new file mode 100644 index 0000000..f4a7ee3 --- /dev/null +++ b/tests/function-args-by-ref/warn-for-overridden-methods.cpp @@ -0,0 +1,22 @@ +struct NonTrivial { + NonTrivial() {} + NonTrivial(const NonTrivial &) {} + void constFunction() const {}; + void nonConstFunction() {}; + int a; +}; + +class BaseWithVirtuals +{ +public: + virtual void virtualMethod1(NonTrivial) {}; // Warn + virtual void virtualMethod2(NonTrivial) {}; // Warn + void nonVirtualMethod(NonTrivial) {}; // Warn +}; + +class DerivedWithVirtuals : BaseWithVirtuals { +public: + void virtualMethod1(NonTrivial) override {}; // Warn + void virtualMethod2(NonTrivial) {}; // Warn + void nonVirtualMethod(NonTrivial) {}; // Warn +}; diff --git a/tests/function-args-by-ref/warn-for-overridden-methods.cpp.expected b/tests/function-args-by-ref/warn-for-overridden-methods.cpp.expected new file mode 100644 index 0000000..d9acacb --- /dev/null +++ b/tests/function-args-by-ref/warn-for-overridden-methods.cpp.expected @@ -0,0 +1,7 @@ +function-args-by-ref/warn-for-overridden-methods.cpp:20:10: warning: 'virtualMethod2' overrides a member function but is not marked 'override' [-Winconsistent-missing-override] +function-args-by-ref/warn-for-overridden-methods.cpp:12:33: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] +function-args-by-ref/warn-for-overridden-methods.cpp:13:33: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] +function-args-by-ref/warn-for-overridden-methods.cpp:14:27: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] +function-args-by-ref/warn-for-overridden-methods.cpp:19:25: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] +function-args-by-ref/warn-for-overridden-methods.cpp:20:25: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] +function-args-by-ref/warn-for-overridden-methods.cpp:21:27: warning: Missing reference on non-trivial type (struct NonTrivial) [-Wclazy-function-args-by-ref] diff --git a/tests/function-args-by-value/config.json b/tests/function-args-by-value/config.json index 6bb3f06..6a13e6c 100644 --- a/tests/function-args-by-value/config.json +++ b/tests/function-args-by-value/config.json @@ -1,20 +1,29 @@ { "tests" : [ { "filename" : "main.cpp" }, { "filename" : "main.cpp_fixed.cpp", "isFixedFile" : true }, { "filename" : "lambdas.cpp" }, { "filename" : "sharedptrs.cpp" }, { "filename" : "bug379342.cpp" + }, + { + "filename" : "warn-for-overridden-methods.cpp", + "env" : { "CLAZY_EXTRA_OPTIONS" : "function-args-by-value-warn-for-overridden-methods" } + }, + { + "filename" : "warn-for-overridden-methods.cpp_fixed.cpp", + "env" : { "CLAZY_EXTRA_OPTIONS" : "function-args-by-value-warn-for-overridden-methods" }, + "isFixedFile" : true } ] } diff --git a/tests/function-args-by-value/warn-for-overridden-methods.cpp b/tests/function-args-by-value/warn-for-overridden-methods.cpp new file mode 100644 index 0000000..37f8412 --- /dev/null +++ b/tests/function-args-by-value/warn-for-overridden-methods.cpp @@ -0,0 +1,16 @@ +struct Trivial {}; + +class BaseWithVirtuals +{ +public: + virtual void virtualMethod1(const Trivial &) {}; // Warn + virtual void virtualMethod2(const Trivial &) {}; // Warn + void nonVirtualMethod(const Trivial &) {}; // Warn +}; + +class DerivedWithVirtuals : BaseWithVirtuals { +public: + void virtualMethod1(const Trivial &) override {}; // Warn + void virtualMethod2(const Trivial &) {}; // Warn + void nonVirtualMethod(const Trivial &) {}; // Warn +}; diff --git a/tests/function-args-by-value/warn-for-overridden-methods.cpp.expected b/tests/function-args-by-value/warn-for-overridden-methods.cpp.expected new file mode 100644 index 0000000..52723a6 --- /dev/null +++ b/tests/function-args-by-value/warn-for-overridden-methods.cpp.expected @@ -0,0 +1,7 @@ +function-args-by-value/warn-for-overridden-methods.cpp:14:10: warning: 'virtualMethod2' overrides a member function but is not marked 'override' [-Winconsistent-missing-override] +function-args-by-value/warn-for-overridden-methods.cpp:6:33: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] +function-args-by-value/warn-for-overridden-methods.cpp:7:33: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] +function-args-by-value/warn-for-overridden-methods.cpp:8:27: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] +function-args-by-value/warn-for-overridden-methods.cpp:13:25: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] +function-args-by-value/warn-for-overridden-methods.cpp:14:25: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] +function-args-by-value/warn-for-overridden-methods.cpp:15:27: warning: Pass small and trivially-copyable type by value (const struct Trivial &) [-Wclazy-function-args-by-value] diff --git a/tests/function-args-by-value/warn-for-overridden-methods.cpp_fixed.cpp.expected b/tests/function-args-by-value/warn-for-overridden-methods.cpp_fixed.cpp.expected new file mode 100644 index 0000000..a451add --- /dev/null +++ b/tests/function-args-by-value/warn-for-overridden-methods.cpp_fixed.cpp.expected @@ -0,0 +1,16 @@ +struct Trivial {}; + +class BaseWithVirtuals +{ +public: + virtual void virtualMethod1(Trivial ) {}; // Warn + virtual void virtualMethod2(Trivial ) {}; // Warn + void nonVirtualMethod(Trivial ) {}; // Warn +}; + +class DerivedWithVirtuals : BaseWithVirtuals { +public: + void virtualMethod1(Trivial ) override {}; // Warn + void virtualMethod2(Trivial ) {}; // Warn + void nonVirtualMethod(Trivial ) {}; // Warn +};