diff options
author | Sergio Martins <smartins@kde.org> | 2020-04-06 11:44:39 +0100 |
---|---|---|
committer | Sergio Martins <smartins@kde.org> | 2020-04-06 11:44:39 +0100 |
commit | 8b171d7bc9ab789a88b8d52cbf18fb29ebc0dd04 (patch) | |
tree | bd131efc1355e8bdd42e763e8af213b10149b097 | |
parent | be4f13112f1a92440f6b211bf89f1c429686f41b (diff) |
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | CheckSources.cmake | 1 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | checks.json | 6 | ||||
-rw-r--r-- | docs/checks/README-keeping-unstable-ref.md | 1 | ||||
-rw-r--r-- | readmes.cmake | 1 | ||||
-rw-r--r-- | src/Checks.h | 2 | ||||
-rw-r--r-- | src/checks/manuallevel/keeping-unstable-ref.cpp | 112 | ||||
-rw-r--r-- | src/checks/manuallevel/keeping-unstable-ref.h | 41 | ||||
-rw-r--r-- | tests/keeping-unstable-ref/config.json | 7 | ||||
-rw-r--r-- | tests/keeping-unstable-ref/main.cpp | 29 | ||||
-rw-r--r-- | tests/keeping-unstable-ref/main.cpp.expected | 0 |
12 files changed, 203 insertions, 0 deletions
@@ -125,3 +125,5 @@ - New Checks: - overloaded signal - qstring-arg warns when using QLatin1String::arg(int), as it casts to QChar + + - <dont forget changelog entry for keeping-unstable-ref> diff --git a/CheckSources.cmake b/CheckSources.cmake index 46aafac1..c8569c5c 100644 --- a/CheckSources.cmake +++ b/CheckSources.cmake @@ -6,6 +6,7 @@ set(CLAZY_CHECKS_SRCS ${CLAZY_CHECKS_SRCS} ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/ifndef-define-typo.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/inefficient-qlist.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/isempty-vs-count.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/keeping-unstable-ref.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qhash-with-char-pointer-key.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qproperty-type-mismatch.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qrequiredresult-candidates.cpp @@ -221,6 +221,7 @@ clazy runs all checks from level1 by default. - [ifndef-define-typo](docs/checks/README-ifndef-define-typo.md) - [inefficient-qlist](docs/checks/README-inefficient-qlist.md) - [isempty-vs-count](docs/checks/README-isempty-vs-count.md) + - [keeping-unstable-ref](docs/checks/README-keeping-unstable-ref.md) - [qhash-with-char-pointer-key](docs/checks/README-qhash-with-char-pointer-key.md) - [qproperty-type-mismatch](docs/checks/README-qproperty-type-mismatch.md) - [qrequiredresult-candidates](docs/checks/README-qrequiredresult-candidates.md) diff --git a/checks.json b/checks.json index 7fed28e2..7abf3733 100644 --- a/checks.json +++ b/checks.json @@ -23,6 +23,12 @@ "visits_decls" : true }, { + "name" : "keeping-unstable-ref", + "level" : -1, + "categories" : ["bug"], + "visits_stmts" : true + }, + { "name" : "ifndef-define-typo", "level" : -1, "categories" : ["bug"] diff --git a/docs/checks/README-keeping-unstable-ref.md b/docs/checks/README-keeping-unstable-ref.md new file mode 100644 index 00000000..b163ab48 --- /dev/null +++ b/docs/checks/README-keeping-unstable-ref.md @@ -0,0 +1 @@ +# keeping-unstable-ref diff --git a/readmes.cmake b/readmes.cmake index 663b2556..f6b49a45 100644 --- a/readmes.cmake +++ b/readmes.cmake @@ -6,6 +6,7 @@ SET(README_manuallevel_FILES ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-ifndef-define-typo.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-inefficient-qlist.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-isempty-vs-count.md + ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-keeping-unstable-ref.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qhash-with-char-pointer-key.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qproperty-type-mismatch.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qrequiredresult-candidates.md diff --git a/src/Checks.h b/src/Checks.h index 9ae9d580..992ba02f 100644 --- a/src/Checks.h +++ b/src/Checks.h @@ -34,6 +34,7 @@ #include "checks/manuallevel/ifndef-define-typo.h" #include "checks/manuallevel/inefficient-qlist.h" #include "checks/manuallevel/isempty-vs-count.h" +#include "checks/manuallevel/keeping-unstable-ref.h" #include "checks/manuallevel/qhash-with-char-pointer-key.h" #include "checks/manuallevel/qproperty-type-mismatch.h" #include "checks/manuallevel/qrequiredresult-candidates.h" @@ -128,6 +129,7 @@ void CheckManager::registerChecks() registerCheck(check<IfndefDefineTypo>("ifndef-define-typo", ManualCheckLevel, RegisteredCheck::Option_None)); registerCheck(check<InefficientQList>("inefficient-qlist", ManualCheckLevel, RegisteredCheck::Option_VisitsDecls)); registerCheck(check<IsEmptyVSCount>("isempty-vs-count", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); + registerCheck(check<KeepingUnstableRef>("keeping-unstable-ref", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); registerCheck(check<QHashWithCharPointerKey>("qhash-with-char-pointer-key", ManualCheckLevel, RegisteredCheck::Option_VisitsDecls)); registerCheck(check<QPropertyTypeMismatch>("qproperty-type-mismatch", ManualCheckLevel, RegisteredCheck::Option_VisitsDecls)); registerCheck(check<QRequiredResultCandidates>("qrequiredresult-candidates", ManualCheckLevel, RegisteredCheck::Option_VisitsDecls)); diff --git a/src/checks/manuallevel/keeping-unstable-ref.cpp b/src/checks/manuallevel/keeping-unstable-ref.cpp new file mode 100644 index 00000000..1bd3f3b0 --- /dev/null +++ b/src/checks/manuallevel/keeping-unstable-ref.cpp @@ -0,0 +1,112 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2020 Sergio Martins <smartins@kde.org> + + 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 "keeping-unstable-ref.h" +#include "Utils.h" +#include "HierarchyUtils.h" +#include "QtUtils.h" +#include "TypeUtils.h" +#include "ClazyContext.h" + +#include <clang/AST/AST.h> + +using namespace clang; +using namespace std; + + +KeepingUnstableRef::KeepingUnstableRef(const std::string &name, ClazyContext *context) + : CheckBase(name, context) +{ +} + +void KeepingUnstableRef::VisitStmt(clang::Stmt *stmt) +{ + auto subscriptOp = dyn_cast<CXXOperatorCallExpr>(stmt); // operator[] + if (!subscriptOp || subscriptOp->getOperator() != OO_Subscript) + return; + + auto subscriptMethod = dyn_cast<CXXMethodDecl>(subscriptOp->getCalleeDecl()); + if (!subscriptMethod) + return; + + CXXRecordDecl *classDecl = subscriptMethod->getParent(); + if (!classDecl) + return; + + StringRef className = classDecl->getName(); + if (className != "QMap" && className != "QList") + return; + + //if (processDeclRefCase(subscriptOp)) + // return; + + if (processMemberAssignment(subscriptOp)) + return; +} + +bool KeepingUnstableRef::processDeclRefCase(CXXOperatorCallExpr *op) +{ + Stmt *s = op; + DeclStmt *declStmt = nullptr; + while (s) { + s = clazy::parent(m_context->parentMap, s); + if (!s) + break; + if ((declStmt = dyn_cast<DeclStmt>(s))) + break; + } + + if (!declStmt || !declStmt->isSingleDecl()) + return false; + + auto varDecl = dyn_cast<VarDecl>(declStmt->getSingleDecl()); + const QualType qtype = varDecl->getType(); + if (!varDecl || (!qtype->isReferenceType() && !qtype->isPointerType())) { + return false; + } + + emitWarning(op, "storing a reference to an unstable container element"); + return true; +} + +bool KeepingUnstableRef::processMemberAssignment(CXXOperatorCallExpr *op) +{ + Stmt *s = op; + BinaryOperator *binaryOp = nullptr; + while (s) { + s = clazy::parent(m_context->parentMap, s); + if (!s) + break; + if ((binaryOp = dyn_cast<BinaryOperator>(s))) + break; + } + + if (!binaryOp || binaryOp->getOpcode() != BO_Assign) + return false; + + const QualType qtype = binaryOp->getType(); + if (!qtype->isPointerType()) { + return false; + } + + emitWarning(op, "storing a reference to an unstable container element"); + return true; +} diff --git a/src/checks/manuallevel/keeping-unstable-ref.h b/src/checks/manuallevel/keeping-unstable-ref.h new file mode 100644 index 00000000..d236085a --- /dev/null +++ b/src/checks/manuallevel/keeping-unstable-ref.h @@ -0,0 +1,41 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2020 Sergio Martins <smartins@kde.org> + + 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. +*/ + +#ifndef CLAZY_KEEPING_UNSTABLE_REF_H +#define CLAZY_KEEPING_UNSTABLE_REF_H + +#include "checkbase.h" + + +/** + * See README-keeping-unstable-ref.md for more info. + */ +class KeepingUnstableRef : public CheckBase +{ +public: + explicit KeepingUnstableRef(const std::string &name, ClazyContext *context); + void VisitStmt(clang::Stmt *) override; +private: + bool processDeclRefCase(clang::CXXOperatorCallExpr *op); + bool processMemberAssignment(clang::CXXOperatorCallExpr *op); +}; + +#endif diff --git a/tests/keeping-unstable-ref/config.json b/tests/keeping-unstable-ref/config.json new file mode 100644 index 00000000..e7e6e0cb --- /dev/null +++ b/tests/keeping-unstable-ref/config.json @@ -0,0 +1,7 @@ +{ + "tests" : [ + { + "filename" : "main.cpp" + } + ] +} diff --git a/tests/keeping-unstable-ref/main.cpp b/tests/keeping-unstable-ref/main.cpp new file mode 100644 index 00000000..d5d78c57 --- /dev/null +++ b/tests/keeping-unstable-ref/main.cpp @@ -0,0 +1,29 @@ +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QMap> + +QMap<int, int> getMap() { + return {}; +} + + +struct Foo { + int *m = nullptr; +}; + +void test() +{ + QMap<int,int> map; + map.insert(0, 0); + int &a = map[0]; // Warn + int b = map[0]; + + int &c = b; // OK + + int &d = getMap()[0]; // Warn + //Foo f; + //f.m = &map[0]; + int aa; + map[0] = aa; +} + diff --git a/tests/keeping-unstable-ref/main.cpp.expected b/tests/keeping-unstable-ref/main.cpp.expected new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/keeping-unstable-ref/main.cpp.expected |