summaryrefslogtreecommitdiff
path: root/compilerplugins/clang
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-10-20 20:51:50 +0200
committerStephan Bergmann <sbergman@redhat.com>2017-10-21 15:44:11 +0200
commitead920a48aa8c35075fdb980b9d213ff1c580dd1 (patch)
treebb1628fd293f03b22920bc74e89657320da6442e /compilerplugins/clang
parentfe5b70723fc83f229fb4b41231a663a8700f48c4 (diff)
loplugin:redundantcast handle dynamic_cast
Change-Id: I7855c76e820efce96778b1c19ec71dffcc4b4abb Reviewed-on: https://gerrit.libreoffice.org/43621 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins/clang')
-rw-r--r--compilerplugins/clang/redundantcast.cxx24
-rw-r--r--compilerplugins/clang/test/redundantcast.cxx20
2 files changed, 44 insertions, 0 deletions
diff --git a/compilerplugins/clang/redundantcast.cxx b/compilerplugins/clang/redundantcast.cxx
index 30914a460dc4..c28878e9e536 100644
--- a/compilerplugins/clang/redundantcast.cxx
+++ b/compilerplugins/clang/redundantcast.cxx
@@ -128,6 +128,8 @@ public:
bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * expr);
+ bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr);
+
bool VisitCallExpr(CallExpr const * expr);
bool VisitCXXDeleteExpr(CXXDeleteExpr const * expr);
@@ -676,6 +678,28 @@ bool RedundantCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * exp
return true;
}
+bool RedundantCast::VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ // ignore dynamic_cast<T1>(static_cast<T1>(void*)), it's necessary
+ if (auto subStaticCast = dyn_cast<CXXStaticCastExpr>(expr->getSubExpr())) {
+ if (loplugin::TypeCheck(subStaticCast->getSubExpr()->getType()).Pointer().Void())
+ return true;
+ }
+ // so far this only deals with dynamic casting from T to T
+ auto const sub = compat::getSubExprAsWritten(expr);
+ auto const t1 = expr->getTypeAsWritten();
+ auto const t2 = sub->getType();
+ if (t1.getCanonicalType() != t2.getCanonicalType())
+ return true;
+ report(
+ DiagnosticsEngine::Warning,
+ "redundant dynamic cast from %0 to %1", expr->getExprLoc())
+ << t2 << t1 << expr->getSourceRange();
+ return true;
+}
+
bool RedundantCast::VisitCallExpr(CallExpr const * expr) {
if (ignoreLocation(expr)) {
return true;
diff --git a/compilerplugins/clang/test/redundantcast.cxx b/compilerplugins/clang/test/redundantcast.cxx
index ff3e8392906a..38c44f837cbc 100644
--- a/compilerplugins/clang/test/redundantcast.cxx
+++ b/compilerplugins/clang/test/redundantcast.cxx
@@ -325,6 +325,25 @@ void testReinterpretConstCast() {
(void) reinterpret_cast<std::size_t>((const_cast<int const *>(&n))); // expected-error-re {{redundant const_cast from 'int *' to 'const int *' within reinterpret_cast to fundamental type 'std::size_t' (aka 'unsigned {{.+}}') [loplugin:redundantcast]}}
}
+void testDynamicCast() {
+
+ struct S1 { virtual ~S1(); };
+ struct S2 final: S1 {};
+ struct S3: S1 {};
+
+ S1 * s1 = nullptr;
+ S2 * s2 = nullptr;
+ void * v1 = nullptr;
+
+ (void) dynamic_cast<S2 *>(s1);
+ (void) dynamic_cast<S1 *>(s2);
+ (void) dynamic_cast<S2 *>(s2); // expected-error {{redundant dynamic cast from 'S2 *' to 'S2 *' [loplugin:redundantcast]}}
+ (void) dynamic_cast<S3 *>(s2);
+ // used in some assert in vcl
+ (void) dynamic_cast<S1 *>(static_cast<S1*>(v1));
+ (void) dynamic_cast<S2 *>(static_cast<S2*>(s1)); // expected-error {{redundant dynamic cast from 'S2 *' to 'S2 *' [loplugin:redundantcast]}}
+}
+
int main() {
testConstCast();
testStaticCast();
@@ -332,6 +351,7 @@ int main() {
testCStyleCast();
testCStyleCastOfTemplateMethodResult(nullptr);
testReinterpretConstCast();
+ testDynamicCast();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */