diff options
Diffstat (limited to 'compilerplugins/clang/test')
105 files changed, 7900 insertions, 0 deletions
diff --git a/compilerplugins/clang/test/badstatics.cxx b/compilerplugins/clang/test/badstatics.cxx new file mode 100644 index 000000000..db9a023d9 --- /dev/null +++ b/compilerplugins/clang/test/badstatics.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <memory> +#include <vector> +#include <map> +#include <cstdlib> + +class Image { public: ~Image() { ::std::abort(); } }; +class Bitmap { public: ~Bitmap() { ::std::abort(); } }; + +struct WithImage +{ + Image image; +}; + +struct WithBitmap +{ + Bitmap bitmap; +}; + +WithImage g_bug1; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} +WithBitmap g_bug2; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +static WithImage g_bug3; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +void foo() { + static Image s_bug1; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + Image nobug; +} + +::std::unique_ptr<WithImage> g_bug4; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::shared_ptr<WithImage> g_bug5; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::weak_ptr<WithImage> g_nobug; + +struct DerivedWithImage : WithImage +{ +}; + +DerivedWithImage g_bug6; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::vector<Image> g_bug7; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::vector<::std::unique_ptr<Image>> g_bug8; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::map<Image, int> g_bug9; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +::std::map<int, Image> g_bug10; // expected-error {{bad static variable causes crash on shutdown [loplugin:badstatics]}} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/blockblock.cxx b/compilerplugins/clang/test/blockblock.cxx new file mode 100644 index 000000000..422430f9c --- /dev/null +++ b/compilerplugins/clang/test/blockblock.cxx @@ -0,0 +1,47 @@ +/* -*- 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/. + */ + +int f(bool b1, bool b2) { + if (b1 || b2) { // no warning +#if 0 + if (b1) +#endif + { // expected-error {{block directly inside block [loplugin:blockblock]}} + { // expected-note {{inner block here [loplugin:blockblock]}} + return 0; + } + } + } + return 1; +} + +void foo(int x) +{ + switch (x) + { + case 1: break; + case 2: {} break; + case 3: + { // expected-error {{block directly inside block [loplugin:blockblock]}} + { + } + break; + } + } +} + + +int main() { // expected-error {{block directly inside block [loplugin:blockblock]}} + { // expected-note {{inner block here [loplugin:blockblock]}} + int x = 1; + (void)x; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/bufferadd.cxx b/compilerplugins/clang/test/bufferadd.cxx new file mode 100644 index 000000000..a9f28b13b --- /dev/null +++ b/compilerplugins/clang/test/bufferadd.cxx @@ -0,0 +1,110 @@ +/* -*- 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 <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> + +// --------------------------------------------------------------- +// replacing OUStringBuffer.append sequences to OUString+ +namespace test1 +{ +void f1() +{ + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OUStringBuffer v; + v.append("xxx"); + v.append("xxx"); +} +void f2() +{ + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OUStringBuffer v; + v.append("xxx").append("aaaa"); +} +void f3(OString class_name) +{ + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OStringBuffer sig_buf(5 + class_name.getLength()); + sig_buf.append("(I)L"); + //sig_buf.append( class_name.replace( '.', '/' ) ); + sig_buf.append(';'); + OString sig(sig_buf.makeStringAndClear()); + (void)sig; +} +void f4(sal_Unicode const* pPathBegin) +{ + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OUStringBuffer v; + v.append(pPathBegin, 12); + v.append("aaaa"); +} +void f5(OUStringBuffer& input) +{ + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OUStringBuffer v(input); + v.append("aaaa"); +} +struct Footer +{ + OStringBuffer m_descriptorStart; + OString m_descriptorEnd; + OString f8() const + { + // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}} + OStringBuffer buf(m_descriptorStart); + buf.append(m_descriptorEnd); + return buf.makeStringAndClear(); + } +}; +} + +namespace test2 +{ +void f2() +{ + // no warning expected + OUStringBuffer v; + v.append("xxx"); + if (true) + v.append("yyyy"); +} +void appendTo(OUStringBuffer&); +void f3() +{ + // no warning expected + OUStringBuffer v; + appendTo(v); + v.append("xxx"); +} +void f4() +{ + // no warning expected + OUStringBuffer v; + v.append("xxx"); + v.setLength(0); +} +void f5() +{ + // no warning expected + OUStringBuffer v; + v.append("xxx"); + v[1] = 'x'; +} +void f6() +{ + // no warning expected + OUStringBuffer noel1("xxx"); + while (true) + noel1.append("ffff").append("aaa"); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/buriedassign.cxx b/compilerplugins/clang/test/buriedassign.cxx new file mode 100644 index 000000000..b44a7cce6 --- /dev/null +++ b/compilerplugins/clang/test/buriedassign.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <map> +#include <memory> +#include <rtl/ustring.hxx> + +namespace test1 +{ +int foo(int); + +void main() +{ + int x = 1; + foo(x = 2); + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} + int y = x = 1; // no warning expected + (void)y; + int z = foo(x = 1); + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} + (void)z; + switch (x = 1) + { // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} + } + std::map<int, int> map1; + map1[x = 1] = 1; + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} +} +} + +namespace test2 +{ +struct MyInt +{ + int x; + MyInt(int i) + : x(i) + { + } + MyInt& operator=(MyInt const&) = default; + MyInt& operator=(int) { return *this; } + bool operator<(MyInt const& other) const { return x < other.x; } +}; + +MyInt foo(MyInt); + +void main() +{ + MyInt x = 1; + foo(x = 2); + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} + MyInt y = x = 1; // no warning expected + (void)y; + MyInt z = foo(x = 1); + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} + (void)z; + z = x; // no warning expected + std::map<MyInt, int> map1; + map1[x = 1] = 1; + // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} +} +} + +namespace test3 +{ +void main(OUString sUserAutoCorrFile, OUString sExt) +{ + OUString sRet; + if (sUserAutoCorrFile == "xxx") + sRet = sUserAutoCorrFile; // no warning expected + if (sUserAutoCorrFile == "yyy") + (sRet = sUserAutoCorrFile) + += sExt; // expected-error@-1 {{buried assignment, rather put on own line [loplugin:buriedassign]}} +} +} + +// no warning expected +namespace test4 +{ +struct Task +{ + void exec(); +}; +std::unique_ptr<Task> pop(); + +void foo() +{ + std::unique_ptr<Task> pTask; + while ((pTask = pop())) + pTask->exec(); +} +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/casttovoid.cxx b/compilerplugins/clang/test/casttovoid.cxx new file mode 100644 index 000000000..9904c8b5a --- /dev/null +++ b/compilerplugins/clang/test/casttovoid.cxx @@ -0,0 +1,111 @@ +/* -*- 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/. + */ + +#undef NDEBUG +#include <cassert> + +#define CAST_N3 (void) n3 +#define ASSERT_N4 assert(n4 == 0) +#define ASSERT(x) assert(x) +#define USE(x) x + +int f1(int n1, int n2, int n3, int n4, int n5) { + (void) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int const & r1 = n1; // expected-note {{first consumption is here [loplugin:casttovoid]}} + (void) n2; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int const & r2 = {n2}; // expected-note {{first consumption is here [loplugin:casttovoid]}} + (void) n3; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int const & r3{n3}; // expected-note {{first consumption is here [loplugin:casttovoid]}} + (void) n4; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int const & r4(n4); // expected-note {{first consumption is here [loplugin:casttovoid]}} + (void) n5; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int const & r5 = (n5); // expected-note {{first consumption is here [loplugin:casttovoid]}} + return r1 + r2 + r3 + r4 + r5; +} + +int const & f2(int const & n) { + (void) n; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return n; // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +int const & f3(int const & n) { + (void) n; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return (n); // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +int const & f4(int const & n) { + (void) n; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return {n}; // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +int const & f5(int const & n) { + (void) n; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return {(n)}; // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +struct S1 { + S1(int n1, int n2): + n1_(n1), // expected-note {{first consumption is here [loplugin:casttovoid]}} + n2_{n2} // expected-note {{first consumption is here [loplugin:casttovoid]}} + { + (void) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void) n2; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + } + int const n1_; + int const n2_; +}; + +struct S2 { int n; }; + +int fS2_1(S2 s) { + (void) s; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return s.n; // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +int const & fS2_2(S2 const & s) { + (void) s; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + return s.n; // expected-note {{first consumption is here [loplugin:casttovoid]}} +} + +int main() { + int n1 = 0; + (void) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void const) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void volatile) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void const volatile) n1; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void) (n1); // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void) ((n1)); // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + (void(n1)); // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + static_cast<void>(n1); // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int n2 = 0; + assert(n2 == 0); + (void) n2; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}} + int n3 = 0; + CAST_N3; + int n4 = 0; + ASSERT_N4; + (void) n4; + int n5 = 0; + assert(n5 == 0); + (void) n5; + int n6 = 0; + ASSERT(n6 == 0); + (void) n6; + int n7 = 0; + assert(USE(n7) == 0); + (void) n7; + int n8 = 0; + ASSERT(USE(USE(n8 == 0))); + (void) n8; + return n1 // expected-note 8 {{first consumption is here [loplugin:casttovoid]}} + + n2 // expected-note {{first consumption is here [loplugin:casttovoid]}} + + n3; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/classmemaccess.cxx b/compilerplugins/clang/test/classmemaccess.cxx new file mode 100644 index 000000000..05bb457f8 --- /dev/null +++ b/compilerplugins/clang/test/classmemaccess.cxx @@ -0,0 +1,36 @@ +/* -*- 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 <cstring> + +void f(struct Incomplete* p1, struct S* p2); + +struct S +{ + S(); +}; + +void f(struct Incomplete* p1, struct S* p2) +{ + S s; + // expected-error@+1 {{writing to an object of non-trivial type 'S'; use assignment instead [loplugin:classmemaccess]}} + std::memset(&s, 0, sizeof s); + // expected-error@+1 {{writing to an object of non-trivial type 'S'; use assignment instead [loplugin:classmemaccess]}} + std::memset(static_cast<void*>(&s), 0, sizeof s); + auto const disableWarning = static_cast<void*>(&s); + std::memset(disableWarning, 0, sizeof s); + S a[1][1]; + // expected-error@+1 {{writing to an object of non-trivial type 'S'; use assignment instead [loplugin:classmemaccess]}} + std::memset(a, 0, sizeof a); + std::memset(p1, 0, 10); // conservatively assume Incomplete may be trivial + // expected-error@+1 {{writing to an object of non-trivial type 'S'; use assignment instead [loplugin:classmemaccess]}} + std::memset(p2, 0, 10); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/collapseif.cxx b/compilerplugins/clang/test/collapseif.cxx new file mode 100644 index 000000000..6f8658473 --- /dev/null +++ b/compilerplugins/clang/test/collapseif.cxx @@ -0,0 +1,55 @@ +/* -*- 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 <sal/config.h> + +int f1(int x) +{ + // expected-error@+1 {{nested if should be collapsed into one statement 9 9 [loplugin:collapseif]}} + if (x == 1) + if (x == 2) + return 1; + + // expected-error@+1 {{nested if should be collapsed into one statement 9 9 [loplugin:collapseif]}} + if (x == 1) + { + if (x == 2) + return 1; + } + + // no warning expected + if (x == 1) + { + // comment here prevents warning + if (x == 2) + return 1; + } + + // no warning expected + if (x == 1) + { + if (x == 2) + return 1; + } + else + return 3; + + // no warning expected + if (x == 1) + { + if (x == 2) + return 1; + else + return 3; + } + + return 2; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/commaoperator.cxx b/compilerplugins/clang/test/commaoperator.cxx new file mode 100644 index 000000000..260aeab4e --- /dev/null +++ b/compilerplugins/clang/test/commaoperator.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/. + */ + +bool f(); + +struct S { S(); }; + +int main() { + f(), f(), f(); // expected-error {{comma operator hides code [loplugin:commaoperator]}} + (f(), f()); + for ( + f(), f(); + f(), f(); // expected-error {{comma operator hides code [loplugin:commaoperator]}} + f(), f()) + f(), f(); // expected-error {{comma operator hides code [loplugin:commaoperator]}} + S s; + (s = S(), s = S(), s = S()); + for (s = S(), f(); f(); s = S(), f()) {} + while (s = S(), f()) {} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/conditionalstring.cxx b/compilerplugins/clang/test/conditionalstring.cxx new file mode 100644 index 000000000..e10b02519 --- /dev/null +++ b/compilerplugins/clang/test/conditionalstring.cxx @@ -0,0 +1,30 @@ +/* -*- 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 <sal/config.h> + +#include <rtl/ustring.hxx> + +void f(OUString s, bool b) +{ + // expected-error@+2 {{replace 2nd operand of conditional expression with `rtl::OUStringLiteral` [loplugin:conditionalstring]}} + // expected-note@+1 {{conditional expression is here [loplugin:conditionalstring]}} + s += (b ? OUString("a") : throw 0); + // expected-error@+2 {{replace 2nd operand of conditional expression with `rtl::OUStringLiteral` [loplugin:conditionalstring]}} + // expected-note@+1 {{conditional expression is here [loplugin:conditionalstring]}} + s += (b ? OUString("a") : OUStringLiteral("b")); + // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `rtl::OUStringLiteral` [loplugin:conditionalstring]}} + b = (b ? ("x") : (OUString(("y")))) == s; + // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `rtl::OUStringLiteral` [loplugin:conditionalstring]}} + b = operator==(s, b ? OUString("x") : OUString("y")); + // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `rtl::OUStringLiteral` [loplugin:conditionalstring]}} + s.operator+=(b ? OUString("x") : OUString("y")); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/constfields.cxx b/compilerplugins/clang/test/constfields.cxx new file mode 100644 index 000000000..c045396d5 --- /dev/null +++ b/compilerplugins/clang/test/constfields.cxx @@ -0,0 +1,45 @@ +/* -*- 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 <vector> +#include <ostream> +#include <com/sun/star/uno/Any.hxx> + +struct Test0 +{ + void method1() {} +}; + +// checking for calling non-const method +struct Test1 +// expected-error@-1 {{notconst m_field1 [loplugin:constfields]}} +{ + Test0* m_field1; + + void method1() + { + if (m_field1) + m_field1->method1(); + } +}; + +// checking for assigning to field +struct Test2 +// expected-error@-1 {{notconst m_field1 [loplugin:constfields]}} +{ + Test0* m_field1; + + Test2() + : m_field1(nullptr) + { + } + + void method1() { m_field1 = nullptr; } +}; +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/constmethod.cxx b/compilerplugins/clang/test/constmethod.cxx new file mode 100644 index 000000000..e5efcae16 --- /dev/null +++ b/compilerplugins/clang/test/constmethod.cxx @@ -0,0 +1,59 @@ +/* -*- 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 <memory> +#include <vcl/vclptr.hxx> + +class OutputDevice; + +struct Class1 +{ + struct Impl { + void foo_notconst(); + void foo_const() const; + int & foo_int_ref() const; + int const & foo_const_int_ref() const; + int * foo_int_ptr() const; + int const * foo_const_int_ptr() const; + }; + std::unique_ptr<Impl> pImpl; + int* m_pint; + VclPtr<OutputDevice> m_pvcl; + + void GetFoo1() { + pImpl->foo_notconst(); + } + void GetFoo2() { + pImpl->foo_const(); + } + int& GetFoo3() { + return pImpl->foo_int_ref(); + } + int const & GetFoo3a() { // expected-error {{this method can be const [loplugin:constmethod]}} + return pImpl->foo_const_int_ref(); + } + int* GetFoo3b() { + return pImpl->foo_int_ptr(); + } + int const * GetFoo3c() { // expected-error {{this method can be const [loplugin:constmethod]}} + return pImpl->foo_const_int_ptr(); + } + Impl* GetFoo4() { + return pImpl.get(); // no warning expected + } + int* GetFoo5() { + return m_pint; // no warning expected + } + int& GetFoo6() { + return *m_pint; // no warning expected + } + OutputDevice* GetFoo7() { + return m_pvcl; // no warning expected + } +}; diff --git a/compilerplugins/clang/test/constparams.cxx b/compilerplugins/clang/test/constparams.cxx new file mode 100644 index 000000000..2cffd87fd --- /dev/null +++ b/compilerplugins/clang/test/constparams.cxx @@ -0,0 +1,48 @@ +/* -*- 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 <string> + +struct Class1 +{ + int const * m_f1; + Class1(int * f1) : m_f1(f1) {} // expected-error {{this parameter can be const Class1::Class1 [loplugin:constparams]}} +}; + +struct Class2 +{ + int * m_f2; + Class2(int * f2) : m_f2(f2) {} +}; +struct Class3 +{ + int * m_f2; + Class3(void * f2) : m_f2(static_cast<int*>(f2)) {} +}; + +int const * f1(int *); // expected-note {{canonical parameter declaration here [loplugin:constparams]}} +int const * f2(int *); +int const * f3(int *); +void g() { + int const * (*p1)(int *); + int n = 0; + f1(&n); + p1 = f2; + typedef void (*P2)(); + P2 p2; + p2 = (P2) (f3); +} +int const * f1(int * p) { // expected-error {{this parameter can be const f1 [loplugin:constparams]}} + return p; +} +void f4(std::string * p) { + *p = std::string("xxx"); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/consttobool.cxx b/compilerplugins/clang/test/consttobool.cxx new file mode 100644 index 000000000..281848255 --- /dev/null +++ b/compilerplugins/clang/test/consttobool.cxx @@ -0,0 +1,68 @@ +/* -*- 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 <sal/config.h> + +#include <cassert> + +#include <sal/types.h> + +#pragma clang diagnostic ignored "-Wnull-conversion" + +enum E +{ + E0, + E1, + E2 +}; + +int const c1 = 1; +constexpr int c2 = 2; + +struct S +{ + S() + // expected-error-re@+1 {{implicit conversion of constant {{nullptr|0}} of type 'nullptr_t' to 'bool'; use 'false' instead [loplugin:consttobool]}} + : b(nullptr) + { + } + bool b; +}; + +int main() +{ + bool b; + // expected-error@+1 {{implicit conversion of constant 0 of type 'int' to 'bool'; use 'false' instead [loplugin:consttobool]}} + b = 0; + // expected-error@+1 {{implicit conversion of constant 1 of type 'sal_Bool' (aka 'unsigned char') to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = sal_True; + // expected-error@+1 {{implicit conversion of constant 1.000000e+00 of type 'double' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = 1.0; + // expected-error@+1 {{implicit conversion of constant 2 of type 'E' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = E2; + // expected-error@+1 {{implicit conversion of constant 97 of type 'char' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = 'a'; + // expected-error@+1 {{implicit conversion of constant 1 of type 'int' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = c1; + // expected-error@+1 {{implicit conversion of constant 2 of type 'int' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = c2; + // expected-error@+1 {{implicit conversion of constant 3 of type 'int' to 'bool'; use 'true' instead [loplugin:consttobool]}} + b = (c1 | c2); + + assert(b); // no warnings from within assert macro itself + assert(b && "msg"); // no warnings for `&& "msg"` + if (b) + { + assert(!"msg"); // no warnings for `!"msg"` + } + // expected-error@+1 {{implicit conversion of constant &"msg"[0] of type 'const char *' to 'bool'; use 'true' instead [loplugin:consttobool]}} + assert("msg"); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/constvars.cxx b/compilerplugins/clang/test/constvars.cxx new file mode 100644 index 000000000..dc3c1ecb9 --- /dev/null +++ b/compilerplugins/clang/test/constvars.cxx @@ -0,0 +1,107 @@ +/* -*- 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/. + */ + +#if defined _WIN32 //TODO, see corresponding TODO in compilerplugins/clang/writeonlyvars.cxx +// expected-no-diagnostics +#else + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <map> +#include <list> +#include <vector> +#include <rtl/ustring.hxx> + +namespace test1 +{ +int const aFormalArgs[] = { 1, 2 }; +// expected-error@+1 {{var can be const [loplugin:constvars]}} +static sal_uInt16 nMediaArgsCount = SAL_N_ELEMENTS(aFormalArgs); +sal_uInt16 foo() +{ + (void)aFormalArgs; + return nMediaArgsCount; +} +}; + +// no warning expected +namespace test2 +{ +static char const* ar[] = { "xxxx" }; +static const char* lcl_DATA_OTHERS = "localedata_others"; +void foo() +{ + (void)ar; + (void)lcl_DATA_OTHERS; +} +}; + +// no warning expected +namespace test3 +{ +static sal_uInt16 nMediaArgsCount = 1; // loplugin:constvars:ignore +sal_uInt16 foo() { return nMediaArgsCount; } +}; + +// no warning expected, we don't handle these destructuring assignments properly yet +namespace test4 +{ +void foo() +{ + std::map<OUString, OUString> aMap; + for (auto & [ rName, rEntry ] : aMap) + { + rEntry.clear(); + } +} +}; + +// no warning expected +namespace test5 +{ +struct Struct1 +{ +}; +void release(Struct1*); +void foo(std::list<Struct1*> aList) +{ + for (Struct1* pItem : aList) + { + release(pItem); + } +} +}; + +namespace test6 +{ +void foo(css::uno::Sequence<css::uno::Reference<css::uno::XInterface>>& aSeq) +{ + // expected-error@+1 {{var can be const [loplugin:constvars]}} + for (css::uno::Reference<css::uno::XInterface>& x : aSeq) + { + x.get(); + } +} +}; + +// no warning expected +namespace test7 +{ +void foo(std::vector<std::vector<int>> aVecVec) +{ + for (auto& rVec : aVecVec) + for (auto& rElement : rVec) + rElement = 1; +} +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/convertlong.cxx b/compilerplugins/clang/test/convertlong.cxx new file mode 100644 index 000000000..850da3ede --- /dev/null +++ b/compilerplugins/clang/test/convertlong.cxx @@ -0,0 +1,41 @@ +/* -*- 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 <tools/solar.h> + +int main() +{ + sal_uIntPtr x = 1; + sal_uInt32 y = x; + y = x; + (void)y; +} + +void main2() +{ + int x = 1; + int y = 1; + long tmp = x + y; + // expected-error@-1 {{rather replace type of decl 'long' with 'int' [loplugin:convertlong]}} + (void)tmp; + tmp = x + y; + + sal_uLong tmp1 = x + y; + // expected-error-re@-1 {{rather replace type of decl 'sal_uLong' (aka 'unsigned {{.+}}') with 'int' [loplugin:convertlong]}} + (void)tmp1; + + int tmp2 = (sal_uLong)1; + tmp2 = (long)1; + + sal_uIntPtr tmp3 = x + y; + // expected-error-re@-1 {{rather replace type of decl 'sal_uIntPtr' (aka 'unsigned {{.+}}') with 'int' [loplugin:convertlong]}} + (void)tmp3; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/cppunitassertequals.cxx b/compilerplugins/clang/test/cppunitassertequals.cxx new file mode 100644 index 000000000..d42007c99 --- /dev/null +++ b/compilerplugins/clang/test/cppunitassertequals.cxx @@ -0,0 +1,77 @@ +/* -*- 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 "sal/config.h" + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include "cppunitassertequals.hxx" + +#define TEST1 CPPUNIT_ASSERT(b1 == b2) +#define TEST2(x) x + +void test( + bool b1, bool b2, OUString const & s1, OUString const & s2, T t, void * p, std::nullptr_t n) +{ + CppUnit::Asserter::failIf(b1,""); +#if 0 // TODO: enable later + CPPUNIT_ASSERT(b1 && b2); // expected-error {{rather split into two CPPUNIT_ASSERT [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT((b1 && b2)); // expected-error {{rather split into two CPPUNIT_ASSERT [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(b1 || b2)); // expected-error {{rather split into two CPPUNIT_ASSERT [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(b1 && b2)); + CPPUNIT_ASSERT(!!(b1 && b2)); // expected-error {{rather split into two CPPUNIT_ASSERT [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_MESSAGE("", b1 && b2); // expected-error {{rather split into two CPPUNIT_ASSERT_MESSAGE [loplugin:cppunitassertequals]}} +#endif + CPPUNIT_ASSERT(b1 == b2); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(b1 != b2); + CPPUNIT_ASSERT((b1 == b2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(b1 != b2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator != call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(b1 == b2)); + CPPUNIT_ASSERT(!!(b1 == b2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_MESSAGE("", b1 == b2); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL_MESSAGE (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(s1 == s2); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(s1 != s2); + CPPUNIT_ASSERT((s1 == s2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(s1 != s2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator != call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT(!(s1 == s2)); + CPPUNIT_ASSERT(!!(s1 == s2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + TEST1; // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + TEST2(CPPUNIT_ASSERT(b1 == b2)); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + TEST2(TEST1); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + + // Useful when testing an equality iterator itself: + CPPUNIT_ASSERT(operator ==(s1, s1)); + CPPUNIT_ASSERT(t.operator ==(t)); + + // `P == nullptr` for P of pointer type is awkward to write with CPPUNIT_ASSERT_EQUAL, and the + // actual pointer values that would be printed if CPPUNIT_ASSERT_EQUAL failed would likely not be + // very meaningful, so let it use CPPUNIT_ASSERT (but stick to CPPUNIT_ASSERT_EQUAL for + // consistency in the unlikely case that P is of type std::nullptr_t): + CPPUNIT_ASSERT(p == nullptr); + CPPUNIT_ASSERT(n == nullptr); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}} + + // There might even be good reasons(?) not to warn inside explicit casts: + CPPUNIT_ASSERT(bool(b1 && b2)); + CPPUNIT_ASSERT(bool(b1 == b2)); + CPPUNIT_ASSERT(bool(s1 == s2)); + + CPPUNIT_ASSERT_EQUAL(b1, true); // expected-error {{CPPUNIT_ASSERT_EQUALS parameters look switched, expected value should be first param [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_EQUAL_MESSAGE("foo", b1, true); // expected-error {{CPPUNIT_ASSERT_EQUALS parameters look switched, expected value should be first param [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_EQUAL(true, b1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("foo", true, b1); + CPPUNIT_ASSERT_EQUAL(s1, OUString("xxx")); // expected-error {{CPPUNIT_ASSERT_EQUALS parameters look switched, expected value should be first param [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_EQUAL_MESSAGE("foo", s1, OUString("xxx")); // expected-error {{CPPUNIT_ASSERT_EQUALS parameters look switched, expected value should be first param [loplugin:cppunitassertequals]}} + CPPUNIT_ASSERT_EQUAL(OUString("xxx"), s1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("foo", OUString("xxx"), s1); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/cppunitassertequals.hxx b/compilerplugins/clang/test/cppunitassertequals.hxx new file mode 100644 index 000000000..7a14886ad --- /dev/null +++ b/compilerplugins/clang/test/cppunitassertequals.hxx @@ -0,0 +1,26 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_CPPUNITASSERTEQUALS_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_CPPUNITASSERTEQUALS_HXX + +#include "sal/config.h" + +#include <cstddef> + +#include "rtl/ustring.hxx" + +struct T { bool operator ==(T); }; + +void test( + bool b1, bool b2, OUString const & s1, OUString const & s2, T t, void * p, std::nullptr_t n); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/cstylecast.cxx b/compilerplugins/clang/test/cstylecast.cxx new file mode 100644 index 000000000..916896d54 --- /dev/null +++ b/compilerplugins/clang/test/cstylecast.cxx @@ -0,0 +1,74 @@ +/* -*- 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 <sal/config.h> + +#include <sal/types.h> + +namespace N +{ +enum E +{ + E1 +}; + +using T = unsigned int; +} + +void FunctionalCast(void* p) +{ + // expected-error@+1 {{Function-style cast from 'void *' to 'sal_IntPtr' (aka 'long') (performs: reinterpret_cast) (PointerToIntegral) [loplugin:cstylecast]}} + auto n = sal_IntPtr(p); + (void(n)); // no warning expected (outer parens to disambiguate expr vs. decl) +} + +static const int C + = (int)0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + +int main() +{ + constexpr int c1 = 0; + int const c2 = 0; + int n + = (int)0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (signed int)0; // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n = (int)~0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (int)-0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (int)+0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (int)!0; // expected-error {{C-style cast from 'bool' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (int) // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + (0 << 0); + n = (int) // expected-error {{C-style cast from 'const int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + c1; + n = (int) // expected-error {{C-style cast from 'const int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + c2; + n = (int) // expected-error {{C-style cast from 'const int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + C; + n = (int) // expected-error {{C-style cast from 'N::E' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + N::E1; + n = (N::E) // expected-error {{C-style cast from 'N::E' to 'N::E' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + N::E1; + n = (enum // expected-error {{C-style cast from 'N::E' to 'enum N::E' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + N::E)N::E1; + n = (N::T)0; // expected-error {{C-style cast from 'int' to 'N::T' (aka 'unsigned int') (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + n = (int) // expected-error-re {{C-style cast from {{.*}} to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + sizeof(int); + n = (int) // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n; + n = (int)~n; // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n = (int)-n; // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n = (int)+n; // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n = (int)!n; // expected-error {{C-style cast from 'bool' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + n = (int) // expected-error {{C-style cast from 'int' to 'int' (performs: static_cast) (NoOp) [loplugin:cstylecast]}} + (0 << n); + n = (double)0; // expected-error {{C-style cast from 'int' to 'double' (performs: functional cast) (NoOp) [loplugin:cstylecast]}} + (void)n; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/datamembershadow.cxx b/compilerplugins/clang/test/datamembershadow.cxx new file mode 100644 index 000000000..a11a7cc51 --- /dev/null +++ b/compilerplugins/clang/test/datamembershadow.cxx @@ -0,0 +1,22 @@ +/* -*- 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 <sal/config.h> + +#include <config_clang.h> + +struct Bar { + int x; // expected-note {{superclass member here [loplugin:datamembershadow]}} +}; + +struct Foo : public Bar { + int x; // expected-error {{data member x is shadowing member in superclass, through inheritance path Foo->Bar [loplugin:datamembershadow]}} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/dbgunhandledexception.cxx b/compilerplugins/clang/test/dbgunhandledexception.cxx new file mode 100644 index 000000000..4ae15a58e --- /dev/null +++ b/compilerplugins/clang/test/dbgunhandledexception.cxx @@ -0,0 +1,38 @@ +/* -*- 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 <tools/diagnose_ex.h> +#include <sal/log.hxx> + +void func1(); + +int main() +{ + try + { + func1(); + } + catch (std::exception const&) + { + SAL_WARN("xmloff", "message"); + DBG_UNHANDLED_EXCEPTION( + "xmloff", + "message"); // expected-error@-2 {{DBG_UNHANDLED_EXCEPTION must be first statement in catch block [loplugin:dbgunhandledexception]}} + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "message"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/dodgyswitch.cxx b/compilerplugins/clang/test/dodgyswitch.cxx new file mode 100644 index 000000000..826971d27 --- /dev/null +++ b/compilerplugins/clang/test/dodgyswitch.cxx @@ -0,0 +1,30 @@ +/* -*- 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 <sal/types.h> + +int foo(); + +int main() { + switch (foo()) + { + case 1: { break; } + case 2: { + [[fallthrough]]; + { + case 3: // expected-error {{case statement not directly under switch [loplugin:dodgyswitch]}} + break; + } + default: // expected-error {{default statement not directly under switch [loplugin:dodgyswitch]}} + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/doubleconvert.cxx b/compilerplugins/clang/test/doubleconvert.cxx new file mode 100644 index 000000000..d0fd8b787 --- /dev/null +++ b/compilerplugins/clang/test/doubleconvert.cxx @@ -0,0 +1,22 @@ +/* -*- 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 "sal/config.h" +#include "tools/color.hxx" + +int main() +{ + Color col1; + Color col2; + col2 = sal_Int32( + col1); // expected-error@-1 {{redundant double conversion [loplugin:doubleconvert]}} + (void)col2; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/emptyif.cxx b/compilerplugins/clang/test/emptyif.cxx new file mode 100644 index 000000000..15dd79627 --- /dev/null +++ b/compilerplugins/clang/test/emptyif.cxx @@ -0,0 +1,61 @@ +/* -*- 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/. + */ + +int main() +{ + int x = 1; + + if (x == 1) // expected-error {{empty if body [loplugin:emptyif]}} + ; + + if (x == 1) + { + } + // expected-error@-3 {{empty if body [loplugin:emptyif]}} + + if (x == 1) + { + } + else + { + } + // expected-error@-2 {{empty else body [loplugin:emptyif]}} + + if (x == 1) + { + } + else + ; // expected-error {{empty else body [loplugin:emptyif]}} + + if (x == 1) + { + } + else + { + x = 2; + } + + // no warning expected + if (x == 1) + { + x = 3; + } + if (x == 1) + x = 3; + if (x == 1) + { + // + } + if (x == 1) + { + /* */ + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/expressionalwayszero.cxx b/compilerplugins/clang/test/expressionalwayszero.cxx new file mode 100644 index 000000000..4986e5d69 --- /dev/null +++ b/compilerplugins/clang/test/expressionalwayszero.cxx @@ -0,0 +1,46 @@ +/* -*- 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 <o3tl/typed_flags_set.hxx> + +constexpr auto ONE = 1; +constexpr auto TWO = 2; + +enum class Enum1 { + ONE = 1, + TWO = 2, +}; +namespace o3tl { + template<> struct typed_flags<Enum1> : is_typed_flags<Enum1, 0x3> {}; +} + +enum class Enum2 { + ZERO = 0, + ONE = 1, + TWO = 2, +}; +namespace o3tl { + template<> struct typed_flags<Enum2> : is_typed_flags<Enum2, 0x3> {}; +} + +int main() +{ + auto v1 = ONE & TWO; // expected-error {{expression always evaluates to zero, lhs=1 rhs=2 [loplugin:expressionalwayszero]}} + (void)v1; + auto v2 = Enum1::ONE & Enum1::TWO; // expected-error {{expression always evaluates to zero, lhs=1 rhs=2 [loplugin:expressionalwayszero]}} + (void)v2; + + auto v3 = Enum2::ONE; + auto v4 = v3 & Enum2::ZERO; // expected-error {{expression always evaluates to zero, lhs=unknown rhs=0 [loplugin:expressionalwayszero]}} + (void)v4; + + auto v5 = Enum2::ONE; + v5 &= Enum2::ZERO; // expected-error {{expression always evaluates to zero, lhs=unknown rhs=0 [loplugin:expressionalwayszero]}} +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/external.cxx b/compilerplugins/clang/test/external.cxx new file mode 100644 index 000000000..6eb486a57 --- /dev/null +++ b/compilerplugins/clang/test/external.cxx @@ -0,0 +1,125 @@ +/* -*- 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 <sal/config.h> + +#include <vector> + +// expected-error@+1 {{externally available entity 'n1' is not previously declared in an included file (if it is only used in this translation unit, make it static or put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +int n1 = 0; +// expected-note@+1 {{another declaration is here [loplugin:external]}} +extern int n1; + +int const n2 = 0; // no warning, internal linkage + +constexpr int n3 = 0; // no warning, internal linkage + +// expected-error@+1 {{externally available entity 'S1' is not previously declared in an included file (if it is only used in this translation unit, put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +struct S1 +{ + friend void f1() {} // no warning for injected function (no place where to mark it `static`) + template <typename> friend void ft1() {} // ...nor for injected function template + // expected-error@+1 {{externally available entity 'f2' is not previously declared in an included file (if it is only used in this translation unit, make it static; otherwise, provide a declaration of it in an included file) [loplugin:external]}} + friend void f2() {} +}; + +// expected-error@+1 {{externally available entity 'S2' is not previously declared in an included file (if it is only used in this translation unit, put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +struct S2 +{ + friend void f1(); + template <typename> friend void ft1(); + // expected-note@+1 {{another declaration is here [loplugin:external]}} + friend void f2(); +}; + +static void g() +{ + void f1(); + // expected-note@+1 {{another declaration is here [loplugin:external]}} + void f2(); +} + +// expected-note@+1 {{another declaration is here [loplugin:external]}} +void f2(); + +namespace N +{ +inline namespace I1 +{ +extern "C++" { +// expected-note@+1 {{another declaration is here [loplugin:external]}} +enum E : int; + +// expected-error@+1 {{externally available entity 'E' is not previously declared in an included file (if it is only used in this translation unit, put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +enum E : int +{ +}; +} +} + +// expected-note@+1 {{a function associating 'N::I1::E' is declared here [loplugin:external]}} +static void g(std::vector<E>) +{ + // expected-note@+1 {{another declaration is here [loplugin:external]}} + void f(E const*); +} + +// expected-note@+1 {{a function associating 'N::I1::E' is declared here [loplugin:external]}} +void f(E const*); + +extern "C++" { +// expected-note@+1 {{a function associating 'N::I1::E' is declared here [loplugin:external]}} +void fc(E const*); +} + +// expected-error@+1 {{externally available entity 'S1' is not previously declared in an included file (if it is only used in this translation unit, put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +struct S1 +{ + struct S2; + // No note about associating function; injected friend function not found by ADL: + friend void f2(E const*); + // expected-note@+1 {{a function associating 'N::S1' is declared here [loplugin:external]}} + friend void h(S1); +}; + +// expected-error@+1 {{externally available entity 'S3' is not previously declared in an included file (if it is only used in this translation unit, put it in an unnamed namespace; otherwise, provide a declaration of it in an included file) [loplugin:external]}} +struct S3 +{ + // expected-note@+1 {{another declaration is here [loplugin:external]}} + friend void h(S1); +}; + +inline namespace I2 +{ +// expected-note@+1 {{a function associating 'N::I1::E' is declared here [loplugin:external]}} +void f3(E); + +inline namespace I3 +{ +// expected-note@+1 {{a function associating 'N::I1::E' is declared here [loplugin:external]}} +void f4(E); +} +} +} + +struct N::S1::S2 +{ + // expected-note@+1 {{another declaration is here [loplugin:external]}} + friend void f(E const*); +}; + +int main() +{ + (void)n2; + (void)n3; + g(); + (void)&N::g; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/externvar.cxx b/compilerplugins/clang/test/externvar.cxx new file mode 100644 index 000000000..c4b30d662 --- /dev/null +++ b/compilerplugins/clang/test/externvar.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "externvar.hxx" + +int v1; +int v2; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +static int v3; +int const v4 = 0; + +extern int v5; // expected-note {{previously declared here [loplugin:externvar]}} +int v5; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} + +extern "C" int v6; // expected-note {{previously declared here [loplugin:externvar]}} +int v6; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +extern "C" { int v7; } // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} + +namespace { + +int u1; +static int u2; +extern "C" int u3; // expected-note {{previously declared here [loplugin:externvar]}} +int u3; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +extern "C" { int u4; } + +} + +namespace N { + +int v1; +int v2; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +static int v3; + +} + +struct S { + static int f() { + static int s = 0; + return s; + } + + static int m; +}; + +int S::m = 0; + +int f(int a) { + static int s = 0; + ++s; + int b = a + s + v1 + v2 + v3 + v4 + v5 + v6 + v7 + u1 + u2 + u3 + u4 + N::v1 + + N::v2 + N::v3 + S::f(); + return b; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/externvar.hxx b/compilerplugins/clang/test/externvar.hxx new file mode 100644 index 000000000..225f1ee59 --- /dev/null +++ b/compilerplugins/clang/test/externvar.hxx @@ -0,0 +1,27 @@ +/* -*- 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/. + */ + +#ifndef INClUDED_COMPILERPLUGINS_CLANG_TEST_EXTERNVAR_HXX +#define INClUDED_COMPILERPLUGINS_CLANG_TEST_EXTERNVAR_HXX + +extern int v1; + +namespace N { + +extern int v1; + +} + +struct S; + +int f(int a); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/faileddyncast.cxx b/compilerplugins/clang/test/faileddyncast.cxx new file mode 100644 index 000000000..7d835e041 --- /dev/null +++ b/compilerplugins/clang/test/faileddyncast.cxx @@ -0,0 +1,21 @@ +/* -*- 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 S1 { virtual ~S1(); }; +struct S2 final: S1 {}; +struct S3: S1 {}; + +void f(S1 * s1, S2 * s2) { + (void) dynamic_cast<S2 *>(s1); + (void) dynamic_cast<S1 *>(s2); + (void) dynamic_cast<S2 *>(s2); + (void) dynamic_cast<S3 *>(s2); // expected-error {{dynamic_cast from 'S2 *' to 'S3 *' always fails [loplugin:faileddyncast]}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/fakebool.cxx b/compilerplugins/clang/test/fakebool.cxx new file mode 100644 index 000000000..936e970e5 --- /dev/null +++ b/compilerplugins/clang/test/fakebool.cxx @@ -0,0 +1,36 @@ +/* -*- 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 <sal/config.h> + +#include <sal/types.h> + +namespace { + +struct S { + sal_Bool b; // expected-error {{FieldDecl, use "bool" instead of 'sal_Bool' (aka 'unsigned char') [loplugin:fakebool]}} +}; + +struct S2 { + sal_Bool & b_; + // The following should arguably not warn, but currently does (and does find cases that actually + // can be cleaned up; if it ever produces false warnings for cases that cannot, we need to fix + // it): + S2(sal_Bool & b): // expected-error {{ParmVarDecl, use "bool" instead of 'sal_Bool' (aka 'unsigned char') [loplugin:fakebool]}} + b_(b) {} +}; + +} + +struct S3 { + sal_Bool b_; + void f() { S2 s(b_); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/finalprotected.cxx b/compilerplugins/clang/test/finalprotected.cxx new file mode 100644 index 000000000..c15564874 --- /dev/null +++ b/compilerplugins/clang/test/finalprotected.cxx @@ -0,0 +1,35 @@ +/* -*- 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/. + */ + + +class S final { +protected: + void f(int f) { f1 = f; } // expected-error {{final class should not have protected members - convert them to private [loplugin:finalprotected]}} + int f1; // expected-error {{final class should not have protected members - convert them to private [loplugin:finalprotected]}} +public: + void g(); + int g1; +private: + void h(); + int h1; +}; + +class S2 { +protected: + void f(int f) { f1 = f; } + int f1; +public: + void g(); + int g1; +private: + void h(); + int h1; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/flatten.cxx b/compilerplugins/clang/test/flatten.cxx new file mode 100644 index 000000000..300067b9b --- /dev/null +++ b/compilerplugins/clang/test/flatten.cxx @@ -0,0 +1,191 @@ +/* -*- 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 <exception> + +extern int foo(); +extern int bar(int = 0); +class Class {}; + +void top1() { + if (foo() == 1) { // expected-note {{if condition here [loplugin:flatten]}} + foo(); + } else { + throw std::exception(); // expected-error {{unconditional throw in else branch, rather invert the condition, throw early, and flatten the normal case [loplugin:flatten]}} + } + if (foo() == 1) { + Class aClass; + (void)aClass; + } else { + throw std::exception(); // no warning expected + } + if (foo() == 1) { // expected-note {{if condition here [loplugin:flatten]}} + Class aClass; + (void)aClass; + } else { + throw std::exception(); // expected-error {{unconditional throw in else branch, rather invert the condition, throw early, and flatten the normal case [loplugin:flatten]}} + } +} + +void top2() { + if (foo() == 2) { + throw std::exception(); // expected-error {{unconditional throw in then branch, just flatten the else [loplugin:flatten]}} + } else { + foo(); + } + if (foo() == 2) { + throw std::exception(); // no warning expected + } else { + Class aClass; + (void)aClass; + } + if (foo() == 2) { + throw std::exception(); // expected-error {{unconditional throw in then branch, just flatten the else [loplugin:flatten]}} + } else { + Class aClass; + (void)aClass; + } +} + +void top3() { + // no warning expected + if (foo() == 2) { + throw std::exception(); + } else { + Class aClass; + (void)aClass; + } + int x = 1; + (void)x; +} + +void top4() { + // no warning expected + if (foo() == 2) { + Class aClass; + (void)aClass; + } else { + throw std::exception(); + } + int x = 1; + (void)x; +} + +void top5() { +#if 1 + if (foo() == 2) { + if (foo() == 3) { // expected-note {{if condition here [loplugin:flatten]}} + bar(); + } else { + throw std::exception(); // expected-error {{unconditional throw in else branch, rather invert the condition, throw early, and flatten the normal case [loplugin:flatten]}} + } + } else +#endif + throw std::exception(); // no warning expected +} + +int main() { + // no warning expected + if (bar() == 3) { + throw std::exception(); + } else { + throw std::exception(); + } +} + +void top6() { + // no warning expected + if (foo() == 2) { + Class aClass; + (void)aClass; + } else if (foo() == 2) { + Class aClass; + (void)aClass; + } else { + throw std::exception(); + } + int x = 1; + (void)x; +} + +void top7() { + // no warning expected + if (foo() == 1) { + throw std::exception(); + } else if (foo() == 2) { + throw std::exception(); + } else { + throw std::exception(); + } +} + +void top8() { + if (foo() == 1) { + if (foo() == 2) { + throw std::exception(); // expected-error {{unconditional throw in then branch, just flatten the else [loplugin:flatten]}} + } else { + bar(); + } + } else if (foo() == 2) { + bar(1); + } else { + bar(2); + } +} + +void top9() { + if (foo() == 1) { // expected-error {{large if statement at end of function, rather invert the condition and exit early, and flatten the function [loplugin:flatten]}} + Class aClass1; + (void)aClass1; + Class aClass2; + (void)aClass2; + Class aClass3; + (void)aClass3; + Class aClass4; + (void)aClass4; + Class aClass5; + (void)aClass5; + Class aClass6; + (void)aClass6; + } +} + +void top10() { + // no warning expected + if (foo() == 2) { + if (foo() == 1) { + Class aClass1; + (void)aClass1; + Class aClass2; + (void)aClass2; + Class aClass3; + (void)aClass3; + } + } +} + +int top11() { + // no warning expected + if (foo() == 1) { + Class aClass1; + (void)aClass1; + Class aClass2; + (void)aClass2; + Class aClass3; + (void)aClass3; + Class aClass4; + (void)aClass4; + Class aClass5; + (void)aClass5; + Class aClass6; + (void)aClass6; + } + return 1; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/fragiledestructor.cxx b/compilerplugins/clang/test/fragiledestructor.cxx new file mode 100644 index 000000000..e2fbfc596 --- /dev/null +++ b/compilerplugins/clang/test/fragiledestructor.cxx @@ -0,0 +1,88 @@ +/* -*- 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 "sal/config.h" + +// no warning expected +namespace test1 +{ +class Foo +{ + ~Foo() { f(); } + void f(); +}; +} + +namespace test2 +{ +class Foo +{ + ~Foo() { f(); } + // expected-error@-1 {{calling virtual method from destructor, either make the virtual method final, or make this class final [loplugin:fragiledestructor]}} + virtual void f(); + // expected-note@-1 {{callee method here [loplugin:fragiledestructor]}} +}; +} + +// no warning expected +namespace test3 +{ +class Foo final +{ + ~Foo() { f(); } + virtual void f(); +}; +} + +namespace test4 +{ +struct Bar +{ + virtual ~Bar(); + virtual void f(); + // expected-note@-1 {{callee method here [loplugin:fragiledestructor]}} +}; +class Foo : public Bar +{ + ~Foo() { f(); } + // expected-error@-1 {{calling virtual method from destructor, either make the virtual method final, or make this class final [loplugin:fragiledestructor]}} +}; +} + +// no warning expected +namespace test5 +{ +struct Bar +{ + virtual ~Bar(); + virtual void f(); +}; +class Foo : public Bar +{ + ~Foo() { f(); } + virtual void f() final override; +}; +} + +// no warning expected +namespace test6 +{ +struct Bar +{ + virtual ~Bar(); + virtual void f(); +}; +class Foo : public Bar +{ + ~Foo() { Foo::f(); } + virtual void f() override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/getstr.cxx b/compilerplugins/clang/test/getstr.cxx new file mode 100644 index 000000000..59b52a390 --- /dev/null +++ b/compilerplugins/clang/test/getstr.cxx @@ -0,0 +1,59 @@ +/* -*- 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 <sal/config.h> + +#include <ostream> + +#include <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +// Determine whether std::ostream operator << for sal_Unicode* (aka char16_t*) is deleted (see +// <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1423r3.html> "char8_t backward +// compatibility remediation", as implemented now by +// <https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0c5b35933e5b150df0ab487efb2f11ef5685f713> +// "libstdc++: P1423R3 char8_t remediation (2/4)" for -std=c++2a; TODO: the checks here and the +// relevant code in loplugin:getstr should eventually be removed once support for the deleted +// operators is widespread): +#if __cplusplus > 201703L && defined __GLIBCXX__ +#define HAVE_DELETED_OPERATORS true +#else +#define HAVE_DELETED_OPERATORS false +#endif + +using S = OString; + +void f(std::ostream& st, OString const& s1, OStringBuffer const& s2, + OUString const& s3[[maybe_unused]], OUStringBuffer const& s4[[maybe_unused]], S const& s5, + OString* p1, OStringBuffer* p2, OUString* p3[[maybe_unused]], + OUStringBuffer* p4[[maybe_unused]], S* p5, char const* (OString::*pf)() const) +{ + st << s1.getStr() // expected-error {{directly use object of type 'rtl::OString' in a call of 'operator <<', instead of calling 'getStr' first [loplugin:getstr]}} + << s2.getStr() +#if !HAVE_DELETED_OPERATORS + << s3.getStr() // expected-error {{suspicious use of 'getStr' on an object of type 'rtl::OUString'; the result is implicitly cast to a void pointer in a call of 'operator <<' [loplugin:getstr]}} + << s4.getStr() // expected-error {{suspicious use of 'getStr' on an object of type 'rtl::OUStringBuffer'; the result is implicitly cast to a void pointer in a call of 'operator <<' [loplugin:getstr]}} +#endif + << s5.getStr() // expected-error {{directly use object of type 'S' (aka 'rtl::OString') in a call of 'operator <<', instead of calling 'getStr' first [loplugin:getstr]}} + << p1->getStr() // expected-error {{directly use object of type 'rtl::OString' in a call of 'operator <<', instead of calling 'getStr' first [loplugin:getstr]}} + << p2->getStr() +#if !HAVE_DELETED_OPERATORS + << p3->getStr() // expected-error {{suspicious use of 'getStr' on an object of type 'rtl::OUString'; the result is implicitly cast to a void pointer in a call of 'operator <<' [loplugin:getstr]}} + << p4->getStr() // expected-error {{suspicious use of 'getStr' on an object of type 'rtl::OUStringBuffer'; the result is implicitly cast to a void pointer in a call of 'operator <<' [loplugin:getstr]}} +#endif + << p5->getStr() // expected-error {{directly use object of type 'rtl::OString' in a call of 'operator <<', instead of calling 'getStr' first [loplugin:getstr]}} + << (s1.*pf)(); + SAL_INFO( // expected-error 1+ {{directly use object of type 'rtl::OString' in a call of 'operator <<', instead of calling 'getStr' first [loplugin:getstr]}} + "test", s1.getStr()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/implicitboolconversion.cxx b/compilerplugins/clang/test/implicitboolconversion.cxx new file mode 100644 index 000000000..c438822d3 --- /dev/null +++ b/compilerplugins/clang/test/implicitboolconversion.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/. + */ + +#include <sal/config.h> + +#include <atomic> + +void f() +{ + // expected-error@+1 {{implicit conversion (IntegralCast) from 'bool' to 'int' [loplugin:implicitboolconversion]}} + int i = false; + (void)i; + std::atomic<bool> b = false; + (void)b; + //TODO: Emit only one diagnostic here: + // expected-error@+2 {{implicit conversion (ConstructorConversion) from 'bool' to 'std::atomic<int>' [loplugin:implicitboolconversion]}} + // expected-error-re@+1 {{implicit conversion (IntegralCast) from 'bool' to {{.+}} [loplugin:implicitboolconversion]}} + std::atomic<int> a = false; + (void)a; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/indentation.cxx b/compilerplugins/clang/test/indentation.cxx new file mode 100644 index 000000000..e0e25884e --- /dev/null +++ b/compilerplugins/clang/test/indentation.cxx @@ -0,0 +1,94 @@ +/* -*- 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 "config_clang.h" + +int foo(); +int foo2(int); + +#define SOME_MACRO(x) foo2(x) + +void top1(int x) { + { + foo(); // expected-note {{measured against this one [loplugin:indentation]}} + foo(); // expected-error {{statement mis-aligned compared to neighbours [loplugin:indentation]}} + } + { + foo(); // expected-note {{measured against this one [loplugin:indentation]}} + SOME_MACRO(1); // expected-error {{statement mis-aligned compared to neighbours SOME_MACRO [loplugin:indentation]}} + } + // no warning expected + { + foo(); foo(); + } + // no warning expected + /*xxx*/ foo(); + + +// disable this for now, ends up touching some very large switch statements in sw/ and sc/ + switch (x) + { + case 1: foo(); break; // 1expected-note {{measured against this one [loplugin:indentation]}} + case 2: foo(); break; // 1expected-error {{statement mis-aligned compared to neighbours [loplugin:indentation]}} + }; + + + if (x) + foo(); // expected-error {{if body should be indented [loplugin:indentation]}} + + if (x) + { + foo(); + } + + if (x) + ; + else + foo(); // expected-error {{else body should be indented [loplugin:indentation]}} + + if (x) + ; + else + { + foo(); + } + + if (x) + ; + else // expected-error {{if and else not aligned [loplugin:indentation]}} + foo(); + + if (x) + { + } else + { + foo(); + } + +#if 0 + if (x) + foo(); + else +#endif + foo(); +} + +void attr() { + [[maybe_unused]] int i = foo(); + foo(); +} + +#if CLANG_VERSION >= 100000 +void attr_bad() { + [[maybe_unused]] int i = foo(); // expected-note {{measured against this one [loplugin:indentation]}} + foo(); // expected-error {{statement mis-aligned compared to neighbours [loplugin:indentation]}} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/intvsfloat.cxx b/compilerplugins/clang/test/intvsfloat.cxx new file mode 100644 index 000000000..4746873e7 --- /dev/null +++ b/compilerplugins/clang/test/intvsfloat.cxx @@ -0,0 +1,62 @@ +/* -*- 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/. + */ + +static const float PI = 3.4; +struct Class1 +{ + float getFloat() const { return 1.5; } + int getInt() const { return 1; } + static constexpr float PI = 3.4; + static constexpr float E() { return 3.4; } +}; + +void func1(Class1 const& class1) +{ + // expected-error@+1 {{comparing integer to float constant, can never be true [loplugin:intvsfloat]}} + if (1 == PI) + return; + // expected-error@+1 {{comparing integer to float constant, can never be true [loplugin:intvsfloat]}} + if (1 == class1.PI) + return; + // expected-error@+1 {{comparing integer to float constant, can never be true [loplugin:intvsfloat]}} + if (true == class1.PI) + return; + if (1 == class1.getInt()) // no warning expected + return; + // expected-error@+1 {{comparing integer to float constant, can never be true [loplugin:intvsfloat]}} + if (1 == class1.E()) + return; + // expected-error@+1 {{comparing integer to float constant, can never be true [loplugin:intvsfloat]}} + if (true == class1.E()) + return; + if (1 == class1.getFloat()) // no warning expected + return; +} + +void func2(Class1 const& class1) +{ + // expected-error@+1 {{assigning constant float value to int truncates data [loplugin:intvsfloat]}} + int i0 = PI; + (void)i0; + // expected-error@+1 {{assigning constant float value to int truncates data [loplugin:intvsfloat]}} + int i1 = class1.PI; + (void)i1; + // expected-error@+1 {{assigning constant float value to int truncates data [loplugin:intvsfloat]}} + int i2 = class1.E(); + (void)i2; + int i3 = class1.getFloat(); // no warning expected + (void)i3; + int i4 = class1.getInt(); // no warning expected + (void)i4; + // expected-error@+1 {{assigning constant float value to int truncates data [loplugin:intvsfloat]}} + bool b1 = class1.E(); + (void)b1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/logexceptionnicely.cxx b/compilerplugins/clang/test/logexceptionnicely.cxx new file mode 100644 index 000000000..458eef8c4 --- /dev/null +++ b/compilerplugins/clang/test/logexceptionnicely.cxx @@ -0,0 +1,52 @@ +/* -*- 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 <tools/diagnose_ex.h> +#include <sal/log.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/Any.hxx> + +void func1(); + +int main() +{ + // no warning expected + try + { + func1(); + } + catch (css::uno::Exception const&) + { + css::uno::Any ex(cppu::getCaughtException()); + SAL_WARN("avmedia", "exception: " << exceptionToString(ex)); + } + + try + { + func1(); + } + catch (css::uno::Exception const& ex) + { + SAL_WARN("xmloff", "message " << ex); + // expected-error@-1 {{use TOOLS_WARN_EXCEPTION/TOOLS_INFO_EXCEPTION/exceptionToString to print exception nicely [loplugin:logexceptionnicely]}} + } + + try + { + func1(); + } + catch (const css::lang::IndexOutOfBoundsException& ex) + { + SAL_WARN("xmloff", "message " << ex); + // expected-error@-1 {{use TOOLS_WARN_EXCEPTION/TOOLS_INFO_EXCEPTION/exceptionToString to print exception nicely [loplugin:logexceptionnicely]}} + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/loopvartoosmall.cxx b/compilerplugins/clang/test/loopvartoosmall.cxx new file mode 100644 index 000000000..bebf88c79 --- /dev/null +++ b/compilerplugins/clang/test/loopvartoosmall.cxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * +*/ + +#include <cstdint> + +std::int32_t size() { return 1; } + +int main() { + for (std::int16_t i = 0; i < size(); ++i) {} // expected-error {{[loplugin:loopvartoosmall]}} + for (std::int16_t i = 0; i <= size(); ++i) {} // expected-error {{[loplugin:loopvartoosmall]}} + for (std::int16_t i = 0; i != size(); ++i) {} // expected-error {{[loplugin:loopvartoosmall]}} + std::int16_t j; + for (j = 0; j < size(); ++j) {} // expected-error {{[loplugin:loopvartoosmall]}} + for (j = 0; j <= size(); ++j) {} // expected-error {{[loplugin:loopvartoosmall]}} + for (j = 0; j != size(); ++j) {} // expected-error {{[loplugin:loopvartoosmall]}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/makeshared.cxx b/compilerplugins/clang/test/makeshared.cxx new file mode 100644 index 000000000..fe73d7e0e --- /dev/null +++ b/compilerplugins/clang/test/makeshared.cxx @@ -0,0 +1,63 @@ +/* -*- 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 <sal/config.h> + +#include <memory> +#include <o3tl/deleter.hxx> +#include <o3tl/sorted_vector.hxx> + +struct S1 +{ + friend void test1(); + +private: + S1() {} +}; + +void test1() +{ + // expected-error@+1 {{rather use make_shared than constructing from 'int *' [loplugin:makeshared]}} + std::shared_ptr<int> x(new int); + // expected-error@+1 {{rather use make_shared [loplugin:makeshared]}} + x.reset(new int); + // expected-error@+1 {{rather use make_shared than constructing from 'int *' [loplugin:makeshared]}} + x = std::shared_ptr<int>(new int); + + // no warning expected + std::shared_ptr<int> y(new int, o3tl::default_delete<int>()); + y.reset(new int, o3tl::default_delete<int>()); + // no warning expected, no public constructor + std::shared_ptr<S1> z(new S1); + z.reset(new S1); + + // no warning expected - this constructor takes an initializer-list, which make_shared does not support + auto a = std::shared_ptr<o3tl::sorted_vector<int>>(new o3tl::sorted_vector<int>({ 1, 2 })); +}; + +void test2() +{ + // expected-error-re@+1 {{rather use make_shared than constructing from {{.+}} (aka 'unique_ptr<int>') [loplugin:makeshared]}} + std::shared_ptr<int> x = std::make_unique<int>(1); + // expected-error-re@+1 {{rather use make_shared than constructing from {{.+}} (aka 'unique_ptr<int>') [loplugin:makeshared]}} + x = std::make_unique<int>(1); + (void)x; + + // expected-error-re@+1 {{rather use make_shared than constructing from {{.+}} (aka 'unique_ptr<int>') [loplugin:makeshared]}} + std::shared_ptr<int> y(std::make_unique<int>(1)); + (void)y; + + std::unique_ptr<int> u1; + // expected-error-re@+1 {{rather use make_shared than constructing from {{.+}} (aka 'std{{.*}}::unique_ptr<int, std{{.*}}::default_delete<int>{{ ?}}>') [loplugin:makeshared]}} + std::shared_ptr<int> z = std::move(u1); + // expected-error-re@+1 {{rather use make_shared than constructing from {{.+}} (aka 'std{{.*}}::unique_ptr<int, std{{.*}}::default_delete<int>{{ ?}}>') [loplugin:makeshared]}} + z = std::move(u1); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/mapindex.cxx b/compilerplugins/clang/test/mapindex.cxx new file mode 100644 index 000000000..de7dd2590 --- /dev/null +++ b/compilerplugins/clang/test/mapindex.cxx @@ -0,0 +1,43 @@ +/* -*- 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 <map> +#include <memory> +#include <string> + +struct CallbackFlushHandler +{ +}; + +struct LibLODocument_Impl +{ + std::map<size_t, std::shared_ptr<CallbackFlushHandler>> mpCallbackFlushHandlers; +}; + +void foo(LibLODocument_Impl* pDoc) +{ + std::map<int, int> aMap; + if (aMap[0]) // expected-error {{will create an empty entry in the map, you sure about that, rather use count()2 [loplugin:mapindex]}} + ; + + // expected-error@+1 {{will create an empty entry in the map, you sure about that, rather use count()1 [loplugin:mapindex]}} + if (pDoc->mpCallbackFlushHandlers[0]) + ; +} + +void no_warning_expected(const std::string& payload) +{ + for (size_t numberPos = 0; numberPos < payload.length(); ++numberPos) + { + if (payload[numberPos] == ',') + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/namespaceindentation.cxx b/compilerplugins/clang/test/namespaceindentation.cxx new file mode 100644 index 000000000..f97f781fc --- /dev/null +++ b/compilerplugins/clang/test/namespaceindentation.cxx @@ -0,0 +1,50 @@ +/* -*- 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 "config_clang.h" + +// no warning expected +namespace xxx::yyy +{ +} +namespace xxx::yyy { +} +// expected-error@+1 {{statement left brace mis-aligned [loplugin:namespaceindentation]}} +namespace xxx::yyy + { +// expected-error@+1 {{statement right brace mis-aligned [loplugin:namespaceindentation]}} + } +namespace xxx::yyy +{ + // expected-error@+1 {{statement right brace mis-aligned [loplugin:namespaceindentation]}} + } +// expected-error@+1 {{statement left brace mis-aligned [loplugin:namespaceindentation]}} +namespace xxx::yyy + { +} +namespace xxx::yyy { +// expected-error@+1 {{statement right brace mis-aligned [loplugin:namespaceindentation]}} + } +namespace xxx::yyy +{ +} // fooo baaaar +// expected-error@-1 {{incorrect comment at end of namespace xxx::yyy [loplugin:namespaceindentation]}} +namespace aaa::bbb +{ +} // namespace foo +// expected-error@-1 {{incorrect comment at end of namespace aaa::bbb [loplugin:namespaceindentation]}} +namespace xxx::yyy +{ +} // xxx::yyy +// no warning expected +namespace com { namespace sun { namespace star { } } } +// no warning expected +namespace com::sun::star::uno { class XComponentContext; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/noexceptmove.cxx b/compilerplugins/clang/test/noexceptmove.cxx new file mode 100644 index 000000000..fda58deae --- /dev/null +++ b/compilerplugins/clang/test/noexceptmove.cxx @@ -0,0 +1,102 @@ +/* -*- 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 "config_clang.h" + +// clang before V9 does not have API to report exception spec type +#if CLANG_VERSION >= 90000 + +namespace test1 +{ +class Mapping +{ + char* m_pMapping; + + // expected-error@+1 {{move constructor can be noexcept [loplugin:noexceptmove]}} + Mapping(Mapping&& other) + : m_pMapping(other.m_pMapping) + { + other.m_pMapping = nullptr; + } + + // expected-error@+1 {{move operator= can be noexcept [loplugin:noexceptmove]}} + Mapping& operator=(Mapping&& other) + { + m_pMapping = other.m_pMapping; + other.m_pMapping = nullptr; + return *this; + } +}; +}; + +// No warning expected, because calling throwing function. +namespace test2 +{ +void foo() noexcept(false); + +class Bar +{ + Bar(Bar&&) { foo(); } +}; +}; + +// no warning expected, because calling throwing constructor +namespace test3 +{ +struct Foo +{ + Foo() noexcept(false); +}; +class Bar +{ + Bar(Bar&&) { Foo aFoo; } +}; + +class Bar2 +{ + Foo m_foo; + + Bar2(Bar2&&) {} +}; +}; + +// No warning expected, because calling throwing destructor. +namespace test4 +{ +struct Foo +{ + ~Foo() noexcept(false); +}; + +class Bar +{ + Bar(Bar&&) { Foo aFoo; } +}; +}; + +// Check for calls to defaulted constructors. +namespace test5 +{ +struct Foo +{ + Foo() = default; // non-throwing +}; +class Bar +{ + Bar(Bar&&) // expected-error {{move constructor can be noexcept [loplugin:noexceptmove]}} + { + Foo aFoo; + (void)aFoo; + } +}; +}; + +#else +// expected-no-diagnostics +#endif // CLANG_VERSION +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/nullptr.cxx b/compilerplugins/clang/test/nullptr.cxx new file mode 100644 index 000000000..bf7376cb6 --- /dev/null +++ b/compilerplugins/clang/test/nullptr.cxx @@ -0,0 +1,23 @@ +/* -*- 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 S +{ + void* p; +}; + +int main() +{ + S s{ + 0 // expected-error {{NullToPointer ValueDependentIsNotNull ZeroLiteral -> nullptr [loplugin:nullptr]}} + }; + (void)s; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/oncevar.cxx b/compilerplugins/clang/test/oncevar.cxx new file mode 100644 index 000000000..c8cc7bc13 --- /dev/null +++ b/compilerplugins/clang/test/oncevar.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <rtl/ustring.hxx> + +/*int foo() { return 1; }*/ + +void call_value(int); +void call_const_ref(int const &); +void call_ref(int &); +void call_value(OUString); +void call_const_ref(OUString const &); +void call_ref(OUString &); + +template<typename T> void f() { + int i = sizeof (T) + 1; // expected-error {{var used only once, should be inlined or declared const [loplugin:oncevar]}} + call_value(i); // expected-note {{used here [loplugin:oncevar]}} +} +template void f<int>(); // needed for clang-cl + +class Foo; +void method1(const Foo**); + +int main() { +/* TODO + int i; + int x = 2; + if ( (i = foo()) == 0 ) { + x = 1; + } +*/ + + + int i1 = 2; // expected-error {{var used only once, should be inlined or declared const [loplugin:oncevar]}} + call_value(i1); // expected-note {{used here [loplugin:oncevar]}} + int i2 = 2; // expected-error {{var used only once, should be inlined or declared const [loplugin:oncevar]}} + call_const_ref(i2); // expected-note {{used here [loplugin:oncevar]}} + + // don't expect warnings here + int i3; + call_ref(i3); + int const i4 = 2; + call_value(i4); + + OUString s1("xxx"); // expected-error {{var used only once, should be inlined or declared const [loplugin:oncevar]}} + call_value(s1); // expected-note {{used here [loplugin:oncevar]}} + OUString s2("xxx"); // expected-error {{var used only once, should be inlined or declared const [loplugin:oncevar]}} + call_const_ref(s2); // expected-note {{used here [loplugin:oncevar]}} + + // don't expect warnings here + OUString s3; + call_ref(s3); + OUString const s4("xxx"); + call_value(s4); + + const Foo* pInternalArgs[] = { nullptr }; + method1(pInternalArgs); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/oslendian-1.cxx b/compilerplugins/clang/test/oslendian-1.cxx new file mode 100644 index 000000000..7349239aa --- /dev/null +++ b/compilerplugins/clang/test/oslendian-1.cxx @@ -0,0 +1,47 @@ +/* -*- 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 <sal/config.h> + +#include <osl/endian.h> + +#if defined OSL_BIGENDIAN || defined OSL_LITENDIAN +#endif +#ifdef OSL_BIGENDIAN +#endif +#ifdef OSL_LITENDIAN +#endif +#ifndef OSL_BIGENDIAN +#endif +#ifndef OSL_LITENDIAN +#endif + +#if !defined OSL_BIGENDIAN +#define OSL_BIGENDIAN + // expected-error@-1 {{macro 'OSL_BIGENDIAN' defined in addition to 'OSL_LITENDIAN' [loplugin:oslendian]}} + // expected-note@osl/endian.h:* {{conflicting macro definition is here [loplugin:oslendian]}} +#endif + +#if !defined OSL_LITENDIAN +#define OSL_LITENDIAN + // expected-error@-1 {{macro 'OSL_LITENDIAN' defined in addition to 'OSL_BIGENDIAN' [loplugin:oslendian]}} + // expected-note@osl/endian.h:* {{conflicting macro definition is here [loplugin:oslendian]}} +#endif + +#if defined OSL_BIGENDIAN +#undef OSL_BIGENDIAN + // expected-error@-1 {{macro 'OSL_BIGENDIAN' undefinition [loplugin:oslendian]}} +#endif + +#if defined OSL_LITENDIAN +#undef OSL_LITENDIAN + // expected-error@-1 {{macro 'OSL_LITENDIAN' undefinition [loplugin:oslendian]}} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/oslendian-2.cxx b/compilerplugins/clang/test/oslendian-2.cxx new file mode 100644 index 000000000..76e1a6b38 --- /dev/null +++ b/compilerplugins/clang/test/oslendian-2.cxx @@ -0,0 +1,23 @@ +/* -*- 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 <sal/config.h> + +#if defined OSL_BIGENDIAN || defined OSL_LITENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifdef OSL_BIGENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifdef OSL_LITENDIAN // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifndef OSL_BIGENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifndef OSL_LITENDIAN // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/oslendian-3.cxx b/compilerplugins/clang/test/oslendian-3.cxx new file mode 100644 index 000000000..90de9643c --- /dev/null +++ b/compilerplugins/clang/test/oslendian-3.cxx @@ -0,0 +1,25 @@ +/* -*- 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 <sal/config.h> + +#if defined OSL_BIGENDIAN || defined OSL_LITENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifdef OSL_BIGENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifdef OSL_LITENDIAN // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifndef OSL_BIGENDIAN // expected-error {{definition of macro 'OSL_BIGENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif +#ifndef OSL_LITENDIAN // expected-error {{definition of macro 'OSL_LITENDIAN' checked but 'osl/endian.h' is not included [loplugin:oslendian]}} +#endif + +#include <osl/endian.h> + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/passparamsbyref.cxx b/compilerplugins/clang/test/passparamsbyref.cxx new file mode 100644 index 000000000..e58aa79bc --- /dev/null +++ b/compilerplugins/clang/test/passparamsbyref.cxx @@ -0,0 +1,39 @@ +/* -*- 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 <rtl/ustring.hxx> + +struct S { + OUString mv1; + OUString mv2; + + // make sure we ignore cases where the passed in parameter is std::move'd + S(OUString v1, OUString v2) + : mv1(std::move(v1)), mv2((std::move(v2))) {} +}; + + +void f() +{ + S* s; + OUString v1, v2; + s = new S(v1, v2); +} + + +// check that we don't warn when the param is modified +OUString trim_string(OUString aString) +{ + aString += "xxx"; + return aString; +} + +// expected-no-diagnostics + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/passstuffbyref.cxx b/compilerplugins/clang/test/passstuffbyref.cxx new file mode 100644 index 000000000..3f0efb1d1 --- /dev/null +++ b/compilerplugins/clang/test/passstuffbyref.cxx @@ -0,0 +1,81 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <o3tl/cow_wrapper.hxx> +#include <vector> + +struct S1 { + OUString mv1; + OUString const & get() const { return mv1; } + OUString const & get2(bool) const { return mv1; } +}; +struct S2 { + OUString mv1; + OUString mv2; + OUString mv3[2]; + S1 child; + static OUString gs1; + o3tl::cow_wrapper<S1> mxCow; + + // make sure we ignore cases where the passed in parameter is std::move'd + S2(OUString v1, OUString v2) + : mv1(std::move(v1)), mv2((std::move(v2))) {} + + OUString get1() { return mv1; } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get2(bool b) { return b ? mv1 : mv2; } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get3() { return child.mv1; } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get4() { return mv3[0]; } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get5() { return gs1; } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString const & get6() { return gs1; } + OUString get7() { return get6(); } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString & get8() { return gs1; } + OUString get9() { return get8(); } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + // TODO + OUString get10() { return OUString(*&get6()); } // todoexpected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get11() const { return mxCow->get(); } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + OUString get12() { return child.get2(false); } // expected-error {{rather return class rtl::OUString by const& than by value, to avoid unnecessary copying [loplugin:passstuffbyref]}} + + // no warning expected + OUString set1() { return OUString("xxx"); } + OUString set2() { OUString v1("xxx"); return v1; } + OUString set3() { S1 v1; return v1.get(); } + OUString set4() { OUString v1[1]; return v1[0]; } + OUString set5(OUString const & s) { return s; } + OUString set6() { std::vector<OUString> v1(1); return v1[0]; } + OUString set7(S1 const & s) { return s.get(); } + OUString set8() { OUString * p = nullptr; return *p; } +}; + + +// no warning expected + +// Don't flag stuff where the local var is hidden behind a self-returning operation like -=: +S2 &operator -= ( S2 &t1, const S2 &t2 ); +S2 operator-( const S2 &t1, const S2 &t2 ) +{ + S2 t0 = t1; + return t0 -= t2; +} + +void f() +{ + S2* s; + OUString v1, v2; + s = new S2(v1, v2); +} + +struct S3 { S3(int); }; + +S3 f2() { + static int n; + return n; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/pointerbool.cxx b/compilerplugins/clang/test/pointerbool.cxx new file mode 100644 index 000000000..276a95ae1 --- /dev/null +++ b/compilerplugins/clang/test/pointerbool.cxx @@ -0,0 +1,32 @@ +/* -*- 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 <sal/types.h> +#include <com/sun/star/uno/Sequence.hxx> + +#define FALSE 0 + +void func_ptr(int*); +void func_bool(bool); // expected-note {{method here [loplugin:pointerbool]}} +void func_salbool(sal_Bool); + +void test1(int* p1) +{ + func_ptr(p1); + func_bool( + p1); // expected-error {{possibly unwanted implicit conversion when calling bool param [loplugin:pointerbool]}} + // no warning expected + func_bool(FALSE); + func_salbool(sal_False); + func_salbool(sal_True); + css::uno::Sequence<sal_Bool> aSeq; + func_bool(aSeq[0]); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantcast.cxx b/compilerplugins/clang/test/redundantcast.cxx new file mode 100644 index 000000000..03ce47796 --- /dev/null +++ b/compilerplugins/clang/test/redundantcast.cxx @@ -0,0 +1,447 @@ +/* -*- 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 <sal/config.h> + +#include <cstddef> + +#include <sal/types.h> + +#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<char *>(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *' prvalue [loplugin:redundantcast]}} + f1(const_cast<char * const>(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *const' prvalue [loplugin:redundantcast]}} + f1(const_cast<char *>(p2)); + f1(const_cast<char * const>(p2)); + f2(const_cast<char *>(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *' prvalue [loplugin:redundantcast]}} + f2(const_cast<char * const>(p1)); // expected-error {{redundant const_cast from 'char *' lvalue to 'char *const' prvalue [loplugin:redundantcast]}} + f2(const_cast<char const *>(p1)); + f2(const_cast<char const * const>(p1)); + f2(const_cast<char *>(p2)); // expected-error {{redundant const_cast from 'const char *' to 'char *', result is implicitly cast to 'const char *' [loplugin:redundantcast]}} + f2(const_cast<char * const>(p2)); // expected-error {{redundant const_cast from 'const char *' to 'char *', result is implicitly cast to 'const char *' [loplugin:redundantcast]}} + f2(const_cast<char const *>(p2)); // expected-error {{redundant const_cast from 'const char *' lvalue to 'const char *' prvalue [loplugin:redundantcast]}} + f2(const_cast<char const * const>(p2)); // expected-error {{redundant const_cast from 'const char *' lvalue to 'const char *const' prvalue [loplugin:redundantcast]}} + + void * vp = nullptr; + (void) const_cast<char *>(static_cast<char const *>(vp)); // expected-error {{redundant static_cast/const_cast combination from 'void *' via 'const char *' to 'char *' [loplugin:redundantcast]}} + (void) const_cast<char *>(static_cast<char const *>(nullptr)); // expected-error {{redundant static_cast/const_cast combination from 'nullptr_t' via 'const char *' to 'char *' [loplugin:redundantcast]}} + (void) const_cast<S &>(static_cast<S const &>(D{})); // expected-error {{redundant static_cast/const_cast combination from 'D' via 'const S &' to 'S &' [loplugin:redundantcast]}} + + S const s{}; + const_cast<S &>(s).f1(); + const_cast<S &>(s).f2(); // expected-error {{redundant const_cast from 'const S' to 'S', result is implicitly cast to 'const S' [loplugin:redundantcast]}} + const_cast<S &>(s).f3(); + s.f3(); + + // non-class lvalue, non-const: + int ni{}; +// (void) const_cast<int>(ni); + (void) const_cast<int &>(ni); // expected-error {{redundant const_cast from 'int' lvalue to 'int &' lvalue [loplugin:redundantcast]}} + (void) const_cast<int &&>(ni); +// (void) const_cast<int const>(ni); + (void) const_cast<int const &>(ni); + (void) const_cast<int const &&>(ni); + + // non-class lvalue, const: + int const ci{}; +// (void) const_cast<int>(ci); + (void) const_cast<int &>(ci); + (void) const_cast<int &&>(ci); +// (void) const_cast<int const>(ci); + (void) const_cast<int const &>(ci); // expected-error {{redundant const_cast from 'const int' lvalue to 'const int &' lvalue [loplugin:redundantcast]}} + (void) const_cast<int const &&>(ci); + + // non-class xvalue, non-const: +// (void) const_cast<int>(nix()); +// (void) const_cast<int &>(nix()); + (void) const_cast<int &&>(nix()); // expected-error {{redundant const_cast from 'int' xvalue to 'int &&' xvalue [loplugin:redundantcast]}} +// (void) const_cast<int const>(nix()); +// (void) const_cast<int const &>(nix()); + (void) const_cast<int const &&>(nix()); + + // non-class xvalue, const: +// (void) const_cast<int>(cix()); +// (void) const_cast<int &>(cix()); + (void) const_cast<int &&>(cix()); +// (void) const_cast<int const>(cix()); +// (void) const_cast<int const &>(cix()); + (void) const_cast<int const &&>(cix()); // expected-error {{redundant const_cast from 'const int' xvalue to 'const int &&' xvalue [loplugin:redundantcast]}} + + // non-class prvalue, non-const: +// (void) const_cast<int>(nir()); +// (void) const_cast<int &>(nir()); +// (void) const_cast<int &&>(nir()); +// (void) const_cast<int const>(nir()); +// (void) const_cast<int const &>(nir()); +// (void) const_cast<int const &&>(nir()); + + // non-class prvalue, const: +// (void) const_cast<int>(cir()); +// (void) const_cast<int &>(cir()); +// (void) const_cast<int &&>(cir()); +// (void) const_cast<int const>(cir()); +// (void) const_cast<int const &>(cir()); +// (void) const_cast<int const &&>(cir()); + + // class lvalue, non-const: + S ns{}; +// (void) const_cast<S>(ns); + (void) const_cast<S &>(ns); // expected-error {{redundant const_cast from 'S' lvalue to 'S &' lvalue [loplugin:redundantcast]}} + (void) const_cast<S &&>(ns); +// (void) const_cast<S const>(ns); + (void) const_cast<S const &>(ns); + (void) const_cast<S const &&>(ns); + + // class lvalue, const: + S const cs{}; +// (void) const_cast<S>(cs); + (void) const_cast<S &>(cs); + (void) const_cast<S &&>(cs); +// (void) const_cast<S const>(cs); + (void) const_cast<S const &>(cs); // expected-error {{redundant const_cast from 'const S' lvalue to 'const S &' lvalue [loplugin:redundantcast]}} + (void) const_cast<S const &&>(cs); + + // class xvalue, non-const: +// (void) const_cast<S>(nsx()); +// (void) const_cast<S &>(nsx()); + (void) const_cast<S &&>(nsx()); // expected-error {{redundant const_cast from 'S' xvalue to 'S &&' xvalue [loplugin:redundantcast]}} +// (void) const_cast<S const>(nsx()); +// (void) const_cast<S const &>(nsx()); + (void) const_cast<S const &&>(nsx()); + + // class xvalue, const: +// (void) const_cast<S>(csx()); +// (void) const_cast<S &>(csx()); + (void) const_cast<S &&>(csx()); +// (void) const_cast<S const>(csx()); +// (void) const_cast<S const &>(csx()); + (void) const_cast<S const &&>(csx()); // expected-error {{redundant const_cast from 'const S' xvalue to 'const S &&' xvalue [loplugin:redundantcast]}} + + // class prvalue, non-const: +// (void) const_cast<S>(nsr()); +// (void) const_cast<S &>(nsr()); + (void) const_cast<S &&>(nsr()); +// (void) const_cast<S const>(nsr()); +// (void) const_cast<S const &>(nsr()); + (void) const_cast<S const &&>(nsr()); + + // class prvalue, const: +// (void) const_cast<S>(csr()); +// (void) const_cast<S &>(csr()); + (void) const_cast<S &&>(csr()); +// (void) const_cast<S const>(csr()); +// (void) const_cast<S const &>(csr()); + (void) const_cast<S const &&>(csr()); +} + +void testStaticCast() { + // non-class lvalue, non-const: + int ni{}; + (void) static_cast<int>(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<int &>(ni); // expected-error {{static_cast from 'int' lvalue to 'int &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int &&>(ni); + (void) static_cast<int const>(ni); // expected-error {{in static_cast from 'int' lvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} + /* => */ (void) static_cast<int>(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<int const &>(ni); // expected-error {{static_cast from 'int' lvalue to 'const int &' lvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<int const &>(ni); + (void) static_cast<int const &&>(ni); // expected-error {{static_cast from 'int' lvalue to 'const int &&' xvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<int const &&>(ni); + + // non-class lvalue, const: + int const ci{}; + (void) static_cast<int>(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<int &>(ci); +// (void) static_cast<int &&>(ci); + (void) static_cast<int const>(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<int>(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<int const &>(ci); // expected-error {{static_cast from 'const int' lvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const &&>(ci); + + // non-class xvalue, non-const: + (void) static_cast<int>(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<int &>(nix()); + (void) static_cast<int &&>(nix()); // expected-error {{static_cast from 'int' xvalue to 'int &&' xvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const>(nix()); // expected-error {{in static_cast from 'int' xvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} + /* => */ (void) static_cast<int>(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<int const &>(nix()); + (void) static_cast<int const &&>(nix()); // expected-error {{static_cast from 'int' xvalue to 'const int &&' xvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<int const &&>(nix()); + + // non-class xvalue, const: + (void) static_cast<int>(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<int &>(cix()); +// (void) static_cast<int &&>(cix()); + (void) static_cast<int const>(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<int>(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<int const &>(cix()); + (void) static_cast<int const &&>(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<int>(nir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} +// (void) static_cast<int &>(nir()); + (void) static_cast<int &&>(nir()); + (void) static_cast<int const>(nir()); // expected-error {{in static_cast from 'int' prvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} + /* => */ (void) static_cast<int>(nir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const &>(nir()); // expected-error {{static_cast from 'int' prvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const &&>(nir()); + + // non-class prvalue, const: + (void) static_cast<int>(cir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} +// (void) static_cast<int &>(cir()); + (void) static_cast<int &&>(cir()); + (void) static_cast<int const>(cir()); // expected-error {{in static_cast from 'int' prvalue to 'const int' prvalue, remove redundant top-level const qualifier [loplugin:redundantcast]}} + /* => */ (void) static_cast<int>(cir()); // expected-error {{static_cast from 'int' prvalue to 'int' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const &>(cir()); // expected-error {{static_cast from 'int' prvalue to 'const int &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<int const &&>(cir()); + + // class lvalue, non-const: + S ns{}; + (void) static_cast<S>(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<S &>(ns); // expected-error {{static_cast from 'S' lvalue to 'S &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<S &&>(ns); + (void) static_cast<S const>(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<S const &>(ns); // expected-error {{static_cast from 'S' lvalue to 'const S &' lvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<S const &>(ns); + (void) static_cast<S const &&>(ns); // expected-error {{static_cast from 'S' lvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<S const &&>(ns); + + // class lvalue, const: + S const cs{}; + (void) static_cast<S>(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<S &>(cs); +// (void) static_cast<S &&>(cs); + (void) static_cast<S const>(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<S const &>(cs); // expected-error {{static_cast from 'const S' lvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<S const &&>(cs); + + // class xvalue, non-const: + (void) static_cast<S>(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<S &>(nsx()); + (void) static_cast<S &&>(nsx()); // expected-error {{static_cast from 'S' xvalue to 'S &&' xvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<S const>(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<S const &>(nsx()); + (void) static_cast<S const &&>(nsx()); // expected-error {{static_cast from 'S' xvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<S const &&>(nsx()); + + // class xvalue, const: + (void) static_cast<S>(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<S &>(csx()); +// (void) static_cast<S &&>(csx()); + (void) static_cast<S const>(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<S const &>(csx()); + (void) static_cast<S const &&>(csx()); // expected-error {{static_cast from 'const S' xvalue to 'const S &&' xvalue is redundant [loplugin:redundantcast]}} + + // class prvalue, non-const: + (void) static_cast<S>(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<S &>(nsr()); + (void) static_cast<S &&>(nsr()); + (void) static_cast<S const>(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<S const &>(nsr()); // expected-error {{static_cast from 'S' prvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<S const &&>(nsr()); // expected-error {{static_cast from 'S' prvalue to 'const S &&' xvalue should be written as const_cast [loplugin:redundantcast]}} + /* => */ (void) const_cast<S const &&>(nsr()); + + // class prvalue, const: + (void) static_cast<S>(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<S &>(csr()); +// (void) static_cast<S &&>(csr()); + (void) static_cast<S const>(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<S const &>(csr()); // expected-error {{static_cast from 'const S' prvalue to 'const S &' lvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<S const &&>(csr()); +} + +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<typename T> +struct EnumItemInterface { + T GetValue() { return static_cast<T>(0); } +}; +class Enum1Item : public EnumItemInterface<Enum1> { +}; +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<T1>(nir()); + (void) T1(nir()); + (void) (T1) nir(); + (void) static_cast<int>(nt1r()); + (void) int(nt1r()); + (void) (int) nt1r(); + using T2 = T1; + (void) static_cast<T2>(nt1r()); + (void) T2(nt1r()); + (void) (T2) nt1r(); + (void) static_cast<T1>(nt1r()); // expected-error {{redundant}} + (void) T1(nt1r()); // expected-error {{redundant}} + (void) (T1) nt1r(); // expected-error {{redundant}} + + T1 const c{}; + (void) static_cast<T1>(c); // expected-error {{redundant}} +} + +void testReinterpretConstCast() { + int n = 0; + (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) 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); +} + +void overload(int); +void overload(long); +void nonOverload(); + +struct Overload { + int overload(); + long overload() const; + void nonOverload(); +}; + +void testOverloadResolution() { + (void) static_cast<void (*)(long)>(overload); + (void) static_cast<void (*)(long)>((overload)); + (void) static_cast<void (*)(long)>(&overload); + (void) static_cast<void (*)(long)>((&overload)); + (void) static_cast<void (*)(long)>(&((overload))); + (void) static_cast<void (*)()>(nonOverload); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<void (*)()>((nonOverload)); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<void (*)()>(&nonOverload); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<void (*)()>((&nonOverload)); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<void (*)()>(&((nonOverload))); // expected-error {{static_cast from 'void (*)()' prvalue to 'void (*)()' prvalue is redundant [loplugin:redundantcast]}} + (void) static_cast<long (Overload::*)() const>(&Overload::overload); + (void) static_cast<void (Overload::*)()>(&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<double>(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<int>(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<char const *>(""); // expected-error {{redundant static_cast from 'const char [1]' to 'const char *' [loplugin:redundantcast]}} + (void) reinterpret_cast<char const *>(""); // expected-error {{redundant reinterpret_cast from 'const char [1]' to 'const char *' [loplugin:redundantcast]}} + (void) reinterpret_cast<char const *>(u8""); +} + +void testNew() { + class A {}; + class B : public A {}; + A* p = static_cast<A*>(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<B*>(new D); + // no warning expected for down-cast + auto p2 = static_cast<B*>(p); + (void)p2; +} + +using F = void (*)(); +auto testNullFunctionPointer(int i, F p) { + switch (i) { + case 0: + return static_cast<F>(nullptr); + case 1: + return F(nullptr); + default: + return p; + } +} + +void testSalIntTypes() { + sal_Int16 const n = 0; + (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<::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<short>(n); // doesn't warn, even if 'sal_Int16' is 'short' + using Other = sal_Int16; + (void) static_cast<Other>(n); // doesn't warn either +} + +int main() { + testConstCast(); + testStaticCast(); + testFunctionalCast(); + testCStyleCast(); + testCStyleCastOfTemplateMethodResult(nullptr); + testReinterpretConstCast(); + testDynamicCast(); + testIntermediaryStaticCast(); + testArrayDecay(); + testSalIntTypes(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantcast.hxx b/compilerplugins/clang/test/redundantcast.hxx new file mode 100644 index 000000000..014aecea4 --- /dev/null +++ b/compilerplugins/clang/test/redundantcast.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_REDUNDANTCAST_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_REDUNDANTCAST_HXX + +struct S { + void f1(); + void f2() const; + void f3(); + void f3() const; +}; + +int && nix(); +int const && cix(); +int nir(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-qualifiers" +int const cir(); +#pragma clang diagnostic pop + +S && nsx(); +S const && csx(); +S nsr(); +S const csr(); + +void testArithmeticTypedefs(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantfcast.cxx b/compilerplugins/clang/test/redundantfcast.cxx new file mode 100644 index 000000000..255c1d44b --- /dev/null +++ b/compilerplugins/clang/test/redundantfcast.cxx @@ -0,0 +1,204 @@ +/* -*- 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 "sal/config.h" + +#include "rtl/ustring.hxx" +#include "tools/color.hxx" + +#include <functional> +#include <initializer_list> +#include <memory> + +void method1(OUString const&); // expected-note {{in call to method here [loplugin:redundantfcast]}} + +struct Foo +{ + Foo(int) {} +}; + +void func1(Foo const& f); // expected-note {{in call to method here [loplugin:redundantfcast]}} + +namespace tools +{ +struct Polygon +{ + Polygon() = default; +}; +struct PolyPolygon +{ + PolyPolygon( + Polygon const&); // expected-note {{in call to method here [loplugin:redundantfcast]}} +}; +} + +void ImplWritePolyPolygonRecord(const tools::PolyPolygon& rPolyPoly); + +int main() +{ + OUString s; + (void)OUString( + s); // expected-error@-1 {{redundant functional cast from 'rtl::OUString' to 'rtl::OUString' [loplugin:redundantfcast]}} + using T1 = OUString; + (void)T1( + s); // expected-error@-1 {{redundant functional cast from 'rtl::OUString' to 'T1' (aka 'rtl::OUString') [loplugin:redundantfcast]}} + using T2 = OUString const; + (void)T2( + s); // expected-error@-1 {{redundant functional cast from 'rtl::OUString' to 'T2' (aka 'const rtl::OUString') [loplugin:redundantfcast]}} + + (void)std::unique_ptr<int>(std::unique_ptr<int>( + new int{})); // expected-error@-1 {{redundant functional cast from 'std::unique_ptr<int>' to 'std::unique_ptr<int>' [loplugin:redundantfcast]}} + + OUString s1; + method1(OUString( + s1)); // expected-error@-1 {{redundant functional cast from 'rtl::OUString' to 'rtl::OUString' [loplugin:redundantfcast]}} + OUString s2; + s2 = OUString( + s1); // expected-error@-1 {{redundant functional cast from 'rtl::OUString' to 'rtl::OUString' [loplugin:redundantfcast]}} + + Color col1; + Color col2 = Color( + col1); // expected-error@-1 {{redundant functional cast from 'Color' to 'Color' [loplugin:redundantfcast]}} + (void)col2; + + Foo foo(1); + func1(Foo( + foo)); // expected-error@-1 {{redundant functional cast from 'Foo' to 'Foo' [loplugin:redundantfcast]}} + + const tools::Polygon aPolygon; + ImplWritePolyPolygonRecord(tools::PolyPolygon(tools::Polygon( + aPolygon))); // expected-error@-1 {{redundant functional cast from 'const tools::Polygon' to 'tools::Polygon' [loplugin:redundantfcast]}} +} + +class Class1 +{ + Foo foo; + Foo func2() + { + return Foo( + foo); // expected-error@-1 {{redundant functional cast from 'Foo' to 'Foo' [loplugin:redundantfcast]}} + } +}; + +// casting of lambdas +namespace test5 +{ +void f1(std::function<void()> x); +void f2() +{ + // expected-error-re@+1 {{redundant functional cast {{.+}} [loplugin:redundantfcast]}} + f1(std::function([&]() {})); +} +}; +namespace test6 +{ +void f1(std::function<void(int)>); +void f1(std::function<void(long)>); +void f2() +{ + f1(std::function<void(long)>([&](int) {})); // should not warn here +} +} + +namespace test7 +{ +// expected-note@+1 6 {{in call to method here [loplugin:redundantfcast]}} +void f1(std::initializer_list<int> const&); +// expected-note@+1 6 {{in call to method here [loplugin:redundantfcast]}} +template <typename T> void f2(std::initializer_list<T> const&); +// expected-note@+1 4 {{in call to method here [loplugin:redundantfcast]}} +template <typename T> void f3(T const&); +// expected-note@+1 4 {{in call to method here [loplugin:redundantfcast]}} +template <typename... T> void f4(T const&...); +void f5(int, ...); +void g(std::initializer_list<int> il) +{ + f1(il); + f2(il); + f3(il); + f4(il); + f5(0, il); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>(il)); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>(il)); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f3(std::initializer_list<int>(il)); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f4(std::initializer_list<int>(il)); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f5(0, std::initializer_list<int>(il)); + f1({}); + f1(std::initializer_list<int>{}); // should warn, but not modelled as CXXFunctionalCastExpr + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>({})); + // f2({}); //error + f2(std::initializer_list<int>{}); // should warn, but not modelled as CXXFunctionalCastExpr + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>({})); + // f3({}); //error + f3(std::initializer_list<int>{}); // (not modelled as CXXFunctionalCastExpr anyway) + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f3(std::initializer_list<int>({})); // arguably rather subtle, remove "("...")" + // f4({}); //error + f4(std::initializer_list<int>{}); // (not modelled as CXXFunctionalCastExpr anyway) + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f4(std::initializer_list<int>({})); // arguably rather subtle, remove "("...")" + // f5(0, {}); //error + f5(0, std::initializer_list<int>{}); // (not modelled as CXXFunctionalCastExpr anyway) + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f5(0, std::initializer_list<int>({})); // arguably rather subtle, remove "("...")" + f1({ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>{ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>({ 1 })); + f2({ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>{ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>({ 1 })); + // f3({1}); //error + f3(std::initializer_list<int>{ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f3(std::initializer_list<int>({ 1 })); // arguably rather subtle, remove "("...")" + // f4({1}); //error + f4(std::initializer_list<int>{ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f4(std::initializer_list<int>({ 1 })); // arguably rather subtle, remove "("...")" + // f5(0, {1}); //error + f5(0, std::initializer_list<int>{ 1 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f5(0, std::initializer_list<int>({ 1 })); // arguably rather subtle, remove "("...")" + f1({ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>{ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f1(std::initializer_list<int>({ 1, 2, 3 })); + f2({ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>{ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f2(std::initializer_list<int>({ 1, 2, 3 })); + // f3({1, 2, 3}); //error + f3(std::initializer_list<int>{ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f3(std::initializer_list<int>({ 1, 2, 3 })); // arguably rather subtle, remove "("...")" + // f4({1, 2, 3}); //error + f4(std::initializer_list<int>{ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f4(std::initializer_list<int>({ 1, 2, 3 })); // arguably rather subtle, remove "("...")" + // f5(0, {1, 2, 3}); //error + f5(0, std::initializer_list<int>{ 1, 2, 3 }); + // expected-error@+1 {{redundant functional cast from 'std::initializer_list<int>' to 'std::initializer_list<int>' [loplugin:redundantfcast]}} + f5(0, std::initializer_list<int>({ 1, 2, 3 })); // arguably rather subtle, remove "("...")" +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantinline.cxx b/compilerplugins/clang/test/redundantinline.cxx new file mode 100644 index 000000000..f69e0a3b8 --- /dev/null +++ b/compilerplugins/clang/test/redundantinline.cxx @@ -0,0 +1,24 @@ +/* -*- 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 "redundantinline.hxx" + +S1::~S1() = default; + +static inline int f8() { return 0; } // expected-error {{function has no external linkage but is explicitly declared 'inline' [loplugin:redundantinline]}} + +namespace { + +static inline int f9() { return 0; } // expected-error {{function has no external linkage but is explicitly declared 'inline' [loplugin:redundantinline]}} + +} + +int main() { return f8() + f9(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantinline.hxx b/compilerplugins/clang/test/redundantinline.hxx new file mode 100644 index 000000000..8e87ae05f --- /dev/null +++ b/compilerplugins/clang/test/redundantinline.hxx @@ -0,0 +1,81 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_REDUNDANTINLINE_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_REDUNDANTINLINE_HXX + +struct S1 { + inline S1(); + inline ~S1(); +}; + +S1::S1() = default; + +struct S2 { + inline S2() = default; // expected-error {{[loplugin:redundantinline]}} + inline ~S2() = default; // expected-error {{[loplugin:redundantinline]}} +}; + +struct S3 { + inline S3(); + inline ~S3(); + + inline void f1(); + + static inline void f2(); + + inline void operator +(); + + inline operator int(); + + friend inline void f3(); +}; + +S3::S3() {} + +S3::~S3() { f1(); } + +void S3::f1() { (void)this; } + +void S3::f2() {} + +void S3::operator +() {} + +void f3() {} + +S3::operator int() { return 0; } + +struct S4 { + inline S4() {} // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + inline ~S4() { f1(); } // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + inline void f1() { (void)this; } // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + static inline void f2() {} // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + inline void operator +() {} // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + inline operator int() { return 0; } // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + friend inline void f4() {} // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + + static constexpr int f5() { return 0; } + + static constexpr inline int f6() { return 0; } // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} +}; + +constexpr int f5() { return 0; } + +constexpr inline int f6() { return 0; } // expected-error {{function definition redundantly declared 'inline' [loplugin:redundantinline]}} + +static inline int f7() { return 0; } + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantpointerops.cxx b/compilerplugins/clang/test/redundantpointerops.cxx new file mode 100644 index 000000000..c766099fc --- /dev/null +++ b/compilerplugins/clang/test/redundantpointerops.cxx @@ -0,0 +1,95 @@ +/* -*- 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 <sal/config.h> + +#include <memory> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <rtl/ref.hxx> +#include <sal/types.h> +#include <tools/ref.hxx> + +struct Struct1 { + int x; +}; + +void function1(Struct1& s) +{ + (&s)->x = 1; // expected-error {{'&' followed by '->' operating on 'Struct1', rather use '.' [loplugin:redundantpointerops]}} +}; + +struct Struct2 { + int x; + Struct2* operator&() { return this; } +}; + +void function2(Struct2 s) +{ + (&s)->x = 1; // expected-error {{'&' followed by '->' operating on 'Struct2', rather use '.' [loplugin:redundantpointerops]}} +}; + +void function3(Struct1& s) +{ + (*(&s)).x = 1; // expected-error {{'&' followed by '*' operating on 'Struct1', rather use '.' [loplugin:redundantpointerops]}} +}; + +//void function4(Struct1* s) +//{ +// (*s).x = 1; // xxexpected-error {{'*' followed by '.', rather use '->' [loplugin:redundantpointerops]}} +//}; + +int function5(std::unique_ptr<int> x) +{ + return *x.get(); // expected-error-re {{'*' followed by '.get()' operating on '{{.*}}unique_ptr{{.*}}', just use '*' [loplugin:redundantpointerops]}} +}; + +void function6(std::shared_ptr<int> x) +{ + (void) *x.get(); // expected-error-re {{'*' followed by '.get()' operating on '{{.*}}shared_ptr{{.*}}', just use '*' [loplugin:redundantpointerops]}} +} + +void function6b(std::shared_ptr<Struct1> x) +{ + x.get()->x = 1; // expected-error-re {{'get()' followed by '->' operating on '{{.*}}shared_ptr{{.*}}', just use '->' [loplugin:redundantpointerops]}} +} + +void function7(rtl::Reference<css::uno::XInterface> x) +{ + (void) *x.get(); // expected-error {{'*' followed by '.get()' operating on 'rtl::Reference<css::uno::XInterface>', just use '*' [loplugin:redundantpointerops]}} +} + +void function8(css::uno::Reference<css::uno::XInterface> x) +{ + (void) *x.get(); // expected-error {{'*' followed by '.get()' operating on 'css::uno::Reference<css::uno::XInterface>', just use '*' [loplugin:redundantpointerops]}} +} + +void function9(tools::SvRef<SvRefBase> x) +{ + (void) *x.get(); // expected-error {{'*' followed by '.get()' operating on 'tools::SvRef<SvRefBase>', just use '*' [loplugin:redundantpointerops]}} +} + +struct DerivedRtlReference: public rtl::Reference<css::uno::XInterface> {}; + +void function10(DerivedRtlReference x) +{ + (void) *x.get(); // expected-error {{'*' followed by '.get()' operating on 'DerivedRtlReference', just use '*' [loplugin:redundantpointerops]}} +} + +struct DerivedUnoReference: public css::uno::Reference<css::uno::XInterface> {}; + +void function11(DerivedUnoReference x) +{ + (void) *x.get(); // expected-error {{'*' followed by '.get()' operating on 'DerivedUnoReference', just use '*' [loplugin:redundantpointerops]}} +} + +// tools::SvRef is final + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/redundantpreprocessor.cxx b/compilerplugins/clang/test/redundantpreprocessor.cxx new file mode 100644 index 000000000..18ab10559 --- /dev/null +++ b/compilerplugins/clang/test/redundantpreprocessor.cxx @@ -0,0 +1,15 @@ +/* -*- 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/. + */ + +#ifdef __clang__ // expected-note {{previous ifdef [loplugin:redundantpreprocessor]}} +#ifdef __clang__ // expected-error {{nested ifdef [loplugin:redundantpreprocessor]}} +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/refassign.cxx b/compilerplugins/clang/test/refassign.cxx new file mode 100644 index 000000000..7fc20cbe2 --- /dev/null +++ b/compilerplugins/clang/test/refassign.cxx @@ -0,0 +1,31 @@ +/* -*- 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 <sal/config.h> +#include <vector> + +int& f1(); +int& f2(); + +void test1() +{ + int& v1 = f1(); + v1 = f2(); // expected-error {{assigning a 'int &' to a var of type 'int &' probably does not do what you think [loplugin:refassign]}} + f1() + = f2(); // expected-error {{assigning a 'int &' to a var of type 'int &' probably does not do what you think [loplugin:refassign]}} + + // no warning expected + int x = 1; + x = f1(); + std::vector<int> v; + v[0] = f1(); + v1 = std::min(1, 2); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/refcounting.cxx b/compilerplugins/clang/test/refcounting.cxx new file mode 100644 index 000000000..4bcb03e2e --- /dev/null +++ b/compilerplugins/clang/test/refcounting.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/. + */ + +#include <sal/config.h> + +#include <memory> +#include <boost/intrusive_ptr.hpp> +#include <com/sun/star/uno/XInterface.hpp> + +// expected-no-diagnostics + +struct Foo +{ +// Not in general (dbaccess::DocumentEvents, dbaccess/source/core/dataaccess/databasedocument.hxx): +#if 0 + std::unique_ptr<css::uno::XInterface> m_foo1; // expected-error {{XInterface subclass 'com::sun::star::uno::XInterface' being managed via smart pointer, should be managed via uno::Reference, parent is 'Foo' [loplugin:refcounting]}} + std::shared_ptr<css::uno::XInterface> m_foo2; // expected-error {{XInterface subclass 'com::sun::star::uno::XInterface' being managed via smart pointer, should be managed via uno::Reference, parent is 'Foo' [loplugin:refcounting]}} + boost::intrusive_ptr<css::uno::XInterface> m_foo3; // expected-error {{XInterface subclass 'com::sun::star::uno::XInterface' being managed via smart pointer, should be managed via uno::Reference, parent is 'Foo' [loplugin:refcounting]}} +#endif +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/referencecasting.cxx b/compilerplugins/clang/test/referencecasting.cxx new file mode 100644 index 000000000..0272bc89c --- /dev/null +++ b/compilerplugins/clang/test/referencecasting.cxx @@ -0,0 +1,159 @@ +/* -*- 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 "sal/config.h" + +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/io/XStreamListener.hpp" +#include "com/sun/star/lang/XTypeProvider.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "cppuhelper/weak.hxx" + +void test1(const css::uno::Reference<css::io::XStreamListener>& a) +{ + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + css::uno::Reference<css::lang::XEventListener> b(a, css::uno::UNO_QUERY); +} + +namespace test2 +{ +css::uno::Reference<css::io::XStreamListener> getListener(); + +void test() +{ + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + css::uno::Reference<css::lang::XEventListener> b(getListener(), css::uno::UNO_QUERY); +} +} + +namespace test3 +{ +void callListener(css::uno::Reference<css::uno::XInterface> const&); + +void test(css::uno::Reference<css::io::XStreamListener> const& l) +{ + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + callListener(css::uno::Reference<css::lang::XEventListener>(l, css::uno::UNO_QUERY)); +} +} + +void test4(const css::uno::Reference<css::io::XStreamListener>& a) +{ + // no warning expected, used to reject null references + css::uno::Reference<css::lang::XEventListener> b(a, css::uno::UNO_SET_THROW); +} + +// no warning expected +namespace test5 +{ +void test(css::uno::Reference<css::io::XStreamListener> l) +{ + css::uno::Reference<css::uno::XInterface> a = l; +} +} + +namespace test6 +{ +void test(css::uno::Reference<css::io::XStreamListener> l) +{ + css::uno::Reference<css::lang::XEventListener> a; + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + a.set(l, css::uno::UNO_QUERY); +} +} + +namespace test7 +{ +void test(css::uno::Reference<css::io::XStreamListener> l) +{ + // expected-error@+1 {{unnecessary get() call [loplugin:referencecasting]}} + css::uno::Reference<css::lang::XEventListener> a(l.get(), css::uno::UNO_QUERY); + // expected-error@+1 {{unnecessary get() call [loplugin:referencecasting]}} + a.set(l.get(), css::uno::UNO_QUERY); +} +} + +namespace test8 +{ +void test(css::io::XStreamListener* l) +{ + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + css::uno::Reference<css::lang::XEventListener> a(l, css::uno::UNO_QUERY); + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + a.set(l, css::uno::UNO_QUERY); +} +} + +// check for looking through casts +namespace test9 +{ +class StatusbarController : public css::io::XStreamListener, public ::cppu::OWeakObject +{ +}; + +void test(StatusbarController* pController) +{ + css::uno::Reference<css::io::XStreamListener> xController; + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + xController.set(static_cast<::cppu::OWeakObject*>(pController), css::uno::UNO_QUERY); +} +} + +// no warning expected when we have an ambiguous base +namespace test10 +{ +class Foo : public css::lang::XTypeProvider, public css::lang::XComponent +{ + virtual ~Foo(); + void bar() + { + css::uno::Reference<css::lang::XEventListener> xSource( + static_cast<css::lang::XTypeProvider*>(this), css::uno::UNO_QUERY); + } +}; +} + +// no warning expected for SAL_NO_ACQUIRE +namespace test11 +{ +void test(css::io::XStreamListener* l) +{ + css::uno::Reference<css::lang::XEventListener> a(l, SAL_NO_ACQUIRE); + a.set(l, SAL_NO_ACQUIRE); +} +} + +// no warning expected: querying for XInterface (instead of doing an upcast) has special semantics, +// to check for UNO object equivalence. +void test12(const css::uno::Reference<css::io::XStreamListener>& a) +{ + css::uno::Reference<css::uno::XInterface> b(a, css::uno::UNO_QUERY); +} + +// no warning expected: querying for XInterface (instead of doing an upcast) has special semantics, +// to check for UNO object equivalence. +struct Test13 +{ + css::uno::Reference<css::uno::XInterface> m_xNormalizedIFace; + void newObject(const css::uno::Reference<css::uno::XInterface>& _rxIFace) + { + m_xNormalizedIFace.set(_rxIFace, css::uno::UNO_QUERY); + } +}; + +void test14(css::uno::Sequence<css::uno::Reference<css::io::XStreamListener>> seq) +{ + for (sal_Int32 i = 0; i < seq.getLength(); ++i) + { + // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}} + css::uno::Reference<css::io::XStreamListener> xDataSeries(seq[i], css::uno::UNO_QUERY); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/returnconstval.cxx b/compilerplugins/clang/test/returnconstval.cxx new file mode 100644 index 000000000..481ae84df --- /dev/null +++ b/compilerplugins/clang/test/returnconstval.cxx @@ -0,0 +1,21 @@ +/* -*- 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 <rtl/ustring.hxx> + +struct S2 +{ + OUString mv1; + // expected-error@+1 {{either return non-const, or by const ref [loplugin:returnconstval]}} + const OUString get1() { return mv1; } + const OUString& get2() { return mv1; } + OUString get3() { return mv1; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/salcall.cxx b/compilerplugins/clang/test/salcall.cxx new file mode 100644 index 000000000..e424432c4 --- /dev/null +++ b/compilerplugins/clang/test/salcall.cxx @@ -0,0 +1,163 @@ +/* -*- 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 <sal/types.h> + +#define VOID void + +class Class1 +{ + SAL_CALL Class1() {} // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}} + SAL_CALL ~Class1() {} // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}} + SAL_CALL operator int() // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}} + { + return 0; + } + + void SAL_CALL method1(); // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}} + VOID method2() {} + // no SAL_CALL for above method2, even though "SAL_CALL" appears between definition of VOID and + // the declaration's name, "method2" +}; +void SAL_CALL Class1::method1() +{ // expected-error@-1 {{SAL_CALL unnecessary here [loplugin:salcall]}} +} + +class Class2 +{ + void method1(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} +}; +void SAL_CALL Class2::method1() {} // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} + +// comment this out because it seems to generate a warning in some internal buffer of clang that I can't annotate +#if 0 +// no warning, this appears to be legal +class Class3 +{ + void SAL_CALL method1(); // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}} +}; +void Class3::method1() {} +#endif + +// no warning, normal case for reference +class Class4 +{ + void method1(); +}; +void Class4::method1() {} + +class Class5_1 +{ + virtual void method1(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} + virtual ~Class5_1(); +}; +class Class5_2 +{ + virtual void SAL_CALL method1(); + virtual ~Class5_2(); +}; +class Class5_3 : public Class5_1, public Class5_2 +{ + virtual void SAL_CALL + method1() override; // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} + virtual ~Class5_3(); +}; + +class Class6_1 +{ + virtual void SAL_CALL method1(); + virtual ~Class6_1(); +}; +class Class6_2 +{ + virtual void SAL_CALL method1(); + virtual ~Class6_2(); +}; +class Class6_3 : public Class6_1, public Class6_2 +{ + virtual void SAL_CALL method1() override; + virtual ~Class6_3(); +}; + +class Class7_1 +{ + virtual void method1(); + virtual ~Class7_1(); +}; +class Class7_2 +{ + virtual void method1(); + virtual ~Class7_2(); +}; +class Class7_3 : public Class7_1, public Class7_2 +{ + virtual void method1() override; + virtual ~Class7_3(); +}; + +class Class8_1 +{ + virtual void method2(); + virtual ~Class8_1(); +}; +class Class8_2 +{ + virtual void SAL_CALL method2(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} + virtual ~Class8_2(); +}; +class Class8_3 : public Class8_1, public Class8_2 +{ + virtual void method2() override; // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} + virtual ~Class8_3(); +}; + +#define M1(m) VOID m +class Class9 +{ + Class9(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} + M1(method1)(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} + void method2(); // expected-note {{SAL_CALL inconsistency [loplugin:salcall]}} +}; +#define MC(num) \ + Class##num::Class##num() {} +SAL_CALL MC(9) // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} + ; // to appease clang-format +void SAL_CALL Class9::method1() // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} +{ +} +#define M2(T) T SAL_CALL +M2(void) Class9::method2() {} // expected-error {{SAL_CALL inconsistency [loplugin:salcall]}} + +#if 0 // see TODO in SalCall::isSalCallFunction +class Class10 +{ + void method1(); +}; +#define M3(T, SAL_CALL) T SAL_CALL:: +M3(void, Class10) method1() {} // false "SAL_CALL inconsistency" +#endif + +#if 0 //TODO +template<typename> struct S { + virtual ~S(); + virtual void f(); +}; +template<typename T> S<T>::~S() {} +template<typename T> void S<T>::f() {} +struct S2: S<int> { + ~S2(); + void f() {} +}; +int main() { + S2 s2; + s2->f(); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/sallogareas.cxx b/compilerplugins/clang/test/sallogareas.cxx new file mode 100644 index 000000000..1b172ebd0 --- /dev/null +++ b/compilerplugins/clang/test/sallogareas.cxx @@ -0,0 +1,51 @@ +/* -*- 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 <tools/diagnose_ex.h> +#include <sal/log.hxx> + +void func1(); + +int main() +{ + SAL_WARN( + "bob.none", + "message"); // expected-error@-2 {{unknown log area 'bob.none' (check or extend include/sal/log-areas.dox) [loplugin:sallogareas]}} + + SAL_WARN("xmloff", "message"); + + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION( + "bob.none", + "message"); // expected-error@-2 {{unknown log area 'bob.none' (check or extend include/sal/log-areas.dox) [loplugin:sallogareas]}} + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "message"); + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/salunicodeliteral.cxx b/compilerplugins/clang/test/salunicodeliteral.cxx new file mode 100644 index 000000000..bf14e4843 --- /dev/null +++ b/compilerplugins/clang/test/salunicodeliteral.cxx @@ -0,0 +1,40 @@ +/* -*- 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 "sal/config.h" + +#include "sal/types.h" + +#include "salunicodeliteral.hxx" + +#define TEST1 'x' +#define TEST2 sal_Unicode('x') + +namespace { + +void f(sal_Unicode) {} + +} + +void test() { + f(sal_Unicode('x')); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + f(static_cast<sal_Unicode>('x')); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + using T = sal_Unicode const; + f(static_cast<T>('x')); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'T' (aka 'const char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + f((sal_Unicode) 'x'); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + f(sal_Unicode(('x'))); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + f(sal_Unicode(120)); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + f(sal_Unicode(TEST1)); + f(TEST2); // expected-error {{in LIBO_INTERNAL_ONLY code, replace literal cast to 'sal_Unicode' (aka 'char16_t') with a u'...' char16_t character literal [loplugin:salunicodeliteral]}} + char c = 'x'; + f(sal_Unicode(c)); + f(char16_t('x')); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/salunicodeliteral.hxx b/compilerplugins/clang/test/salunicodeliteral.hxx new file mode 100644 index 000000000..f4491c723 --- /dev/null +++ b/compilerplugins/clang/test/salunicodeliteral.hxx @@ -0,0 +1,17 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_SALUNICODELITERAL_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_SALUNICODELITERAL_HXX + +void test(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/selfinit.cxx b/compilerplugins/clang/test/selfinit.cxx new file mode 100644 index 000000000..412a65b70 --- /dev/null +++ b/compilerplugins/clang/test/selfinit.cxx @@ -0,0 +1,33 @@ +/* -*- 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 <typeinfo> + +extern int i; +int i = i; +// expected-error@-1 {{referencing a variable during its own initialization is error-prone and thus suspicious [loplugin:selfinit]}} +// expected-note@-2 {{variable declared here [loplugin:selfinit]}} + +int j = [](int n) { return j + n; }(0); +// expected-error@-1 {{referencing a variable during its own initialization is error-prone and thus suspicious [loplugin:selfinit]}} +// expected-note@-2 {{variable declared here [loplugin:selfinit]}} + +int k = sizeof k; + +int f(std::type_info const&); + +int l = f(typeid(l)); + +bool m = noexcept(m); + +template <typename T> int g(); + +int n = g<decltype(n)>(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/sequenceloop.cxx b/compilerplugins/clang/test/sequenceloop.cxx new file mode 100644 index 000000000..e124fda27 --- /dev/null +++ b/compilerplugins/clang/test/sequenceloop.cxx @@ -0,0 +1,35 @@ +/* -*- 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 <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <utility> + +namespace test1 +{ +void foo(css::uno::Sequence<css::uno::Reference<css::uno::XInterface>>& aSeq) +{ + // expected-error@+1 {{use std::as_const, or otherwise make the for-range-initializer expression const, to avoid creating a copy of the Sequence [loplugin:sequenceloop]}} + for (const auto& x : aSeq) + x.get(); + // no warning expected + for (auto& x : aSeq) + x.get(); + for (const auto& x : std::as_const(aSeq)) + x.get(); +} +// no warning expected +void foo2(const css::uno::Sequence<css::uno::Reference<css::uno::XInterface>>& aSeq) +{ + for (const auto& x : aSeq) + x.get(); +} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/sequentialassign.cxx b/compilerplugins/clang/test/sequentialassign.cxx new file mode 100644 index 000000000..e656e1a7a --- /dev/null +++ b/compilerplugins/clang/test/sequentialassign.cxx @@ -0,0 +1,95 @@ +/* -*- 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 <rtl/ustring.hxx> + +namespace test1 +{ +void f(OUString s1) +{ + OUString s2 = s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + s2 = s2.getToken(0, '('); +} +} + +namespace test2 +{ +OUString s2; +void f(OUString s1) +{ + s2 = s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + s2 = s2.getToken(0, '('); +} +} + +namespace test3 +{ +struct VolumeInfo +{ + OUString getFileSystemName(); +}; +OUString aNullURL(""); +void f(VolumeInfo _aVolumeInfo) +{ + OUString aFileSysName(aNullURL); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + aFileSysName = _aVolumeInfo.getFileSystemName(); +} +} + +namespace test4 +{ +struct B3DVector +{ + B3DVector getPerpendicular(); +}; +void f(B3DVector aNewVPN) +{ + B3DVector aNewToTheRight = aNewVPN; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + aNewToTheRight = aNewToTheRight.getPerpendicular(); +} +} + +namespace test5 +{ +void f(OUString s, int x) +{ + int nPos = x; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + nPos = s.indexOf("x", nPos); +} +} + +namespace test6 +{ +void f() +{ + OUString s2("xxxx"); + s2 = s2.getToken(0, '('); // no warning expected +} +} + +namespace test7 +{ +class Class1 +{ + OUString m_field1; + void foo(Class1& rOther) + { + OUString s = rOther.m_field1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:sequentialassign]}} + s = s.copy(1, 2); + } +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/shouldreturnbool.cxx b/compilerplugins/clang/test/shouldreturnbool.cxx new file mode 100644 index 000000000..03a698e30 --- /dev/null +++ b/compilerplugins/clang/test/shouldreturnbool.cxx @@ -0,0 +1,31 @@ +/* -*- 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/. + */ + +int foo1(char ch) +{ + // expected-error@-2 {{only returning one or zero is an indication you want to return bool [loplugin:shouldreturnbool]}} + if (ch == 'x') + return 1; + return 0; +} + +long foo2() +{ + // expected-error@-2 {{only returning one or zero is an indication you want to return bool [loplugin:shouldreturnbool]}} + return 1; +} + +enum Enum1 +{ + NONE +}; + +Enum1 foo3() { return Enum1::NONE; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/simplifybool.cxx b/compilerplugins/clang/test/simplifybool.cxx new file mode 100644 index 000000000..906feabee --- /dev/null +++ b/compilerplugins/clang/test/simplifybool.cxx @@ -0,0 +1,173 @@ +/* -*- 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 <rtl/ustring.hxx> +// expected-note@rtl/ustring.hxx:* 2 {{the presumed corresponding negated operator for 'rtl::OUString' and 'rtl::OUString' is declared here [loplugin:simplifybool]}} +#include <rtl/string.hxx> +// expected-note@rtl/string.hxx:* {{the presumed corresponding negated operator for 'rtl::OString' and 'rtl::OString' is declared here [loplugin:simplifybool]}} +#include <basegfx/vector/b3dvector.hxx> +// expected-note@basegfx/tuple/b3dtuple.hxx:* {{the presumed corresponding negated operator for 'basegfx::B3DVector' and 'basegfx::B3DVector' is declared here [loplugin:simplifybool]}} + +#include <map> + +namespace group1 +{ +void f1(int a, int b) +{ + if (!(a < b)) + { // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + a = b; + } +}; + +void f2(float a, float b) +{ + // no warning expected + if (!(a < b)) + { + a = b; + } +}; +}; + +// Consistently either warn about all or none of the below occurrences of "!!": +namespace group2 +{ +enum E1 +{ + E1_1 = 1 +}; + +enum E2 +{ + E2_1 = 1 +}; +E2 operator&(E2 e1, E2 e2); +bool operator!(E2 e); + +enum class E3 +{ + E1 = 1 +}; +struct W +{ + operator bool(); +}; +W operator&(E3 e1, E3 e2); + +bool f0(int n) { return !!(n & 1); } + +bool f1(E1 e) { return !!(e & E1_1); } + +bool f2(E2 e) { return !!(e & E2_1); } + +bool f3(E3 e) { return !!(e & E3::E1); } +}; + +// record types +namespace group3 +{ +struct Record1 +{ + bool operator==(const Record1&) const; +}; + +struct Record2 +{ + bool operator==(const Record2&) const; + bool operator!=(const Record2&) const; + // expected-note@-1 {{the presumed corresponding negated operator for 'group3::Record2' and 'group3::Record2' is declared here [loplugin:simplifybool]}} +}; + +struct Record3 +{ +}; + +bool operator==(const Record3&, const Record3&); +bool operator!=(const Record3&, const Record3&); +// expected-note@-1 {{the presumed corresponding negated operator for 'group3::Record3' and 'group3::Record3' is declared here [loplugin:simplifybool]}} + +void testRecord() +{ + Record1 a1; + Record1 a2; + // no warning expected, because a negated operator does not exist + bool v = !(a1 == a2); + Record2 b1; + Record2 b2; + v = !(b1 == b2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + Record3 c1; + Record3 c2; + v = !(c1 == c2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + OUString d1; + OUString d2; + v = !(d1 == d2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + OString e1; + OString e2; + v = !(e1 == e2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + + // the operator != is in a base-class, and the param is a base-type + basegfx::B3DVector f1; + basegfx::B3DVector f2; + v = !(f1 == f2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} +} + +struct Record4 +{ + bool operator==(Record4 const&) const; + bool operator!=(Record4 const& other) const + { + // no warning expected + bool v = !operator==(other); + v = !(*this == other); + OUString c1; + OUString c2; + v = !(c1 == c2); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} + return v; + } +}; +}; + +namespace group4 +{ +bool foo1(bool a, bool b) +{ + return !(!a && !b); + // expected-error@-1 {{logical negation of logical op containing negation, can be simplified [loplugin:simplifybool]}} +} +bool foo2(int a, bool b) +{ + return !(a != 1 && !b); + // expected-error@-1 {{logical negation of logical op containing negation, can be simplified [loplugin:simplifybool]}} +} +bool foo3(int a, bool b) +{ + // no warning expected + return !(a != 1 && b); +} +}; + +namespace group5 +{ +bool foo1(std::map<int, int>* pActions, int aKey) +{ + auto aIter = pActions->find(aKey); + //TODO this doesn't work yet because I'd need to implement conversion operators during method/func lookup + return !(aIter == pActions->end()); + // expected-error@-1 {{logical negation of comparison operator, can be simplified by inverting operator [loplugin:simplifybool]}} +} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/simplifyconstruct.cxx b/compilerplugins/clang/test/simplifyconstruct.cxx new file mode 100644 index 000000000..d44738f78 --- /dev/null +++ b/compilerplugins/clang/test/simplifyconstruct.cxx @@ -0,0 +1,88 @@ +/* -*- 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 <memory> +#include <rtl/ref.hxx> +#include <tools/gen.hxx> + +namespace test1 +{ +struct Foo +{ + void acquire(); + void release(); +}; +class Foo1 +{ + std::unique_ptr<int> m_pbar1; + rtl::Reference<Foo> m_pbar2; + Foo1() + : m_pbar1(nullptr) + // expected-error@-1 {{no need to explicitly init an instance of 'std::unique_ptr<int>' with nullptr, just use default constructor [loplugin:simplifyconstruct]}} + , m_pbar2(nullptr) + // expected-error@-1 {{no need to explicitly init an instance of 'rtl::Reference<Foo>' with nullptr, just use default constructor [loplugin:simplifyconstruct]}} + { + } +}; +} + +// no warning expected when using std::unique_ptr constructor with a custom deleter +namespace test2 +{ +struct ITypeLib +{ +}; +struct IUnknown +{ + void Release(); +}; +void func2() +{ + std::unique_ptr<IUnknown, void (*)(IUnknown * p)> aITypeLibGuard(nullptr, [](IUnknown* p) { + if (p) + p->Release(); + }); +} +} + +namespace test3 +{ +struct Foo +{ + void acquire(); + void release(); +}; +void f(Foo* f) +{ + // expected-error@+1 {{simplify [loplugin:simplifyconstruct]}} + rtl::Reference<Foo> x = rtl::Reference(f); +} +} + +// no warning expected +namespace test4 +{ +struct Foo +{ + void acquire(); + void release(); +}; +void f(Foo* f) { auto x = rtl::Reference(f); } +} + +namespace test5 +{ +void f() +{ + // expected-error@+1 {{simplify [loplugin:simplifyconstruct]}} + tools::Rectangle x = tools::Rectangle(10, 10, 10, 10); + (void)x; +} +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/simplifydynamiccast.cxx b/compilerplugins/clang/test/simplifydynamiccast.cxx new file mode 100644 index 000000000..111734f0a --- /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: */ diff --git a/compilerplugins/clang/test/simplifypointertobool.cxx b/compilerplugins/clang/test/simplifypointertobool.cxx new file mode 100644 index 000000000..18e1da607 --- /dev/null +++ b/compilerplugins/clang/test/simplifypointertobool.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/. + */ + +#include <memory> + +void foo(); + +bool test1(std::unique_ptr<int> p2) +{ + // expected-error@+1 {{simplify, drop the get() [loplugin:simplifypointertobool]}} + if (p2.get()) + foo(); + // expected-error@+1 {{simplify, drop the get() and wrap the expression in a functional cast to bool [loplugin:simplifypointertobool]}} + bool b1 = p2.get(); + //TODO: + bool b2 = ( // deliberately spread across multiple lines + p2.get()); + return b1 && b2; +} + +void test2(std::shared_ptr<int> p) +{ + // expected-error@+1 {{simplify, drop the get() [loplugin:simplifypointertobool]}} + if (p.get()) + foo(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/singlevalfields.cxx b/compilerplugins/clang/test/singlevalfields.cxx new file mode 100644 index 000000000..14be377c3 --- /dev/null +++ b/compilerplugins/clang/test/singlevalfields.cxx @@ -0,0 +1,26 @@ +/* -*- 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 <rtl/ustring.hxx> + +struct Foo +{ + // expected-error@+1 {{assign XXX [loplugin:singlevalfields]}} + OUString m_aMenuResourceURL; + + Foo() + : m_aMenuResourceURL("XXX") + { + m_aMenuResourceURL = "XXX"; + m_aMenuResourceURL = "X" + "XX"; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/staticconstfield.cxx b/compilerplugins/clang/test/staticconstfield.cxx new file mode 100644 index 000000000..fd36a6452 --- /dev/null +++ b/compilerplugins/clang/test/staticconstfield.cxx @@ -0,0 +1,120 @@ +/* -*- 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 <config_clang.h> +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> +#include <vector> + +class Class1 +{ + OUString const + m_field1; // expected-error {{const field can be static [loplugin:staticconstfield]}} + Class1() + : m_field1("xxxx") + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + { + (void)m_field1; + } +}; + +class Class2 +{ + OString const + m_field2; // expected-error {{const field can be static [loplugin:staticconstfield]}} + Class2() + : m_field2("yyyy") + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + { + (void)m_field2; + } +}; + +// no warning expected +class Class4 +{ + OUString m_field3; + Class4() + : m_field3("zzzz") + { + (void)m_field3; + } +}; + +class Class5 +{ + enum class Enum + { + ONE + }; + float const + m_fielda1; // expected-error {{const field can be static [loplugin:staticconstfield]}} + int const m_fielda2; // expected-error {{const field can be static [loplugin:staticconstfield]}} + bool const + m_fielda3; // expected-error {{const field can be static [loplugin:staticconstfield]}} + Enum const + m_fielda4; // expected-error {{const field can be static [loplugin:staticconstfield]}} + Class5() + : m_fielda1(1.0) + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + , m_fielda2(1) + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + , m_fielda3(true) + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + , m_fielda4(Enum::ONE) + // expected-note@-1 {{init here [loplugin:staticconstfield]}} + { + (void)m_fielda1; + (void)m_fielda2; + (void)m_fielda3; + (void)m_fielda4; + } +}; + +// no warning expected +class Class6 +{ + enum class Enum + { + ONE + }; + float m_fieldb1; + int m_fieldb2; + bool m_fieldb3; + Enum m_fieldb4; + Class6() + : m_fieldb1(1.0) + , m_fieldb2(1) + , m_fieldb3(true) + , m_fieldb4(Enum::ONE) + { + (void)m_fieldb1; + (void)m_fieldb2; + (void)m_fieldb3; + (void)m_fieldb4; + } +}; + +// no warning expected, checking for assigning to const field from multiple constructors +class Class7 +{ + bool const m_field7; + Class7() + : m_field7(true) + { + (void)m_field7; + } + Class7(bool b) + : m_field7(b) + { + (void)m_field7; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/staticvar.cxx b/compilerplugins/clang/test/staticvar.cxx new file mode 100644 index 000000000..639e6cce4 --- /dev/null +++ b/compilerplugins/clang/test/staticvar.cxx @@ -0,0 +1,78 @@ +/* -*- 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 <config_clang.h> +#include <sal/config.h> +#include <rtl/ustring.hxx> + +struct S1 +{ + int x, y; +}; + +S1 const& f1(int a) +{ + static S1 s1[]{ + // expected-error@-1 {{var should be static const, or whitelisted [loplugin:staticvar]}} + { 1, 1 } + }; + // no warning expected + const S1 s2[]{ { a, 1 } }; + (void)s2; + return s1[0]; +} + +struct S2 +{ + OUString x; +}; + +S2 const& f2() +{ + static S2 const s1[]{ + // expected-error@-1 {{static const var requires runtime initialization? [loplugin:staticvar]}} + { "xxx" } + }; + return s1[0]; +} + +// no warning expected +S2 const& f3() +{ + static S2 s1[]{ { "xxx" } }; + return s1[0]; +} + +// no warning expected +struct S4 +{ + OUStringLiteral const cName; + bool const bCanBeVisible; +}; +S4 const& f4() +{ + static const S4 s1[] = { + { OUStringLiteral("/DocColor"), false }, + }; + return s1[0]; +} + +struct S5 +{ + bool const bCanBeVisible; +}; +void f5(bool b) +{ + const S5 s1[] = { + { b }, + }; + (void)s1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stdfunction.cxx b/compilerplugins/clang/test/stdfunction.cxx new file mode 100644 index 000000000..492ba4249 --- /dev/null +++ b/compilerplugins/clang/test/stdfunction.cxx @@ -0,0 +1,56 @@ +/* -*- 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 <iterator> +#include <vector> + +struct S +{ + bool empty() const; +}; + +template <typename> struct ST +{ + bool empty() const; +}; + +namespace std +{ +bool empty( //expected-error {{Do not declare a function in namespace 'std' [loplugin:stdfunction]}} + S const&); + +template <> +bool empty( //expected-error {{Do not declare a function template specialization in namespace 'std' [loplugin:stdfunction]}} + S const&); + +template <typename T> +bool empty( //expected-error {{Do not declare a function template in namespace 'std' [loplugin:stdfunction]}} + ST<T> const&); + +template <> class vector<S> +{ +public: + [[nodiscard]] constexpr bool empty() const noexcept; +}; + +[[nodiscard]] constexpr bool vector<S>::empty() const noexcept { return true; } +} + +namespace std::inner +{ +bool empty( //expected-error {{Do not declare a function in namespace 'std' [loplugin:stdfunction]}} + S const&); +} + +namespace outer::std +{ +bool empty(S const&); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringadd.cxx b/compilerplugins/clang/test/stringadd.cxx new file mode 100644 index 000000000..748ee35cf --- /dev/null +++ b/compilerplugins/clang/test/stringadd.cxx @@ -0,0 +1,228 @@ +/* -*- 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 <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> + +// --------------------------------------------------------------- +// += tests + +namespace test1 +{ +static const char XXX1[] = "xxx"; +static const char XXX2[] = "xxx"; +void f1(OUString s1, int i, OString o) +{ + OUString s2 = s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += s1; + s2 = s1 + "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += OUString::number(i); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += XXX1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += OUStringLiteral(XXX1) + XXX2; + + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += OStringToOUString(o, RTL_TEXTENCODING_UTF8); +} +void f2(OString s1, int i, OUString u) +{ + OString s2 = s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += s1; + s2 = s1 + "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += s1; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += OString::number(i); + + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += OUStringToOString(u, RTL_TEXTENCODING_ASCII_US); +} +void f3(OUString aStr, int nFirstContent) +{ + OUString aFirstStr = aStr.copy(0, nFirstContent); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + aFirstStr += "..."; +} +OUString side_effect(); +void f4(int i) +{ + OUString s1; + OUString s2("xxx"); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += "xxx"; + ++i; + // any other kind of statement breaks the chain (at least for now) + s2 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s2 += side_effect(); + s1 += "yyy"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s1 += "yyy"; +} +} + +namespace test2 +{ +void f(OUString s3) +{ + s3 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s3 += "xxx"; +} +void g(OString s3) +{ + s3 += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s3 += "xxx"; +} +} + +namespace test3 +{ +struct Bar +{ + OUString m_field; +}; +void f(Bar b1, Bar& b2, Bar* b3) +{ + OUString s3 = "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s3 += b1.m_field; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s3 += b2.m_field; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + s3 += b3->m_field; +} +OUString side_effect(); +void f2(OUString s) +{ + OUString sRet = "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += side_effect(); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += "xxx"; + sRet += side_effect(); + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += "xxx"; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += "xxx"; + sRet += s; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += "xxx"; +} +} + +// no warning expected +namespace test4 +{ +OUString side_effect(); +void f() +{ + OUString sRet = "xxx"; +#if OSL_DEBUG_LEVEL > 0 + sRet += ";"; +#endif + sRet += " "; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sRet += side_effect(); +} +} + +// no warning expected +namespace test5 +{ +OUString side_effect(); +void f() +{ + OUString sRet = side_effect(); + sRet += side_effect(); +} +} + +namespace test6 +{ +void f(OUString sComma, OUString maExtension, int mnDocumentIconID) +{ + OUString sValue; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sValue += sComma + sComma + maExtension + sComma; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sValue += OUString::number(mnDocumentIconID) + sComma; +} +struct Foo +{ + OUString sFormula1; +}; +void g(int x, const Foo& aValidation) +{ + OUString sCondition; + switch (x) + { + case 1: + sCondition += "cell-content-is-in-list("; + // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}} + sCondition += aValidation.sFormula1 + ")"; + } +} +} + +// --------------------------------------------------------------- +// detecting OUString temporary construction in + + +namespace test9 +{ +OUString getByValue(); +const OUString& getByRef(); +void f1(OUString s, OUString t, int i, const char* pChar) +{ + // no warning expected + t = t + "xxx"; + // expected-error@+1 {{avoid constructing 'rtl::OUString' from 'const char [4]' on RHS of + (where LHS is of type 'rtl::OUString') [loplugin:stringadd]}} + s = s + OUString("xxx"); + // expected-error@+1 {{avoid constructing 'rtl::OUString' from 'const rtl::OUString' on RHS of + (where LHS is of type 'rtl::OUString') [loplugin:stringadd]}} + s = s + OUString(getByRef()); + + // no warning expected + OUString a; + a = a + getByValue(); + + // no warning expected + OUString b; + b = b + (i == 1 ? "aaa" : "bbb"); + + // no warning expected + OUString c; + c = c + OUString(pChar, strlen(pChar), RTL_TEXTENCODING_UTF8); +} +void f2(char ch) +{ + OString s; + // expected-error@+1 {{avoid constructing 'rtl::OString' from 'const char [4]' on RHS of + (where LHS is of type 'rtl::OString') [loplugin:stringadd]}} + s = s + OString("xxx"); + // expected-error@+1 {{avoid constructing 'rtl::OString' from 'char' on RHS of + (where LHS is of type 'rtl::OString') [loplugin:stringadd]}} + s = s + OString(ch); +} +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringbuffer.cxx b/compilerplugins/clang/test/stringbuffer.cxx new file mode 100644 index 000000000..929eb4782 --- /dev/null +++ b/compilerplugins/clang/test/stringbuffer.cxx @@ -0,0 +1,22 @@ +/* -*- 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 "sal/config.h" +#include "rtl/string.hxx" +#include "rtl/ustring.hxx" +#include "rtl/ustrbuf.hxx" + +void func2(OUString s1, OUString s2) +{ + OUStringBuffer buf; + buf.append(s1 + s2); + // expected-error@-1 {{appending added result of OUString to OUStringBuffer, rather do .append(x).append(y) [loplugin:stringbuffer]}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringconcatauto.cxx b/compilerplugins/clang/test/stringconcatauto.cxx new file mode 100644 index 000000000..6c9a72c29 --- /dev/null +++ b/compilerplugins/clang/test/stringconcatauto.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +#include <rtl/ustring.hxx> + +void foo() +{ + auto str1 = "str1" + OUString::number( 10 ); + // expected-error-re@-1 {{creating a variable of type 'rtl::OUStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + OUString str2 = "str2" + OUString::number( 20 ) + "ing"; + const auto& str3 = "str3" + OUString::number( 30 ); + // expected-error-re@-1 {{creating a variable of type 'const rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + const auto str4 = "str4" + OString::number( 40 ); + // expected-error-re@-1 {{creating a variable of type 'const rtl::OStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OString instead}} + auto str5 = OUString::number( 50 ); + // expected-error-re@-1 {{creating a variable of type 'rtl::OUStringNumber<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + (void) str1; + (void) str2; + (void) str3; + (void) str4; + (void) str5; +} + +struct A +{ + auto bar() + // expected-error-re@-1 {{returning a variable of type 'rtl::OStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OString instead}} + { + return "bar" + OString::number( 110 ); + } + auto baz() + // expected-error-re@-1 {{returning a variable of type 'rtl::OStringNumber<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OString instead}} + { + return OString::number( 120 ); + } +}; + +template< typename T > +void fun( const T& par ) +// parameters are without warnings +{ + const T& var = par; + // expected-error-re@-1 {{creating a variable of type 'const rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + (void) var; +} + +void testfun() +{ + fun( "fun" + OUString::number( 200 )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/stringconcatliterals.cxx b/compilerplugins/clang/test/stringconcatliterals.cxx new file mode 100644 index 000000000..e2d5a8ce2 --- /dev/null +++ b/compilerplugins/clang/test/stringconcatliterals.cxx @@ -0,0 +1,65 @@ +/* -*- 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 <sal/config.h> + +#include <ostream> + +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> + +#define FOO "foo" + +void f(std::ostream& s1) +{ + static char const foo[] = "foo"; + s1 << "foo" + << "foo"; + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << FOO; + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << foo; + s1 << "foo" << OString("foo"); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OString(FOO); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OString(foo); + s1 << "foo" << OUString("foo"); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OUString(FOO); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OUString(foo); + s1 << "foo" << OUStringLiteral("foo"); //TODO: warn too, OUStringLiteral wrapped in OUString + s1 << "foo" << OUStringLiteral(FOO); //TODO: warn too, OUStringLiteral wrapped in OUString + s1 << "foo" << OUStringLiteral(foo); + OString s2; + s2 = "foo" + OString("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OString(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OString(foo); + s2 = "foo" + OStringLiteral("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OStringLiteral(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OStringLiteral(foo); + OUString s3; + s3 = "foo" + OUString("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUString(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUString(foo); + s3 = "foo" + OUStringLiteral("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUStringLiteral(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUStringLiteral(foo); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringconstant.cxx b/compilerplugins/clang/test/stringconstant.cxx new file mode 100644 index 000000000..1e325633d --- /dev/null +++ b/compilerplugins/clang/test/stringconstant.cxx @@ -0,0 +1,132 @@ +/* -*- 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 "sal/config.h" + +#include <cstring> + +#include "com/sun/star/uno/Reference.hxx" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" + +extern void foo(OUString const &); + +struct Foo { + Foo(OUString const &, int) {} + Foo(OUString const &) {} + void foo(OUString const &) const {} +}; + +struct Foo2 { + Foo2(OString const &, int) {} + Foo2(OString const &) {} + void foo(OString const &) const {} +}; + +OString ret1() { + return OString("foo"); // expected-error {{elide constructor call [loplugin:stringconstant]}} +} + +OString const ret2() { + return OString("foo"); // expected-error {{elide constructor call [loplugin:stringconstant]}} +} + +auto ret3() { + return OString("foo"); +} + +OUString ret4() { + return OUString("foo"); // expected-error {{elide constructor call [loplugin:stringconstant]}} +} + +OUString const ret5() { + return OUString("foo"); // expected-error {{elide constructor call [loplugin:stringconstant]}} +} + +auto ret6() { + return OUString("foo"); +} + +int main() { + char const s1[] = "foo"; + char const * const s2 = "foo"; + + OStringBuffer sb; + + sb.append(OString()); // expected-error {{in call of 'rtl::OStringBuffer::append', replace empty 'OString' constructor with empty string literal [loplugin:stringconstant]}} + sb.append(OString("foo")); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.append(OString(s1)); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.append(OString(s2)); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.append(OString("foo", std::strlen("foo"))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.append(OString(s1, std::strlen(s1))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.append(OString(s2, std::strlen(s2))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.append("foo"); + sb.append(s1); + sb.append(s2); // expected-error {{in call of 'rtl::OStringBuffer::append' with non-array string constant argument, turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.append("foo", std::strlen("foo")); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append' [loplugin:stringconstant]}} + sb.append(s1, 3/*std::strlen(s1)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append' [loplugin:stringconstant]}} + sb.append(s2, 3/*std::strlen(s2)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append', and turn the non-array string constant into an array [loplugin:stringconstant]}} + + sb.insert(0, OString()); // expected-error {{in call of 'rtl::OStringBuffer::insert', replace empty 'OString' constructor with empty string literal [loplugin:stringconstant]}} + sb.insert(0, OString("foo")); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.insert(0, OString(s1)); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.insert(0, OString(s2)); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.insert(0, OString("foo", std::strlen("foo"))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.insert(0, OString(s1, std::strlen(s1))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}} + sb.insert(0, OString(s2, std::strlen(s2))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.insert(0, "foo"); + sb.insert(0, s1); + sb.insert(0, s2); // expected-error {{in call of 'rtl::OStringBuffer::insert' with non-array string constant argument, turn the non-array string constant into an array [loplugin:stringconstant]}} + sb.insert(0, "foo", std::strlen("foo")); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert' [loplugin:stringconstant]}} + sb.insert(0, s1, 3/*std::strlen(s1)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert' [loplugin:stringconstant]}} + sb.insert(0, s2, 3/*std::strlen(s2)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert', and turn the non-array string constant into an array [loplugin:stringconstant]}} + + foo(OUString("xxx")); // expected-error {{in call of 'foo', replace 'OUString' constructed from a string literal directly with the string literal [loplugin:stringconstant}} + Foo aFoo(OUString("xxx"), 1); // expected-error {{in call of 'Foo::Foo', replace 'OUString' constructed from a string literal directly with the string literal}} + (void)aFoo; + Foo aFoo2(OUString("xxx")); // expected-error {{in call of 'Foo::Foo', replace 'OUString' constructed from a string literal directly with the string literal}} + aFoo2.foo(OUString("xxx")); // expected-error {{in call of 'Foo::foo', replace 'OUString' constructed from a string literal directly with the string literal}} + + Foo2 aFoo3(OString("xxx")); // expected-error {{in call of 'Foo2::Foo2', replace 'OUString' constructed from a string literal directly with the string literal}} + aFoo3.foo(OString("xxx")); // expected-error {{in call of 'Foo2::foo', replace 'OUString' constructed from a string literal directly with the string literal}} + + (void) OUString("xxx", 3, RTL_TEXTENCODING_ASCII_US); // expected-error {{simplify construction of 'OUString' with string constant argument [loplugin:stringconstant]}} + (void) OUString("xxx", 3, RTL_TEXTENCODING_ISO_8859_1); // expected-error {{suspicious 'rtl::OUString' constructor with text encoding 12 but plain ASCII content; use 'RTL_TEXTENCODING_ASCII_US' instead [loplugin:stringconstant]}} + (void) OUString("x\xA0x", 3, RTL_TEXTENCODING_ISO_8859_1); + + (void) OUString("xxx", 2, RTL_TEXTENCODING_ASCII_US); // expected-error {{suspicious 'rtl::OUString' constructor with literal of length 3 and non-matching length argument 2 [loplugin:stringconstant]}} + +#if !defined __cpp_char8_t + (void) OUString(u8"xxx", 3, RTL_TEXTENCODING_ASCII_US); // expected-error {{simplify construction of 'OUString' with string constant argument [loplugin:stringconstant]}} +#endif + + (void) OUString("\x80", 1, RTL_TEXTENCODING_UTF8); // expected-error {{suspicious 'rtl::OUString' constructor with text encoding 'RTL_TEXTENCODING_UTF8' but non-UTF-8 content [loplugin:stringconstant]}} + + (void) OUString("\xC2\x80", 2, RTL_TEXTENCODING_UTF8); // expected-error {{simplify construction of 'OUString' with UTF-8 content as OUString(u"\u0080") [loplugin:stringconstant]}} + + OUStringBuffer ub; + ub.append(""); // expected-error {{call of 'rtl::OUStringBuffer::append' with suspicious empty string constant argument [loplugin:stringconstant]}} + ub.append("foo\0bar"); // expected-error {{call of 'rtl::OUStringBuffer::append' with string constant argument containing embedded NULLs [loplugin:stringconstant]}} + ub.append("foo\x80" "bar"); // expected-error {{call of 'rtl::OUStringBuffer::append' with string constant argument containing non-ASCII characters [loplugin:stringconstant]}} + char const sc1[] = ""; + ub.append(sc1); // expected-error {{call of 'rtl::OUStringBuffer::append' with suspicious empty string constant argument [loplugin:stringconstant]}} + char const sc2[] = "foo\0bar"; + ub.append(sc2); // expected-error {{call of 'rtl::OUStringBuffer::append' with string constant argument containing embedded NULLs [loplugin:stringconstant]}} + char const sc3[] = "foo\x80" "bar"; + ub.append(sc3); // expected-error {{call of 'rtl::OUStringBuffer::append' with string constant argument containing non-ASCII characters [loplugin:stringconstant]}} + char const sc4[] = {'f', 'o', 'o', 'b', 'a', 'r'}; + ub.append(sc4); // expected-error {{call of 'rtl::OUStringBuffer::append' with string constant argument lacking a terminating NULL [loplugin:stringconstant]}} + ub.append(static_cast<char const *>(sc1)); + ub.append(static_cast<char const *>(sc2)); // at runtime: append "foo" + ub.append(static_cast<char const *>(sc3)); // at runtime: assert + ub.append(static_cast<char const *>(sc4)); // at runtime: UB +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringloop.cxx b/compilerplugins/clang/test/stringloop.cxx new file mode 100644 index 000000000..0e9183d42 --- /dev/null +++ b/compilerplugins/clang/test/stringloop.cxx @@ -0,0 +1,38 @@ +/* -*- 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 "sal/config.h" +#include "rtl/string.hxx" +#include "rtl/ustring.hxx" + +struct Foo +{ + OUString m_field; // expected-note {{field here [loplugin:stringloop]}} + void func1() + { + for (int i = 0; i < 10; ++i) + m_field += "xxx"; + // expected-error@-1 {{appending to OUString in loop, rather use OUStringBuffer [loplugin:stringloop]}} + // no warning expected + m_field += "xxx"; + } +}; + +void func2() +{ + OUString s; // expected-note {{var here [loplugin:stringloop]}} + for (int i = 0; i < 10; ++i) + s += "xxx"; // expected-error {{appending to OUString in loop, rather use OUStringBuffer [loplugin:stringloop]}} + + // no warning expected + OUString s2; + s2 += "xxx"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/typedefparam.cxx b/compilerplugins/clang/test/typedefparam.cxx new file mode 100644 index 000000000..777a5128d --- /dev/null +++ b/compilerplugins/clang/test/typedefparam.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "tools/solar.h" + +namespace test1 +{ +class Foo +{ + void bar(sal_uIntPtr x); // expected-note {{declaration site here [loplugin:typedefparam]}} + sal_uIntPtr bar(); // expected-note {{declaration site here [loplugin:typedefparam]}} +}; + +void Foo::bar(sal_uLong) +// expected-error-re@-1 {{function param 1 at definition site does not match function param at declaration site, 'sal_uLong' (aka 'unsigned {{.+}}') vs 'sal_uIntPtr' (aka 'unsigned {{.+}}') [loplugin:typedefparam]}} +{ +} + +sal_uLong Foo::bar() +// expected-error-re@-1 {{function return type at definition site does not match function param at declaration site, 'sal_uLong' (aka 'unsigned {{.+}}') vs 'sal_uIntPtr' (aka 'unsigned {{.+}}') [loplugin:typedefparam]}} +{ + return 1; +} +}; + +// Carve out an exception for the "typedef struct S {...} T" idiom we use in the UNO code +namespace test2 +{ +typedef struct Foo +{ + int x; +} FooT; + +void bar(struct Foo*); + +void bar(FooT*){ + // no warning expected +}; +}; +namespace test3 +{ +typedef struct Foo +{ + int x; +} FooT; + +void bar(Foo*); + +void bar(FooT*){ + // no warning expected +}; +}; + +// check method overrides +namespace test4 +{ +struct Struct1 +{ + virtual sal_uIntPtr foo1(); + // expected-note@-1 {{super-class method here [loplugin:typedefparam]}} + virtual void foo2(sal_uIntPtr); + // expected-note@-1 {{super-class method here [loplugin:typedefparam]}} + virtual ~Struct1(); +}; +struct Struct2 : public Struct1 +{ + virtual sal_uLong foo1() override; + // expected-error-re@-1 {{method return type does not match overridden method 'sal_uLong' (aka 'unsigned {{.+}}') vs 'sal_uIntPtr' (aka 'unsigned {{.+}}') [loplugin:typedefparam]}} + virtual void foo2(sal_uLong) override; + // expected-error-re@-1 {{method param 1 does not match overridden method param 'sal_uLong' (aka 'unsigned {{.+}}') vs 'sal_uIntPtr' (aka 'unsigned {{.+}}') [loplugin:typedefparam]}} +}; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unnecessarycatchthrow.cxx b/compilerplugins/clang/test/unnecessarycatchthrow.cxx new file mode 100644 index 000000000..a9b32d86f --- /dev/null +++ b/compilerplugins/clang/test/unnecessarycatchthrow.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <iostream> +#include <fstream> + +void foo(); + +int main() +{ + try { + foo(); + } catch(int const &) { // expected-error {{unnecessary catch and throw [loplugin:unnecessarycatchthrow]}} + throw; + } + try { + foo(); + } catch(int const & ex) { // expected-error {{unnecessary catch and throw [loplugin:unnecessarycatchthrow]}} + throw ex; + } + try { + foo(); + } catch(int const &) { + std::cout << "test"; + throw; + } + +} + +void test1() +{ + // cannot remove catch/throw where the throw is of a non-final class + struct B {}; + struct D: B {}; + try { + throw D(); + } catch (B & b) { + throw b; // must not be removed + } +}; + +void test2() +{ + struct F final {}; + try { + throw F(); + } catch (F const & f) { // expected-error {{unnecessary catch and throw [loplugin:unnecessarycatchthrow]}} + throw f; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unnecessaryoverride-dtor.cxx b/compilerplugins/clang/test/unnecessaryoverride-dtor.cxx new file mode 100644 index 000000000..b54957be2 --- /dev/null +++ b/compilerplugins/clang/test/unnecessaryoverride-dtor.cxx @@ -0,0 +1,137 @@ +/* -*- 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 <sal/config.h> + +#include <salhelper/simplereferenceobject.hxx> + +#include "unnecessaryoverride-dtor.hxx" + +struct NonVirtualBase {}; + +struct NonVirtualDerived1: NonVirtualBase { + ~NonVirtualDerived1() {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct NonVirtualDerived2: NonVirtualBase { + virtual ~NonVirtualDerived2() {} +}; + +struct PrivateDerived: VirtualBase { +private: + ~PrivateDerived() override {} +}; + +struct ProtectedDerived: VirtualBase { +protected: + ~ProtectedDerived() override {} +}; + +IncludedDerived2::~IncludedDerived2() {} + +struct Incomplete: salhelper::SimpleReferenceObject {}; + +IncludedDerived3::IncludedDerived3() {} + +IncludedDerived3::~IncludedDerived3() {} + +// vmiklos likes these because he can quickly add a DEBUG or something similar without +// massive recompile +IncludedNotDerived::~IncludedNotDerived() {} + +struct NoExSpecDerived: VirtualBase { + ~NoExSpecDerived() override {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct NoThrowDerived: VirtualBase { + ~NoThrowDerived() throw () override {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct NoexceptDerived: VirtualBase { + ~NoexceptDerived() noexcept override {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct NoexceptTrueDerived: VirtualBase { + ~NoexceptTrueDerived() noexcept(true) override {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +#if 0 +struct NoexceptFalseBase { + virtual ~NoexceptFalseBase() noexcept(false) {} +}; + +struct NoexceptFalseDerived: NoexceptFalseBase { + ~NoexceptFalseDerived() noexcept(false) override {} +}; +#endif + +struct NoDtorDerived: VirtualBase {}; + +struct DefaultDerived1: VirtualBase { + ~DefaultDerived1() override = default; // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct DefaultDerived2: VirtualBase { + ~DefaultDerived2() override; // expected-note {{declared here [loplugin:unnecessaryoverride]}} +}; + +DefaultDerived2::~DefaultDerived2() = default; // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} + +struct EmptyDerived1: VirtualBase { + ~EmptyDerived1() override {}; // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct EmptyDerived2: VirtualBase { + ~EmptyDerived2() override; // expected-note {{declared here [loplugin:unnecessaryoverride]}} +}; + +EmptyDerived2::~EmptyDerived2() {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} + +struct NonEmptyDerived: VirtualBase { + ~NonEmptyDerived() override { (void) 0; } +}; + +struct CatchDerived: VirtualBase { + ~CatchDerived() override try {} catch (...) {} +}; + +struct DeleteBase { + virtual ~DeleteBase() = delete; +}; + +struct DeleteDerived: DeleteBase { + ~DeleteDerived() override = delete; +}; + +struct PureBase { + virtual ~PureBase() = 0; +}; + +struct PureDerived: PureBase { + ~PureDerived() override {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct CompleteBase { + ~CompleteBase() {} // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +// <sberg> noelgrandin, there's one other corner case one can imagine: +// a class defined in a .hxx with the dtor declared (but not defined) as inline in the .hxx, +// and then defined in the cxx (making it effectively only callable from within the cxx); +// removing the dtor declaration from the class definition would change the dtor to be callable from everywhere +MarkedInlineButNotDefined::~MarkedInlineButNotDefined() {} + +// avoid loplugin:unreffun: +int main() { + (void) NonVirtualDerived1(); + (void) DefaultDerived1(); + (void) CompleteBase(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unnecessaryoverride-dtor.hxx b/compilerplugins/clang/test/unnecessaryoverride-dtor.hxx new file mode 100644 index 000000000..e26024be1 --- /dev/null +++ b/compilerplugins/clang/test/unnecessaryoverride-dtor.hxx @@ -0,0 +1,55 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_UNNECESSARYOVERRIDE_DTOR_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_UNNECESSARYOVERRIDE_DTOR_HXX + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +struct VirtualBase { + virtual ~VirtualBase() {} +}; + +struct IncludedDerived1: VirtualBase { + ~IncludedDerived1() override {}; // expected-error {{unnecessary user-declared destructor [loplugin:unnecessaryoverride]}} +}; + +struct IncludedDerived2: VirtualBase { + ~IncludedDerived2() override; +}; + +struct IncludedNotDerived { + ~IncludedNotDerived(); +}; + +struct Incomplete; +struct IncludedDerived3: VirtualBase { + IncludedDerived3(); + ~IncludedDerived3() override; + +private: + IncludedDerived3(IncludedDerived3 &) = delete; + void operator =(IncludedDerived3) = delete; + + rtl::Reference<Incomplete> m; +}; + +struct MarkedInlineButNotDefined { + inline ~MarkedInlineButNotDefined(); +}; + +template<typename T> struct TemplateBase: T { + virtual ~TemplateBase() {} +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unnecessaryoverride.cxx b/compilerplugins/clang/test/unnecessaryoverride.cxx new file mode 100644 index 000000000..bf1e61352 --- /dev/null +++ b/compilerplugins/clang/test/unnecessaryoverride.cxx @@ -0,0 +1,196 @@ +/* -*- 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 <sal/config.h> + +#include <config_clang.h> +#include <o3tl/typed_flags_set.hxx> + +struct Base +{ + Base(); + Base(Base const&); + virtual ~Base(); + Base& operator=(Base const&); + virtual void f(); + void variadic(int, ...); + void cv() const volatile; + void ref(); + static void staticFn(); + void defaults(void* = nullptr, int = 0, double = 1, Base const& = {}, char const* = "foo"); +}; + +struct SimpleDerived : Base +{ + void + f() override // expected-error {{public virtual function just calls public parent [loplugin:unnecessaryoverride]}} + { + Base::f(); + } +}; + +struct Intermediate1 : Base +{ +}; + +struct MultiFunctionIntermediate2 : Base +{ + void f() override; +}; + +struct MultiFunctionDerived : Intermediate1, MultiFunctionIntermediate2 +{ + void f() override { Intermediate1::f(); } // no warning +}; + +struct MultiClassIntermediate2 : Base +{ +}; + +struct MultiClassDerived : Intermediate1, MultiClassIntermediate2 +{ + void f() override { Intermediate1::f(); } // no warning +}; + +struct DerivedDifferent : Base +{ + void variadic(int x) { Base::variadic(x); } // no warning + void cv() { Base::cv(); } // no warning + void ref() && { Base::ref(); } // no warning + void staticFn() { Base::staticFn(); } // no warning + void defaults(void* x1, int x2, double x3, Base const& x4, char const* x5) + { + Base::defaults(x1, x2, x3, x4, x5); // no warning + } +}; + +struct DerivedSame : Base +{ + void + defaults( // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + void* x1 = 0, int x2 = (1 - 1), double x3 = 1.0, Base const& x4 = (Base()), + char const* x5 = "f" + "oo") + { + Base::defaults(x1, x2, x3, x4, x5); + } +}; + +struct DerivedSlightlyDifferent : Base +{ + void defaults( // no warning + void* x1 = nullptr, int x2 = 0, double x3 = 1, Base const& x4 = DerivedSlightlyDifferent(), + char const* x5 = "foo") + { + Base::defaults(x1, x2, x3, x4, x5); + } +}; + +enum class E +{ + E1 = 1, + E2 = 2, + E3 = 4 +}; +namespace o3tl +{ +template <> struct typed_flags<E> : is_typed_flags<E, 7> +{ +}; +} + +struct Base2 +{ + void default1(Base const& = SimpleDerived()); + void default2(Base const& = SimpleDerived()); + void default3(Base = Base()); + void default4(E = (E::E1 | E::E2 | E::E3)); +}; + +struct Derived2 : Base2 +{ + void default1(Base const& x = Intermediate1()) { Base2::default1(x); } // no warning + void + default2( // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + Base const& x = SimpleDerived()) + { + Base2::default2(x); + } + void + default3( // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + Base x = Base()) + { + (Base2::default3(x)); + } + void + default4( // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + E x = (E::E1 | E::E2 | E::E3)) + { + Base2::default4(x); + } +}; + +class Base3 +{ +public: + void f1(); +}; + +class Derived3 : protected Base3 +{ +public: + // effectively changing access from protected to public + void f1() { Base3::f1(); } +}; + +// check the case where the method occurs more than once in a direct path up the class hierarchy +struct Base4 +{ + void f1(); +}; +struct Derived4_1 : public Base4 +{ + void f1(); +}; +struct Derived4_2 : public Derived4_1 +{ + void + f1() // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + { + Derived4_1::f1(); + } +}; + +struct Base5_1 +{ + void f1(); +}; +struct Base5_2 +{ + void f1(); +}; +struct Derived5 : public Base5_1, public Base5_2 +{ + void f1() { Base5_1::f1(); } // no warning expected +}; + +struct Base6_1 +{ + bool f1(); +}; +struct Derived6 : public Base6_1 +{ + bool + f1() // expected-error {{public function just calls public parent [loplugin:unnecessaryoverride]}} + { + bool ret = Base6_1::f1(); + return ret; + } +}; +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unnecessaryparen.cxx b/compilerplugins/clang/test/unnecessaryparen.cxx new file mode 100644 index 000000000..f932cd312 --- /dev/null +++ b/compilerplugins/clang/test/unnecessaryparen.cxx @@ -0,0 +1,141 @@ +/* -*- 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 <memory> +#include <string> +#include <rtl/ustring.hxx> +#include <o3tl/typed_flags_set.hxx> + +#define MACRO (1) + +bool foo(int); + +enum class EFoo { Bar }; + +struct S { operator bool(); }; + +enum class BrowseMode +{ + Modules = 0x01, + Top = 0x02, + Bottom = 0x04, + Left = 0x08, +}; +namespace o3tl +{ +template <> struct typed_flags<BrowseMode> : is_typed_flags<BrowseMode, 0xf> +{ +}; +} + +int main() +{ + int x = 1; + x = ((2)); // expected-error {{parentheses around parentheses [loplugin:unnecessaryparen]}} + + if ((foo(1))) foo(2); // expected-error {{parentheses immediately inside if statement [loplugin:unnecessaryparen]}} + + foo((1)); // expected-error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}} + + int y = (x); // expected-error {{parentheses immediately inside vardecl statement [loplugin:unnecessaryparen]}} + (void)y; + + EFoo efoo = EFoo::Bar; + switch (efoo) { + case (EFoo::Bar): break; // expected-error {{parentheses immediately inside case statement [loplugin:unnecessaryparen]}} + } + + int z = (y) ? 1 : 0; // expected-error {{unnecessary parentheses around identifier [loplugin:unnecessaryparen]}} + (void)z; + + int v1 = (static_cast<short>(1)) + 1; // expected-error {{unnecessary parentheses around cast [loplugin:unnecessaryparen]}} + (void)v1; + + // No warnings, used to silence -Wunreachable-code: + if ((false)) { + return 0; + } + x = (true) ? 0 : 1; + + // More "no warnings", at least potentially used to silence -Wunreachable-code: + while ((false)) { + return 0; + } + for (; (false);) { + return 0; + } + x = foo(0) && (false) ? 0 : 1; + x = MACRO < (0) ? 0 : 1; + // cf. odd Clang -Wunreachable-code--suppression mechanism when the macro itself contains + // parentheses, causing the issue that lead to c421ac3f9432f2e9468d28447dc4c2e45b6f4da3 + // "Revert loplugin:unnecessaryparen warning around integer literals" + + int v2 = (1); // expected-error {{parentheses immediately inside vardecl statement [loplugin:unnecessaryparen]}} + (void)v2; + + std::string v3; + v3 = (std::string("xx") + "xx"); // expected-error {{parentheses immediately inside assignment [loplugin:unnecessaryparen]}} + (void)v3; + + S s1; + if ((s1)) { // expected-error {{parentheses immediately inside if statement [loplugin:unnecessaryparen]}} + return 0; + } + S s2; + if ((s2 = s1)) { + return 0; + } + + (void) sizeof (int); + (void) sizeof (x); // expect no warning (for whatever reason; for symmetry with above case?) + + // Expecting just one error, not reported twice during TraverseInitListExpr: + int a[] = {(x)}; // expected-error {{unnecessary parentheses around identifier [loplugin:unnecessaryparen]}} + (void) a; + + (void) (+1); // expected-error {{unnecessary parentheses around signed numeric literal [loplugin:unnecessaryparen]}} + (void) (-1); // expected-error {{unnecessary parentheses around signed numeric literal [loplugin:unnecessaryparen]}} + + // For simplicity's sake, even warn about pathological cases that would require adding + // whitespace when removing the parentheses (as is also necessary in other cases anyway, like + // "throw(x);"); it is unlikely that there are any actual occurrences of code like "-(-1)" that + // would benefit from the parentheses readability-wise, compared to "- -1": + (void) -(-1); // expected-error {{unnecessary parentheses around signed numeric literal [loplugin:unnecessaryparen]}} + + char *p = nullptr; + delete (p); // expected-error {{parentheses immediately inside delete expr [loplugin:unnecessaryparen]}} + + BrowseMode nBits = ( BrowseMode::Modules | BrowseMode::Top ); // expected-error {{parentheses immediately inside vardecl statement [loplugin:unnecessaryparen]}} + (void)nBits; +}; + +struct B { operator bool() const; }; + +struct N { bool operator !(); }; + +class Foo2 +{ + int* p; + B b; + N n; + + int foo2() + { + return (p) ? 1 : 0; // expected-error {{unnecessary parentheses around member expr [loplugin:unnecessaryparen]}} + } + + static int foo3(Foo2 & foo) { + (void) !(foo.p); + (void) !(foo.b); + (void) !(foo.n); + return (foo.p) ? 1 : 0; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unoany.cxx b/compilerplugins/clang/test/unoany.cxx new file mode 100644 index 000000000..1b4bfaa2b --- /dev/null +++ b/compilerplugins/clang/test/unoany.cxx @@ -0,0 +1,27 @@ +/* -*- 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 "sal/config.h" + +#include "com/sun/star/uno/Any.hxx" + +css::uno::Any getAny() { return css::uno::Any(true); } + +int main() +{ + css::uno::Any a; + css::uno::Any b; + a = b; + a = getAny(); + a = css::uno::makeAny(true); // expected-error {{unnecessary copy, rather use <<= operator directly with the 'makeAny' argument [loplugin:unoany]}} + a = css::uno::Any(true); // expected-error {{unnecessary copy, rather use <<= operator directly with the 'Any' constructor argument [loplugin:unoany]}} +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unoquery.cxx b/compilerplugins/clang/test/unoquery.cxx new file mode 100644 index 000000000..a80786a17 --- /dev/null +++ b/compilerplugins/clang/test/unoquery.cxx @@ -0,0 +1,19 @@ +/* -*- 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 "sal/config.h" +#include "com/sun/star/beans/XProperty.hpp" + +void foo(css::uno::Reference<css::uno::XInterface> model) +{ + css::uno::Reference<css::beans::XProperty>(model, css::uno::UNO_QUERY)->getAsProperty(); + // expected-error@-1 {{calling UNO_QUERY followed by unconditional method call might result in SIGSEGV, rather use UNO_QUERY_THROW [loplugin:unoquery]}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unreffun.cxx b/compilerplugins/clang/test/unreffun.cxx new file mode 100644 index 000000000..b61171a87 --- /dev/null +++ b/compilerplugins/clang/test/unreffun.cxx @@ -0,0 +1,39 @@ +/* -*- 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 "unreffun.hxx" + +template <typename> struct S +{ + friend void f(); +}; + +void f() {} + +void g(); // expected-error {{Unreferenced function declaration [loplugin:unreffun]}} + +void h() // expected-error {{Unreferenced externally visible function definition [loplugin:unreffun]}} +{ +} + +void i() {} + +extern void j(); // expected-error {{Unreferenced function declaration [loplugin:unreffun]}} + +extern void +k() // expected-error {{Unreferenced externally visible function definition [loplugin:unreffun]}} +{ +} + +extern void l(); // expected-note {{first declaration is here [loplugin:unreffun]}} +void l() // expected-error {{Unreferenced externally visible function definition [loplugin:unreffun]}} +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unreffun.hxx b/compilerplugins/clang/test/unreffun.hxx new file mode 100644 index 000000000..1df266584 --- /dev/null +++ b/compilerplugins/clang/test/unreffun.hxx @@ -0,0 +1,19 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPILERPLUGINS_CLANG_TEST_UNREFFUN_HXX +#define INCLUDED_COMPILERPLUGINS_CLANG_TEST_UNREFFUN_HXX + +void f(); + +extern void i(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unsignedcompare.cxx b/compilerplugins/clang/test/unsignedcompare.cxx new file mode 100644 index 000000000..32b9af813 --- /dev/null +++ b/compilerplugins/clang/test/unsignedcompare.cxx @@ -0,0 +1,16 @@ +/* -*- 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/. + */ + +bool f(int i1, unsigned i2) +{ + // expected-error@+1 {{explicit cast from 'int' to 'unsigned int' (of equal rank) in comparison against 'unsigned int': if the cast value is known to be non-negative, use o3tl::make_unsigned instead of the cast [loplugin:unsignedcompare]}} + return unsigned(i1) < i2; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedenumconstants.cxx b/compilerplugins/clang/test/unusedenumconstants.cxx new file mode 100644 index 000000000..189a03767 --- /dev/null +++ b/compilerplugins/clang/test/unusedenumconstants.cxx @@ -0,0 +1,119 @@ +/* -*- 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 <o3tl/typed_flags_set.hxx> + +namespace test1 +{ +void test1() +{ + enum NameClashMode + { + NONE, + NO_CLASH // expected-error {{write NO_CLASH [loplugin:unusedenumconstants]}} + }; + NameClashMode eNameClashMode = NO_CLASH; + (void)eNameClashMode; +} +}; + +enum class BrowseMode +{ + Modules = 0x01, // expected-error {{read Modules [loplugin:unusedenumconstants]}} + Top = 0x02, // expected-error {{write Top [loplugin:unusedenumconstants]}} + Bottom = 0x04, // expected-error {{read Bottom [loplugin:unusedenumconstants]}} + Left = 0x08, // expected-error {{write Left [loplugin:unusedenumconstants]}} +}; +namespace o3tl +{ +template <> struct typed_flags<BrowseMode> : is_typed_flags<BrowseMode, 0xf> +{ +}; +} +BrowseMode g_flags; +int test2(BrowseMode nMode) +{ + if (nMode & BrowseMode::Modules) + return 1; + g_flags |= BrowseMode::Top; + return 0; +} +bool test2b(BrowseMode nMode) { return bool(nMode & BrowseMode::Bottom); } +BrowseMode test2c() { return BrowseMode::Left; } + +enum class Enum3 +{ + One = 0x01, // expected-error {{write One [loplugin:unusedenumconstants]}} + Two = 0x02 // expected-error {{write Two [loplugin:unusedenumconstants]}} +}; +namespace o3tl +{ +template <> struct typed_flags<Enum3> : is_typed_flags<Enum3, 0x3> +{ +}; +} +void test3_foo(Enum3); +void test3() { test3_foo(Enum3::One | Enum3::Two); } + +namespace test4 +{ +enum Enum4 +{ + ONE, // expected-error {{write ONE [loplugin:unusedenumconstants]}} + TWO +}; +struct Test4Base +{ + Test4Base(Enum4) {} +}; +struct Test4 : public Test4Base +{ + Test4() + : Test4Base(Enum4::ONE) + { + } +}; +}; + +//----------------------------------------------------------------------------------- + +// check that conditional operator walks up the tree +namespace test5 +{ +enum Enum +{ + ONE, // expected-error {{write ONE [loplugin:unusedenumconstants]}} + TWO // expected-error {{write TWO [loplugin:unusedenumconstants]}} +}; + +Enum foo(int x) { return x == 1 ? Enum::ONE : Enum::TWO; } +}; + +//----------------------------------------------------------------------------------- +// Ignore a common pattern that does not introduce any new information, merely removes +// information. +enum class Enum6 +{ + Modules = 0x01, // expected-error {{write Modules [loplugin:unusedenumconstants]}} + Top = 0x02, +}; +namespace o3tl +{ +template <> struct typed_flags<Enum6> : is_typed_flags<Enum6, 0x03> +{ +}; +} +void test6() +{ + Enum6 foo = Enum6::Modules; + foo &= ~Enum6::Top; + foo &= (~Enum6::Top); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedfields.cxx b/compilerplugins/clang/test/unusedfields.cxx new file mode 100644 index 000000000..6b54b4f7a --- /dev/null +++ b/compilerplugins/clang/test/unusedfields.cxx @@ -0,0 +1,383 @@ +/* -*- 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 "config_clang.h" + +// CLANG_VERSION = older versions of clang need something different in getParentFunctionDecl +// WIN32 = TODO, see corresponding TODO in compilerplugins/clang/unusedfields.cxx +#if CLANG_VERSION < 110000 || defined _WIN32 +// expected-no-diagnostics +#else + +#include <vector> +#include <ostream> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <rtl/ref.hxx> + +struct Foo +// expected-error@-1 {{read m_foo1 [loplugin:unusedfields]}} +// expected-error@-2 {{outside m_foo1 [loplugin:unusedfields]}} +{ + int m_foo1; +}; + +struct Bar +// expected-error@-1 {{read m_bar2 [loplugin:unusedfields]}} +// expected-error@-2 {{read m_bar4 [loplugin:unusedfields]}} +// expected-error@-3 {{read m_bar5 [loplugin:unusedfields]}} +// expected-error@-4 {{read m_bar6 [loplugin:unusedfields]}} +// expected-error@-5 {{read m_barfunctionpointer [loplugin:unusedfields]}} +// expected-error@-6 {{read m_bar8 [loplugin:unusedfields]}} +// expected-error@-7 {{read m_bar10 [loplugin:unusedfields]}} +// expected-error@-8 {{read m_bar11 [loplugin:unusedfields]}} +// expected-error@-9 {{write m_bar1 [loplugin:unusedfields]}} +// expected-error@-10 {{write m_bar2 [loplugin:unusedfields]}} +// expected-error@-11 {{write m_bar3 [loplugin:unusedfields]}} +// expected-error@-12 {{write m_bar3b [loplugin:unusedfields]}} +// expected-error@-13 {{write m_bar4 [loplugin:unusedfields]}} +// expected-error@-14 {{write m_bar7 [loplugin:unusedfields]}} +// expected-error@-15 {{write m_bar9 [loplugin:unusedfields]}} +// expected-error@-16 {{write m_bar12 [loplugin:unusedfields]}} +// expected-error@-17 {{outside-constructor m_bar2 [loplugin:unusedfields]}} +// expected-error@-18 {{outside-constructor m_bar3 [loplugin:unusedfields]}} +// expected-error@-19 {{outside-constructor m_bar3b [loplugin:unusedfields]}} +// expected-error@-20 {{outside-constructor m_bar4 [loplugin:unusedfields]}} +// expected-error@-21 {{outside-constructor m_bar5 [loplugin:unusedfields]}} +// expected-error@-22 {{outside-constructor m_bar6 [loplugin:unusedfields]}} +// expected-error@-23 {{outside-constructor m_bar7 [loplugin:unusedfields]}} +// expected-error@-24 {{outside-constructor m_bar8 [loplugin:unusedfields]}} +// expected-error@-25 {{outside-constructor m_bar9 [loplugin:unusedfields]}} +// expected-error@-26 {{outside-constructor m_bar10 [loplugin:unusedfields]}} +// expected-error@-27 {{outside-constructor m_bar11 [loplugin:unusedfields]}} +// expected-error@-28 {{outside-constructor m_bar12 [loplugin:unusedfields]}} +// expected-error@-29 {{outside-constructor m_barfunctionpointer [loplugin:unusedfields]}} +// expected-error@-30 {{outside m_barstream [loplugin:unusedfields]}} +{ + int m_bar1; + int m_bar2 = 1; + int* m_bar3; + int* m_bar3b; + int m_bar4; + void (*m_barfunctionpointer)(int&); + int m_bar5; + std::vector<int> m_bar6; + int m_bar7[5]; + int m_bar8; + int m_barstream; + sal_Int32 m_bar9; + sal_Int32 m_bar10; + css::uno::Any m_bar11; + css::uno::Any m_bar12; + + // check that we see reads of fields like m_foo1 when referred to via constructor initializer + Bar(Foo const & foo) : m_bar1(foo.m_foo1) {} + + // check that we don't see reads when inside copy/move constructor + Bar(Bar const & other) { m_bar3 = other.m_bar3; } + + // check that we don't see reads when inside copy/move assignment operator + Bar& operator=(Bar const & other) { m_bar3 = other.m_bar3; return *this; } + + // check that we DON'T see reads here + int bar2() { return m_bar2; } + + // check that we DON'T see reads here + void bar3() + { + m_bar3 = nullptr; + m_bar3b = m_bar3 = nullptr; + } + + // check that we see reads of field when passed to a function pointer + // check that we see read of a field that is a function pointer + void bar4() { m_barfunctionpointer(m_bar4); } + + // check that we see reads of a field when used in variable init + void bar5() { int x = m_bar5; (void) x; } + + // check that we see reads of a field when used in ranged-for + void bar6() { for (auto i : m_bar6) { (void)i; } } + + // check that we see don't see reads of array fields + void bar7() { m_bar7[3] = 1; } + + // check that we see reads when a field is used in an array expression + char bar8() + { + char tmp[5]; + return tmp[m_bar8]; + } + + // check that we don't see reads when calling operator>>= + void bar9() + { + css::uno::Any any; + any >>= m_bar9; + } + + // check that we see don't see writes when calling operator<<= + void bar10() + { + css::uno::Any any; + any <<= m_bar10; + } + + // check that we see reads of the LHS when calling operator>>= + void bar11() + { + int x; + m_bar11 >>= x; + } + + // check that we see writes of the LHS when calling operator<<= + void bar12() + { + int x; + m_bar12 <<= x; + } +}; + +// check that we __dont__ see a read of m_barstream +std::ostream& operator<<(std::ostream& s, Bar const & bar) +{ + s << bar.m_barstream; + return s; +}; + +struct ReadOnly1 { ReadOnly1(int&); }; + +struct ReadOnlyAnalysis +// expected-error@-1 {{read m_f2 [loplugin:unusedfields]}} +// expected-error@-2 {{read m_f3 [loplugin:unusedfields]}} +// expected-error@-3 {{read m_f5 [loplugin:unusedfields]}} +// expected-error@-4 {{read m_f6 [loplugin:unusedfields]}} +// expected-error@-5 {{write m_f2 [loplugin:unusedfields]}} +// expected-error@-6 {{write m_f3 [loplugin:unusedfields]}} +// expected-error@-7 {{write m_f4 [loplugin:unusedfields]}} +// expected-error@-8 {{write m_f5 [loplugin:unusedfields]}} +// expected-error@-9 {{write m_f6 [loplugin:unusedfields]}} +// expected-error@-10 {{outside-constructor m_f2 [loplugin:unusedfields]}} +// expected-error@-11 {{outside-constructor m_f3 [loplugin:unusedfields]}} +// expected-error@-12 {{outside-constructor m_f4 [loplugin:unusedfields]}} +// expected-error@-13 {{outside-constructor m_f5 [loplugin:unusedfields]}} +// expected-error@-14 {{outside-constructor m_f6 [loplugin:unusedfields]}} +{ + int m_f1; + int m_f2; + int m_f3; + std::vector<int> m_f4; + int m_f5; + int m_f6; + + // check that we don't see a write of m_f1 + ReadOnlyAnalysis() : m_f1(0) {} + + void method1(int&); + + // check that we see a write when we pass by non-const ref + void method2() { method1(m_f2); } + + int& method3() { return m_f3; } + + void method4() { m_f4.push_back(1); } + + // check that we see a write when we pass by non-const ref + void method5() { ReadOnly1 a(m_f5); } + + // check that we see a write when we pass by non-const ref + void method6() + { + int& r = m_f6; + r = 1; + } +}; + +struct ReadOnlyAnalysis2 +// expected-error@-1 {{write m_r2f1 [loplugin:unusedfields]}} +{ + int m_r2f1; +}; + +ReadOnlyAnalysis2 global { 1 }; + +struct ReadOnlyAnalysis3 +// expected-error@-1 {{read m_f1 [loplugin:unusedfields]}} +// expected-error@-2 {{outside-constructor m_f1 [loplugin:unusedfields]}} +{ + int m_f1; + + void func1() + { + if (m_f1) + m_f1 = 1; + } +}; + +// Verify the special logic for container fields that only contains mutations that +// add elements. +struct ReadOnlyAnalysis4 +// expected-error@-1 {{read m_readonly [loplugin:unusedfields]}} +// expected-error@-2 {{write m_writeonly [loplugin:unusedfields]}} +// expected-error@-3 {{read m_readonlyCss [loplugin:unusedfields]}} +// expected-error@-4 {{outside-constructor m_readonly [loplugin:unusedfields]}} +// expected-error@-5 {{outside-constructor m_readonlyCss [loplugin:unusedfields]}} +// expected-error@-6 {{outside-constructor m_writeonly [loplugin:unusedfields]}} +{ + std::vector<int> m_readonly; + std::vector<int> m_writeonly; + css::uno::Sequence<sal_Int32> m_readonlyCss; + + void func1() + { + int x = m_readonly[0]; + (void)x; + *m_readonly.begin() = 1; + + m_writeonly.push_back(0); + m_writeonly.clear(); + + x = m_readonlyCss.getArray()[0]; + } +}; + +template<class T> +struct VclPtr +{ + VclPtr(T*); + void clear(); +}; + +// Check calls to operators +struct WriteOnlyAnalysis2 +// expected-error@-1 {{write m_vclwriteonly [loplugin:unusedfields]}} +// expected-error@-2 {{outside-constructor m_vclwriteonly [loplugin:unusedfields]}} +{ + VclPtr<int> m_vclwriteonly; + + WriteOnlyAnalysis2() : m_vclwriteonly(nullptr) + { + m_vclwriteonly = nullptr; + } + + ~WriteOnlyAnalysis2() + { + m_vclwriteonly.clear(); + } +}; + +namespace WriteOnlyAnalysis3 +{ + void setFoo(int); + struct Foo1 + // expected-error@-1 {{read m_field1 [loplugin:unusedfields]}} + // expected-error@-2 {{write m_field1 [loplugin:unusedfields]}} + // expected-error@-3 {{outside-constructor m_field1 [loplugin:unusedfields]}} + { + int m_field1; + Foo1() : m_field1(1) {} + ~Foo1() + { + setFoo(m_field1); + } + }; +}; + +// Check that writes to fields that are wrapped by conditional checks are ignored, +// where those conditional checks use an 'operator bool' +namespace ReadOnlyAnalysis5 +{ + struct RefTarget + { + void acquire(); + void release(); + }; + struct Foo1 + // expected-error@-1 {{read m_field1 [loplugin:unusedfields]}} + // expected-error@-2 {{read m_field2 [loplugin:unusedfields]}} + // expected-error@-3 {{read m_field3xx [loplugin:unusedfields]}} + // expected-error@-4 {{outside-constructor m_field1 [loplugin:unusedfields]}} + // expected-error@-5 {{outside-constructor m_field2 [loplugin:unusedfields]}} + // expected-error@-6 {{outside-constructor m_field3xx [loplugin:unusedfields]}} + { + std::unique_ptr<int> m_field1; + rtl::Reference<RefTarget> m_field2; + css::uno::Reference<css::uno::XInterface> m_field3xx; + void f1(css::uno::Reference<css::uno::XInterface> a) + { + if (m_field1) + m_field1.reset(new int); + if (m_field1.get()) + m_field1.reset(new int); + if (m_field2) + m_field2 = new RefTarget; + if (m_field2.get()) + m_field2 = new RefTarget; + if (m_field3xx) + m_field3xx = a; + if (m_field3xx.get()) + m_field3xx = a; + } + }; +}; + + +namespace TouchFromOutsideConstructorAnalysis1 +{ + struct RenderContextGuard + // expected-error@-1 {{write m_pRef [loplugin:unusedfields]}} + // expected-error@-2 {{read m_pRef [loplugin:unusedfields]}} + // expected-error@-3 {{write m_pOriginalValue [loplugin:unusedfields]}} + { + int& m_pRef; + int m_pOriginalValue; + + RenderContextGuard(int& pRef, int pValue) + : m_pRef(pRef), + m_pOriginalValue(m_pRef) + { + m_pRef = pValue; + } + }; +}; + +namespace TouchFromOutsideAnalysis1 +{ + struct SwViewShell + { + int* GetWin(); + int* Imp(); + }; + struct RenderContextGuard + // expected-error@-1 {{write m_pShell [loplugin:unusedfields]}} + // expected-error@-2 {{read m_pShell [loplugin:unusedfields]}} + { + SwViewShell* m_pShell; + + RenderContextGuard(SwViewShell* pShell) + : m_pShell(pShell) + { + if (m_pShell->GetWin()) + { + int* pDrawView(m_pShell->Imp()); + + if (nullptr != pDrawView) + { + FindPageWindow(*m_pShell->GetWin()); + } + } + } + + void FindPageWindow(int x); + }; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedindex.cxx b/compilerplugins/clang/test/unusedindex.cxx new file mode 100644 index 000000000..7b98f8645 --- /dev/null +++ b/compilerplugins/clang/test/unusedindex.cxx @@ -0,0 +1,39 @@ +/* -*- 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 <vector> + +void func1() +{ + std::vector<int> v1; + int n = 0; + + for (int i = 0; i < 10; ++i) // expected-error {{loop variable not used [loplugin:unusedindex]}} + n += 1; + for (int i = 0; i < 10; ++i) + n += i; + + for (int i = 0; i < 10; ++i) // expected-error {{loop variable not used [loplugin:unusedindex]}} + { + for (int j = 0; j < 10; ++j) + { + n += j; + } + } + for (int i = 0; i < 10; ++i) + { + for (int j = 0; j < 10; ++j) + { + n += j; + n += i; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedmember.cxx b/compilerplugins/clang/test/unusedmember.cxx new file mode 100644 index 000000000..00b136249 --- /dev/null +++ b/compilerplugins/clang/test/unusedmember.cxx @@ -0,0 +1,218 @@ +/* -*- 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/. + */ + +namespace Enum +{ +namespace +{ +struct S +{ + enum E + { + E1, + E2 + }; + E e; +}; +} +void f(S s) { (void)s.e; } +} + +namespace ElaboratedEnum +{ +namespace +{ +struct S +{ + S() + { + enum E1 e1 = E11; + (void)e1; + } + enum E1 + { + E11, + E12 + }; + enum E2 + { + E21, + E22 + }; + enum E2 e2; +}; +} +void f() +{ + S s; + (void)s; + (void)s.e2; +} +} + +namespace UnusedEnum +{ +namespace +{ +struct S +{ + enum E // expected-error {{unused class member [loplugin:unusedmember]}} + { + E1, + E2 + }; +}; +} +void f() { (void)S::E1; } +} + +namespace UnusedDataMember +{ +namespace +{ +struct NT +{ + NT(int = 0) {} + ~NT() {} +}; +struct __attribute__((warn_unused)) T +{ + T(int = 0) {} + ~T() {} +}; +struct S +{ + int i1; + int i2; // expected-error {{unused class member [loplugin:unusedmember]}} + int const& i3; // expected-error {{unused class member [loplugin:unusedmember]}} + NT nt; + T t1; + T t2; // expected-error {{unused class member [loplugin:unusedmember]}} + T const& t3; // expected-error {{unused class member [loplugin:unusedmember]}} + S() + : i1(0) + , i3(i1) + , t1(0) + , t3(t1) + { + (void)i1; + (void)t1; + } +}; +} +void f() +{ + S s; + (void)s; +} +} + +namespace Alignof +{ +namespace +{ +struct S +{ + int i; +}; +} +void f() { (void)alignof(S const(&)[][10]); } +} + +namespace Aligned +{ +namespace +{ +struct S1 +{ + int i; +}; +struct S2 +{ + int i __attribute__((aligned(__alignof__(S1)))); +}; +} +void f() +{ + S2 s; + s.i = 0; +} +} + +namespace Bases +{ +namespace +{ +struct S1 +{ + int i1; +}; +struct S2 : S1 +{ + int i2; +}; +struct S3 : S2 +{ +}; +} +void f() { (void)sizeof(S3); } +} + +namespace Unnamed +{ +namespace +{ +struct S +{ + struct + { + struct + { + int i; + } s2; + struct // anonymous struct extension (widely supported) + { + int j; + }; + int k; + } s1; +#if false //TODO: see corresponding TODO in compilerplugins/clang/unusedmember.cxx + static constexpr struct + { + int l; // expected-error {{unused class member [loplugin:unusedmember]}} + } s = {}; +#endif + typedef struct + { + int m; // expected-error {{unused class member [loplugin:unusedmember]}} + } t; // expected-error {{unused class member [loplugin:unusedmember]}} +}; +} +void f() +{ + (void)sizeof(S); +#if false //TODO: see corresponding TODO in compilerplugins/clang/unusedmember.cxx + (void)S::s; // avoid "unused variable 's'" (non-loplugin) warning +#endif +} +} + +int main() +{ + (void)&Enum::f; + (void)&ElaboratedEnum::f; + (void)&UnusedEnum::f; + (void)&UnusedDataMember::f; + (void)&Alignof::f; + (void)&Aligned::f; + (void)&Bases::f; + (void)&Unnamed::f; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedvariablecheck.cxx b/compilerplugins/clang/test/unusedvariablecheck.cxx new file mode 100644 index 000000000..c5b2a04d8 --- /dev/null +++ b/compilerplugins/clang/test/unusedvariablecheck.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/. + */ + +#include <sal/config.h> + +#include <list> +#include <string> +#include <vector> + +namespace +{ +template <typename T> using Vec = std::vector<T>; +} + +int main() +{ + std::list<int> v1; // expected-error {{unused variable 'v1' [loplugin:unusedvariablecheck]}} + std::string v2; // expected-error {{unused variable 'v2' [loplugin:unusedvariablecheck]}} + Vec<int> v3; // expected-error {{unused variable 'v3' [loplugin:unusedvariablecheck]}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/unusedvariablemore.cxx b/compilerplugins/clang/test/unusedvariablemore.cxx new file mode 100644 index 000000000..712bcf403 --- /dev/null +++ b/compilerplugins/clang/test/unusedvariablemore.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <sal/config.h> +#include <sal/types.h> +#include <map> + +struct SAL_WARN_UNUSED Point +{ +}; +struct SAL_WARN_UNUSED Rectangle +{ + Rectangle(); + Rectangle(int width, int height); + Rectangle& Union(const Rectangle&) { return *this; } + Rectangle& Intersection(const Rectangle&); + Rectangle& operator+=(const Point& rPt); +}; + +void func1() +{ + Rectangle aTmp1; // expected-error {{unused variable 'aTmp1' [loplugin:unusedvariablemore]}} + aTmp1.Union(Rectangle(10, 10)); +} + +void func2() +{ + Rectangle aViewArea( + 10, 10); // expected-error@-1 {{unused variable 'aViewArea' [loplugin:unusedvariablemore]}} + aViewArea += Point(); + aViewArea.Intersection(Rectangle(0, 0)); +} + +//--------------------------------------------------------------------- +// Negative tests +//--------------------------------------------------------------------- + +Rectangle func3(const Rectangle& rRect) +{ + Rectangle aTmpRect(Rectangle(10, 10)); + return aTmpRect.Union(rRect); +} + +void func4() +{ + std::map<int, int> aMimeTypeMap; + aMimeTypeMap[1] = 0; + int aExportMimeType(aMimeTypeMap[0]); + (void)aExportMimeType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/useuniqueptr.cxx b/compilerplugins/clang/test/useuniqueptr.cxx new file mode 100644 index 000000000..3d4f62d5d --- /dev/null +++ b/compilerplugins/clang/test/useuniqueptr.cxx @@ -0,0 +1,311 @@ +/* -*- 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 <sal/config.h> +#include <config_clang.h> +#include <array> +#include <memory> +#include <vector> +#include <unordered_map> + +struct XXX { + ~XXX() {} +}; + +class Foo1 { + XXX* m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo1() + { + delete m_pbar; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + m_pbar = nullptr; + } +}; + + +class Foo2 { + char* m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + char* m_pbar2; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo2() + { + delete[] m_pbar1; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + delete[] m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } +}; + +class Foo3 { + char* m_pbar; + bool bMine; + ~Foo3() + { + if (bMine) + delete[] m_pbar; + } +}; + +class Class4 { + int* m_pbar[10]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class4() + { + for (int i = 0; i < 10; ++i) + delete m_pbar[i]; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Class5 { + int* m_pbar[10]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class5() + { + for (auto p : m_pbar) // expected-note {{var is here [loplugin:useuniqueptr]}} + delete p; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} expected-error {{call to delete on a var, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } +}; +class Class5a { + int* m_pbar[10]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class5a() + { + for (auto p : m_pbar) // expected-note {{var is here [loplugin:useuniqueptr]}} + { + int x = 1; + x = x + 2; + delete p; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} expected-error {{call to delete on a var, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + } +}; +class Class6 { + std::array<int*,10> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class6() + { + for (auto p : m_pbar) // expected-note {{var is here [loplugin:useuniqueptr]}} + delete p; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} expected-error {{call to delete on a var, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } +}; +class Class7 { + std::array<int*,10> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class7() + { + for (int i = 0; i < 10; ++i) + delete m_pbar[i]; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Class8 { + std::unordered_map<int, int*> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class8() + { + for (auto & i : m_pbar) + delete i.second; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Foo8 { + XXX* m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + XXX* m_pbar2; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo8() + { + delete m_pbar1; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + delete m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } +}; +class Foo9 { + XXX* m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + XXX* m_pbar2; // expected-note {{member is here [loplugin:useuniqueptr]}} + XXX* m_pbar3; // expected-note {{member is here [loplugin:useuniqueptr]}} + XXX* m_pbar4; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo9() + { + if (m_pbar1) + { + delete m_pbar1; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + if (m_pbar2 != nullptr) + { + delete m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + if (m_pbar3 != nullptr) + delete m_pbar3; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + if (m_pbar4 != nullptr) + { + int x = 1; + (void)x; + delete m_pbar4; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + } +}; +// no warning expected +class Foo10 { + XXX* m_pbar1; + ~Foo10() + { + if (m_pbar1 != getOther()) + { + delete m_pbar1; + } + } + XXX* getOther() { return nullptr; } +}; +class Foo11 { + std::vector<XXX*> m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo11() + { + for (const auto & p : m_pbar1) // expected-note {{var is here [loplugin:useuniqueptr]}} + { + delete p; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} expected-error {{call to delete on a var, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + } +}; +class Foo12 { + std::array<int*,10> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo12() + { + int i = 0; + while (i < 10) + delete m_pbar[i++]; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +#define DELETEZ( p ) ( delete p,p = NULL ) +class Foo13 { + int * m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + int * m_pbar2; // expected-note {{member is here [loplugin:useuniqueptr]}} + int * m_pbar3; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo13() + { + if (m_pbar1) + DELETEZ(m_pbar1); // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + DELETEZ(m_pbar2); // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + if (m_pbar3) + { + DELETEZ(m_pbar3); // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + } +}; + +// check for unconditional inner compound statements +class Foo14 { + int * m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo14() + { + { + delete m_pbar1; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } + } +}; + +void Foo15(int * p) +{ + delete p; // expected-error {{calling delete on a pointer param, should be either whitelisted or simplified [loplugin:useuniqueptr]}} +}; + +class Foo16 { + Foo16(int * p) + { + delete p; // expected-error {{calling delete on a pointer param, should be either whitelisted or simplified [loplugin:useuniqueptr]}} + }; + void foo(int * p) + { + delete p; // expected-error {{calling delete on a pointer param, should be either whitelisted or simplified [loplugin:useuniqueptr]}} + }; +}; + +// check for delete on array members +class Foo17 { + int * m_pbar1[6]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo17() + { + delete m_pbar1[0]; // expected-error {{unconditional call to delete on an array member, should be using std::unique_ptr [loplugin:useuniqueptr]}} + } +}; + +// this only starts to work somewhere after clang 3.8 and before clang7 +class Foo18 { + std::vector<char*> m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo18() + { + for (auto aIter = m_pbar1.begin(); aIter != m_pbar1.end(); ++aIter) + delete *aIter; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; + +void foo19() +{ + std::vector<char*> vec; // expected-note {{var is here [loplugin:useuniqueptr]}} + for(char * p : vec) // expected-note {{var is here [loplugin:useuniqueptr]}} + delete p; // expected-error {{rather manage this var with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} expected-error {{call to delete on a var, should be using std::unique_ptr [loplugin:useuniqueptr]}} +} + +// no warning expected +namespace foo20 +{ + struct struct20_1 {}; + struct struct20_2 : public struct20_1 { + char * p; + }; + void foo20(struct20_1 * pMapping) + { + delete static_cast< struct20_2 * >( pMapping )->p; + } +}; + +// ------------------------------------------------------------------------------------------------ +// tests for deleting when looping via iterators +// ------------------------------------------------------------------------------------------------ + +void foo21() +{ + std::vector<bool*> vec; // expected-note {{var is here [loplugin:useuniqueptr]}} + for(auto it = vec.begin(); it != vec.end(); ++it) + delete *it; // expected-error {{rather manage this var with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} +} + +void foo22() +{ + std::unordered_map<int, float*> map; // expected-note {{var is here [loplugin:useuniqueptr]}} + for(auto it = map.begin(); it != map.end(); ++it) + delete it->second; // expected-error {{rather manage this var with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} +} + +class Foo23 +{ + std::unordered_map<int, float*> map; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo23() + { + for(auto it = map.begin(); it != map.end(); ++it) + delete it->second; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; + +class Foo24 +{ + typedef std::vector<int*> HTMLAttrs; + HTMLAttrs m_aSetAttrTab; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Foo24() + { + for ( HTMLAttrs::const_iterator it = m_aSetAttrTab.begin(); it != m_aSetAttrTab.end(); ++it ) + delete *it; // expected-error {{rather manage this member with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; + +// ------------------------------------------------------------------------------------------------ +// tests for passing owning pointers to constructors +// ------------------------------------------------------------------------------------------------ + + +class Bravo1 +{ + std::unique_ptr<int> m_field1; + Bravo1(int* p) + : m_field1(p) // expected-error {{should be passing via std::unique_ptr param [loplugin:useuniqueptr]}} + {} +}; +class Bravo2 +{ + std::unique_ptr<int> m_field1; + Bravo2(std::unique_ptr<int> p) + : m_field1(std::move(p)) // no warning expected + {} +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/vclwidgets.cxx b/compilerplugins/clang/test/vclwidgets.cxx new file mode 100644 index 000000000..f08faaefe --- /dev/null +++ b/compilerplugins/clang/test/vclwidgets.cxx @@ -0,0 +1,98 @@ +/* -*- 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 <sal/config.h> + +#include <atomic> + +#include <vcl/vclptr.hxx> +#include <vcl/vclreferencebase.hxx> + +struct Widget : public VclReferenceBase +{ + VclPtr<Widget> mpParent; + + void widget1() + { + // test that we ignore assignments from a member field + Widget* p = mpParent; + (void)p; + // test against false+ + p = (true) ? mpParent.get() : nullptr; + } + + ~Widget() override + { + disposeOnce(); + } + + void dispose() override + { + mpParent.clear(); + VclReferenceBase::dispose(); + } +}; + +VclPtr<Widget> f() +{ + return nullptr; +} + +Widget* g() +{ + return nullptr; +} + +// test the variable init detection +void bar() +{ + Widget* p = f(); // expected-error {{assigning a returned-by-value VclPtr<T> to a T* variable is dodgy, should be assigned to a VclPtr. If you know that the RHS does not return a newly created T, then add a '.get()' to the RHS [loplugin:vclwidgets]}} + (void)p; + Widget* q = g(); + (void)q; + Widget* r = nullptr; + (void)r; +} + +// test the assignment detection +void bar2() +{ + Widget* p; + p = nullptr; + p = f(); // expected-error {{assigning a returned-by-value VclPtr<T> to a T* variable is dodgy, should be assigned to a VclPtr. If you know that the RHS does not return a newly created T, then add a '.get()' to the RHS [loplugin:vclwidgets]}} + (void)p; + Widget* q; + q = g(); + (void)q; +} + + +// test against false+ + +template<class T> +T * get() { return nullptr; } + +void bar3() +{ + Widget* p; + p = get<Widget>(); +} + +void bar4() { + VclPtr<Widget> p1; + //TODO: one error should be enough here? + // expected-error@+2 {{calling delete on instance of VclReferenceBase subclass, must rather call disposeAndClear() [loplugin:vclwidgets]}} + // expected-error@+1 {{calling delete on instance of VclPtr, must rather call disposeAndClear() [loplugin:vclwidgets]}} + delete p1; + std::atomic<int *> p2; + // No false positive here: + delete p2; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/weakbase.cxx b/compilerplugins/clang/test/weakbase.cxx new file mode 100644 index 000000000..a59a53728 --- /dev/null +++ b/compilerplugins/clang/test/weakbase.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/. + */ + +namespace tools +{ +struct WeakBase +{ + virtual ~WeakBase(); +}; +} + +struct Foo1 : public tools::WeakBase +{ + virtual ~Foo1(); +}; + +struct Foo2 : public tools::WeakBase +{ + virtual ~Foo2(); +}; + +// expected-error@+1 {{multiple copies of WeakBase, through inheritance paths Bar->Foo1->WeakBase, Bar->Foo2->WeakBase [loplugin:weakbase]}} +struct Bar : public Foo1, public Foo2 +{ + virtual ~Bar(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/writeonlyvars.cxx b/compilerplugins/clang/test/writeonlyvars.cxx new file mode 100644 index 000000000..c2f78bddd --- /dev/null +++ b/compilerplugins/clang/test/writeonlyvars.cxx @@ -0,0 +1,166 @@ +/* -*- 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/. + */ + +#if defined _WIN32 //TODO, see corresponding TODO in compilerplugins/clang/writeonlyvars.cxx +// expected-no-diagnostics +#else + +#include <vector> +#include <ostream> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +// See 1d0bc2139759f087d50432f8a2116060676f34e1 "use std::experimental::source_location in +// uno::Exception" modification to +// workdir/UnoApiHeadersTarget/udkapi/normal/com/sun/star/uno/Exception.hdl, which is indirectly +// included through the above #include directives, in turn causing conditional inclusion of +// include/o3tl/runtimetooustring.hxx (and where `ok` is only read in an assert in !NDEBUG builds): +#if defined LIBO_USE_SOURCE_LOCATION +// expected-error@o3tl/runtimetooustring.hxx:* {{read s [loplugin:writeonlyvars]}} +// expected-error@o3tl/runtimetooustring.hxx:* {{write s [loplugin:writeonlyvars]}} +#if !defined NDEBUG +// expected-error@o3tl/runtimetooustring.hxx:* {{read ok [loplugin:writeonlyvars]}} +#endif +#endif + +namespace Bar +{ +void test() +{ + // check that we DON'T see reads here + // expected-error@+1 {{write m_bar3 [loplugin:writeonlyvars]}} + int* m_bar3; + // expected-error@+1 {{write m_bar3b [loplugin:writeonlyvars]}} + int* m_bar3b; + m_bar3 = nullptr; + m_bar3b = m_bar3 = nullptr; + + // check that we see reads of field when passed to a function pointer + // check that we see read of a field that is a function pointer + // expected-error@+2 {{write m_bar4 [loplugin:writeonlyvars]}} + // expected-error@+1 {{read m_bar4 [loplugin:writeonlyvars]}} + int m_bar4; + // expected-error@+1 {{read m_barfunctionpointer [loplugin:writeonlyvars]}} + void (*m_barfunctionpointer)(int&) = nullptr; + m_barfunctionpointer(m_bar4); + + // check that we see reads of a field when used in variable init + // expected-error@+1 {{read m_bar5 [loplugin:writeonlyvars]}} + int m_bar5 = 1; + int x = m_bar5; + (void)x; + + // check that we see reads of a field when used in ranged-for + // expected-error@+1 {{read m_bar6 [loplugin:writeonlyvars]}} + std::vector<int> m_bar6; + for (auto i : m_bar6) + { + (void)i; + } + + // check that we see writes of array fields + // expected-error@+1 {{write m_bar7 [loplugin:writeonlyvars]}} + int m_bar7[5]; + m_bar7[3] = 1; + + // check that we see reads when a field is used in an array expression + // expected-error@+1 {{read m_bar8 [loplugin:writeonlyvars]}} + int m_bar8 = 1; + // expected-error@+1 {{read tmp [loplugin:writeonlyvars]}} + char tmp[5]; + auto x2 = tmp[m_bar8]; + (void)x2; + + // check that we don't see reads when calling operator>>= + // expected-error@+1 {{write m_bar9 [loplugin:writeonlyvars]}} + sal_Int32 m_bar9; + // expected-error@+1 {{read any [loplugin:writeonlyvars]}} + css::uno::Any any; + any >>= m_bar9; + + // check that we see don't see writes when calling operator<<= + // expected-error@+1 {{read m_bar10 [loplugin:writeonlyvars]}} + sal_Int32 m_bar10; + // expected-error@+2 {{write any2 [loplugin:writeonlyvars]}} + // expected-error@+1 {{read any2 [loplugin:writeonlyvars]}} + css::uno::Any any2; + any2 <<= m_bar10; +}; +}; + +struct ReadOnly1 +{ + ReadOnly1(int&); +}; + +namespace ReadOnlyAnalysis +{ +void method1(int&); + +void test() +{ + // check that we see a write when we pass by non-const ref + // expected-error@+2 {{read m_f2 [loplugin:writeonlyvars]}} + // expected-error@+1 {{write m_f2 [loplugin:writeonlyvars]}} + int m_f2; + method1(m_f2); + + // expected-error@+1 {{write m_f4 [loplugin:writeonlyvars]}} + std::vector<int> m_f4; + m_f4.push_back(1); + + // check that we see a write when we pass by non-const ref + // expected-error@+2 {{read m_f5 [loplugin:writeonlyvars]}} + // expected-error@+1 {{write m_f5 [loplugin:writeonlyvars]}} + int m_f5; + ReadOnly1 a(m_f5); + + // check that we see a write when we pass by non-const ref + // expected-error@+2 {{read m_f6 [loplugin:writeonlyvars]}} + // expected-error@+1 {{write m_f6 [loplugin:writeonlyvars]}} + int m_f6; + // expected-error@+1 {{write r [loplugin:writeonlyvars]}} + int& r = m_f6; + r = 1; +}; +}; + +void ReadOnlyAnalysis3() +{ + // expected-error@+1 {{read m_f1 [loplugin:writeonlyvars]}} + int m_f1 = 0; + + if (m_f1) + m_f1 = 1; +}; + +// Verify the special logic for container fields that only contains mutations that +// add elements. +void ReadOnlyAnalysis4() +{ + // expected-error@+1 {{read m_readonly [loplugin:writeonlyvars]}} + std::vector<int> m_readonly; + // expected-error@+1 {{write m_writeonly [loplugin:writeonlyvars]}} + std::vector<int> m_writeonly; + // expected-error@+1 {{read m_readonlyCss [loplugin:writeonlyvars]}} + css::uno::Sequence<sal_Int32> m_readonlyCss; + + // expected-error@+1 {{write x [loplugin:writeonlyvars]}} + int x = m_readonly[0]; + (void)x; + *m_readonly.begin() = 1; // TODO? + + m_writeonly.push_back(0); + + x = m_readonlyCss.getArray()[0]; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/xmlimport.cxx b/compilerplugins/clang/test/xmlimport.cxx new file mode 100644 index 000000000..965d4936e --- /dev/null +++ b/compilerplugins/clang/test/xmlimport.cxx @@ -0,0 +1,54 @@ +/* -*- 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 "sal/config.h" + +// Cannot include this, makes clang crash +//#include "xmloff/xmlimp.hxx" + +class SvXMLImportContext +{ +public: + virtual ~SvXMLImportContext() {} + + virtual void createFastChildContext() {} + virtual void startFastElement() {} + virtual void endFastElement() {} +}; + +class Test1 : public SvXMLImportContext +{ +public: + // expected-error@+1 {{must override startFastElement too [loplugin:xmlimport]}} + virtual void createFastChildContext() override; +}; + +class Test2 : public SvXMLImportContext +{ +public: + // no warning expected + virtual void createFastChildContext() override; + virtual void startFastElement() override {} +}; + +class Test3 : public Test2 +{ +public: + // no warning expected + virtual void createFastChildContext() override; +}; + +class Test4 : public SvXMLImportContext +{ +public: + // expected-error@+1 {{must override startFastElement too [loplugin:xmlimport]}} + virtual void endFastElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |