summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-11-07 13:55:06 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-11-09 07:31:24 +0100
commit5ba447bdcd13ba3d7c27c8609f207910227e4ab6 (patch)
tree9a59e7058ef40be90867518590e35abb6c0615f5 /compilerplugins
parentea4a47d7d442d5d897cfa3a6e9f09ce3f1f233c5 (diff)
new loplugin simplifydynamiccast
simplify dynamic_cast followed by static_cast Change-Id: I965afcf05d1675094cfde53d3590a0fd00f26279 Reviewed-on: https://gerrit.libreoffice.org/44460 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/simplifydynamiccast.cxx116
-rw-r--r--compilerplugins/clang/test/simplifydynamiccast.cxx34
2 files changed, 150 insertions, 0 deletions
diff --git a/compilerplugins/clang/simplifydynamiccast.cxx b/compilerplugins/clang/simplifydynamiccast.cxx
new file mode 100644
index 000000000000..f305f8cbeaef
--- /dev/null
+++ b/compilerplugins/clang/simplifydynamiccast.cxx
@@ -0,0 +1,116 @@
+/* -*- 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/.
+ */
+
+#include <cassert>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <set>
+
+#include <clang/AST/CXXInheritance.h>
+#include "compat.hxx"
+#include "plugin.hxx"
+
+namespace
+{
+class SimplifyDynamicCast : public RecursiveASTVisitor<SimplifyDynamicCast>, public loplugin::Plugin
+{
+public:
+ explicit SimplifyDynamicCast(loplugin::InstantiationData const& data)
+ : Plugin(data)
+ {
+ }
+
+ virtual void run() override
+ {
+ // StringRef fn( compiler.getSourceManager().getFileEntryForID(
+ // compiler.getSourceManager().getMainFileID())->getName() );
+ // if (loplugin::isSamePathname(fn, WORKDIR "/YaccTarget/unoidl/source/sourceprovider-parser.cxx"))
+ // return;
+
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+ }
+
+ bool TraverseIfStmt(IfStmt*);
+ bool VisitCXXStaticCastExpr(CXXStaticCastExpr const*);
+
+private:
+ std::vector<QualType> dynamicCastVec;
+ std::vector<Decl const*> dynamicCastSubExprVec;
+ std::vector<IfStmt const*> ifVec;
+};
+
+bool SimplifyDynamicCast::TraverseIfStmt(IfStmt* ifStmt)
+{
+ auto condExpr = ifStmt->getCond()->IgnoreParenImpCasts();
+ auto dynamicCastExpr = dyn_cast<CXXDynamicCastExpr>(condExpr);
+ if (!dynamicCastExpr)
+ {
+ if (auto binaryOp = dyn_cast<BinaryOperator>(condExpr))
+ {
+ if (binaryOp->getOpcode() == BO_NE)
+ dynamicCastExpr
+ = dyn_cast<CXXDynamicCastExpr>(binaryOp->getLHS()->IgnoreParenImpCasts());
+ }
+ }
+ Decl const* subExprDecl = nullptr;
+ if (dynamicCastExpr)
+ {
+ auto subExprDeclRefExpr
+ = dyn_cast<DeclRefExpr>(dynamicCastExpr->getSubExpr()->IgnoreParenImpCasts());
+ if (!subExprDeclRefExpr)
+ dynamicCastExpr = nullptr;
+ else
+ subExprDecl = subExprDeclRefExpr->getDecl();
+ }
+ if (dynamicCastExpr)
+ {
+ auto qt = dynamicCastExpr->getTypeAsWritten();
+ dynamicCastVec.push_back(qt);
+ dynamicCastSubExprVec.push_back(subExprDecl);
+ ifVec.push_back(ifStmt);
+ }
+ bool ret = RecursiveASTVisitor::TraverseIfStmt(ifStmt);
+ if (dynamicCastExpr)
+ {
+ dynamicCastVec.pop_back();
+ dynamicCastSubExprVec.pop_back();
+ ifVec.pop_back();
+ }
+ return ret;
+}
+
+bool SimplifyDynamicCast::VisitCXXStaticCastExpr(CXXStaticCastExpr const* staticCastExpr)
+{
+ if (ignoreLocation(staticCastExpr))
+ return true;
+ if (dynamicCastVec.empty())
+ return true;
+
+ auto qt = staticCastExpr->getTypeAsWritten();
+ auto it = std::find(dynamicCastVec.begin(), dynamicCastVec.end(), qt);
+ if (it == dynamicCastVec.end())
+ return true;
+ int idx = it - dynamicCastVec.begin();
+ auto subExprDecl = dyn_cast<DeclRefExpr>(staticCastExpr->getSubExpr()->IgnoreParenImpCasts());
+ if (!subExprDecl)
+ return true;
+ if (dynamicCastSubExprVec[idx] != subExprDecl->getDecl())
+ return true;
+ report(DiagnosticsEngine::Warning, "simplify, use var in if", staticCastExpr->getLocStart())
+ << staticCastExpr->getSourceRange();
+ auto ifStmt = ifVec[idx];
+ report(DiagnosticsEngine::Note, "if here", ifStmt->getLocStart()) << ifStmt->getSourceRange();
+ return true;
+}
+
+loplugin::Plugin::Registration<SimplifyDynamicCast> X("simplifydynamiccast", true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/compilerplugins/clang/test/simplifydynamiccast.cxx b/compilerplugins/clang/test/simplifydynamiccast.cxx
new file mode 100644
index 000000000000..111734f0a511
--- /dev/null
+++ b/compilerplugins/clang/test/simplifydynamiccast.cxx
@@ -0,0 +1,34 @@
+/* -*- 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)
+{
+ if (dynamic_cast<ClassB*>(p1)) // expected-note {{if here [loplugin:simplifydynamiccast]}}
+ {
+ static_cast<ClassB*>(p1)
+ ->foo(); // expected-error@-1 {{simplify, use var in if [loplugin:simplifydynamiccast]}}
+ }
+ if (dynamic_cast<ClassB*>(p1) != nullptr)
+ { // expected-note@-1 {{if here [loplugin:simplifydynamiccast]}}
+ static_cast<ClassB*>(p1)
+ ->foo(); // expected-error@-1 {{simplify, use var in if [loplugin:simplifydynamiccast]}}
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */