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