diff options
author | Noel <noel.grandin@collabora.co.uk> | 2021-02-26 15:20:17 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2021-03-01 12:33:17 +0100 |
commit | 11083d1fcfc2dde543c6daddea51b554d032392c (patch) | |
tree | 1f6305db0c157f4b5514d012a22ba3e3b16c5f00 /compilerplugins | |
parent | 46d3370d6c5a571c3013e3a964e49f0997d4eabf (diff) |
new loplugin:staticdynamic
look for places we are dynamic_cast'ing after static_cast'ing,
which means the dynamic_cast is a waste of time.
Change-Id: Ife11bb675020738040646230bbd038278d84f7f2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111631
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/sharedvisitor/dummyplugin.hxx | 1 | ||||
-rw-r--r-- | compilerplugins/clang/staticdynamic.cxx | 120 | ||||
-rw-r--r-- | compilerplugins/clang/test/staticdynamic.cxx | 28 |
3 files changed, 149 insertions, 0 deletions
diff --git a/compilerplugins/clang/sharedvisitor/dummyplugin.hxx b/compilerplugins/clang/sharedvisitor/dummyplugin.hxx index d20f82f9278e..fea2786a796e 100644 --- a/compilerplugins/clang/sharedvisitor/dummyplugin.hxx +++ b/compilerplugins/clang/sharedvisitor/dummyplugin.hxx @@ -43,6 +43,7 @@ public: bool TraverseWhileStmt( WhileStmt* ) { return complain(); } bool TraverseDoStmt( DoStmt* ) { return complain(); } bool TraverseForStmt( ForStmt* ) { return complain(); } + bool TraverseCompoundStmt( CompoundStmt* ) { return complain(); } bool TraverseCXXForRangeStmt( CXXForRangeStmt* ) { return complain(); } bool TraverseConditionalOperator( ConditionalOperator* ) { return complain(); } bool TraverseCXXCatchStmt( CXXCatchStmt* ) { return complain(); } diff --git a/compilerplugins/clang/staticdynamic.cxx b/compilerplugins/clang/staticdynamic.cxx new file mode 100644 index 000000000000..b2383413b287 --- /dev/null +++ b/compilerplugins/clang/staticdynamic.cxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef LO_CLANG_SHARED_PLUGINS + +#include <cassert> +#include <string> +#include <iostream> +#include <fstream> +#include <map> +#include <vector> + +#include "compat.hxx" +#include "check.hxx" +#include "plugin.hxx" + +namespace +{ +class StaticDynamic : public loplugin::FilteringPlugin<StaticDynamic> +{ +public: + explicit StaticDynamic(loplugin::InstantiationData const& data) + : FilteringPlugin(data) + { + } + + bool preRun() override { return compiler.getLangOpts().CPlusPlus; } + void postRun() override {} + virtual void run() override + { + if (preRun()) + TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); + } + + bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const*); + bool VisitCXXStaticCastExpr(CXXStaticCastExpr const*); + bool PreTraverseCompoundStmt(CompoundStmt*); + bool PostTraverseCompoundStmt(CompoundStmt*, bool); + bool TraverseCompoundStmt(CompoundStmt*); + +private: + // the key is the pair of VarDecl and the type being cast to. + typedef std::map<std::pair<VarDecl const*, clang::Type const*>, SourceLocation> MapType; + MapType staticCastVars; + // only maintain state inside a single basic block, we're not trying to analyse + // cross-block interactions. + std::vector<MapType> blockStack; +}; + +bool StaticDynamic::PreTraverseCompoundStmt(CompoundStmt*) +{ + blockStack.push_back(std::move(staticCastVars)); + return true; +} + +bool StaticDynamic::PostTraverseCompoundStmt(CompoundStmt*, bool) +{ + staticCastVars = std::move(blockStack.back()); + blockStack.pop_back(); + return true; +} + +bool StaticDynamic::TraverseCompoundStmt(CompoundStmt* compoundStmt) +{ + bool ret = true; + if (PreTraverseCompoundStmt(compoundStmt)) + { + ret = FilteringPlugin::TraverseCompoundStmt(compoundStmt); + PostTraverseCompoundStmt(compoundStmt, ret); + } + return ret; +} + +bool StaticDynamic::VisitCXXStaticCastExpr(CXXStaticCastExpr const* staticCastExpr) +{ + if (ignoreLocation(staticCastExpr)) + return true; + auto subExprDecl = dyn_cast<DeclRefExpr>(staticCastExpr->getSubExpr()->IgnoreParenImpCasts()); + if (!subExprDecl) + return true; + auto varDecl = dyn_cast_or_null<VarDecl>(subExprDecl->getDecl()); + if (!varDecl) + return true; + staticCastVars.insert({ { varDecl, staticCastExpr->getTypeAsWritten().getTypePtr() }, + compat::getBeginLoc(staticCastExpr) }); + return true; +} + +bool StaticDynamic::VisitCXXDynamicCastExpr(CXXDynamicCastExpr const* dynamicCastExpr) +{ + if (ignoreLocation(dynamicCastExpr)) + return true; + + auto subExprDecl = dyn_cast<DeclRefExpr>(dynamicCastExpr->getSubExpr()->IgnoreParenImpCasts()); + if (!subExprDecl) + return true; + auto varDecl = dyn_cast_or_null<VarDecl>(subExprDecl->getDecl()); + if (!varDecl) + return true; + auto it = staticCastVars.find({ varDecl, dynamicCastExpr->getTypeAsWritten().getTypePtr() }); + if (it == staticCastVars.end()) + return true; + report(DiagnosticsEngine::Warning, "dynamic_cast after static_cast", + compat::getBeginLoc(dynamicCastExpr)) + << dynamicCastExpr->getSourceRange(); + report(DiagnosticsEngine::Note, "static_cast here", it->second); + return true; +} + +loplugin::Plugin::Registration<StaticDynamic> staticdynamic("staticdynamic"); +} + +#endif // LO_CLANG_SHARED_PLUGINS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/staticdynamic.cxx b/compilerplugins/clang/test/staticdynamic.cxx new file mode 100644 index 000000000000..af4ea94c754a --- /dev/null +++ b/compilerplugins/clang/test/staticdynamic.cxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +struct ClassA +{ + virtual ~ClassA() {} +}; + +struct ClassB : public ClassA +{ + void foo() {} +}; + +void f1(ClassA* p1) +{ + // expected-note@+1 {{static_cast here [loplugin:staticdynamic]}} + static_cast<ClassB*>(p1)->foo(); + // expected-error@+1 {{dynamic_cast after static_cast [loplugin:staticdynamic]}} + dynamic_cast<ClassB*>(p1)->foo(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |