1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
// RUN: %check_clang_tidy -std=c++11,c++14 %s bugprone-dangling-handle %t -- \
// RUN: -config="{CheckOptions: \
// RUN: [{key: bugprone-dangling-handle.HandleClasses, \
// RUN: value: 'std::basic_string_view; ::llvm::StringRef;'}]}"
// FIXME: Fix the checker to work in C++17 mode.
namespace std {
template <typename T>
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 <typename, typename>
class pair {};
template <typename T>
class set {
public:
using const_iterator = const T*;
using iterator = T*;
std::pair<iterator, bool> insert(const T& value);
std::pair<iterator, bool> insert(T&& value);
iterator insert(const_iterator hint, const T& value);
iterator insert(const_iterator hint, T&& value);
};
template <typename Key, typename Value>
class map {
public:
using value_type = pair<Key, Value>;
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<std::string_view> 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<std::string_view> 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<std::string_view, int> 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());
}
|