xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/dangling-handle.cpp (revision 1097c71dbeefaff0c353c90cb57bc07b6ede6383)
1f2e50009SIgnat Loskutov // RUN: %check_clang_tidy -std=c++11,c++14 -check-suffix=,CXX14 %s bugprone-dangling-handle %t -- \
289a1d03eSRichard // RUN:   -config="{CheckOptions: \
3e8a3ddafSNathan James // RUN:             {bugprone-dangling-handle.HandleClasses: \
4e8a3ddafSNathan James // RUN:               'std::basic_string_view; ::llvm::StringRef;'}}"
5f2e50009SIgnat Loskutov 
6f2e50009SIgnat Loskutov // RUN: %check_clang_tidy -std=c++17-or-later -check-suffix=,CXX17 %s bugprone-dangling-handle %t -- \
7f2e50009SIgnat Loskutov // RUN:   -config="{CheckOptions: \
8f2e50009SIgnat Loskutov // RUN:             {bugprone-dangling-handle.HandleClasses: \
9f2e50009SIgnat Loskutov // RUN:               'std::basic_string_view; ::llvm::StringRef;'}}"
1089a1d03eSRichard 
1189a1d03eSRichard namespace std {
1289a1d03eSRichard 
1389a1d03eSRichard template <typename T>
1489a1d03eSRichard class vector {
1589a1d03eSRichard  public:
1689a1d03eSRichard   using const_iterator = const T*;
1789a1d03eSRichard   using iterator = T*;
1889a1d03eSRichard   using size_type = int;
1989a1d03eSRichard 
2089a1d03eSRichard   void assign(size_type count, const T& value);
2189a1d03eSRichard   iterator insert(const_iterator pos, const T& value);
2289a1d03eSRichard   iterator insert(const_iterator pos, T&& value);
2389a1d03eSRichard   iterator insert(const_iterator pos, size_type count, const T& value);
2489a1d03eSRichard   void push_back(const T&);
2589a1d03eSRichard   void push_back(T&&);
2689a1d03eSRichard   void resize(size_type count, const T& value);
2789a1d03eSRichard };
2889a1d03eSRichard 
2989a1d03eSRichard template <typename, typename>
3089a1d03eSRichard class pair {};
3189a1d03eSRichard 
3289a1d03eSRichard template <typename T>
3389a1d03eSRichard class set {
3489a1d03eSRichard  public:
3589a1d03eSRichard   using const_iterator = const T*;
3689a1d03eSRichard   using iterator = T*;
3789a1d03eSRichard 
3889a1d03eSRichard   std::pair<iterator, bool> insert(const T& value);
3989a1d03eSRichard   std::pair<iterator, bool> insert(T&& value);
4089a1d03eSRichard   iterator insert(const_iterator hint, const T& value);
4189a1d03eSRichard   iterator insert(const_iterator hint, T&& value);
4289a1d03eSRichard };
4389a1d03eSRichard 
4489a1d03eSRichard template <typename Key, typename Value>
4589a1d03eSRichard class map {
4689a1d03eSRichard  public:
4789a1d03eSRichard   using value_type = pair<Key, Value>;
4889a1d03eSRichard   value_type& operator[](const Key& key);
4989a1d03eSRichard   value_type& operator[](Key&& key);
5089a1d03eSRichard };
5189a1d03eSRichard 
5289a1d03eSRichard class basic_string_view;
5389a1d03eSRichard 
5489a1d03eSRichard class basic_string {
5589a1d03eSRichard  public:
5689a1d03eSRichard   basic_string();
5789a1d03eSRichard   basic_string(const char*);
5889a1d03eSRichard 
5935f466ebSPiotr Zegar   typedef basic_string_view str_view;
6035f466ebSPiotr Zegar   operator str_view() const noexcept;
6189a1d03eSRichard 
6289a1d03eSRichard   ~basic_string();
6389a1d03eSRichard };
6489a1d03eSRichard 
6589a1d03eSRichard typedef basic_string string;
6689a1d03eSRichard 
6789a1d03eSRichard class basic_string_view {
6889a1d03eSRichard  public:
6989a1d03eSRichard   basic_string_view(const char*);
7089a1d03eSRichard };
7189a1d03eSRichard 
7289a1d03eSRichard typedef basic_string_view string_view;
7389a1d03eSRichard 
7489a1d03eSRichard }  // namespace std
7589a1d03eSRichard 
7689a1d03eSRichard namespace llvm {
7789a1d03eSRichard 
7889a1d03eSRichard class StringRef {
7989a1d03eSRichard  public:
8089a1d03eSRichard   StringRef();
8189a1d03eSRichard   StringRef(const char*);
8289a1d03eSRichard   StringRef(const std::string&);
8389a1d03eSRichard };
8489a1d03eSRichard 
8589a1d03eSRichard }  // namespace llvm
8689a1d03eSRichard 
8789a1d03eSRichard std::string ReturnsAString();
8889a1d03eSRichard 
Positives()8989a1d03eSRichard void Positives() {
9089a1d03eSRichard   std::string_view view1 = std::string();
91f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
92f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:28: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
9389a1d03eSRichard 
9489a1d03eSRichard   std::string_view view_2 = ReturnsAString();
95f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
96f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:29: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
9789a1d03eSRichard 
9889a1d03eSRichard   view1 = std::string();
9989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
10089a1d03eSRichard 
10189a1d03eSRichard   const std::string& str_ref = "";
10289a1d03eSRichard   std::string_view view3 = true ? "A" : str_ref;
103f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives
104f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:28: warning: std::basic_string_view outlives
10589a1d03eSRichard   view3 = true ? "A" : str_ref;
10689a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
10789a1d03eSRichard 
10889a1d03eSRichard   std::string_view view4(ReturnsAString());
109f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives
110f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:26: warning: std::basic_string_view outlives
111*1097c71dSPiotr Zegar 
112*1097c71dSPiotr Zegar   std::string_view view5 = std::string("test");
113*1097c71dSPiotr Zegar   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
114*1097c71dSPiotr Zegar   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:28: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
115*1097c71dSPiotr Zegar 
116*1097c71dSPiotr Zegar   std::string_view view6 = std::string{"test"};
117*1097c71dSPiotr Zegar   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
118*1097c71dSPiotr Zegar   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:28: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
11989a1d03eSRichard }
12089a1d03eSRichard 
OtherTypes()12189a1d03eSRichard void OtherTypes() {
12289a1d03eSRichard   llvm::StringRef ref = std::string();
123f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX14: [[@LINE-1]]:19: warning: llvm::StringRef outlives its value
124f2e50009SIgnat Loskutov   // CHECK-MESSAGES-CXX17: [[@LINE-2]]:25: warning: llvm::StringRef outlives its value
12589a1d03eSRichard }
12689a1d03eSRichard 
12789a1d03eSRichard const char static_array[] = "A";
ReturnStatements(int i,std::string value_arg,const std::string & ref_arg)12889a1d03eSRichard std::string_view ReturnStatements(int i, std::string value_arg,
12989a1d03eSRichard                                   const std::string &ref_arg) {
13089a1d03eSRichard   const char array[] = "A";
13189a1d03eSRichard   const char* ptr = "A";
13289a1d03eSRichard   std::string s;
13389a1d03eSRichard   static std::string ss;
13489a1d03eSRichard   switch (i) {
13589a1d03eSRichard     // Bad cases
13689a1d03eSRichard     case 0:
13789a1d03eSRichard       return array;  // refers to local
13889a1d03eSRichard       // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
13989a1d03eSRichard     case 1:
14089a1d03eSRichard       return s;  // refers to local
14189a1d03eSRichard       // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
14289a1d03eSRichard     case 2:
14389a1d03eSRichard       return std::string();  // refers to temporary
14489a1d03eSRichard       // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
14589a1d03eSRichard     case 3:
14689a1d03eSRichard       return value_arg;  // refers to by-value arg
14789a1d03eSRichard       // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
14889a1d03eSRichard 
14989a1d03eSRichard     // Ok cases
15089a1d03eSRichard     case 100:
15189a1d03eSRichard       return ss;  // refers to static
15289a1d03eSRichard     case 101:
15389a1d03eSRichard       return static_array;  // refers to static
15489a1d03eSRichard     case 102:
15589a1d03eSRichard       return ptr;  // pointer is ok
15689a1d03eSRichard     case 103:
15789a1d03eSRichard       return ref_arg;  // refers to by-ref arg
15889a1d03eSRichard   }
15989a1d03eSRichard 
16089a1d03eSRichard   struct S {
16189a1d03eSRichard     std::string_view view() { return value; }
16289a1d03eSRichard     std::string value;
16389a1d03eSRichard   };
16489a1d03eSRichard 
16589a1d03eSRichard   (void)[&]()->std::string_view {
16689a1d03eSRichard     // This should not warn. The string is bound by reference.
16789a1d03eSRichard     return s;
16889a1d03eSRichard   };
16989a1d03eSRichard   (void)[=]() -> std::string_view {
17089a1d03eSRichard     // This should not warn. The reference is valid as long as the lambda.
17189a1d03eSRichard     return s;
17289a1d03eSRichard   };
17389a1d03eSRichard   (void)[=]() -> std::string_view {
17489a1d03eSRichard     // FIXME: This one should warn. We are returning a reference to a local
17589a1d03eSRichard     // lambda variable.
17689a1d03eSRichard     std::string local;
17789a1d03eSRichard     return local;
17889a1d03eSRichard   };
17989a1d03eSRichard   return "";
18089a1d03eSRichard }
18189a1d03eSRichard 
Containers()18289a1d03eSRichard void Containers() {
18389a1d03eSRichard   std::vector<std::string_view> v;
18489a1d03eSRichard   v.assign(3, std::string());
18589a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
18689a1d03eSRichard   v.insert(nullptr, std::string());
18789a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
18889a1d03eSRichard   v.insert(nullptr, 3, std::string());
18989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
19089a1d03eSRichard   v.push_back(std::string());
19189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
19289a1d03eSRichard   v.resize(3, std::string());
19389a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
19489a1d03eSRichard 
19589a1d03eSRichard   std::set<std::string_view> s;
19689a1d03eSRichard   s.insert(std::string());
19789a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
19889a1d03eSRichard   s.insert(nullptr, std::string());
19989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
20089a1d03eSRichard 
20189a1d03eSRichard   std::map<std::string_view, int> m;
20289a1d03eSRichard   m[std::string()];
20389a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
20489a1d03eSRichard }
20589a1d03eSRichard 
20689a1d03eSRichard void TakesAStringView(std::string_view);
20789a1d03eSRichard 
Negatives(std::string_view default_arg=ReturnsAString ())20889a1d03eSRichard void Negatives(std::string_view default_arg = ReturnsAString()) {
20989a1d03eSRichard   std::string str;
21089a1d03eSRichard   std::string_view view = str;
21189a1d03eSRichard 
21289a1d03eSRichard   TakesAStringView(std::string());
21389a1d03eSRichard }
21435f466ebSPiotr Zegar 
215