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