[analyzer] Model strsep(), particularly that it returns its input.

This handles the false positive leak warning in PR15374, and also serves
as a basic model for the strsep() function.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180069 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index 74cf33c..6cf52f7 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1028,6 +1028,57 @@
 }
 
 //===----------------------------------------------------------------------===
+// strsep()
+//===----------------------------------------------------------------------===
+
+char *strsep(char **stringp, const char *delim);
+
+void strsep_null_delim(char *s) {
+  strsep(&s, NULL); // expected-warning{{Null pointer argument in call to strsep()}}
+}
+
+void strsep_null_search() {
+  strsep(NULL, ""); // expected-warning{{Null pointer argument in call to strsep()}}
+}
+
+void strsep_return_original_pointer(char *s) {
+  char *original = s;
+  char *result = strsep(&s, ""); // no-warning
+  clang_analyzer_eval(original == result); // expected-warning{{TRUE}}
+}
+
+void strsep_null_string() {
+  char *s = NULL;
+  char *result = strsep(&s, ""); // no-warning
+  clang_analyzer_eval(result == NULL); // expected-warning{{TRUE}}
+}
+
+void strsep_changes_input_pointer(char *s) {
+  char *original = s;
+  strsep(&s, ""); // no-warning
+  clang_analyzer_eval(s == original); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s == NULL); // expected-warning{{UNKNOWN}}
+
+  // Check that the value is symbolic.
+  if (s == NULL) {
+    clang_analyzer_eval(s == NULL); // expected-warning{{TRUE}}
+  }
+}
+
+void strsep_changes_input_string() {
+  char str[] = "abc";
+
+  clang_analyzer_eval(str[1] == 'b'); // expected-warning{{TRUE}}
+
+  char *s = str;
+  strsep(&s, "b"); // no-warning
+
+  // The real strsep will change the first delimiter it finds into a NUL
+  // character. For now, we just model the invalidation.
+  clang_analyzer_eval(str[1] == 'b'); // expected-warning{{UNKNOWN}}
+}
+
+//===----------------------------------------------------------------------===
 // FIXMEs
 //===----------------------------------------------------------------------===