summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/test/unusedfields.cxx
blob: 6efb17334e210cd9106b4fd14ae68a7095d642eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* -*- 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 <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]}}
{
    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]}}
{
    int  m_bar1;
    int  m_bar2 = 1;
    int* m_bar3;
    int* m_bar3b;
    int  m_bar4;
    void (*m_barfunctionpointer)(int&);
    int  m_bar5;
    std::vector<int> m_bar6;
    int m_bar7[5];
    int m_bar8;
    int m_barstream;
    sal_Int32 m_bar9;
    sal_Int32 m_bar10;
    css::uno::Any m_bar11;
    css::uno::Any m_bar12;

    // check that we see reads of fields like m_foo1 when referred to via constructor initializer
    Bar(Foo const & foo) : m_bar1(foo.m_foo1) {}

    // check that we don't see reads when inside copy/move constructor
    Bar(Bar const & other) { m_bar3 = other.m_bar3; }

    // check that we don't see reads when inside copy/move assignment operator
    Bar& operator=(Bar const & other) { m_bar3 = other.m_bar3; return *this; }

    // check that we DON'T see reads here
    int bar2() { return m_bar2; }

    // check that we DON'T see reads here
    void bar3()
    {
        m_bar3 = nullptr;
        m_bar3b = m_bar3 = nullptr;
    }

    // check that we see reads of field when passed to a function pointer
    // check that we see read of a field that is a function pointer
    void bar4() { m_barfunctionpointer(m_bar4); }

    // check that we see reads of a field when used in variable init
    void bar5() { int x = m_bar5; (void) x; }

    // check that we see reads of a field when used in ranged-for
    void bar6() { for (auto i : m_bar6) { (void)i; } }

    // check that we see don't see reads of array fields
    void bar7() { m_bar7[3] = 1; }

    // check that we see reads when a field is used in an array expression
    char bar8()
    {
        char tmp[5];
        return tmp[m_bar8];
    }

    // check that we don't see reads when calling operator>>=
    void bar9()
    {
        css::uno::Any any;
        any >>= m_bar9;
    }

    // check that we see don't see writes when calling operator<<=
    void bar10()
    {
        css::uno::Any any;
        any <<= m_bar10;
    }

    // check that we see reads of the LHS when calling operator>>=
    void bar11()
    {
        int x;
        m_bar11 >>= x;
    }

    // check that we see writes of the LHS when calling operator<<=
    void bar12()
    {
        int x;
        m_bar12 <<= x;
    }
};

// check that we __dont__ see a read of m_barstream
std::ostream& operator<<(std::ostream& s, Bar const & bar)
{
    s << bar.m_barstream;
    return s;
};

struct ReadOnly1 { ReadOnly1(int&); };

struct ReadOnlyAnalysis
// expected-error@-1 {{read m_f2 [loplugin:unusedfields]}}
// expected-error@-2 {{read m_f3 [loplugin:unusedfields]}}
// expected-error@-3 {{read m_f5 [loplugin:unusedfields]}}
// expected-error@-4 {{read m_f6 [loplugin:unusedfields]}}
// expected-error@-5 {{write m_f2 [loplugin:unusedfields]}}
// expected-error@-6 {{write m_f3 [loplugin:unusedfields]}}
// expected-error@-7 {{write m_f4 [loplugin:unusedfields]}}
// expected-error@-8 {{write m_f5 [loplugin:unusedfields]}}
// expected-error@-9 {{write m_f6 [loplugin:unusedfields]}}
{
    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]}}
{
    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]}}
{
    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]}}
{
    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]}}
    {
        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]}}
    {
        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;
        }
    };
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */