summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/test')
-rw-r--r--compilerplugins/clang/test/badstatics.cxx58
-rw-r--r--compilerplugins/clang/test/blockblock.cxx47
-rw-r--r--compilerplugins/clang/test/bufferadd.cxx116
-rw-r--r--compilerplugins/clang/test/buriedassign.cxx133
-rw-r--r--compilerplugins/clang/test/casttovoid.cxx125
-rw-r--r--compilerplugins/clang/test/classmemaccess.cxx36
-rw-r--r--compilerplugins/clang/test/collapseif.cxx55
-rw-r--r--compilerplugins/clang/test/commaoperator.cxx28
-rw-r--r--compilerplugins/clang/test/conditionalstring.cxx27
-rw-r--r--compilerplugins/clang/test/constfields.cxx45
-rw-r--r--compilerplugins/clang/test/constmethod.cxx59
-rw-r--r--compilerplugins/clang/test/constparams.cxx73
-rw-r--r--compilerplugins/clang/test/consttobool.cxx70
-rw-r--r--compilerplugins/clang/test/constvars.cxx94
-rw-r--r--compilerplugins/clang/test/convertlong.cxx42
-rw-r--r--compilerplugins/clang/test/cow_wrapper.cxx44
-rw-r--r--compilerplugins/clang/test/cppunitassertequals.cxx75
-rw-r--r--compilerplugins/clang/test/cppunitassertequals.hxx23
-rw-r--r--compilerplugins/clang/test/cstylecast.cxx74
-rw-r--r--compilerplugins/clang/test/datamembershadow.cxx24
-rw-r--r--compilerplugins/clang/test/dbgunhandledexception.cxx38
-rw-r--r--compilerplugins/clang/test/dodgyswitch.cxx30
-rw-r--r--compilerplugins/clang/test/doubleconvert.cxx25
-rw-r--r--compilerplugins/clang/test/elidestringvar.cxx46
-rw-r--r--compilerplugins/clang/test/emptyif.cxx61
-rw-r--r--compilerplugins/clang/test/expressionalwayszero.cxx47
-rw-r--r--compilerplugins/clang/test/external.cxx195
-rw-r--r--compilerplugins/clang/test/external.hxx23
-rw-r--r--compilerplugins/clang/test/faileddyncast.cxx21
-rw-r--r--compilerplugins/clang/test/fakebool.cxx50
-rw-r--r--compilerplugins/clang/test/flatten.cxx191
-rw-r--r--compilerplugins/clang/test/fragiledestructor.cxx88
-rw-r--r--compilerplugins/clang/test/getstr.cxx59
-rw-r--r--compilerplugins/clang/test/implicitboolconversion.cxx83
-rw-r--r--compilerplugins/clang/test/indentation.cxx110
-rw-r--r--compilerplugins/clang/test/intvsfloat.cxx62
-rw-r--r--compilerplugins/clang/test/logexceptionnicely.cxx52
-rw-r--r--compilerplugins/clang/test/loopvartoosmall.cxx26
-rw-r--r--compilerplugins/clang/test/makeshared.cxx63
-rw-r--r--compilerplugins/clang/test/mapindex.cxx43
-rw-r--r--compilerplugins/clang/test/moveit.cxx60
-rw-r--r--compilerplugins/clang/test/moveparam.cxx60
-rw-r--r--compilerplugins/clang/test/namespaceindentation.cxx50
-rw-r--r--compilerplugins/clang/test/noexcept.cxx16
-rw-r--r--compilerplugins/clang/test/noexceptmove.cxx95
-rw-r--r--compilerplugins/clang/test/nullptr.cxx23
-rw-r--r--compilerplugins/clang/test/oncevar.cxx66
-rw-r--r--compilerplugins/clang/test/optmove.cxx53
-rw-r--r--compilerplugins/clang/test/oslendian-1.cxx47
-rw-r--r--compilerplugins/clang/test/oslendian-2.cxx23
-rw-r--r--compilerplugins/clang/test/oslendian-3.cxx25
-rw-r--r--compilerplugins/clang/test/overridevirtual.cxx44
-rw-r--r--compilerplugins/clang/test/passparamsbyref.cxx42
-rw-r--r--compilerplugins/clang/test/passstuffbyref.cxx84
-rw-r--r--compilerplugins/clang/test/pointerbool.cxx46
-rw-r--r--compilerplugins/clang/test/putpoolitem.cxx48
-rw-r--r--compilerplugins/clang/test/reducevarscope.cxx99
-rw-r--r--compilerplugins/clang/test/redundantcast.cxx458
-rw-r--r--compilerplugins/clang/test/redundantcast.hxx35
-rw-r--r--compilerplugins/clang/test/redundantfcast.cxx224
-rw-r--r--compilerplugins/clang/test/redundantinline.cxx24
-rw-r--r--compilerplugins/clang/test/redundantinline.hxx78
-rw-r--r--compilerplugins/clang/test/redundantpointerops.cxx95
-rw-r--r--compilerplugins/clang/test/redundantpreprocessor.cxx15
-rw-r--r--compilerplugins/clang/test/refassign.cxx31
-rw-r--r--compilerplugins/clang/test/refcounting.cxx120
-rw-r--r--compilerplugins/clang/test/referencecasting.cxx212
-rw-r--r--compilerplugins/clang/test/returnconstval.cxx21
-rw-r--r--compilerplugins/clang/test/salcall.cxx188
-rw-r--r--compilerplugins/clang/test/sallogareas.cxx51
-rw-r--r--compilerplugins/clang/test/salunicodeliteral.cxx40
-rw-r--r--compilerplugins/clang/test/salunicodeliteral.hxx14
-rw-r--r--compilerplugins/clang/test/selfinit.cxx33
-rw-r--r--compilerplugins/clang/test/sequentialassign.cxx98
-rw-r--r--compilerplugins/clang/test/shouldreturnbool.cxx31
-rw-r--r--compilerplugins/clang/test/simplifyconstruct.cxx88
-rw-r--r--compilerplugins/clang/test/simplifydynamiccast.cxx34
-rw-r--r--compilerplugins/clang/test/simplifypointertobool.cxx74
-rw-r--r--compilerplugins/clang/test/singlevalfields.cxx26
-rw-r--r--compilerplugins/clang/test/staticconstfield.cxx120
-rw-r--r--compilerplugins/clang/test/staticdynamic.cxx44
-rw-r--r--compilerplugins/clang/test/staticvar.cxx80
-rw-r--r--compilerplugins/clang/test/stdfunction.cxx56
-rw-r--r--compilerplugins/clang/test/stringadd.cxx262
-rw-r--r--compilerplugins/clang/test/stringbuffer.cxx22
-rw-r--r--compilerplugins/clang/test/stringconcatauto.cxx56
-rw-r--r--compilerplugins/clang/test/stringconcatliterals.cxx67
-rw-r--r--compilerplugins/clang/test/stringconstant.cxx134
-rw-r--r--compilerplugins/clang/test/stringliteraldefine.cxx56
-rw-r--r--compilerplugins/clang/test/stringliteralvar.cxx134
-rw-r--r--compilerplugins/clang/test/stringloop.cxx41
-rw-r--r--compilerplugins/clang/test/stringstatic.cxx29
-rw-r--r--compilerplugins/clang/test/stringstatic.hxx23
-rw-r--r--compilerplugins/clang/test/stringview-c++03.cxx21
-rw-r--r--compilerplugins/clang/test/stringview.cxx221
-rw-r--r--compilerplugins/clang/test/stringviewdangle.cxx37
-rw-r--r--compilerplugins/clang/test/stringviewparam.cxx98
-rw-r--r--compilerplugins/clang/test/stringviewvar.cxx65
-rw-r--r--compilerplugins/clang/test/trivialconstructor.cxx58
-rw-r--r--compilerplugins/clang/test/trivialdestructor.cxx57
-rw-r--r--compilerplugins/clang/test/typedefparam.cxx80
-rw-r--r--compilerplugins/clang/test/typeidcomparison.cxx41
-rw-r--r--compilerplugins/clang/test/unnecessarycatchthrow.cxx58
-rw-r--r--compilerplugins/clang/test/unnecessarylocking.cxx71
-rw-r--r--compilerplugins/clang/test/unnecessaryoverride-dtor.cxx137
-rw-r--r--compilerplugins/clang/test/unnecessaryoverride-dtor.hxx52
-rw-r--r--compilerplugins/clang/test/unnecessaryoverride.cxx196
-rw-r--r--compilerplugins/clang/test/unnecessaryparen.cxx143
-rw-r--r--compilerplugins/clang/test/unoany.cxx29
-rw-r--r--compilerplugins/clang/test/unoquery.cxx19
-rw-r--r--compilerplugins/clang/test/unreffun.cxx39
-rw-r--r--compilerplugins/clang/test/unreffun.hxx16
-rw-r--r--compilerplugins/clang/test/unsignedcompare.cxx16
-rw-r--r--compilerplugins/clang/test/unusedcapturedefault.cxx16
-rw-r--r--compilerplugins/clang/test/unusedenumconstants.cxx120
-rw-r--r--compilerplugins/clang/test/unusedfields.cxx382
-rw-r--r--compilerplugins/clang/test/unusedindex.cxx42
-rw-r--r--compilerplugins/clang/test/unusedmember.cxx238
-rw-r--r--compilerplugins/clang/test/unusedvariablecheck.cxx38
-rw-r--r--compilerplugins/clang/test/unusedvariablemore.cxx58
-rw-r--r--compilerplugins/clang/test/unusedvarsglobal.cxx24
-rw-r--r--compilerplugins/clang/test/useuniqueptr.cxx311
-rw-r--r--compilerplugins/clang/test/vclwidgets.cxx99
-rw-r--r--compilerplugins/clang/test/weakbase.cxx34
-rw-r--r--compilerplugins/clang/test/weakobject.cxx31
-rw-r--r--compilerplugins/clang/test/writeonlyvars.cxx168
-rw-r--r--compilerplugins/clang/test/xmlimport.cxx233
127 files changed, 9804 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..c8057a6f4
--- /dev/null
+++ b/compilerplugins/clang/test/bufferadd.cxx
@@ -0,0 +1,116 @@
+/* -*- 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");
+}
+void f6(OString const& s)
+{
+ // expected-error@+1 {{convert this append sequence into a *String + sequence [loplugin:bufferadd]}}
+ OUStringBuffer b("foo");
+ b.append(OStringToOUString(s, RTL_TEXTENCODING_ASCII_US));
+}
+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..0d9f01193
--- /dev/null
+++ b/compilerplugins/clang/test/buriedassign.cxx
@@ -0,0 +1,133 @@
+/* -*- 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(MyInt const&) = default;
+ 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();
+}
+}
+
+namespace test5
+{
+void main(OUString sUserAutoCorrFile, int* p2)
+{
+ OUString sRet;
+ int* p1;
+ if (sUserAutoCorrFile == "yyy" && (p1 = p2))
+ sRet = sUserAutoCorrFile;
+ if (sUserAutoCorrFile == "yyy" && nullptr != (p1 = p2))
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if (nullptr != (p1 = p2))
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if ((p1 = p2) != nullptr)
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if ((p1 = p2))
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if ((p1 = p2) && sUserAutoCorrFile == "yyy")
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if ((p1 = p2) || sUserAutoCorrFile == "yyy")
+ sRet = sUserAutoCorrFile;
+ // expected-error@+1 {{buried assignment, rather put on own line [loplugin:buriedassign]}}
+ if ((p1 = p2) && sUserAutoCorrFile == "yyy")
+ sRet = sUserAutoCorrFile;
+ (void)sRet;
+}
+}
+
+/* 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..3d8c22b49
--- /dev/null
+++ b/compilerplugins/clang/test/casttovoid.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/.
+ */
+
+#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]}}
+}
+
+// Don't trigger assert in CastToVoid::VisitReturnStmt:
+int n = [] { return 0; }();
+
+int f() {
+ int n1 = n;
+ int n2 = [](int const & n) -> int const & {
+ (void) n; // expected-error {{unnecessary cast to void [loplugin:casttovoid]}}
+ return n; // expected-note {{first consumption is here [loplugin:casttovoid]}}
+ }(n1);
+ return n2;
+}
+
+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;
+ int volatile n9 = 0;
+ (void) n9;
+ 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..c044ee324
--- /dev/null
+++ b/compilerplugins/clang/test/conditionalstring.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 <rtl/ustring.hxx>
+
+void f(OUString s, bool b)
+{
+ // expected-error@+2 {{replace 2nd operand of conditional expression with `std::u16string_view` [loplugin:conditionalstring]}}
+ // expected-note@+1 {{conditional expression is here [loplugin:conditionalstring]}}
+ s += (b ? OUString("a") : throw 0);
+ // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `std::u16string_view` [loplugin:conditionalstring]}}
+ b = (b ? ("x") : (OUString(("y")))) == s;
+ // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `std::u16string_view` [loplugin:conditionalstring]}}
+ b = operator==(s, b ? OUString("x") : OUString("y"));
+ // expected-error@+1 {{replace both 2nd and 3rd operands of conditional expression with `std::u16string_view` [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..e6b22ca91
--- /dev/null
+++ b/compilerplugins/clang/test/constparams.cxx
@@ -0,0 +1,73 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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");
+}
+
+
+namespace test5
+{
+struct Rectangle {};
+
+struct Foo
+{
+ void CallConst(const Rectangle*);
+ void CallNonConst(Rectangle*);
+ // expected-error@+1 {{this parameter can be const test5::Foo::ImplInvalidateParentFrameRegion [loplugin:constparams]}}
+ void ImplInvalidateParentFrameRegion( Rectangle& rRegion )
+ {
+ CallConst( &rRegion );
+ }
+ // no warning expected
+ void ImplInvalidateParentFrameRegion2( Rectangle& rRegion )
+ {
+ CallNonConst( &rRegion );
+ }
+};
+
+}
+/* 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..4fe41a814
--- /dev/null
+++ b/compilerplugins/clang/test/consttobool.cxx
@@ -0,0 +1,70 @@
+/* -*- 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 '{{(std::)?}}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);
+
+#if !defined NDEBUG
+ 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");
+#endif
+}
+
+/* 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..88df50f8e
--- /dev/null
+++ b/compilerplugins/clang/test/constvars.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/.
+ */
+
+#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/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);
+ }
+}
+};
+
+// no warning expected
+namespace test6
+{
+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..020cdbb68
--- /dev/null
+++ b/compilerplugins/clang/test/convertlong.cxx
@@ -0,0 +1,42 @@
+/* -*- 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;
+ (void)tmp2;
+
+ 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/cow_wrapper.cxx b/compilerplugins/clang/test/cow_wrapper.cxx
new file mode 100644
index 000000000..5c95f87f0
--- /dev/null
+++ b/compilerplugins/clang/test/cow_wrapper.cxx
@@ -0,0 +1,44 @@
+/* -*- 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 "o3tl/cow_wrapper.hxx"
+#include <utility>
+
+struct ImplBitmapPalette
+{
+ void foo() const;
+};
+
+struct BitmapPalette
+{
+ void foo1()
+ {
+ // expected-error@+1 {{calling const method on o3tl::cow_wrapper impl class via non-const pointer, rather use std::as_const to prevent triggering an unnecessary copy [loplugin:cow_wrapper]}}
+ mpImpl->foo();
+ }
+ void foo2() const
+ {
+ // no error expected
+ mpImpl->foo();
+ }
+ void foo3()
+ {
+ // expected-error@+1 {{calling const method on o3tl::cow_wrapper impl class via non-const pointer, rather use std::as_const to prevent triggering an unnecessary copy [loplugin:cow_wrapper]}}
+ (*mpImpl).foo();
+ }
+ void foo4()
+ {
+ // expected-error@+1 {{calling const method on o3tl::cow_wrapper impl class via non-const pointer, rather use std::as_const to prevent triggering an unnecessary copy [loplugin:cow_wrapper]}}
+ std::as_const(*mpImpl).foo();
+ }
+ o3tl::cow_wrapper<ImplBitmapPalette> mpImpl;
+};
+
+/* 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..48bea83f6
--- /dev/null
+++ b/compilerplugins/clang/test/cppunitassertequals.cxx
@@ -0,0 +1,75 @@
+/* -*- 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,"");
+ 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]}}
+ CPPUNIT_ASSERT(b1 == b2); // expected-error {{rather call CPPUNIT_ASSERT_EQUAL when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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 when comparing 'const rtl::OUString' and 'const rtl::OUString' (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 when comparing 'const rtl::OUString' and 'const rtl::OUString' (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 when comparing 'const rtl::OUString' and 'const rtl::OUString' (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 when comparing 'const rtl::OUString' and 'const rtl::OUString' (or rewrite as an explicit operator == call when the operator itself is the topic) [loplugin:cppunitassertequals]}}
+ TEST1; // expected-error {{rather call CPPUNIT_ASSERT_EQUAL when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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 when comparing 'bool' and 'bool' (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-re {{rather call CPPUNIT_ASSERT_EQUAL when comparing 'std::nullptr_t'{{( \(aka 'nullptr_t'\))?}} and '{{(std::)?}}nullptr_t' (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..2448d64e9
--- /dev/null
+++ b/compilerplugins/clang/test/cppunitassertequals.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#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);
+
+/* 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..8d212700a
--- /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-re@+1 {{Function-style cast from 'void *' to 'sal_IntPtr' (aka '{{.+}}') (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..ef8722d5c
--- /dev/null
+++ b/compilerplugins/clang/test/datamembershadow.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 <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..12763d966
--- /dev/null
+++ b/compilerplugins/clang/test/doubleconvert.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"
+#include "tools/color.hxx"
+
+int main()
+{
+ constexpr Color col1;
+ Color col2;
+ col2 = sal_Int32(
+ col1); // expected-error@-1 {{redundant double conversion [loplugin:doubleconvert]}}
+ (void)col2;
+ // expected-error@+1 {{redundant double conversion [loplugin:doubleconvert]}}
+ Color col3 = sal_Int32(Color());
+ (void)col3;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/elidestringvar.cxx b/compilerplugins/clang/test/elidestringvar.cxx
new file mode 100644
index 000000000..0b2164472
--- /dev/null
+++ b/compilerplugins/clang/test/elidestringvar.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 "sal/config.h"
+
+#include "rtl/ustring.hxx"
+
+template <sal_Unicode C> OUString f(sal_Unicode c, int n)
+{
+ OUString s0(C);
+ OUString s1(c);
+ // expected-note@+1 {{literal 'rtl::OUString' variable defined here [loplugin:elidestringvar]}}
+ OUString s2('a');
+ // expected-note@+1 {{literal 'rtl::OUString' variable defined here [loplugin:elidestringvar]}}
+ OUString s3(u'a');
+ static constexpr OUStringLiteral s4lit(u"a");
+ // expected-note@+1 {{literal 'rtl::OUString' variable defined here [loplugin:elidestringvar]}}
+ OUString s4 = s4lit;
+ switch (n)
+ {
+ case 0:
+ return s0;
+ case 1:
+ return s1;
+ case 2:
+ // expected-error@+1 {{replace single use of literal 'rtl::OUString' variable with a literal [loplugin:elidestringvar]}}
+ return s2;
+ case 3:
+ // expected-error@+1 {{replace single use of literal 'rtl::OUString' variable with a literal [loplugin:elidestringvar]}}
+ return s3;
+ default:
+ // expected-error@+1 {{replace single use of literal 'rtl::OUString' variable with a literal [loplugin:elidestringvar]}}
+ return s4;
+ }
+}
+
+// Trigger clang-cl to actually parse f under MSVC template instantiation model:
+template OUString f<'a'>(sal_Unicode, int);
+
+/* 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..23d3e2652
--- /dev/null
+++ b/compilerplugins/clang/test/expressionalwayszero.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 <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]}}
+ (void)v5;
+}
+/* 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..77bb53c6b
--- /dev/null
+++ b/compilerplugins/clang/test/external.cxx
@@ -0,0 +1,195 @@
+/* -*- 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>
+
+#include "external.hxx"
+
+int n0; // no warning, see external.hxx
+
+// 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
+
+static int n4; // no warning, internal linkage
+
+// expected-note@+1 {{another declaration is here [loplugin:external]}}
+extern int n5;
+// expected-error@+1 {{externally available entity 'n5' 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 n5;
+
+// expected-note@+1 {{another declaration is here [loplugin:external]}}
+extern "C" int n6;
+// expected-error@+1 {{externally available entity 'n6' 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 n6;
+
+extern "C" {
+// expected-error@+1 {{externally available entity 'n7' 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 n7;
+}
+
+namespace
+{
+int u1; // no warning, internal linkage
+
+static int u2; // no warning, internal linkage
+
+extern "C" int u3;
+int u3; // no warning, see the comment about DR1113 in compilerplugins/clang/external.cxx
+
+extern "C" {
+int u4; // no warning, internal linkage
+}
+}
+
+namespace N
+{
+int v1; // no warning, see external.hxx
+
+// expected-error@+1 {{externally available entity 'v2' 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 v2;
+
+static int v3; // no warning, internal linkage
+}
+
+struct S
+{
+ static int f()
+ {
+ static int s = 0;
+ return s;
+ }
+
+ static int m;
+};
+
+int S::m = 0; // no warning
+
+int f(int a) // no warning about parameters
+{
+ static int s = 0; // no warning about local static variables
+ ++s;
+ int b = a + s; // no warning about local variables
+ return b;
+}
+
+// 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-re@+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-re@+1 {{a function associating 'N{{(::I1)?}}::E' is declared here [loplugin:external]}}
+void f(E const*);
+
+extern "C++" {
+// expected-note-re@+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-re@+1 {{a function associating 'N{{(::I1)?}}::E' is declared here [loplugin:external]}}
+void f3(E);
+
+inline namespace I3
+{
+// expected-note-re@+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;
+ (void)n4;
+ (void)u1;
+ (void)u2;
+ (void)N::v3;
+ 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/external.hxx b/compilerplugins/clang/test/external.hxx
new file mode 100644
index 000000000..40e8d55c0
--- /dev/null
+++ b/compilerplugins/clang/test/external.hxx
@@ -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/.
+ */
+
+#pragma once
+
+extern int n0;
+
+namespace N
+{
+extern int v1;
+}
+
+struct S;
+
+int f(int a);
+
+/* 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..144bf4a28
--- /dev/null
+++ b/compilerplugins/clang/test/fakebool.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 <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_); }
+};
+
+namespace {
+
+struct S4 {
+ sal_Bool b;
+};
+
+}
+
+void f() {
+ sal_Bool b;
+ (void) &b;
+ (void) &S4::b;
+}
+
+/* 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..976d39c25
--- /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__ || defined _MSC_VER)
+#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..122ee363a
--- /dev/null
+++ b/compilerplugins/clang/test/implicitboolconversion.cxx
@@ -0,0 +1,83 @@
+/* -*- 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 <array>
+#include <atomic>
+#include <initializer_list>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <sal/types.h>
+
+template <typename T> struct Sequence
+{
+ Sequence(std::initializer_list<T>);
+};
+
+template <typename T> struct Wrap1
+{
+ T element;
+};
+
+template <typename T> struct Wrap2
+{
+ Wrap2(T const& e)
+ : element(e)
+ {
+ }
+ T element;
+};
+
+bool g();
+
+void h(bool);
+
+void f()
+{
+ // expected-error@+1 {{implicit conversion (IntegralCast) from 'bool' to 'int' [loplugin:implicitboolconversion]}}
+ int i = false;
+ // expected-error@+1 {{implicit conversion (IntegralCast) from 'bool' to 'int' [loplugin:implicitboolconversion]}}
+ i = true;
+ (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;
+ bool b2 = true;
+ b2 &= g();
+ (void)b2;
+ Sequence<sal_Bool> s1{ false };
+ (void)s1;
+ Sequence<Sequence<sal_Bool>> s2{ { false } };
+ (void)s2;
+ // expected-error@+1 {{implicit conversion (IntegralCast) from 'bool' to 'const int' [loplugin:implicitboolconversion]}}
+ Sequence<int> s3{ false };
+ (void)s3;
+ // expected-error@+1 {{implicit conversion (IntegralCast) from 'bool' to 'const int' [loplugin:implicitboolconversion]}}
+ Sequence<Sequence<int>> s4{ { false } };
+ (void)s4;
+ Wrap1<sal_Bool> w1{ false };
+ Sequence<Wrap1<sal_Bool>> s5{ { false } };
+ (void)s5;
+ Wrap2<sal_Bool> w2{ false };
+ (void)w2;
+ Sequence<Wrap2<sal_Bool>> s6{ { false } };
+ (void)s6;
+ h(w1.element);
+ css::uno::Sequence<sal_Bool> s7(1);
+ h(s7[0]);
+ std::array<sal_Bool, 1> s8;
+ s8[0] = false;
+}
+
+/* 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..1c57c6cee
--- /dev/null
+++ b/compilerplugins/clang/test/indentation.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/.
+ */
+
+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)
+ { // expected-note {{start brace here [loplugin:indentation]}}
+ foo();
+ } // expected-error {{start and end brace not aligned [loplugin:indentation]}}
+
+ if (x) // expected-note {{statement beginning here [loplugin:indentation]}}
+ { // expected-error {{start brace not aligned with beginning of parent statement [loplugin:indentation]}}
+ 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();
+}
+
+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]}}
+}
+
+void xxx();
+void test5(bool x)
+{
+ if (x)
+ {
+ xxx(); // expected-error {{body inside brace not indented [loplugin:indentation]}}
+ }
+}
+
+
+/* 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..d6c3cbdac
--- /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 {{.*}}'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 {{.*}}'unique_ptr<int>'{{.*}} [loplugin:makeshared]}}
+ x = std::make_unique<int>(1);
+ (void)x;
+
+ // expected-error-re@+1 {{rather use make_shared than constructing from {{.*}}'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{{.*}}>') [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{{.*}}>') [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/moveit.cxx b/compilerplugins/clang/test/moveit.cxx
new file mode 100644
index 000000000..06424a6d9
--- /dev/null
+++ b/compilerplugins/clang/test/moveit.cxx
@@ -0,0 +1,60 @@
+/* -*- 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 <memory>
+
+// expected-note@+3 {{type declared here [loplugin:moveit]}}
+// expected-note@+2 {{type declared here [loplugin:moveit]}}
+// expected-note@+1 {{type declared here [loplugin:moveit]}}
+struct Movable
+{
+ std::shared_ptr<int> x;
+};
+
+namespace test1
+{
+struct F
+{
+ // expected-note@+1 {{passing to this param [loplugin:moveit]}}
+ void call_by_value(Movable);
+ // expected-note@+1 {{passing to this param [loplugin:moveit]}}
+ F(Movable);
+ void foo()
+ {
+ // expected-note@+2 {{local var declared here [loplugin:moveit]}}
+ // expected-note@+1 {{local var declared here [loplugin:moveit]}}
+ Movable m;
+ // expected-error@+1 {{can std::move this var into this param [loplugin:moveit]}}
+ call_by_value(m);
+ // expected-error@+1 {{can std::move this var into this param [loplugin:moveit]}}
+ F a(m);
+ (void)a;
+ }
+};
+}
+
+namespace test2
+{
+struct F
+{
+ // expected-note@+1 {{passing to this param [loplugin:moveit]}}
+ F(Movable);
+ void foo()
+ {
+ // expected-note@+1 {{local var declared here [loplugin:moveit]}}
+ Movable m;
+ // expected-error@+1 {{can std::move this var into this param [loplugin:moveit]}}
+ F a(m);
+ (void)a;
+ }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/moveparam.cxx b/compilerplugins/clang/test/moveparam.cxx
new file mode 100644
index 000000000..4e3df5b9c
--- /dev/null
+++ b/compilerplugins/clang/test/moveparam.cxx
@@ -0,0 +1,60 @@
+/* -*- 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 "o3tl/cow_wrapper.hxx"
+#include <map>
+
+namespace drawinglayer::primitive2d
+{
+class Primitive2DContainer
+{
+};
+}
+
+struct Foo
+{
+ drawinglayer::primitive2d::Primitive2DContainer maMine;
+
+ // expected-error@+2 {{rather use move && param3 [loplugin:moveparam]}}
+ Foo(drawinglayer::primitive2d::Primitive2DContainer const& rContainer)
+ : maMine(rContainer)
+ {
+ }
+
+ // no warning expected
+ Foo(drawinglayer::primitive2d::Primitive2DContainer&& rContainer)
+ : maMine(rContainer)
+ {
+ }
+
+ void foo1(const drawinglayer::primitive2d::Primitive2DContainer& rContainer)
+ {
+ // expected-error@+1 {{rather use move && param1 [loplugin:moveparam]}}
+ maMine = rContainer;
+ }
+};
+
+namespace test2
+{
+typedef std::map<int, int> Map2Map;
+
+struct Foo
+{
+ Map2Map maMine;
+
+ // expected-error@+2 {{rather use move && param3 [loplugin:moveparam]}}
+ Foo(Map2Map const& rContainer)
+ : maMine(rContainer)
+ {
+ }
+};
+}
+
+/* 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/noexcept.cxx b/compilerplugins/clang/test/noexcept.cxx
new file mode 100644
index 000000000..f46a3d87f
--- /dev/null
+++ b/compilerplugins/clang/test/noexcept.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/.
+ */
+
+// expected-error@+1 {{Replace legacy dynamic 'throw ()' exception specification with 'noexcept' [loplugin:noexcept]}}
+void f() throw();
+
+// expected-error@+1 {{Replace legacy dynamic 'throw ()' exception specification with 'noexcept' [loplugin:noexcept]}}
+using F = void() throw();
+
+/* 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..c0742c828
--- /dev/null
+++ b/compilerplugins/clang/test/noexceptmove.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/.
+ */
+
+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;
+ }
+};
+};
+
+/* 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/optmove.cxx b/compilerplugins/clang/test/optmove.cxx
new file mode 100644
index 000000000..976806772
--- /dev/null
+++ b/compilerplugins/clang/test/optmove.cxx
@@ -0,0 +1,53 @@
+/* -*- 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 <vector>
+
+namespace test1
+{
+void foo1(std::vector<int> x)
+{
+ std::vector<int> y;
+ // expected-error@+1 {{can std::move value instead of copy [loplugin:optmove]}}
+ y = x;
+}
+}
+
+namespace test2
+{
+void foo(std::vector<int> x)
+{
+ // expected-error@+1 {{can std::move value instead of copy [loplugin:optmove]}}
+ std::vector<int> y = x;
+}
+}
+
+namespace test3
+{
+void foo1(std::vector<int> x)
+{
+ std::vector<int> y, z;
+ y = x;
+ // expected-error@+1 {{can std::move value instead of copy [loplugin:optmove]}}
+ z = x;
+}
+}
+
+namespace test4
+{
+void foo1(std::vector<int> x)
+{
+ std::vector<int> y;
+ // no warning expected, don't even try to follow loop
+ for (int i = 0; i < 10; i++)
+ y = x;
+}
+}
+
+/* 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..7d0023037
--- /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/overridevirtual.cxx b/compilerplugins/clang/test/overridevirtual.cxx
new file mode 100644
index 000000000..0f11d86b1
--- /dev/null
+++ b/compilerplugins/clang/test/overridevirtual.cxx
@@ -0,0 +1,44 @@
+/* -*- 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
+{
+ // expected-note@+1 {{overridden declaration is here [loplugin:overridevirtual]}}
+ virtual ~S1();
+};
+
+struct S2 : S1
+{
+ // expected-error@+1 {{overriding virtual function declaration not marked 'override' [loplugin:overridevirtual]}}
+ ~S2();
+};
+
+template <typename> struct T1
+{
+ virtual ~T1();
+};
+
+template <typename T> struct T2 : T1<T>
+{
+ ~T2();
+};
+
+template <typename> struct U1
+{
+ // expected-note@+1 {{overridden declaration is here [loplugin:overridevirtual]}}
+ virtual ~U1();
+};
+
+template <typename T> struct U2 : U1<int>
+{
+ // expected-error@+1 {{overriding virtual function declaration not marked 'override' [loplugin:overridevirtual]}}
+ ~U2();
+};
+
+/* 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..010556a67
--- /dev/null
+++ b/compilerplugins/clang/test/passparamsbyref.cxx
@@ -0,0 +1,42 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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..d90d6f05b
--- /dev/null
+++ b/compilerplugins/clang/test/passstuffbyref.cxx
@@ -0,0 +1,84 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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..fcb4a9a31
--- /dev/null
+++ b/compilerplugins/clang/test/pointerbool.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 <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]);
+}
+
+void func_bool2(bool); // expected-note {{method here [loplugin:pointerbool]}}
+
+template <typename... Args> void func_bool_via_forward_template(Args&&... args)
+{
+ // expected-error@+1 {{possibly unwanted implicit conversion when calling bool param [loplugin:pointerbool]}}
+ func_bool2(std::forward<Args>(args)...);
+}
+
+void test2(int p1)
+{
+ // expected-note@+1 {{instantiated from here [loplugin:pointerbool]}}
+ func_bool_via_forward_template(p1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/putpoolitem.cxx b/compilerplugins/clang/test/putpoolitem.cxx
new file mode 100644
index 000000000..fb44612a0
--- /dev/null
+++ b/compilerplugins/clang/test/putpoolitem.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 <memory>
+
+class SfxPoolItem
+{
+public:
+ virtual ~SfxPoolItem();
+};
+class SfxPoolItemSubclass : public SfxPoolItem
+{
+};
+class SfxItemSet
+{
+public:
+ void Put(SfxPoolItem&);
+};
+
+void foo(SfxItemSet* pSet)
+{
+ std::unique_ptr<SfxPoolItemSubclass> foo;
+ SfxItemSet aSet;
+ // expected-error@+1 {{could use std::move? [loplugin:putpoolitem]}}
+ aSet.Put(*foo);
+
+ // expected-error@+1 {{could use std::move? [loplugin:putpoolitem]}}
+ pSet->Put(*foo);
+}
+
+class Foo2
+{
+ std::unique_ptr<SfxPoolItemSubclass> m_foo;
+ void foo()
+ {
+ SfxItemSet aSet;
+ // no warning expected
+ aSet.Put(*m_foo);
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/reducevarscope.cxx b/compilerplugins/clang/test/reducevarscope.cxx
new file mode 100644
index 000000000..ca4ed09be
--- /dev/null
+++ b/compilerplugins/clang/test/reducevarscope.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 <rtl/ustring.hxx>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+void test1()
+{
+ int i = 2; // expected-error {{can reduce scope of var [loplugin:reducevarscope]}}
+ {
+ i = 3; // expected-note {{used here [loplugin:reducevarscope]}}
+ }
+ int j = 2; // expected-error {{can reduce scope of var [loplugin:reducevarscope]}}
+ {
+ j = 3; // expected-note {{used here [loplugin:reducevarscope]}}
+ {
+ j = 4; // expected-note {{used here [loplugin:reducevarscope]}}
+ }
+ }
+}
+
+// negative test - seen inside a loop
+void test2()
+{
+ int i = 2;
+ for (int j = 1; j < 10; ++j)
+ {
+ i = 3;
+ }
+}
+
+// negative test - initial assignment from non-constant
+void test3()
+{
+ int j = 1;
+ int i = j;
+ {
+ i = 3;
+ }
+}
+
+// negative test
+void test4()
+{
+ int i = 2;
+ {
+ i = 3;
+ }
+ i = 4;
+}
+
+// negative test
+void test5()
+{
+ int i = 2;
+ i = 3;
+}
+
+// negative test - seen in 2 child blocks
+void test6()
+{
+ int i;
+ {
+ i = 3;
+ }
+ {
+ i = 3;
+ }
+}
+
+// TODO negative test - storing pointer to OUString data
+// void test7()
+// {
+// OUString s;
+// const sal_Unicode* p = nullptr;
+// {
+// p = s.getStr();
+// }
+// auto p2 = p;
+// (void)p2;
+// }
+
+// negative test - passing var into lambda
+void test8()
+{
+ int i;
+ auto l1 = [&]() { i = 1; };
+ (void)l1;
+}
+
+/* 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..7a102cca5
--- /dev/null
+++ b/compilerplugins/clang/test/redundantcast.cxx
@@ -0,0 +1,458 @@
+/* -*- 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-re {{redundant static_cast/const_cast combination from '{{(std::)?}}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());
+}
+
+int & testReturnStaticCast(int && x) { return static_cast<int &>(x); }
+
+void testFunctionalCast() {
+ (void) int(nir()); // expected-error {{redundant functional cast from 'int' to 'int' [loplugin:redundantcast]}}
+ (void) S(nsr());
+}
+
+void testCStyleCast() {
+ Enum1 e = (Enum1)Enum1::X; // expected-error {{redundant cstyle cast from 'Enum1' to 'Enum1' [loplugin:redundantcast]}}
+ (void)e;
+}
+
+template<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 testReinterpretCast() {
+ int * p;
+ (void) reinterpret_cast<int *>(p); // expected-error {{redundant reinterpret_cast from 'int *' to 'int *' [loplugin:redundantcast]}}
+}
+
+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;
+ S3 * s3 = nullptr;
+
+ (void) dynamic_cast<S2 *>(s1);
+ (void) dynamic_cast<S1 *>(s2); // expected-error {{redundant dynamic upcast from 'S2 *' to 'S1 *' [loplugin:redundantcast]}}
+ (void) dynamic_cast<S2 *>(s2); // expected-error {{redundant dynamic cast from 'S2 *' to 'S2 *' [loplugin:redundantcast]}}
+ (void) dynamic_cast<S3 *>(s2);
+ (void) dynamic_cast<const S2 *>(s2); // expected-error {{redundant dynamic cast from 'S2 *' to 'const S2 *' [loplugin:redundantcast]}}
+ (void) dynamic_cast<S1 *>(s3); // expected-error {{redundant dynamic upcast from 'S3 *' to 'S1 *' [loplugin:redundantcast]}}
+}
+
+void overload(int);
+void overload(long);
+void nonOverload();
+
+struct Overload {
+ int overload();
+ long overload() const;
+ void nonOverload();
+};
+
+void testOverloadResolution() {
+ (void) static_cast<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-re {{redundant static_cast from 'const char{{ ?}}[1]' to 'const char *' [loplugin:redundantcast]}}
+ (void) reinterpret_cast<char const *>(""); // expected-error-re {{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);
+ testReinterpretCast();
+ 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..0afab0c2d
--- /dev/null
+++ b/compilerplugins/clang/test/redundantcast.hxx
@@ -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/.
+ */
+
+#pragma once
+
+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();
+
+/* 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..20c939cb2
--- /dev/null
+++ b/compilerplugins/clang/test/redundantfcast.cxx
@@ -0,0 +1,224 @@
+/* -*- 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]}}
+ (void)s2;
+
+ 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' in construct expression [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 "("...")"
+}
+}
+
+namespace test8
+{
+class Primitive2DContainer
+{
+};
+struct GroupPrimitive
+{
+ GroupPrimitive(Primitive2DContainer&&);
+};
+
+const Primitive2DContainer& getChildren();
+
+void foo()
+{
+ // no warning expected, we have to create a temporary for this constructor
+ GroupPrimitive aGroup((Primitive2DContainer(getChildren())));
+ (void)aGroup;
+}
+}
+/* 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..9b1460d58
--- /dev/null
+++ b/compilerplugins/clang/test/redundantinline.hxx
@@ -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/.
+ */
+
+#pragma once
+
+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; }
+
+/* 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..7ab830fc9
--- /dev/null
+++ b/compilerplugins/clang/test/refcounting.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 <sal/config.h>
+
+#include <memory>
+#include <rtl/ref.hxx>
+#include <boost/intrusive_ptr.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+
+namespace cppu
+{
+class OWeakObject
+{
+public:
+ void acquire();
+ void release();
+};
+}
+
+struct UnoObject : public cppu::OWeakObject
+{
+};
+struct UnoSubObject : public UnoObject
+{
+};
+
+//
+// Note, getting duplicate warnings for some reason I cannot fathom
+//
+
+struct Foo
+{
+ // expected-error@+2 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ std::unique_ptr<UnoObject> m_foo1;
+ // expected-error@+2 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ std::shared_ptr<UnoObject> m_foo2;
+ // expected-error@+2 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ boost::intrusive_ptr<UnoObject> m_foo3;
+ rtl::Reference<UnoObject> m_foo4; // no warning expected
+};
+
+// expected-error@+2 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+// expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+std::unique_ptr<UnoObject> foo1();
+rtl::Reference<UnoObject> foo2(); // no warning expected
+// expected-error@+2 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+// expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via smart pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+void foo3(std::unique_ptr<UnoObject> p);
+
+void test2(UnoObject* pUnoObject)
+{
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being deleted via delete, should be managed via rtl::Reference [loplugin:refcounting]}}
+ delete pUnoObject;
+}
+
+template <typename T> struct Dependent : T
+{
+ void f() { delete this; }
+ //TODO: missing expected error@+1 {{cppu::OWeakObject subclass 'Dependent<UnoObject>' being deleted via delete, should be managed via rtl::Reference [loplugin:refcounting]}}
+ void g() { delete this; }
+};
+struct Dummy
+{
+};
+void dummy(Dependent<Dummy>* p1, Dependent<UnoObject>* p2)
+{
+ p1->f();
+ p2->g();
+}
+
+void foo4()
+{
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via raw pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ UnoObject* p = new UnoObject;
+ (void)p;
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoObject' being managed via raw pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ p = new UnoObject;
+}
+
+UnoObject* foo5()
+{
+ // expected-error@+1 {{new object of cppu::OWeakObject subclass 'UnoObject' being returned via raw pointer, should be returned by via rtl::Reference [loplugin:refcounting]}}
+ return new UnoObject;
+}
+rtl::Reference<UnoObject> foo6()
+{
+ // no warning expected
+ return new UnoObject;
+}
+const rtl::Reference<UnoObject>& getConstRef();
+void foo7()
+{
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoSubObject' being managed via raw pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ UnoSubObject* p1 = static_cast<UnoSubObject*>(foo6().get());
+ (void)p1;
+ // expected-error@+1 {{cppu::OWeakObject subclass 'UnoSubObject' being managed via raw pointer, should be managed via rtl::Reference [loplugin:refcounting]}}
+ p1 = static_cast<UnoSubObject*>(foo6().get());
+
+ rtl::Reference<UnoObject> u2;
+ // no warning expected
+ UnoSubObject* p2 = static_cast<UnoSubObject*>(u2.get());
+ (void)p2;
+ p2 = static_cast<UnoSubObject*>(u2.get());
+ // no warning expected
+ UnoSubObject* p3 = static_cast<UnoSubObject*>(getConstRef().get());
+ (void)p3;
+ p3 = static_cast<UnoSubObject*>(getConstRef().get());
+}
+
+/* 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..1f3480dbe
--- /dev/null
+++ b/compilerplugins/clang/test/referencecasting.cxx
@@ -0,0 +1,212 @@
+/* -*- 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/Sequence.hxx"
+#include "com/sun/star/uno/XInterface.hpp"
+#include "com/sun/star/io/XStreamListener.hpp"
+#include "com/sun/star/io/XInputStream.hpp"
+#include "com/sun/star/lang/XTypeProvider.hpp"
+#include "com/sun/star/lang/XComponent.hpp"
+#include "cppuhelper/implbase.hxx"
+#include "cppuhelper/weak.hxx"
+#include "rtl/ref.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);
+ // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}}
+ auto c = css::uno::Reference<css::lang::XEventListener>::query(a);
+}
+
+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);
+}
+
+class FooStream : public css::io::XStreamListener
+{
+ virtual ~FooStream();
+};
+void test(rtl::Reference<FooStream> l)
+{
+ // expected-error@+1 {{unnecessary get() call [loplugin:referencecasting]}}
+ css::uno::Reference<css::io::XStreamListener> a(l.get());
+ // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}}
+ a.set(l.get(), css::uno::UNO_QUERY);
+ // expected-error@+1 {{unnecessary get() call [loplugin:referencecasting]}}
+ a.set(l.get());
+ // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}}
+ css::uno::Reference<css::io::XStreamListener> b(l.get(), css::uno::UNO_QUERY);
+ // no warning expected
+ css::uno::Reference<css::lang::XTypeProvider> c(l.get(), css::uno::UNO_QUERY);
+ // no warning expected
+ css::uno::Reference<css::io::XStreamListener> a2 = l;
+ (void)a2;
+}
+css::uno::Sequence<css::uno::Reference<css::io::XStreamListener>> getContinuations()
+{
+ rtl::Reference<FooStream> noel1;
+ // expected-error@+1 {{unnecessary get() call [loplugin:referencecasting]}}
+ return { noel1.get() };
+}
+}
+
+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);
+ }
+}
+
+namespace test15
+{
+class Foo : public cppu::WeakImplHelper<css::lang::XComponent, css::io::XInputStream>
+{
+ virtual ~Foo();
+ css::uno::Reference<css::lang::XTypeProvider> bar()
+ {
+ // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}}
+ return css::uno::Reference<css::lang::XTypeProvider>(
+ static_cast<css::lang::XTypeProvider*>(this), css::uno::UNO_QUERY);
+ }
+ css::uno::Reference<css::io::XInputStream> bar2()
+ {
+ // expected-error@+1 {{the source reference is already a subtype of the destination reference, just use = [loplugin:referencecasting]}}
+ return css::uno::Reference<css::io::XInputStream>(static_cast<css::io::XInputStream*>(this),
+ 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..a4464cee6
--- /dev/null
+++ b/compilerplugins/clang/test/salcall.cxx
@@ -0,0 +1,188 @@
+/* -*- 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]}}
+
+void SAL_CALL f0() {} // expected-error {{SAL_CALL unnecessary here [loplugin:salcall]}}
+
+void SAL_CALL f1() {}
+
+void SAL_CALL f2() {}
+
+void SAL_CALL f3() {}
+
+void SAL_CALL f4() {}
+
+typedef void SAL_CALL (*Ptr)();
+
+void takePtr(Ptr);
+
+void usePtr()
+{
+ f0();
+ takePtr(f1);
+ takePtr(&f2);
+ Ptr p = f3;
+ takePtr(p);
+ p = f4;
+ takePtr(p);
+}
+
+#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..91bc224e7
--- /dev/null
+++ b/compilerplugins/clang/test/salunicodeliteral.hxx
@@ -0,0 +1,14 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+void test();
+
+/* 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/sequentialassign.cxx b/compilerplugins/clang/test/sequentialassign.cxx
new file mode 100644
index 000000000..b7182db5c
--- /dev/null
+++ b/compilerplugins/clang/test/sequentialassign.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 <rtl/ustring.hxx>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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/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..2980003e1
--- /dev/null
+++ b/compilerplugins/clang/test/simplifypointertobool.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 <memory>
+#include "com/sun/star/uno/XInterface.hpp"
+
+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();
+ // expected-error@+3 {{simplify, drop the get() and turn the surrounding parentheses into a functional cast to bool [loplugin:simplifypointertobool]}}
+ // expected-note@+1 {{surrounding parentheses here [loplugin:simplifypointertobool]}}
+ 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();
+ // expected-error@+1 {{simplify, convert to '!x' [loplugin:simplifypointertobool]}}
+ if (p.get() == nullptr)
+ foo();
+ // TODOexpected-error@+1 {{simplify, convert to '!x' [loplugin:simplifypointertobool]}}
+ if (p == nullptr)
+ foo();
+ // TODOexpected-error@+1 {{simplify, convert to 'x' [loplugin:simplifypointertobool]}}
+ if (p != nullptr)
+ foo();
+ // expected-error@+1 {{simplify, convert to '!x' [loplugin:simplifypointertobool]}}
+ if (nullptr == p.get())
+ foo();
+ // expected-error@+1 {{simplify, convert to 'x' [loplugin:simplifypointertobool]}}
+ if (p.get() != nullptr)
+ foo();
+ // expected-error@+1 {{simplify, convert to 'x' [loplugin:simplifypointertobool]}}
+ if (nullptr != p.get())
+ foo();
+}
+
+void test2(int* p)
+{
+ // TODOexpected-error@+1 {{simplify, convert to '!x' [loplugin:simplifypointertobool]}}
+ if (p == nullptr)
+ foo();
+ // TODOexpected-error@+1 {{simplify, convert to 'x' [loplugin:simplifypointertobool]}}
+ if (p != nullptr)
+ foo();
+}
+
+void test2(css::uno::Reference<css::uno::XInterface> const& p)
+{
+ // expected-error@+1 {{simplify, drop the get() [loplugin:simplifypointertobool]}}
+ if (p.get())
+ foo();
+ // expected-error@+1 {{simplify, convert to '!x' [loplugin:simplifypointertobool]}}
+ if (p.get() == nullptr)
+ 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/staticdynamic.cxx b/compilerplugins/clang/test/staticdynamic.cxx
new file mode 100644
index 000000000..aa6ca7559
--- /dev/null
+++ b/compilerplugins/clang/test/staticdynamic.cxx
@@ -0,0 +1,44 @@
+/* -*- 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() const {}
+};
+
+void f1(ClassA* p1)
+{
+ // expected-note@+1 {{static_cast here [loplugin:staticdynamic]}}
+ static_cast<ClassB*>(p1)->foo();
+ // expected-error@+1 {{dynamic_cast after static_cast [loplugin:staticdynamic]}}
+ dynamic_cast<ClassB*>(p1)->foo();
+};
+
+void f2(ClassA* p1)
+{
+ // expected-note@+1 {{dynamic_cast here [loplugin:staticdynamic]}}
+ dynamic_cast<ClassB*>(p1)->foo();
+ // expected-error@+1 {{static_cast after dynamic_cast [loplugin:staticdynamic]}}
+ static_cast<ClassB*>(p1)->foo();
+};
+
+void f3(ClassA* p1)
+{
+ // expected-note@+1 {{dynamic_cast here [loplugin:staticdynamic]}}
+ dynamic_cast<const ClassB*>(p1)->foo();
+ // expected-error@+1 {{static_cast after dynamic_cast [loplugin:staticdynamic]}}
+ static_cast<ClassB*>(p1)->foo();
+};
+
+/* 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..5c0a86fc4
--- /dev/null
+++ b/compilerplugins/clang/test/staticvar.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 <config_clang.h>
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+
+#include <string_view>
+
+struct S1
+{
+ int x, y;
+};
+
+S1 const& f1(int a)
+{
+ static S1 s1[]{
+ // expected-error@-1 {{var should be static const, or allowlisted [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
+{
+ std::u16string_view const cName;
+ bool const bCanBeVisible;
+};
+S4 const& f4()
+{
+ static const S4 s1[] = {
+ { std::u16string_view(u"/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..f76464b9a
--- /dev/null
+++ b/compilerplugins/clang/test/stringadd.cxx
@@ -0,0 +1,262 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-parameter"
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+// ---------------------------------------------------------------
+// += tests
+
+namespace test1
+{
+static const char XXX1[] = "xxx";
+static constexpr char16_t XXX1u[] = u"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-re@+2 {{rather use O[U]String::Concat than constructing 'rtl::OUStringLiteral<4>' from 'const char16_t{{ ?}}[4]' on LHS of + (where RHS is of type 'const char{{ ?}}[4]') [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ s2 += OUStringLiteral(XXX1u) + 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-re@+1 {{rather use O[U]String::Concat than 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 {{rather use O[U]String::Concat than 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);
+
+ OUStringBuffer buf;
+ // expected-error@+1 {{chained append, rather use single append call and + operator [loplugin:stringadd]}}
+ buf.append(" ").append(b);
+}
+void f2(char ch)
+{
+ OString s;
+ // expected-error-re@+1 {{rather use O[U]String::Concat than 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 {{rather use O[U]String::Concat than constructing 'rtl::OString' from 'char' on RHS of + (where LHS is of type 'rtl::OString') [loplugin:stringadd]}}
+ s = s + OString(ch);
+}
+}
+
+namespace test10
+{
+struct C
+{
+ OString constStringFunction(int) const;
+ OString nonConstStringFunction();
+ int constIntFunction() const;
+ int nonConstIntFunction();
+};
+
+C getC();
+
+void f1(C c)
+{
+ OString s;
+ // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ s += c.constStringFunction(c.constIntFunction());
+ s += c.constStringFunction(c.nonConstIntFunction());
+ s += c.nonConstStringFunction();
+ s += getC().constStringFunction(c.constIntFunction());
+}
+}
+
+/* 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..678d12dd6
--- /dev/null
+++ b/compilerplugins/clang/test/stringconcatauto.cxx
@@ -0,0 +1,56 @@
+/* -*- 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 {{.+}} 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 {{.+}} 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 {{.+}} will make it reference temporaries}}
+ // expected-note@-2 {{use OString instead}}
+ auto str5 = OUString::number(50);
+ (void)str1;
+ (void)str2;
+ (void)str3;
+ (void)str4;
+ (void)str5;
+}
+
+struct A
+{
+ auto bar()
+ // expected-error-re@-1 {{returning a variable of type {{.+}} will make it reference temporaries}}
+ // expected-note@-2 {{use OString instead}}
+ {
+ return "bar" + OString::number(110);
+ }
+ auto baz() { 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..8b390f28f
--- /dev/null
+++ b/compilerplugins/clang/test/stringconcatliterals.cxx
@@ -0,0 +1,67 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+#define FOO "foo"
+#define FOOu u"foo"
+
+void f(std::ostream& s1)
+{
+ static constexpr char foo[] = "foo";
+ static constexpr char16_t foou[] = u"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);
+ 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(u"foo");
+ // expected-error@-1 {{replace '+' between string literals with juxtaposition}}
+ s3 = "foo" + OUStringLiteral(FOOu);
+ // expected-error@-1 {{replace '+' between string literals with juxtaposition}}
+ s3 = "foo" + OUStringLiteral(foou);
+}
+
+/* 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..02f83b531
--- /dev/null
+++ b/compilerplugins/clang/test/stringconstant.cxx
@@ -0,0 +1,134 @@
+/* -*- 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]}}
+
+ OUString().reverseCompareTo(OUString()); // expected-error {{in call of 'rtl::OUString::reverseCompareTo', replace default-constructed 'OUString' with an empty string literal [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/stringliteraldefine.cxx b/compilerplugins/clang/test/stringliteraldefine.cxx
new file mode 100644
index 000000000..ba5f718ed
--- /dev/null
+++ b/compilerplugins/clang/test/stringliteraldefine.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 <sal/config.h>
+
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include <sal/macros.h>
+
+void f(OUString const&);
+
+void f1()
+{
+// expected-error@+1 {{change macro 'XXX' to 'constexpr OUStringLiteral' [loplugin:stringliteraldefine]}}
+#define XXX "xxx"
+
+ // expected-note@+1 {{macro used here [loplugin:stringliteraldefine]}}
+ f(OUString(XXX));
+
+ // FIXME no warning expected
+ //#define FOO f(OUString("xxx"))
+ // FOO;
+}
+
+void f2()
+{
+ struct DataFlavorRepresentation
+ {
+ OUString pMimeType;
+ };
+
+// expected-error@+1 {{change macro 'MIMETYPE_VND_SUN_XML_WRITER_ASCII' to 'constexpr OUStringLiteral' [loplugin:stringliteraldefine]}}
+#define MIMETYPE_VND_SUN_XML_WRITER_ASCII "xxx"
+ static const DataFlavorRepresentation aInstance[] = {
+ // expected-note@+1 {{macro used here [loplugin:stringliteraldefine]}}
+ { MIMETYPE_VND_SUN_XML_WRITER_ASCII },
+ };
+}
+
+void f3()
+{
+// expected-error@+1 {{change macro 'YYY' to 'constexpr OUStringLiteral' [loplugin:stringliteraldefine]}}
+#define YYY "yyy"
+
+ // expected-note@+1 {{macro used here [loplugin:stringliteraldefine]}}
+ f(YYY);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringliteralvar.cxx b/compilerplugins/clang/test/stringliteralvar.cxx
new file mode 100644
index 000000000..b79ee95a0
--- /dev/null
+++ b/compilerplugins/clang/test/stringliteralvar.cxx
@@ -0,0 +1,134 @@
+/* -*- 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>
+
+#include <rtl/ustring.hxx>
+#include <sal/macros.h>
+
+// expected-error-re@+1 {{change type of variable 'literal1' from constant character array ('const char{{ ?}}[4]') to OStringLiteral [loplugin:stringliteralvar]}}
+char const literal1[] = "foo";
+OString f1()
+{
+ // expected-note@+1 {{first passed into a 'rtl::OString' constructor here [loplugin:stringliteralvar]}}
+ return literal1;
+}
+
+void f(OUString const&);
+void f2()
+{
+ // expected-error-re@+1 {{change type of variable 'literal' from constant character array ('const char{{ ?}}[4]') to OUStringLiteral, and make it static [loplugin:stringliteralvar]}}
+ char const literal[] = "foo";
+ // expected-note@+1 {{first passed into a 'rtl::OUString' constructor here [loplugin:stringliteralvar]}}
+ f(literal);
+}
+
+struct S3
+{
+ // expected-error-re@+1 {{change type of variable 'literal' from constant character array ('const char16_t{{ ?}}[4]') to OUStringLiteral [loplugin:stringliteralvar]}}
+ static constexpr char16_t literal[] = u"foo";
+};
+void f3()
+{
+ // expected-note@+1 {{first passed into a 'rtl::OUString' constructor here [loplugin:stringliteralvar]}}
+ f(S3::literal);
+}
+
+std::vector<OUString> f4()
+{
+ // expected-error-re@+1 {{change type of variable 'literal' from constant character array ('const char16_t{{ ?}}[4]') to OUStringLiteral [loplugin:stringliteralvar]}}
+ static constexpr char16_t literal[] = u"foo";
+ // expected-note@+1 {{first passed into a 'rtl::OUString' constructor here [loplugin:stringliteralvar]}}
+ return { literal };
+}
+
+void f5()
+{
+ // expected-error@+1 {{variable 'literal' of type 'const rtl::OUStringLiteral<4>' with automatic storage duration most likely needs to be static [loplugin:stringliteralvar]}}
+ OUStringLiteral const literal = u"foo";
+ // expected-note@+1 {{first converted to 'rtl::OUString' here [loplugin:stringliteralvar]}}
+ f(literal);
+}
+
+void f6()
+{
+ // expected-error@+1 {{variable 'literal' of type 'const rtl::OUStringLiteral<4>' with automatic storage duration most likely needs to be static [loplugin:stringliteralvar]}}
+ constexpr OUStringLiteral literal = u"foo";
+ // expected-note@+1 {{first converted to 'rtl::OUString' here [loplugin:stringliteralvar]}}
+ f(literal);
+}
+
+void f7()
+{
+ static constexpr OUStringLiteral const literal = u"foo";
+ f(literal);
+}
+
+void f8()
+{
+ static constexpr OUStringLiteral const literal = u"foo";
+ // expected-error@+1 {{variable 'literal' of type 'const rtl::OUStringLiteral<4>' suspiciously used in a sizeof expression [loplugin:stringliteralvar]}}
+ (void)sizeof literal;
+}
+
+void f9()
+{
+ // expected-error-re@+1 {{change type of variable 'literal' from constant character array ('const sal_Unicode{{ ?}}[3]'{{( \(aka 'const char16_t\[3\]'\))?}}) to OUStringLiteral [loplugin:stringliteralvar]}}
+ static sal_Unicode const literal[] = { 'f', 'o', 'o' };
+ // expected-note@+1 {{first passed into a 'rtl::OUString' constructor here [loplugin:stringliteralvar]}}
+ f(OUString(literal, SAL_N_ELEMENTS(literal)));
+}
+
+void f10()
+{
+ // expected-error-re@+1 {{change type of variable 'literal' from constant character array ('const sal_Unicode{{ ?}}[3]'{{( \(aka 'const char16_t\[3\]'\))?}}) to OUStringLiteral [loplugin:stringliteralvar]}}
+ static sal_Unicode const literal[] = { 'f', 'o', 'o' };
+ // expected-note@+1 {{first passed into a 'rtl::OUString' constructor here [loplugin:stringliteralvar]}}
+ f(OUString(literal, 3));
+}
+
+void f11(int nStreamType)
+{
+ // expected-error-re@+1 {{change type of variable 'sDocumentType' from constant character array ('const char{{ ?}}[4]') to OUStringLiteral, and make it static [loplugin:stringliteralvar]}}
+ const char sDocumentType[] = "foo";
+ OUString sStreamType;
+ switch (nStreamType)
+ {
+ case 1:
+ // expected-note@+1 {{first assigned here [loplugin:stringliteralvar]}}
+ sStreamType = sDocumentType;
+ break;
+ }
+ (void)sStreamType;
+}
+
+extern sal_Unicode const extarr[1];
+
+sal_Unicode init();
+
+void f12()
+{
+ // Suppress warnings if the array contains a malformed sequence of UTF-16 code units...:
+ static sal_Unicode const arr1[] = { 0xD800 };
+ f(OUString(arr1, 1));
+ // ...Or potentially contains a malformed sequence of UTF-16 code units...:
+ f(OUString(extarr, 1));
+ sal_Unicode const arr2[] = { init() };
+ f(OUString(arr2, 1));
+ // ...But generate a warning if the array contains a well-formed sequence of UTF-16 code units
+ // containing surrogates:
+ // expected-error-re@+1 {{change type of variable 'arr3' from constant character array ('const sal_Unicode{{ ?}}[2]'{{( \(aka 'const char16_t\[2\]'\))?}}) to OUStringLiteral [loplugin:stringliteralvar]}}
+ static sal_Unicode const arr3[] = { 0xD800, 0xDC00 };
+ // expected-note-re@+1 {{first passed into a '{{(rtl::)?}}OUString' constructor here [loplugin:stringliteralvar]}}
+ f(OUString(arr3, 2));
+}
+
+/* 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..7a02cd9ce
--- /dev/null
+++ b/compilerplugins/clang/test/stringloop.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 "sal/config.h"
+#include "rtl/string.hxx"
+#include "rtl/ustring.hxx"
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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/stringstatic.cxx b/compilerplugins/clang/test/stringstatic.cxx
new file mode 100644
index 000000000..3c26d961c
--- /dev/null
+++ b/compilerplugins/clang/test/stringstatic.cxx
@@ -0,0 +1,29 @@
+/* -*- 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 "stringstatic.hxx"
+
+// expected-error@+1 {{rather declare this using OUStringLiteral/OStringLiteral/char[] [loplugin:stringstatic]}}
+static const OUString TEST1 = "xxx";
+
+void f(rtl_uString const*);
+
+void test2()
+{
+ // expected-error@+1 {{rather declare this using OUStringLiteral/OStringLiteral/char[] [loplugin:stringstatic]}}
+ static const OUString XXX = "xxx";
+ // expected-error@+1 {{rather declare this using OUStringLiteral/OStringLiteral/char[] [loplugin:stringstatic]}}
+ static const OUString XXX2 = "xxx";
+ (void)XXX;
+ (void)XXX2;
+ static const OUString DATA = "xxx";
+ f(DATA.pData);
+}
diff --git a/compilerplugins/clang/test/stringstatic.hxx b/compilerplugins/clang/test/stringstatic.hxx
new file mode 100644
index 000000000..ec82a8bf5
--- /dev/null
+++ b/compilerplugins/clang/test/stringstatic.hxx
@@ -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"
+
+#include "rtl/ustring.hxx"
+
+OUString const INCLUDED = "xxx";
+
+inline void f()
+{
+ // expected-error@+1 {{rather declare this using OUStringLiteral/OStringLiteral/char[] [loplugin:stringstatic]}}
+ static OUString const XXX = "xxx";
+ (void)XXX;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringview-c++03.cxx b/compilerplugins/clang/test/stringview-c++03.cxx
new file mode 100644
index 000000000..1824ac9d0
--- /dev/null
+++ b/compilerplugins/clang/test/stringview-c++03.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 <sal/config.h>
+
+#include <rtl/ustrbuf.hxx>
+
+// expected-no-diagnostics
+
+rtl::OUStringBuffer nowarn(rtl::OUStringBuffer const& s, sal_Int32 n)
+{
+ return s.copy(n, s.getLength() - n);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringview.cxx b/compilerplugins/clang/test/stringview.cxx
new file mode 100644
index 000000000..398f14b3d
--- /dev/null
+++ b/compilerplugins/clang/test/stringview.cxx
@@ -0,0 +1,221 @@
+/* -*- 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 <string_view>
+#include <utility>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+void call_view(std::u16string_view) {}
+void call_view(std::string_view) {}
+struct ConstructWithView
+{
+ ConstructWithView(std::u16string_view) {}
+ ConstructWithView(std::string_view) {}
+};
+
+namespace test1
+{
+void f1(std::u16string_view s1)
+{
+ // no warning expected
+ call_view(s1);
+}
+void f1(std::string_view s1)
+{
+ // no warning expected
+ call_view(s1);
+}
+void f1(OUString s1)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1));
+}
+void f1(OString s1)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1));
+}
+void f1(OUStringBuffer s1)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ call_view(s1.copy(1));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1, 2));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ ConstructWithView(s1.copy(1));
+ // expected-error@+1 {{rather than call toString, pass with a view [loplugin:stringview]}}
+ call_view(s1.toString());
+ // expected-error@+1 {{rather than call toString, pass with a view [loplugin:stringview]}}
+ ConstructWithView(s1.toString());
+}
+void f1(OStringBuffer s1)
+{
+ // expected-error@+1 {{rather than call toString, pass with a view [loplugin:stringview]}}
+ call_view(s1.toString());
+ // expected-error@+1 {{rather than call toString, pass with a view [loplugin:stringview]}}
+ ConstructWithView(s1.toString());
+}
+void makeStringAndClear(OUStringBuffer s)
+{
+ call_view(s.makeStringAndClear());
+ ConstructWithView(s.makeStringAndClear());
+ call_view((&s)->makeStringAndClear());
+ ConstructWithView((&s)->makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ call_view(std::move(s).makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ ConstructWithView(std::move(s).makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ call_view((s).copy(1).makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ ConstructWithView(s.copy(1).makeStringAndClear());
+}
+void makeStringAndClear(OStringBuffer s)
+{
+ call_view(s.makeStringAndClear());
+ ConstructWithView(s.makeStringAndClear());
+ call_view((&s)->makeStringAndClear());
+ ConstructWithView((&s)->makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ call_view(std::move(s).makeStringAndClear());
+ // expected-error@+1 {{rather than call makeStringAndClear on an rvalue, pass with a view [loplugin:stringview]}}
+ ConstructWithView(std::move(s).makeStringAndClear());
+}
+}
+
+namespace test2
+{
+void f3(OUString s1)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ OUString s2 = s1.copy(1, 2) + "xxx";
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ s2 = s1.copy(1) + "xxx";
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ s2 = "xxx" + s1.copy(1);
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ s2 += s1.copy(1);
+ (void)s2;
+}
+void f3(OString s1)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ OString s2 = s1.copy(1, 2) + "xxx";
+ (void)s2;
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ OString s3 = s1.copy(1) + "xxx";
+ (void)s3;
+}
+}
+
+namespace test3
+{
+void f4(OUString s1, OUString s2)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ sal_Unicode x = s2.copy(1, 2)[12];
+ (void)x;
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ if (s2.copy(1, 2) < s1)
+ ;
+}
+}
+
+void f5(char const* s1, sal_Int32 n1, char16_t const* s2, sal_Int32 n2, OString s3, OUString s4)
+{
+ // expected-error@+1 {{instead of an 'rtl::OString', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString());
+ // expected-error-re@+1 {{instead of an 'rtl::OString' constructed from a 'const char{{ ?}}[4]', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString("foo"));
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'const char', pass a 'std::string_view' (or an 'rtl::OStringChar') [loplugin:stringview]}}
+ call_view(OString(*s1));
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'const char *', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString(s1));
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'const char *', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString(s1, n1));
+ constexpr OStringLiteral l1("foo");
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'const rtl::OStringLiteral<4>', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString(l1));
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'std::string_view' (aka 'basic_string_view<char>'), pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString(std::string_view("foo")));
+ // expected-error@+1 {{instead of an 'rtl::OString' constructed from a 'OStringNumber<int>', pass a 'std::string_view' [loplugin:stringview]}}
+ call_view(OString(OString::number(0)));
+ // expected-error-re@+1 {{instead of an 'rtl::OString' constructed from a 'typename std::enable_if_t<ToStringHelper<OString>::allowOStringConcat && ToStringHelper<OString>::allowOStringConcat, OStringConcat<OString, OString>{{ ?}}>' (aka 'rtl::OStringConcat<rtl::OString, rtl::OString>'), pass a 'std::string_view' via 'rtl::OStringConcatenation' [loplugin:stringview]}}
+ call_view(OString(s3 + s3));
+ // expected-error@+1 {{instead of an 'rtl::OUString', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString());
+ // expected-error-re@+1 {{instead of an 'rtl::OUString' constructed from a 'const char{{ ?}}[4]', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString("foo"));
+ // expected-error-re@+1 {{instead of an 'rtl::OUString' constructed from a 'const char16_t{{ ?}}[4]', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(u"foo"));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const char', pass a 'std::u16string_view' (or an 'rtl::OUStringChar') [loplugin:stringview]}}
+ call_view(OUString(*s1));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const char16_t', pass a 'std::u16string_view' (or an 'rtl::OUStringChar') [loplugin:stringview]}}
+ call_view(OUString(*s2));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const char16_t *', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(s2));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const char16_t *', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(s2, n2));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const char16_t *', pass a 'std::u16string_view' (or an 'rtl::OUStringChar') [loplugin:stringview]}}
+ call_view(OUString(s2, 1));
+ constexpr OUStringLiteral l2(u"foo");
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'const rtl::OUStringLiteral<4>', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(l2));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'std::u16string_view' (aka 'basic_string_view<char16_t>'), pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(std::u16string_view(u"foo")));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'OUStringNumber<int>', pass a 'std::u16string_view' [loplugin:stringview]}}
+ call_view(OUString(OUString::number(0)));
+ // expected-error-re@+1 {{instead of an 'rtl::OUString' constructed from a 'typename std::enable_if_t<ToStringHelper<OUString>::allowOUStringConcat && ToStringHelper<OUString>::allowOUStringConcat, OUStringConcat<OUString, OUString>{{ ?}}>' (aka 'rtl::OUStringConcat<rtl::OUString, rtl::OUString>'), pass a 'std::u16string_view' via 'rtl::OUStringConcatenation' [loplugin:stringview]}}
+ call_view(OUString(s4 + s4));
+
+ (void)(s3 == l1);
+ (void)(s4 == l2);
+}
+
+void f5(OUString s)
+{
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ OUStringBuffer buf(s.copy(5));
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ buf = s.copy(5);
+ // expected-error@+1 {{rather than copy, pass with a view using subView() [loplugin:stringview]}}
+ buf.append(s.copy(12));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'std::u16string_view' (aka 'basic_string_view<char16_t>'), pass a 'std::u16string_view' [loplugin:stringview]}}
+ buf.append(OUString(std::u16string_view(u"foo")));
+ // expected-error@+1 {{instead of an 'rtl::OUString' constructed from a 'std::u16string_view' (aka 'basic_string_view<char16_t>'), pass a 'std::u16string_view' [loplugin:stringview]}}
+ s += OUString(std::u16string_view(u"foo"));
+}
+
+void f6(OUString s)
+{
+ // expected-error@+1 {{rather than getToken, pass with a view using o3tl::getToken() [loplugin:stringview]}}
+ s.getToken(1, ' ').toInt32();
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringviewdangle.cxx b/compilerplugins/clang/test/stringviewdangle.cxx
new file mode 100644
index 000000000..0a8d2aa54
--- /dev/null
+++ b/compilerplugins/clang/test/stringviewdangle.cxx
@@ -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/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+#include <utility>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace test1
+{
+OUString foo1();
+OUString& foo2();
+void f1()
+{
+ // expected-error@+1 {{view pointing into temporary i.e. dangling [loplugin:stringviewdangle]}}
+ std::u16string_view v = foo1();
+ // expected-error@+1 {{view pointing into temporary i.e. dangling [loplugin:stringviewdangle]}}
+ v = foo1();
+
+ // no warning expected
+ std::u16string_view v2 = foo2();
+ v2 = foo2();
+}
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringviewparam.cxx b/compilerplugins/clang/test/stringviewparam.cxx
new file mode 100644
index 000000000..f5f165804
--- /dev/null
+++ b/compilerplugins/clang/test/stringviewparam.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/.
+ */
+
+#undef NDEBUG
+
+#include "sal/config.h"
+
+#include <string_view>
+
+#include "rtl/string.hxx"
+#include "rtl/ustring.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "sal/types.h"
+
+void f1a(std::string_view);
+// expected-error@+1 {{replace function parameter of type 'const rtl::OString &' with 'std::string_view' [loplugin:stringviewparam]}}
+char f1b(OString const& s)
+{
+ f1a(s);
+ OString rest;
+ if (s.isEmpty() || s.startsWith("foo", &rest) || s.endsWith("foo"))
+ {
+ f1a(std::string_view(s));
+ }
+ return s[0];
+}
+
+void f2a(std::u16string_view);
+// expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+sal_Unicode f2b(OUString const& s)
+{
+ f2a(s);
+ OUString rest;
+ if (s.isEmpty() || s.startsWith("foo", &rest) || s.endsWith("foo"))
+ {
+ f2a(std::u16string_view(s));
+ }
+ return s[0];
+}
+
+void f3a(OUString const&) {}
+using F3 = void(OUString const&);
+F3* f3b() { return f3a; }
+
+SAL_DLLPUBLIC_EXPORT void f4(OUString const&) {}
+
+template <typename T> void f5(T const&);
+template <> void f5<OUString>(OUString const&) {}
+
+void f6([[maybe_unused]] OUString const&) {}
+
+bool f7(
+ // expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+ const OUString& p1,
+ // expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+ const OUString& p2)
+{
+ return p1 == p2;
+}
+// expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+bool f8(const OUString& p1, std::u16string_view p2) { return p1 == p2; }
+
+struct Converter
+{
+ // expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+ static bool convertBool(bool& rBool, const OUString& rString)
+ {
+ rBool = rString == "true";
+ return rBool || (rString == "false");
+ }
+};
+
+void f9(std::u16string_view);
+void f9(OUString const& s) { return f9(std::u16string_view(s)); }
+
+struct S10
+{
+ S10(std::u16string_view);
+ S10(OUString const& s)
+ : S10(std::u16string_view(s))
+ {
+ }
+};
+
+// expected-error@+1 {{replace function parameter of type 'const rtl::OUString &' with 'std::u16string_view' [loplugin:stringviewparam]}}
+void f11(const OUString& f11rString)
+{
+ OUStringBuffer buf;
+ buf.append(f11rString);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringviewvar.cxx b/compilerplugins/clang/test/stringviewvar.cxx
new file mode 100644
index 000000000..016f0fcc8
--- /dev/null
+++ b/compilerplugins/clang/test/stringviewvar.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/.
+ */
+
+#undef NDEBUG
+
+#include "sal/config.h"
+#include <string_view>
+#include "rtl/string.hxx"
+#include "rtl/ustring.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "sal/types.h"
+
+void f1(std::string_view sv)
+{
+ // expected-error@+1 {{replace var of type 'rtl::OString' with 'std::string_view' [loplugin:stringviewvar]}}
+ OString s1(sv);
+ (void)s1;
+}
+
+void f2(const OString s1)
+{
+ // no warning expected
+ OString s2(s1);
+ (void)s2;
+}
+
+std::string_view f3a();
+void f3()
+{
+ // expected-error@+1 {{replace var of type 'rtl::OString' with 'std::string_view' [loplugin:stringviewvar]}}
+ OString s1 = OString(f3a());
+ (void)s1;
+}
+
+void f4a(const OString&);
+void f4(std::string_view sv)
+{
+ // no warning expected
+ OString s1(sv);
+ f4a(s1);
+}
+
+void f5(std::string_view sv)
+{
+ // expected-error@+1 {{replace var of type 'rtl::OString' with 'std::string_view' [loplugin:stringviewvar]}}
+ OString s1(sv);
+ if (s1 == "xxxx")
+ f5(sv);
+}
+
+void f6(std::u16string_view sv)
+{
+ // expected-error@+1 {{replace var of type 'rtl::OUString' with 'std::u16string_view' [loplugin:stringviewvar]}}
+ OUString s6;
+ s6 = sv;
+ (void)s6;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/trivialconstructor.cxx b/compilerplugins/clang/test/trivialconstructor.cxx
new file mode 100644
index 000000000..eed26f8bf
--- /dev/null
+++ b/compilerplugins/clang/test/trivialconstructor.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/.
+ */
+
+struct S1
+{
+ // expected-error@+1 {{no need for explicit constructor decl [loplugin:trivialconstructor]}}
+ S1() {}
+};
+
+struct S2
+{
+ S2() {}
+ S2(int) {}
+};
+
+struct S3
+{
+ S3() {}
+ template <typename T> S3(T);
+};
+
+template <typename> struct S4
+{
+#if !defined _MSC_VER
+// expected-error@+2 {{no need for explicit constructor decl [loplugin:trivialconstructor]}}
+#endif
+ S4() {}
+};
+
+template <typename> struct S5
+{
+ S5() {}
+ S5(int);
+};
+
+template <typename> struct S6
+{
+ S6() {}
+ template <typename T> S6(T);
+};
+
+struct S7
+{
+ S7(int = 0) {}
+};
+
+struct S8
+{
+ template <typename T> S8(T = 0) {}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/trivialdestructor.cxx b/compilerplugins/clang/test/trivialdestructor.cxx
new file mode 100644
index 000000000..b6ba4e968
--- /dev/null
+++ b/compilerplugins/clang/test/trivialdestructor.cxx
@@ -0,0 +1,57 @@
+/* -*- 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
+{
+ // expected-note@+1 {{previous declaration is here [loplugin:trivialdestructor]}}
+ ~S1();
+};
+
+// expected-error@+1 {{no need for explicit destructor decl [loplugin:trivialdestructor]}}
+S1::~S1() {}
+
+struct S2
+{
+ // expected-note@+1 {{previous declaration is here [loplugin:trivialdestructor]}}
+ ~S2();
+};
+
+// expected-error@+1 {{no need for explicit destructor decl [loplugin:trivialdestructor]}}
+S2::~S2() = default;
+
+struct S3
+{
+ ~S3() = delete;
+};
+
+struct S4
+{
+ union {
+ int i;
+ float f;
+ };
+ // expected-error@+1 {{no need for explicit destructor decl [loplugin:trivialdestructor]}}
+ ~S4() {}
+};
+
+struct Nontrivial
+{
+ ~Nontrivial();
+};
+
+struct S5
+{
+ union {
+ int i;
+ Nontrivial n;
+ };
+ ~S5() {}
+};
+
+/* 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/typeidcomparison.cxx b/compilerplugins/clang/test/typeidcomparison.cxx
new file mode 100644
index 000000000..31ab749a2
--- /dev/null
+++ b/compilerplugins/clang/test/typeidcomparison.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 <typeinfo>
+
+struct Base
+{
+ virtual ~Base();
+};
+
+struct Derived : Base
+{
+};
+
+void good(Base* p)
+{
+ (void)(typeid(*p) == typeid(Derived));
+ (void)(typeid(Derived) == typeid(*p));
+ (void)(typeid(*p) != typeid(Derived));
+ (void)(typeid(Derived) != typeid(*p));
+}
+
+void bad(Base* p)
+{
+ // expected-error@+1 {{comparison of type info of mixed pointer and non-pointer types 'Base *' and 'Derived' can never succeed [loplugin:typeidcomparison]}}
+ (void)(typeid(p) == typeid(Derived));
+ // expected-error@+1 {{comparison of type info of mixed pointer and non-pointer types 'Derived' and 'Base *' can never succeed [loplugin:typeidcomparison]}}
+ (void)(typeid(Derived) == typeid(p));
+ // expected-error@+1 {{comparison of type info of mixed pointer and non-pointer types 'Base *' and 'Derived' can never succeed [loplugin:typeidcomparison]}}
+ (void)(typeid(p) != typeid(Derived));
+ // expected-error@+1 {{comparison of type info of mixed pointer and non-pointer types 'Derived' and 'Base *' can never succeed [loplugin:typeidcomparison]}}
+ (void)(typeid(Derived) != typeid(p));
+}
+
+/* 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/unnecessarylocking.cxx b/compilerplugins/clang/test/unnecessarylocking.cxx
new file mode 100644
index 000000000..6dda5d333
--- /dev/null
+++ b/compilerplugins/clang/test/unnecessarylocking.cxx
@@ -0,0 +1,71 @@
+/* -*- 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 <mutex>
+
+static std::mutex gSolarMutex;
+
+class SolarMutexGuard : public std::unique_lock<std::mutex>
+{
+public:
+ SolarMutexGuard()
+ : std::unique_lock<std::mutex>(gSolarMutex)
+ {
+ }
+};
+
+namespace test1
+{
+struct Foo
+{
+ int m_foo;
+ // expected-error@+1 {{unnecessary locking [loplugin:unnecessarylocking]}}
+ int bar1()
+ {
+ SolarMutexGuard guard;
+ return 1;
+ }
+ // no warning expected
+ int bar2()
+ {
+ SolarMutexGuard guard;
+ return m_foo;
+ }
+};
+}
+
+namespace test2
+{
+struct Foo
+{
+ std::mutex m_aMutex;
+ int m_foo;
+
+ // expected-error@+1 {{unnecessary locking [loplugin:unnecessarylocking]}}
+ int bar1()
+ {
+ std::unique_lock guard(m_aMutex);
+ return 1;
+ }
+ // expected-error@+1 {{unnecessary locking [loplugin:unnecessarylocking]}}
+ int bar2()
+ {
+ std::scoped_lock guard(m_aMutex);
+ return 1;
+ }
+ // no warning expected
+ int bar3()
+ {
+ std::scoped_lock guard(m_aMutex);
+ return m_foo;
+ }
+};
+}
+
+/* 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..960909b4e
--- /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;
+};
+
+DefaultDerived2::~DefaultDerived2() = default;
+
+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() = default;
+
+// 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..9f722375a
--- /dev/null
+++ b/compilerplugins/clang/test/unnecessaryoverride-dtor.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#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() {}
+};
+
+/* 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..ccc2b4ce6
--- /dev/null
+++ b/compilerplugins/clang/test/unnecessaryparen.cxx
@@ -0,0 +1,143 @@
+/* -*- 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;
+
+ OUString::number((v2+1)); // expected-error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}}
+};
+
+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..b5d91007f
--- /dev/null
+++ b/compilerplugins/clang/test/unoany.cxx
@@ -0,0 +1,29 @@
+/* -*- 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"
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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::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..a209dd7b6
--- /dev/null
+++ b/compilerplugins/clang/test/unreffun.hxx
@@ -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/.
+ */
+
+#pragma once
+
+void f();
+
+extern void i();
+
+/* 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/unusedcapturedefault.cxx b/compilerplugins/clang/test/unusedcapturedefault.cxx
new file mode 100644
index 000000000..d98eec04d
--- /dev/null
+++ b/compilerplugins/clang/test/unusedcapturedefault.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/.
+ */
+
+auto f1()
+{
+ // expected-error@+1 {{unused capture-default [loplugin:unusedcapturedefault]}}
+ return [=] { return 0; };
+}
+
+/* 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..3f69e8993
--- /dev/null
+++ b/compilerplugins/clang/test/unusedenumconstants.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 <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);
+ (void)foo;
+};
+
+/* 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..b545f4b1a
--- /dev/null
+++ b/compilerplugins/clang/test/unusedfields.cxx
@@ -0,0 +1,382 @@
+/* -*- 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/unusedfields.cxx
+// expected-no-diagnostics
+#else
+
+#include <memory>
+#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;
+ (void)any;
+ }
+
+ // 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 = 0;
+ 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..4d08b5be0
--- /dev/null
+++ b/compilerplugins/clang/test/unusedindex.cxx
@@ -0,0 +1,42 @@
+/* -*- 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>
+
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // for Clang < 13
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+
+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..a495b7869
--- /dev/null
+++ b/compilerplugins/clang/test/unusedmember.cxx
@@ -0,0 +1,238 @@
+/* -*- 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 E1
+ {
+ E11,
+ E12
+ };
+ E1 e1;
+ enum E2
+ {
+ E21,
+ E22
+ };
+ E2 e2; // expected-error {{unused class member [loplugin:unusedmember]}}
+ enum E3
+ {
+ E31,
+ E32
+ } e3;
+ enum E4
+ {
+ E41,
+ E42
+ } e4; // expected-error {{unused class member [loplugin:unusedmember]}}
+};
+}
+void f(S s)
+{
+ (void)s.e1;
+ (void)s.e3;
+}
+}
+
+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..b020fba3e
--- /dev/null
+++ b/compilerplugins/clang/test/unusedvariablecheck.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 <list>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace
+{
+template <typename T> using Vec = std::vector<T>;
+}
+
+struct S : std::unique_ptr<int>
+{
+ S(int* = nullptr);
+};
+
+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]}}
+ std::unique_ptr<int>
+ v4; // expected-error {{unused variable 'v4' [loplugin:unusedvariablecheck]}}
+ S v5; // expected-error {{unused variable 'v5' [loplugin:unusedvariablecheck]}}
+ S v6(nullptr);
+}
+
+/* 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/unusedvarsglobal.cxx b/compilerplugins/clang/test/unusedvarsglobal.cxx
new file mode 100644
index 000000000..e7a0316d4
--- /dev/null
+++ b/compilerplugins/clang/test/unusedvarsglobal.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/.
+ */
+
+#if defined _WIN32 // TODO, see corresponding TODO in compilerplugins/clang/unusedfields.cxx
+// expected-no-diagnostics
+#else
+
+#include <string_view>
+
+namespace something
+{
+// expected-error@+1 {{write [loplugin:unusedvarsglobal]}}
+extern const std::u16string_view literal1;
+}
+const std::u16string_view something::literal1(u"xxx");
+
+#endif
+/* 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..f169959d6
--- /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 allowlisted or simplified [loplugin:useuniqueptr]}}
+};
+
+class Foo16 {
+ Foo16(int * p)
+ {
+ delete p; // expected-error {{calling delete on a pointer param, should be either allowlisted or simplified [loplugin:useuniqueptr]}}
+ };
+ void foo(int * p)
+ {
+ delete p; // expected-error {{calling delete on a pointer param, should be either allowlisted 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..1ff828e28
--- /dev/null
+++ b/compilerplugins/clang/test/vclwidgets.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 <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)p;
+}
+
+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/weakobject.cxx b/compilerplugins/clang/test/weakobject.cxx
new file mode 100644
index 000000000..7c7da5566
--- /dev/null
+++ b/compilerplugins/clang/test/weakobject.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 "config_clang.h"
+
+namespace cppu
+{
+class OWeakObject
+{
+};
+}
+
+class Foo1 : public cppu::OWeakObject
+{
+};
+class Foo2 : public cppu::OWeakObject
+{
+};
+
+// expected-error@+1 {{more than one copy of cppu::OWeakObject inherited [loplugin:weakobject]}}
+class Foo3 : public Foo1, public Foo2
+{
+};
+
+/* 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..0fc141f62
--- /dev/null
+++ b/compilerplugins/clang/test/writeonlyvars.cxx
@@ -0,0 +1,168 @@
+/* -*- 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;
+ (void)m_bar3b;
+
+ // 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 don't see writes when calling operator<<=
+ // expected-error@+1 {{read m_bar10 [loplugin:writeonlyvars]}}
+ sal_Int32 m_bar10 = 0;
+ // expected-error@+2 {{write any2 [loplugin:writeonlyvars]}}
+ // expected-error@+1 {{read any2 [loplugin:writeonlyvars]}}
+ css::uno::Any any2;
+ any2 <<= m_bar10;
+ (void)any2;
+};
+};
+
+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..fa1d42a2f
--- /dev/null
+++ b/compilerplugins/clang/test/xmlimport.cxx
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 2; 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"
+// Cannot include this, cannot be found
+//#include <xmloff/xmlictxt.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::xml::sax
+{
+class XAttributeList;
+class XFastContextHandler;
+}
+
+class SvXMLImportContext;
+typedef rtl::Reference<SvXMLImportContext> SvXMLImportContextRef;
+class SvXMLImportContext
+{
+public:
+ virtual ~SvXMLImportContext() {}
+
+ virtual void startFastElement() {}
+ virtual void endFastElement() {}
+ virtual void characters(const OUString&) {}
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> createFastChildContext()
+ {
+ return nullptr;
+ }
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> createUnknownChildContext()
+ {
+ return nullptr;
+ }
+
+ virtual void StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>&) {}
+ virtual void EndElement() {}
+ virtual void Characters(const OUString&) {}
+ virtual SvXMLImportContextRef CreateChildContext() { return nullptr; }
+
+ void acquire();
+ void release();
+
+ void xxx(); // just here to avoid triggering a warning I don't want to check for
+};
+
+class Test1 : public SvXMLImportContext
+{
+public:
+ // expected-error@+1 {{cannot override both startFastElement and StartElement [loplugin:xmlimport]}}
+ virtual void startFastElement() override { xxx(); }
+ // expected-error@+1 {{cannot override both startFastElement and StartElement [loplugin:xmlimport]}}
+ virtual void StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>&) override
+ {
+ xxx();
+ }
+};
+
+class Test2 : public SvXMLImportContext
+{
+public:
+ // expected-error@+1 {{cannot override both endFastElement and EndElement [loplugin:xmlimport]}}
+ virtual void endFastElement() override { xxx(); }
+ // expected-error@+1 {{cannot override both endFastElement and EndElement [loplugin:xmlimport]}}
+ virtual void EndElement() override { xxx(); }
+};
+
+class Test3 : public SvXMLImportContext
+{
+public:
+ // expected-error@+1 {{cannot override both characters and Characters [loplugin:xmlimport]}}
+ virtual void Characters(const OUString&) override { xxx(); }
+ // expected-error@+1 {{cannot override both characters and Characters [loplugin:xmlimport]}}
+ virtual void characters(const OUString&) override { xxx(); }
+};
+
+class Test7 : public SvXMLImportContext
+{
+public:
+ virtual void startFastElement() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::startFastElement();
+ }
+ virtual void endFastElement() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::endFastElement();
+ }
+ virtual void characters(const OUString& rChars) override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::characters(rChars);
+ }
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler>
+ createFastChildContext() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ return SvXMLImportContext::createFastChildContext();
+ }
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler>
+ createUnknownChildContext() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ return SvXMLImportContext::createUnknownChildContext();
+ }
+};
+
+class Test8 : public SvXMLImportContext
+{
+public:
+ virtual void
+ StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList) override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::StartElement(xAttrList);
+ }
+ virtual void EndElement() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::EndElement();
+ }
+ virtual void Characters(const OUString& rChars) override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ SvXMLImportContext::Characters(rChars);
+ }
+ virtual SvXMLImportContextRef CreateChildContext() override
+ {
+ // expected-error@+1 {{don't call this superclass method [loplugin:xmlimport]}}
+ return SvXMLImportContext::CreateChildContext();
+ }
+};
+
+// no warning expected
+class Test9a : public SvXMLImportContext
+{
+public:
+ virtual void StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>&) override
+ {
+ xxx();
+ }
+};
+class Test9b : public Test9a
+{
+public:
+ virtual void
+ StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList) override
+ {
+ Test9a::StartElement(xAttrList);
+ }
+};
+
+class Test10a : public SvXMLImportContext
+{
+public:
+ // expected-error@+1 {{empty, should be removed [loplugin:xmlimport]}}
+ virtual void startFastElement() override {}
+ // expected-error@+1 {{empty, should be removed [loplugin:xmlimport]}}
+ virtual void endFastElement() override {}
+ // expected-error@+1 {{empty, should be removed [loplugin:xmlimport]}}
+ virtual void characters(const OUString&) override {}
+ // expected-error@+1 {{empty, should be removed [loplugin:xmlimport]}}
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler>
+ createFastChildContext() override
+ {
+ return nullptr;
+ }
+ // expected-error@+1 {{empty, should be removed [loplugin:xmlimport]}}
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler>
+ createUnknownChildContext() override
+ {
+ return nullptr;
+ }
+};
+// no warning expected
+class Test10b : public SvXMLImportContext
+{
+public:
+ virtual void StartElement(const css::uno::Reference<css::xml::sax::XAttributeList>&) override {}
+ virtual void EndElement() override {}
+ virtual void Characters(const OUString&) override {}
+ virtual SvXMLImportContextRef CreateChildContext() override { return nullptr; }
+};
+
+enum XmlTokens
+{
+ XML_TOK_1
+};
+
+void test20(sal_uInt32 p, sal_uInt16 q, XmlTokens e)
+{
+ // expected-error@+1 {{comparing XML_TOK enum to 'sal_uInt32', expected sal_uInt16 [loplugin:xmlimport]}}
+ if (p == XML_TOK_1)
+ ;
+ // no warning expected
+ if (q == XML_TOK_1)
+ ;
+ switch (p)
+ {
+ // expected-error@+1 {{comparing XML_TOK enum to 'sal_uInt32', expected sal_uInt16 [loplugin:xmlimport]}}
+ case XML_TOK_1:
+ break;
+ }
+ switch (q)
+ {
+ // no warning expected
+ case XML_TOK_1:
+ break;
+ }
+ switch (e)
+ {
+ // no warning expected
+ case XML_TOK_1:
+ break;
+ }
+}
+void callInt32(sal_Int32);
+void test21()
+{
+ // expected-error@+1 {{passing XML_TOK enum to 'sal_Int32', wrong param or XML token type [loplugin:xmlimport]}}
+ callInt32(XML_TOK_1);
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */