diff options
author | Sergio Martins <smartins@kde.org> | 2019-05-12 16:49:25 +0100 |
---|---|---|
committer | Sergio Martins <smartins@kde.org> | 2019-05-12 16:49:25 +0100 |
commit | d1cb8a0e5d8dc9932e75e16b79a5b93aee5f129e (patch) | |
tree | 29fa3195d801b805cbdca32f620499e778f51819 | |
parent | e1c8faffca38256ad27cd13c2d8e33c92c092b79 (diff) |
Introduce heap-allocated-small-trivial-type
Catches heap-allocating small trivially copyable/destructible types.
Such as: auto p = new QPoint();
Could contain false-positives, hence going to manual level.
-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-heap-allocated-small-trivial-type.md | 9 | ||||
-rw-r--r-- | readmes.cmake | 1 | ||||
-rw-r--r-- | src/Checks.h | 2 | ||||
-rw-r--r-- | src/checks/manuallevel/heap-allocated-small-trivial-type.cpp | 58 | ||||
-rw-r--r-- | src/checks/manuallevel/heap-allocated-small-trivial-type.h | 39 | ||||
-rw-r--r-- | tests/heap-allocated-small-trivial-type/config.json | 7 | ||||
-rw-r--r-- | tests/heap-allocated-small-trivial-type/main.cpp | 37 | ||||
-rw-r--r-- | tests/heap-allocated-small-trivial-type/main.cpp.expected | 1 |
12 files changed, 164 insertions, 0 deletions
@@ -107,6 +107,8 @@ * v1.6 (, 2019) + - New Checks: + - heap-allocated-small-trivial-type - Moved all level3 checks to manual level. Doesn't make sense to enable all of them. Each one must be carefully considered. - Fixit infrastructure was overhauled diff --git a/CheckSources.cmake b/CheckSources.cmake index 5f8d3d62..cb541688 100644 --- a/CheckSources.cmake +++ b/CheckSources.cmake @@ -2,6 +2,7 @@ set(CLAZY_CHECKS_SRCS ${CLAZY_CHECKS_SRCS} ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/assert-with-side-effects.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/container-inside-loop.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/detaching-member.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/heap-allocated-small-trivial-type.cpp ${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 @@ -218,6 +218,7 @@ clazy runs all checks from level1 by default. - [assert-with-side-effects](docs/checks/README-assert-with-side-effects.md) - [container-inside-loop](docs/checks/README-container-inside-loop.md) - [detaching-member](docs/checks/README-detaching-member.md) + - [heap-allocated-small-trivial-type](docs/checks/README-heap-allocated-small-trivial-type.md) - [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) diff --git a/checks.json b/checks.json index 66ebbe1d..0b409176 100644 --- a/checks.json +++ b/checks.json @@ -11,6 +11,12 @@ ] }, { + "name" : "heap-allocated-small-trivial-type", + "level" : -1, + "categories" : ["performance"], + "visits_stmts" : true + }, + { "name" : "ifndef-define-typo", "level" : -1, "categories" : ["bug"] diff --git a/docs/checks/README-heap-allocated-small-trivial-type.md b/docs/checks/README-heap-allocated-small-trivial-type.md new file mode 100644 index 00000000..0996a866 --- /dev/null +++ b/docs/checks/README-heap-allocated-small-trivial-type.md @@ -0,0 +1,9 @@ +# heap-allocated-small-trivial-type + +Warns when you're allocating small trivially copyable/destructible types on the heap. +Example: +``` + auto p = new QPoint(1, 1); +``` + +Unneeded memory allocations are costly. diff --git a/readmes.cmake b/readmes.cmake index b0dd5871..8d3953ac 100644 --- a/readmes.cmake +++ b/readmes.cmake @@ -2,6 +2,7 @@ SET(README_manuallevel_FILES ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-assert-with-side-effects.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-container-inside-loop.md ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-detaching-member.md + ${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-heap-allocated-small-trivial-type.md ${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 diff --git a/src/Checks.h b/src/Checks.h index 1bb85ee5..00cb6b9c 100644 --- a/src/Checks.h +++ b/src/Checks.h @@ -30,6 +30,7 @@ #include "checks/manuallevel/assert-with-side-effects.h" #include "checks/manuallevel/container-inside-loop.h" #include "checks/manuallevel/detaching-member.h" +#include "checks/manuallevel/heap-allocated-small-trivial-type.h" #include "checks/manuallevel/ifndef-define-typo.h" #include "checks/manuallevel/inefficient-qlist.h" #include "checks/manuallevel/isempty-vs-count.h" @@ -120,6 +121,7 @@ void CheckManager::registerChecks() registerCheck(check<AssertWithSideEffects>("assert-with-side-effects", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); registerCheck(check<ContainerInsideLoop>("container-inside-loop", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); registerCheck(check<DetachingMember>("detaching-member", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); + registerCheck(check<HeapAllocatedSmallTrivialType>("heap-allocated-small-trivial-type", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts)); 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)); diff --git a/src/checks/manuallevel/heap-allocated-small-trivial-type.cpp b/src/checks/manuallevel/heap-allocated-small-trivial-type.cpp new file mode 100644 index 00000000..a730b7c2 --- /dev/null +++ b/src/checks/manuallevel/heap-allocated-small-trivial-type.cpp @@ -0,0 +1,58 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2019 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 "heap-allocated-small-trivial-type.h" +#include "Utils.h" +#include "HierarchyUtils.h" +#include "QtUtils.h" +#include "TypeUtils.h" + +#include <clang/AST/AST.h> + +using namespace clang; +using namespace std; + + +HeapAllocatedSmallTrivialType::HeapAllocatedSmallTrivialType(const std::string &name, + ClazyContext *context) + : CheckBase(name, context) +{ +} + +void HeapAllocatedSmallTrivialType::VisitStmt(clang::Stmt *stmt) +{ + auto newExpr = dyn_cast<CXXNewExpr>(stmt); + if (!newExpr || newExpr->getNumPlacementArgs() > 0) // Placement new, user probably knows what he's doing + return; + + if (newExpr->isArray()) + return; + + QualType qualType = newExpr->getType()->getPointeeType(); + if (TypeUtils::isSmallTrivial(m_context, qualType)) { + if (clazy::contains(qualType.getAsString(), "Private")) { + // Possibly a pimpl, forward declared in header + return; + } + + emitWarning(stmt, "Don't heap-allocate small trivially copyable/destructible types: " + qualType.getAsString()); + } +} diff --git a/src/checks/manuallevel/heap-allocated-small-trivial-type.h b/src/checks/manuallevel/heap-allocated-small-trivial-type.h new file mode 100644 index 00000000..691b53e9 --- /dev/null +++ b/src/checks/manuallevel/heap-allocated-small-trivial-type.h @@ -0,0 +1,39 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2019 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_HEAP_ALLOCATED_SMALL_TRIVIAL_TYPE_H +#define CLAZY_HEAP_ALLOCATED_SMALL_TRIVIAL_TYPE_H + +#include "checkbase.h" + + +/** + * See README-heap-allocated-small-trivial-type.md for more info. + */ +class HeapAllocatedSmallTrivialType : public CheckBase +{ +public: + explicit HeapAllocatedSmallTrivialType(const std::string &name, ClazyContext *context); + void VisitStmt(clang::Stmt *) override; +private: +}; + +#endif diff --git a/tests/heap-allocated-small-trivial-type/config.json b/tests/heap-allocated-small-trivial-type/config.json new file mode 100644 index 00000000..e7e6e0cb --- /dev/null +++ b/tests/heap-allocated-small-trivial-type/config.json @@ -0,0 +1,7 @@ +{ + "tests" : [ + { + "filename" : "main.cpp" + } + ] +} diff --git a/tests/heap-allocated-small-trivial-type/main.cpp b/tests/heap-allocated-small-trivial-type/main.cpp new file mode 100644 index 00000000..a193d51f --- /dev/null +++ b/tests/heap-allocated-small-trivial-type/main.cpp @@ -0,0 +1,37 @@ +#include <QtCore/QObject> +#include <QtCore/QString> + +struct SmallTrivial +{ + int v; +}; + +struct BigTrivial +{ + int v[10]; +}; + +struct NonTrivial +{ + int v; + ~NonTrivial() {} +}; + +struct NonTrivial2 +{ + int v; + NonTrivial2() {} + NonTrivial2(const NonTrivial2 &) {} +}; + +void test() +{ + auto a = new SmallTrivial(); // Warn + auto b = new BigTrivial(); + auto c = new NonTrivial(); + auto d = new NonTrivial2(); + + auto e = new(0) SmallTrivial; + auto f = new SmallTrivial[100]; + +} diff --git a/tests/heap-allocated-small-trivial-type/main.cpp.expected b/tests/heap-allocated-small-trivial-type/main.cpp.expected new file mode 100644 index 00000000..1a720d5e --- /dev/null +++ b/tests/heap-allocated-small-trivial-type/main.cpp.expected @@ -0,0 +1 @@ +heap-allocated-small-trivial-type/main.cpp:29:14: warning: Don't heap-allocate small trivially copyable/destructible types: struct SmallTrivial [-Wclazy-heap-allocated-small-trivial-type] |