bugprone-dangling-handle.cpp
5.46 KB
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
// RUN: %check_clang_tidy -std=c++11,c++14 %s bugprone-dangling-handle %t -- \
// RUN: -config="{CheckOptions: \
// RUN: [{key: bugprone-dangling-handle.HandleClasses, \
// RUN: value: 'std::basic_string_view; ::llvm::StringRef;'}]}"
// FIXME: Fix the checker to work in C++17 mode.
namespace std {
template <typename T>
class vector {
public:
using const_iterator = const T*;
using iterator = T*;
using size_type = int;
void assign(size_type count, const T& value);
iterator insert(const_iterator pos, const T& value);
iterator insert(const_iterator pos, T&& value);
iterator insert(const_iterator pos, size_type count, const T& value);
void push_back(const T&);
void push_back(T&&);
void resize(size_type count, const T& value);
};
template <typename, typename>
class pair {};
template <typename T>
class set {
public:
using const_iterator = const T*;
using iterator = T*;
std::pair<iterator, bool> insert(const T& value);
std::pair<iterator, bool> insert(T&& value);
iterator insert(const_iterator hint, const T& value);
iterator insert(const_iterator hint, T&& value);
};
template <typename Key, typename Value>
class map {
public:
using value_type = pair<Key, Value>;
value_type& operator[](const Key& key);
value_type& operator[](Key&& key);
};
class basic_string_view;
class basic_string {
public:
basic_string();
basic_string(const char*);
operator basic_string_view() const noexcept;
~basic_string();
};
typedef basic_string string;
class basic_string_view {
public:
basic_string_view(const char*);
};
typedef basic_string_view string_view;
} // namespace std
namespace llvm {
class StringRef {
public:
StringRef();
StringRef(const char*);
StringRef(const std::string&);
};
} // namespace llvm
std::string ReturnsAString();
void Positives() {
std::string_view view1 = std::string();
// CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
std::string_view view_2 = ReturnsAString();
// CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
view1 = std::string();
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
const std::string& str_ref = "";
std::string_view view3 = true ? "A" : str_ref;
// CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
view3 = true ? "A" : str_ref;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
std::string_view view4(ReturnsAString());
// CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
}
void OtherTypes() {
llvm::StringRef ref = std::string();
// CHECK-MESSAGES: [[@LINE-1]]:19: warning: llvm::StringRef outlives its value
}
const char static_array[] = "A";
std::string_view ReturnStatements(int i, std::string value_arg,
const std::string &ref_arg) {
const char array[] = "A";
const char* ptr = "A";
std::string s;
static std::string ss;
switch (i) {
// Bad cases
case 0:
return array; // refers to local
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
case 1:
return s; // refers to local
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
case 2:
return std::string(); // refers to temporary
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
case 3:
return value_arg; // refers to by-value arg
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
// Ok cases
case 100:
return ss; // refers to static
case 101:
return static_array; // refers to static
case 102:
return ptr; // pointer is ok
case 103:
return ref_arg; // refers to by-ref arg
}
struct S {
std::string_view view() { return value; }
std::string value;
};
(void)[&]()->std::string_view {
// This should not warn. The string is bound by reference.
return s;
};
(void)[=]() -> std::string_view {
// This should not warn. The reference is valid as long as the lambda.
return s;
};
(void)[=]() -> std::string_view {
// FIXME: This one should warn. We are returning a reference to a local
// lambda variable.
std::string local;
return local;
};
return "";
}
void Containers() {
std::vector<std::string_view> v;
v.assign(3, std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
v.insert(nullptr, std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
v.insert(nullptr, 3, std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
v.push_back(std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
v.resize(3, std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
std::set<std::string_view> s;
s.insert(std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
s.insert(nullptr, std::string());
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
std::map<std::string_view, int> m;
m[std::string()];
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
}
void TakesAStringView(std::string_view);
void Negatives(std::string_view default_arg = ReturnsAString()) {
std::string str;
std::string_view view = str;
TakesAStringView(std::string());
}