From 306ddfb1b87d94a343e8e2b6b9270ca682f92ac3 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Tue, 5 Dec 2017 11:37:59 +0100 Subject: Replace deprecated std::mem_fun et al in reportdesign (as std::mem_fun is gone by default at least from recent libc++ in C++17 mode) Change-Id: Ib66134bd4072dfe0ce3bc36aa684cee710921235 Reviewed-on: https://gerrit.libreoffice.org/45868 Tested-by: Jenkins Reviewed-by: Stephan Bergmann --- compilerplugins/clang/redundantcast.cxx | 63 ++++++++++++++++++++++++++-- compilerplugins/clang/test/redundantcast.cxx | 34 +++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) (limited to 'compilerplugins') diff --git a/compilerplugins/clang/redundantcast.cxx b/compilerplugins/clang/redundantcast.cxx index bdf23d9094cf..2f905d355720 100644 --- a/compilerplugins/clang/redundantcast.cxx +++ b/compilerplugins/clang/redundantcast.cxx @@ -161,6 +161,7 @@ public: private: bool visitBinOp(BinaryOperator const * expr); bool isOkToRemoveArithmeticCast(QualType t1, QualType t2, const Expr* subExpr); + bool isOverloadedFunction(FunctionDecl const * decl); }; bool RedundantCast::VisitImplicitCastExpr(const ImplicitCastExpr * expr) { @@ -362,9 +363,10 @@ bool RedundantCast::VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr) { if (ignoreLocation(expr)) { return true; } - auto const sub = compat::getSubExprAsWritten(expr); - auto const t1 = sub->getType(); auto const t2 = expr->getTypeAsWritten(); + bool const fnptr = t2->isFunctionPointerType() || t2->isMemberFunctionPointerType(); + auto const sub = fnptr ? expr->getSubExpr() : compat::getSubExprAsWritten(expr); + auto const t1 = sub->getType(); auto const nonClassObjectType = t2->isObjectType() && !(t2->isRecordType() || t2->isArrayType()); if (nonClassObjectType && t2.hasLocalQualifiers()) { @@ -445,6 +447,23 @@ bool RedundantCast::VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr) { { return true; } + // Don't warn if a static_cast on a pointer to function or member function is used to + // disambiguate an overloaded function: + if (fnptr) { + auto e = sub->IgnoreParenImpCasts(); + if (auto const e1 = dyn_cast(e)) { + if (e1->getOpcode() == UO_AddrOf) { + e = e1->getSubExpr()->IgnoreParenImpCasts(); + } + } + if (auto const e1 = dyn_cast(e)) { + if (auto const fdecl = dyn_cast(e1->getDecl())) { + if (isOverloadedFunction(fdecl)) { + return true; + } + } + } + } // Suppress warnings from static_cast in C++ definition of assert in // "assert: Support types @@ -625,7 +644,9 @@ bool RedundantCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * exp // ), and only to cases where the sub-expression already is a prvalue of // non-class type (and thus the cast is unlikely to be meant to create a // temporary): - auto const sub = compat::getSubExprAsWritten(expr); + auto const t1 = expr->getTypeAsWritten(); + bool const fnptr = t1->isFunctionPointerType() || t1->isMemberFunctionPointerType(); + auto const sub = fnptr ? expr->getSubExpr() : compat::getSubExprAsWritten(expr); if (sub->getValueKind() != VK_RValue || expr->getType()->isRecordType() || isa(sub) || isa(sub)) { @@ -643,6 +664,24 @@ bool RedundantCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * exp } } + // Don't warn if a functional cast on a pointer to function or member function is used to + // disambiguate an overloaded function: + if (fnptr) { + auto e = sub->IgnoreParenImpCasts(); + if (auto const e1 = dyn_cast(e)) { + if (e1->getOpcode() == UO_AddrOf) { + e = e1->getSubExpr()->IgnoreParenImpCasts(); + } + } + if (auto const e1 = dyn_cast(e)) { + if (auto const fdecl = dyn_cast(e1->getDecl())) { + if (isOverloadedFunction(fdecl)) { + return true; + } + } + } + } + // See the commit message of d0e7d020fa405ab94f19916ec96fbd4611da0031 // "socket.c -> socket.cxx" for the reason to have // @@ -666,7 +705,6 @@ bool RedundantCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * exp } } - auto const t1 = expr->getTypeAsWritten(); auto const t2 = sub->getType(); if (t1.getCanonicalType() != t2.getCanonicalType()) return true; @@ -766,6 +804,23 @@ bool RedundantCast::visitBinOp(BinaryOperator const * expr) { return true; } +bool RedundantCast::isOverloadedFunction(FunctionDecl const * decl) { + auto const ctx = decl->getDeclContext(); + if (!compat::isLookupContext(*ctx)) { + return false; + } + auto const canon = decl->getCanonicalDecl(); + auto const res = ctx->lookup(decl->getDeclName()); + for (auto d = res.begin(); d != res.end(); ++d) { + if (auto const f = dyn_cast(*d)) { + if (f->getCanonicalDecl() != canon) { + return true; + } + } + } + return false; +} + loplugin::Plugin::Registration X("redundantcast", true); } diff --git a/compilerplugins/clang/test/redundantcast.cxx b/compilerplugins/clang/test/redundantcast.cxx index 20578079c2cb..70fcdf3340cb 100644 --- a/compilerplugins/clang/test/redundantcast.cxx +++ b/compilerplugins/clang/test/redundantcast.cxx @@ -340,6 +340,40 @@ void testDynamicCast() { (void) dynamic_cast(s2); } +void overload(int); +void overload(long); +void nonOverload(); + +struct Overload { + int overload(); + long overload() const; + void nonOverload(); +}; + +void testOverloadResolution() { + (void) static_cast(overload); + (void) static_cast((overload)); + (void) static_cast(&overload); + (void) static_cast((&overload)); + (void) static_cast(&((overload))); + (void) static_cast(nonOverload); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast((nonOverload)); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast(&nonOverload); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast((&nonOverload)); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast(&((nonOverload))); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast(&Overload::overload); + (void) static_cast(&Overload::nonOverload); // expected-error {{static_cast from 'void (Overload::*)()' prvalue to 'void (Overload::*)()' prvalue is redundant [loplugin:redundantcast]}} + + using OverloadFn = void (*)(long); + (void) OverloadFn(overload); + using NonOverloadFn = void (*)(); + (void) NonOverloadFn(nonOverload); // expected-error {{redundant functional cast from 'void (*)()' to 'NonOverloadFn' (aka 'void (*)()') [loplugin:redundantcast]}} + using OverloadMemFn = long (Overload::*)() const; + (void) OverloadMemFn(&Overload::overload); + using NonOverloadMemFn = void (Overload::*)(); + (void) NonOverloadMemFn(&Overload::nonOverload); // expected-error {{redundant functional cast from 'void (Overload::*)()' to 'NonOverloadMemFn' (aka 'void (Overload::*)()') [loplugin:redundantcast]}} +}; + int main() { testConstCast(); testStaticCast(); -- cgit