| 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 | |
| 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 | |
| 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" ; |
| 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 | |
| 182 | void Containers() { |
| 183 | std::vector<std::string_view> v; |
| 184 | v.assign(count: 3, value: std::string()); |
| 185 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives |
| 186 | v.insert(pos: nullptr, value: std::string()); |
| 187 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives |
| 188 | v.insert(pos: nullptr, count: 3, value: 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(count: 3, value: 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(value: std::string()); |
| 197 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives |
| 198 | s.insert(hint: nullptr, value: 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 | |
| 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 | |