summaryrefslogtreecommitdiff
path: root/test/Analysis/self-assign.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/self-assign.cpp')
-rw-r--r--test/Analysis/self-assign.cpp89
1 files changed, 89 insertions, 0 deletions
diff --git a/test/Analysis/self-assign.cpp b/test/Analysis/self-assign.cpp
new file mode 100644
index 0000000000000..74fb0fea24767
--- /dev/null
+++ b/test/Analysis/self-assign.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify -analyzer-output=text
+
+extern "C" char *strdup(const char* s);
+extern "C" void free(void* ptr);
+
+namespace std {
+template<class T> struct remove_reference { typedef T type; };
+template<class T> struct remove_reference<T&> { typedef T type; };
+template<class T> struct remove_reference<T&&> { typedef T type; };
+template<class T> typename remove_reference<T>::type&& move(T&& t);
+}
+
+void clang_analyzer_eval(int);
+
+class StringUsed {
+public:
+ StringUsed(const char *s = "") : str(strdup(s)) {}
+ StringUsed(const StringUsed &rhs) : str(strdup(rhs.str)) {}
+ ~StringUsed();
+ StringUsed& operator=(const StringUsed &rhs);
+ StringUsed& operator=(StringUsed &&rhs);
+ operator const char*() const;
+private:
+ char *str;
+};
+
+StringUsed::~StringUsed() {
+ free(str);
+}
+
+StringUsed& StringUsed::operator=(const StringUsed &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
+ clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
+ free(str); // expected-note{{Memory is released}}
+ str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} expected-note{{Use of memory after it is freed}}
+ return *this;
+}
+
+StringUsed& StringUsed::operator=(StringUsed &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
+ clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
+ str = rhs.str;
+ rhs.str = nullptr; // FIXME: An improved leak checker should warn here
+ return *this;
+}
+
+StringUsed::operator const char*() const {
+ return str;
+}
+
+class StringUnused {
+public:
+ StringUnused(const char *s = "") : str(strdup(s)) {}
+ StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {}
+ ~StringUnused();
+ StringUnused& operator=(const StringUnused &rhs);
+ StringUnused& operator=(StringUnused &&rhs);
+ operator const char*() const;
+private:
+ char *str;
+};
+
+StringUnused::~StringUnused() {
+ free(str);
+}
+
+StringUnused& StringUnused::operator=(const StringUnused &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
+ clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
+ free(str); // expected-note{{Memory is released}}
+ str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} expected-note{{Use of memory after it is freed}}
+ return *this;
+}
+
+StringUnused& StringUnused::operator=(StringUnused &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
+ clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
+ str = rhs.str;
+ rhs.str = nullptr; // FIXME: An improved leak checker should warn here
+ return *this;
+}
+
+StringUnused::operator const char*() const {
+ return str;
+}
+
+
+int main() {
+ StringUsed s1 ("test"), s2;
+ s2 = s1;
+ s2 = std::move(s1);
+ return 0;
+}