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
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#if defined _WIN32 //TODO, see corresponding TODO in compilerplugins/clang/writeonlyvars.cxx
// expected-no-diagnostics
#else

#include <vector>
#include <ostream>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>

// See 1d0bc2139759f087d50432f8a2116060676f34e1 "use std::experimental::source_location in
// uno::Exception" modification to
// workdir/UnoApiHeadersTarget/udkapi/normal/com/sun/star/uno/Exception.hdl, which is indirectly
// included through the above #include directives, in turn causing conditional inclusion of
// include/o3tl/runtimetooustring.hxx (and where `ok` is only read in an assert in !NDEBUG builds):
#if defined LIBO_USE_SOURCE_LOCATION
// expected-error@o3tl/runtimetooustring.hxx:* {{read s [loplugin:writeonlyvars]}}
// expected-error@o3tl/runtimetooustring.hxx:* {{write s [loplugin:writeonlyvars]}}
#if !defined NDEBUG
// expected-error@o3tl/runtimetooustring.hxx:* {{read ok [loplugin:writeonlyvars]}}
#endif
#endif

namespace Bar
{
void test()
{
    // check that we DON'T see reads here
    // expected-error@+1 {{write m_bar3 [loplugin:writeonlyvars]}}
    int* m_bar3;
    // expected-error@+1 {{write m_bar3b [loplugin:writeonlyvars]}}
    int* m_bar3b;
    m_bar3 = nullptr;
    m_bar3b = m_bar3 = nullptr;

    // check that we see reads of field when passed to a function pointer
    // check that we see read of a field that is a function pointer
    // expected-error@+2 {{write m_bar4 [loplugin:writeonlyvars]}}
    // expected-error@+1 {{read m_bar4 [loplugin:writeonlyvars]}}
    int m_bar4;
    // expected-error@+1 {{read m_barfunctionpointer [loplugin:writeonlyvars]}}
    void (*m_barfunctionpointer)(int&) = nullptr;<--- Assignment 'm_barfunctionpointer=nullptr', assigned value is 0
    m_barfunctionpointer(m_bar4);<--- Null pointer dereference

    // 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;<--- Variable 'm_bar7[3]' is assigned a value that is never used.

    // 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];<--- Variable 'tmp' is not assigned a value.
    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;<--- Variable 'any' is assigned a value that is never used.

    // 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;<--- Variable 'any2' is assigned a value that is never used.
};
};

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);<--- Variable 'a' is assigned a value that is never used.

    // 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()<--- The function 'ReadOnlyAnalysis3' is never used.
{
    // expected-error@+1 {{read m_f1 [loplugin:writeonlyvars]}}
    int m_f1 = 0;<--- Assignment 'm_f1=0', assigned value is 0

    if (m_f1)<--- Condition 'm_f1' is always false
        m_f1 = 1;<--- Variable 'm_f1' is assigned a value that is never used.
};

// Verify the special logic for container fields that only contains mutations that
// add elements.
void ReadOnlyAnalysis4()<--- The function 'ReadOnlyAnalysis4' is never used.
{
    // 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];<--- Access out of bounds
    (void)x;
    *m_readonly.begin() = 1; // TODO?

    m_writeonly.push_back(0);

    x = m_readonlyCss.getArray()[0];<--- Variable 'x' is assigned a value that is never used.
};

#endif

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