/* -*- 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/. */ #include #include #include #include "redundantcast.hxx" void f1(char *) {} void f2(char const *) {} struct D: S {}; enum Enum1 { X }; void testConstCast() { char * p1; char const * p2; p1 = nullptr; p2 = ""; f1(const_cast(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *' prvalue [loplugin:redundantcast]}} f1(const_cast(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *const' prvalue [loplugin:redundantcast]}} f1(const_cast(p2)); f1(const_cast(p2)); f2(const_cast(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *' prvalue [loplugin:redundantcast]}} f2(const_cast(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *const' prvalue [loplugin:redundantcast]}} f2(const_cast(p1)); f2(const_cast(p1)); f2(const_cast(p2)); // expected-error {{redundant const_cast from 'const char *' to 'char *', result is implicitly cast to 'const char *' [loplugin:redundantcast]}} f2(const_cast(p2)); // expected-error {{redundant const_cast from 'const char *' to 'char *', result is implicitly cast to 'const char *' [loplugin:redundantcast]}} f2(const_cast(p2)); // expected-error {{redundant const_cast from 'const char *' lvalue to 'const char *' prvalue [loplugin:redundantcast]}} f2(const_cast(p2)); // expected-error {{redundant const_cast from 'const char *' lvalue to 'const char *const' prvalue [loplugin:redundantcast]}} void * vp = nullptr; (void) const_cast(static_cast(vp)); // expected-error {{redundant static_cast/const_cast combination from 'void *' via 'const char *' to 'char *' [loplugin:redundantcast]}} (void) const_cast(static_cast(nullptr)); // expected-error-re {{redundant static_cast/const_cast combination from '{{(std::)?}}nullptr_t' via 'const char *' to 'char *' [loplugin:redundantcast]}} (void) const_cast(static_cast(D{})); // expected-error {{redundant static_cast/const_cast combination from 'D' via 'const S &' to 'S &' [loplugin:redundantcast]}} S const s{}; const_cast(s).f1(); const_cast(s).f2(); // expected-error {{redundant const_cast from 'const S' to 'S', result is implicitly cast to 'const S' [loplugin:redundantcast]}} const_cast(s).f3(); s.f3(); // non-class lvalue, non-const: int ni{}; // (void) const_cast(ni); (void) const_cast(ni); // expected-error {{redundant const_cast from 'int' lvalue to 'int &' lvalue [loplugin:redundantcast]}} (void) const_cast(ni); // (void) const_cast(ni); (void) const_cast(ni); (void) const_cast(ni); // non-class lvalue, const: int const ci{}; // (void) const_cast(ci); (void) const_cast(ci); (void) const_cast(ci); // (void) const_cast(ci); (void) const_cast(ci); // expected-error {{redundant const_cast from 'const int' lvalue to 'const int &' lvalue [loplugin:redundantcast]}} (void) const_cast(ci); // non-class xvalue, non-const: // (void) const_cast(nix()); // (void) const_cast(nix()); (void) const_cast(nix()); // expected-error {{redundant const_cast from 'int' xvalue to 'int &&' xvalue [loplugin:redundantcast]}} // (void) const_cast(nix()); // (void) const_cast(nix()); (void) const_cast(nix()); // non-class xvalue, const: // (void) const_cast(cix()); // (void) const_cast(cix()); (void) const_cast(cix()); // (void) const_cast(cix()); // (void) const_cast(cix()); (void) const_cast(cix()); // expected-error {{redundant const_cast from 'const int' xvalue to 'const int &&' xvalue [loplugin:redundantcast]}} // non-class prvalue, non-const: // (void) const_cast(nir()); // (void) const_cast(nir()); // (void) const_cast(nir()); // (void) const_cast(nir()); // (void) const_cast(nir()); // (void) const_cast(nir()); // non-class prvalue, const: // (void) const_cast(cir()); // (void) const_cast(cir()); // (void) const_cast(cir()); // (void) const_cast(cir()); // (void) const_cast(cir()); // (void) const_cast(cir()); // class lvalue, non-const: S ns{}; // (void) const_cast(ns); (void) const_cast(ns); // expected-error {{redundant const_cast from 'S' lvalue to 'S &' lvalue [loplugin:redundantcast]}} (void) const_cast(ns); // (void) const_cast(ns); (void) const_cast(ns); (void) const_cast(ns); // class lvalue, const: S const cs{}; // (void) const_cast(cs); (void) const_cast(cs); (void) const_cast(cs); // (void) const_cast(cs); (void) const_cast(cs); // expected-error {{redundant const_cast from 'const S' lvalue to 'const S &' lvalue [loplugin:redundantcast]}} (void) const_cast(cs); // class xvalue, non-const: // (void) const_cast(nsx()); // (void) const_cast(nsx()); (void) const_cast(nsx()); // expected-error {{redundant const_cast from 'S' xvalue to 'S &&' xvalue [loplugin:redundantcast]}} // (void) const_cast(nsx()); // (void) const_cast(nsx()); (void) const_cast(nsx()); // class xvalue, const: // (void) const_cast(csx()); // (void) const_cast(csx()); (void) const_cast(csx()); // (void) const_cast(csx()); // (void) const_cast(csx()); (void) const_cast(csx()); // expected-error {{redundant const_cast from 'const S' xvalue to 'const S &&' xvalue [loplugin:redundantcast]}} // class prvalue, non-const: // (void) const_cast(nsr()); // (void) const_cast(nsr()); (void) const_cast(nsr()); // (void) const_cast(nsr()); // (void) const_cast(nsr()); (void) const_cast(nsr()); // class prvalue, const: // (void) const_cast(csr()); // (void) const_cast(csr()); (void) const_cast(csr()); // (void) const_cast(csr()); // (void) const_cast(csr()); (void) const_cast(csr()); } void testStaticCast() { // non-class lvalue, non-const: int ni{}; (void) static_cast(ni); // expected-error {{static_cast from 'int' lvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(ni); (void) static_cast(ni); // expected-error {{static_cast from 'int' lvalue to 'int &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(ni); (void) static_cast(ni); // expected-error {{in static_cast from 'int' lvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(ni); // expected-error {{static_cast from 'int' lvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(ni); (void) static_cast(ni); // expected-error {{static_cast from 'int' lvalue to 'const int &' lvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(ni); (void) static_cast(ni); // expected-error {{static_cast from 'int' lvalue to 'const int &&' xvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(ni); // non-class lvalue, const: int const ci{}; (void) static_cast(ci); // expected-error {{static_cast from 'const int' lvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(ci); // (void) static_cast(ci); // (void) static_cast(ci); (void) static_cast(ci); // expected-error {{in static_cast from 'const int' lvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(ci); // expected-error {{static_cast from 'const int' lvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(ci); (void) static_cast(ci); // expected-error {{static_cast from 'const int' lvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(ci); // non-class xvalue, non-const: (void) static_cast(nix()); // expected-error {{static_cast from 'int' xvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(nix()); // (void) static_cast(nix()); (void) static_cast(nix()); // expected-error {{static_cast from 'int' xvalue to 'int &&' xvalue is redundant [loplugin:redundantcast]}} (void) static_cast(nix()); // expected-error {{in static_cast from 'int' xvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(nix()); // expected-error {{static_cast from 'int' xvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} (void) static_cast(nix()); (void) static_cast(nix()); // expected-error {{static_cast from 'int' xvalue to 'const int &&' xvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(nix()); // non-class xvalue, const: (void) static_cast(cix()); // expected-error {{static_cast from 'const int' xvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(cix()); // (void) static_cast(cix()); // (void) static_cast(cix()); (void) static_cast(cix()); // expected-error {{in static_cast from 'const int' xvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(cix()); // expected-error {{static_cast from 'const int' xvalue to 'int' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) int(cix()); (void) static_cast(cix()); (void) static_cast(cix()); // expected-error {{static_cast from 'const int' xvalue to 'const int &&' xvalue is redundant [loplugin:redundantcast]}} // non-class prvalue, non-const: (void) static_cast(nir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} // (void) static_cast(nir()); (void) static_cast(nir()); (void) static_cast(nir()); // expected-error {{in static_cast from 'int' prvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(nir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} (void) static_cast(nir()); // expected-error {{static_cast from 'int' prvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(nir()); // non-class prvalue, const: (void) static_cast(cir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} // (void) static_cast(cir()); (void) static_cast(cir()); (void) static_cast(cir()); // expected-error {{in static_cast from 'int' prvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} /* => */ (void) static_cast(cir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} (void) static_cast(cir()); // expected-error {{static_cast from 'int' prvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(cir()); // class lvalue, non-const: S ns{}; (void) static_cast(ns); // expected-error {{static_cast from 'S' lvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(ns); (void) static_cast(ns); // expected-error {{static_cast from 'S' lvalue to 'S &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(ns); (void) static_cast(ns); // expected-error {{static_cast from 'S' lvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ using CS = const S; (void) CS(ns); (void) static_cast(ns); // expected-error {{static_cast from 'S' lvalue to 'const S &' lvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(ns); (void) static_cast(ns); // expected-error {{static_cast from 'S' lvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(ns); // class lvalue, const: S const cs{}; (void) static_cast(cs); // expected-error {{static_cast from 'const S' lvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(cs); // (void) static_cast(cs); // (void) static_cast(cs); (void) static_cast(cs); // expected-error {{static_cast from 'const S' lvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) CS(cs); (void) static_cast(cs); // expected-error {{static_cast from 'const S' lvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(cs); // class xvalue, non-const: (void) static_cast(nsx()); // expected-error {{static_cast from 'S' xvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(nsx()); // (void) static_cast(nsx()); (void) static_cast(nsx()); // expected-error {{static_cast from 'S' xvalue to 'S &&' xvalue is redundant [loplugin:redundantcast]}} (void) static_cast(nsx()); // expected-error {{static_cast from 'S' xvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) CS(nsx()); (void) static_cast(nsx()); (void) static_cast(nsx()); // expected-error {{static_cast from 'S' xvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(nsx()); // class xvalue, const: (void) static_cast(csx()); // expected-error {{static_cast from 'const S' xvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(csx()); // (void) static_cast(csx()); // (void) static_cast(csx()); (void) static_cast(csx()); // expected-error {{static_cast from 'const S' xvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) CS(csx()); (void) static_cast(csx()); (void) static_cast(csx()); // expected-error {{static_cast from 'const S' xvalue to 'const S &&' xvalue is redundant [loplugin:redundantcast]}} // class prvalue, non-const: (void) static_cast(nsr()); // expected-error {{static_cast from 'S' prvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(nsr()); // (void) static_cast(nsr()); (void) static_cast(nsr()); (void) static_cast(nsr()); // expected-error {{static_cast from 'S' prvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) CS(nsr()); (void) static_cast(nsr()); // expected-error {{static_cast from 'S' prvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(nsr()); // expected-error {{static_cast from 'S' prvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} /* => */ (void) const_cast(nsr()); // class prvalue, const: (void) static_cast(csr()); // expected-error {{static_cast from 'const S' prvalue to 'S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) S(csr()); // (void) static_cast(csr()); // (void) static_cast(csr()); (void) static_cast(csr()); // expected-error {{static_cast from 'const S' prvalue to 'const S' prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} /* => */ (void) CS(csr()); (void) static_cast(csr()); // expected-error {{static_cast from 'const S' prvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} (void) static_cast(csr()); } int & testReturnStaticCast(int && x) { return static_cast(x); } void testFunctionalCast() { (void) int(nir()); // expected-error {{redundant functional cast from 'int' to 'int' [loplugin:redundantcast]}} (void) S(nsr()); } void testCStyleCast() { Enum1 e = (Enum1)Enum1::X; // expected-error {{redundant cstyle cast from 'Enum1' to 'Enum1' [loplugin:redundantcast]}} (void)e; } template struct EnumItemInterface { T GetValue() { return static_cast(0); } }; class Enum1Item : public EnumItemInterface { }; bool testCStyleCastOfTemplateMethodResult(Enum1Item* item) { return (Enum1)item->GetValue() == Enum1::X; // expected-error {{redundant cstyle cast from 'Enum1' to 'Enum1' [loplugin:redundantcast]}} } using T1 = int; T1 nt1r() { return 0; } void testArithmeticTypedefs() { (void) static_cast(nir()); (void) T1(nir()); (void) (T1) nir(); (void) static_cast(nt1r()); (void) int(nt1r()); (void) (int) nt1r(); using T2 = T1; (void) static_cast(nt1r()); (void) T2(nt1r()); (void) (T2) nt1r(); (void) static_cast(nt1r()); // expected-error {{redundant}} (void) T1(nt1r()); // expected-error {{redundant}} (void) (T1) nt1r(); // expected-error {{redundant}} T1 const c{}; (void) static_cast(c); // expected-error {{redundant}} } void testReinterpretCast() { int * p; (void) reinterpret_cast(p); // expected-error {{redundant reinterpret_cast from 'int *' to 'int *' [loplugin:redundantcast]}} } void testReinterpretConstCast() { int n = 0; (void) reinterpret_cast((const_cast(&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; S3 * s3 = nullptr; (void) dynamic_cast(s1); (void) dynamic_cast(s2); // expected-error {{redundant dynamic upcast from 'S2 *' to 'S1 *' [loplugin:redundantcast]}} (void) dynamic_cast(s2); // expected-error {{redundant dynamic cast from 'S2 *' to 'S2 *' [loplugin:redundantcast]}} (void) dynamic_cast(s2); (void) dynamic_cast(s2); // expected-error {{redundant dynamic cast from 'S2 *' to 'const S2 *' [loplugin:redundantcast]}} (void) dynamic_cast(s3); // expected-error {{redundant dynamic upcast from 'S3 *' to 'S1 *' [loplugin:redundantcast]}} } 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]}} }; void testIntermediaryStaticCast() { int n = 0; n = static_cast(n); // expected-error {{suspicious static_cast from 'int' to 'double', result is implicitly cast to 'int' [loplugin:redundantcast]}} n = double(n); // expected-error {{suspicious functional cast from 'int' to 'double', result is implicitly cast to 'int' [loplugin:redundantcast]}} double d = 0.0; d = static_cast(d) + 1.0; // expected-error {{suspicious static_cast from 'double' to 'int', result is implicitly cast to 'double' [loplugin:redundantcast]}} d = int(d) + 1.0; // expected-error {{suspicious functional cast from 'double' to 'int', result is implicitly cast to 'double' [loplugin:redundantcast]}} }; void testArrayDecay() { (void) static_cast(""); // expected-error-re {{redundant static_cast from 'const char{{ ?}}[1]' to 'const char *' [loplugin:redundantcast]}} (void) reinterpret_cast(""); // expected-error-re {{redundant reinterpret_cast from 'const char{{ ?}}[1]' to 'const char *' [loplugin:redundantcast]}} (void) reinterpret_cast(u8""); } void testNew() { class A {}; class B : public A {}; A* p = static_cast(new B); // expected-error {{redundant static_cast from 'B *' to 'A *' [loplugin:redundantcast]}} (void)p; // no warning expected for resolving-ambiguity cast class C : public A {}; class D : public B, public C {}; p = static_cast(new D); // no warning expected for down-cast auto p2 = static_cast(p); (void)p2; } using F = void (*)(); auto testNullFunctionPointer(int i, F p) { switch (i) { case 0: return static_cast(nullptr); case 1: return F(nullptr); default: return p; } } void testSalIntTypes() { sal_Int16 const n = 0; (void) static_cast(n); // expected-error-re {{static_cast from 'const sal_Int16' (aka 'const {{.+}}') lvalue to 'sal_Int16' (aka '{{.+}}') prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} (void) static_cast<::sal_Int16>(n); // expected-error-re {{static_cast from 'const sal_Int16' (aka 'const {{.+}}') lvalue to '::sal_Int16' (aka '{{.+}}') prvalue is redundant or should be written as an explicit construction of a temporary [loplugin:redundantcast]}} (void) static_cast(n); // doesn't warn, even if 'sal_Int16' is 'short' using Other = sal_Int16; (void) static_cast(n); // doesn't warn either } int main() { testConstCast(); testStaticCast(); testFunctionalCast(); testCStyleCast(); testCStyleCastOfTemplateMethodResult(nullptr); testReinterpretCast(); testReinterpretConstCast(); testDynamicCast(); testIntermediaryStaticCast(); testArrayDecay(); testSalIntTypes(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */