// RUN: %check_clang_tidy %s bugprone-dangling-handle %t -- \ // RUN: -config="{CheckOptions: \ // RUN: [{key: bugprone-dangling-handle.HandleClasses, \ // RUN: value: 'std::basic_string_view; ::llvm::StringRef;'}]}" \ // RUN: -- -std=c++11 namespace std { template class vector { public: using const_iterator = const T*; using iterator = T*; using size_type = int; void assign(size_type count, const T& value); iterator insert(const_iterator pos, const T& value); iterator insert(const_iterator pos, T&& value); iterator insert(const_iterator pos, size_type count, const T& value); void push_back(const T&); void push_back(T&&); void resize(size_type count, const T& value); }; template class pair {}; template class set { public: using const_iterator = const T*; using iterator = T*; std::pair insert(const T& value); std::pair insert(T&& value); iterator insert(const_iterator hint, const T& value); iterator insert(const_iterator hint, T&& value); }; template class map { public: using value_type = pair; value_type& operator[](const Key& key); value_type& operator[](Key&& key); }; class basic_string_view; class basic_string { public: basic_string(); basic_string(const char*); operator basic_string_view() const noexcept; ~basic_string(); }; typedef basic_string string; class basic_string_view { public: basic_string_view(const char*); }; typedef basic_string_view string_view; } // namespace std namespace llvm { class StringRef { public: StringRef(); StringRef(const char*); StringRef(const std::string&); }; } // namespace llvm std::string ReturnsAString(); void Positives() { std::string_view view1 = std::string(); // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle] std::string_view view_2 = ReturnsAString(); // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives view1 = std::string(); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives const std::string& str_ref = ""; std::string_view view3 = true ? "A" : str_ref; // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives view3 = true ? "A" : str_ref; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives std::string_view view4(ReturnsAString()); // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives } void OtherTypes() { llvm::StringRef ref = std::string(); // CHECK-MESSAGES: [[@LINE-1]]:19: warning: llvm::StringRef outlives its value } const char static_array[] = "A"; std::string_view ReturnStatements(int i, std::string value_arg, const std::string &ref_arg) { const char array[] = "A"; const char* ptr = "A"; std::string s; static std::string ss; switch (i) { // Bad cases case 0: return array; // refers to local // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv case 1: return s; // refers to local // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv case 2: return std::string(); // refers to temporary // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv case 3: return value_arg; // refers to by-value arg // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv // Ok cases case 100: return ss; // refers to static case 101: return static_array; // refers to static case 102: return ptr; // pointer is ok case 103: return ref_arg; // refers to by-ref arg } struct S { std::string_view view() { return value; } std::string value; }; (void)[&]()->std::string_view { // This should not warn. The string is bound by reference. return s; }; (void)[=]() -> std::string_view { // This should not warn. The reference is valid as long as the lambda. return s; }; (void)[=]() -> std::string_view { // FIXME: This one should warn. We are returning a reference to a local // lambda variable. std::string local; return local; }; return ""; } void Containers() { std::vector v; v.assign(3, std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives v.insert(nullptr, std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives v.insert(nullptr, 3, std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives v.push_back(std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives v.resize(3, std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives std::set s; s.insert(std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives s.insert(nullptr, std::string()); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives std::map m; m[std::string()]; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives } void TakesAStringView(std::string_view); void Negatives(std::string_view default_arg = ReturnsAString()) { std::string str; std::string_view view = str; TakesAStringView(std::string()); }