1 // RUN: %check_clang_tidy -std=c++11,c++14 %s bugprone-dangling-handle %t -- \
2 // RUN: -config="{CheckOptions: \
3 // RUN: [{key: bugprone-dangling-handle.HandleClasses, \
4 // RUN: value: 'std::basic_string_view; ::llvm::StringRef;'}]}"
5 // FIXME: Fix the checker to work in C++17 mode.
6
7 namespace std {
8
9 template <typename T>
10 class vector {
11 public:
12 using const_iterator = const T*;
13 using iterator = T*;
14 using size_type = int;
15
16 void assign(size_type count, const T& value);
17 iterator insert(const_iterator pos, const T& value);
18 iterator insert(const_iterator pos, T&& value);
19 iterator insert(const_iterator pos, size_type count, const T& value);
20 void push_back(const T&);
21 void push_back(T&&);
22 void resize(size_type count, const T& value);
23 };
24
25 template <typename, typename>
26 class pair {};
27
28 template <typename T>
29 class set {
30 public:
31 using const_iterator = const T*;
32 using iterator = T*;
33
34 std::pair<iterator, bool> insert(const T& value);
35 std::pair<iterator, bool> insert(T&& value);
36 iterator insert(const_iterator hint, const T& value);
37 iterator insert(const_iterator hint, T&& value);
38 };
39
40 template <typename Key, typename Value>
41 class map {
42 public:
43 using value_type = pair<Key, Value>;
44 value_type& operator[](const Key& key);
45 value_type& operator[](Key&& key);
46 };
47
48 class basic_string_view;
49
50 class basic_string {
51 public:
52 basic_string();
53 basic_string(const char*);
54
55 operator basic_string_view() const noexcept;
56
57 ~basic_string();
58 };
59
60 typedef basic_string string;
61
62 class basic_string_view {
63 public:
64 basic_string_view(const char*);
65 };
66
67 typedef basic_string_view string_view;
68
69 } // namespace std
70
71 namespace llvm {
72
73 class StringRef {
74 public:
75 StringRef();
76 StringRef(const char*);
77 StringRef(const std::string&);
78 };
79
80 } // namespace llvm
81
82 std::string ReturnsAString();
83
Positives()84 void Positives() {
85 std::string_view view1 = std::string();
86 // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
87
88 std::string_view view_2 = ReturnsAString();
89 // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
90
91 view1 = std::string();
92 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
93
94 const std::string& str_ref = "";
95 std::string_view view3 = true ? "A" : str_ref;
96 // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
97 view3 = true ? "A" : str_ref;
98 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
99
100 std::string_view view4(ReturnsAString());
101 // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
102 }
103
OtherTypes()104 void OtherTypes() {
105 llvm::StringRef ref = std::string();
106 // CHECK-MESSAGES: [[@LINE-1]]:19: warning: llvm::StringRef outlives its value
107 }
108
109 const char static_array[] = "A";
ReturnStatements(int i,std::string value_arg,const std::string & ref_arg)110 std::string_view ReturnStatements(int i, std::string value_arg,
111 const std::string &ref_arg) {
112 const char array[] = "A";
113 const char* ptr = "A";
114 std::string s;
115 static std::string ss;
116 switch (i) {
117 // Bad cases
118 case 0:
119 return array; // refers to local
120 // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
121 case 1:
122 return s; // refers to local
123 // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
124 case 2:
125 return std::string(); // refers to temporary
126 // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
127 case 3:
128 return value_arg; // refers to by-value arg
129 // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
130
131 // Ok cases
132 case 100:
133 return ss; // refers to static
134 case 101:
135 return static_array; // refers to static
136 case 102:
137 return ptr; // pointer is ok
138 case 103:
139 return ref_arg; // refers to by-ref arg
140 }
141
142 struct S {
143 std::string_view view() { return value; }
144 std::string value;
145 };
146
147 (void)[&]()->std::string_view {
148 // This should not warn. The string is bound by reference.
149 return s;
150 };
151 (void)[=]() -> std::string_view {
152 // This should not warn. The reference is valid as long as the lambda.
153 return s;
154 };
155 (void)[=]() -> std::string_view {
156 // FIXME: This one should warn. We are returning a reference to a local
157 // lambda variable.
158 std::string local;
159 return local;
160 };
161 return "";
162 }
163
Containers()164 void Containers() {
165 std::vector<std::string_view> v;
166 v.assign(3, std::string());
167 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
168 v.insert(nullptr, std::string());
169 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
170 v.insert(nullptr, 3, std::string());
171 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
172 v.push_back(std::string());
173 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
174 v.resize(3, std::string());
175 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
176
177 std::set<std::string_view> s;
178 s.insert(std::string());
179 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
180 s.insert(nullptr, std::string());
181 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
182
183 std::map<std::string_view, int> m;
184 m[std::string()];
185 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
186 }
187
188 void TakesAStringView(std::string_view);
189
Negatives(std::string_view default_arg=ReturnsAString ())190 void Negatives(std::string_view default_arg = ReturnsAString()) {
191 std::string str;
192 std::string_view view = str;
193
194 TakesAStringView(std::string());
195 }
196