balazske updated this revision to Diff 504185.
balazske added a comment.

Change format of bug reports.
Now the problem is shown first, then the acceptable values.
Sometimes the messages can become too verbose (in case of
"should be NULL") or grammatically not totally correct,
I can not tell if this is acceptable but this was the most
simple implementation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144003/new/

https://reviews.llvm.org/D144003

Files:
  clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
  clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
  clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
  clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
  clang/test/Analysis/std-c-library-functions-arg-constraints.c
  clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
  clang/test/Analysis/stream-note.c
  clang/test/Analysis/stream-stdlibraryfunctionargs.c

Index: clang/test/Analysis/stream-stdlibraryfunctionargs.c
===================================================================
--- clang/test/Analysis/stream-stdlibraryfunctionargs.c
+++ clang/test/Analysis/stream-stdlibraryfunctionargs.c
@@ -18,31 +18,31 @@
 void test_fopen(void) {
   FILE *fp = fopen("path", "r");
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
-  fclose(fp); // stdargs-warning{{should not be NULL}}
+  fclose(fp); // stdargs-warning{{should be not NULL}}
 }
 
 void test_tmpfile(void) {
   FILE *fp = tmpfile();
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
-  fclose(fp); // stdargs-warning{{should not be NULL}}
+  fclose(fp); // stdargs-warning{{should be not NULL}}
 }
 
 void test_fclose(void) {
   FILE *fp = tmpfile();
-  fclose(fp); // stdargs-warning{{should not be NULL}}
+  fclose(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
 }
 
 void test_freopen(void) {
   FILE *fp = tmpfile();
-  fp = freopen("file", "w", fp); // stdargs-warning{{should not be NULL}}
-  fclose(fp); // stdargs-warning{{should not be NULL}}
+  fp = freopen("file", "w", fp); // stdargs-warning{{should be not NULL}}
+  fclose(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
 }
 
 void test_fread(void) {
   FILE *fp = tmpfile();
-  size_t ret = fread(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fread' should not be NULL}}
+  size_t ret = fread(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fread' is NULL that is out of the accepted range}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   clang_analyzer_eval(ret <= n); // any-warning{{TRUE}}
   clang_analyzer_eval(ret == n); // any-warning{{TRUE}} any-warning{{FALSE}}
@@ -52,7 +52,7 @@
 
 void test_fwrite(void) {
   FILE *fp = tmpfile();
-  size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fwrite' should not be NULL}}
+  size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fwrite' is NULL that is out of the accepted range}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   clang_analyzer_eval(ret <= n); // any-warning{{TRUE}}
   clang_analyzer_eval(ret == n); // any-warning{{TRUE}} any-warning{{FALSE}}
@@ -62,21 +62,21 @@
 
 void test_fseek(void) {
   FILE *fp = tmpfile();
-  fseek(fp, 0, 0); // stdargs-warning{{should not be NULL}}
+  fseek(fp, 0, 0); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_ftell(void) {
   FILE *fp = tmpfile();
-  ftell(fp); // stdargs-warning{{should not be NULL}}
+  ftell(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_rewind(void) {
   FILE *fp = tmpfile();
-  rewind(fp); // stdargs-warning{{should not be NULL}}
+  rewind(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
@@ -84,7 +84,7 @@
 void test_fgetpos(void) {
   FILE *fp = tmpfile();
   fpos_t pos;
-  fgetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
+  fgetpos(fp, &pos); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
@@ -92,35 +92,35 @@
 void test_fsetpos(void) {
   FILE *fp = tmpfile();
   fpos_t pos;
-  fsetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
+  fsetpos(fp, &pos); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_clearerr(void) {
   FILE *fp = tmpfile();
-  clearerr(fp); // stdargs-warning{{should not be NULL}}
+  clearerr(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_feof(void) {
   FILE *fp = tmpfile();
-  feof(fp); // stdargs-warning{{should not be NULL}}
+  feof(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_ferror(void) {
   FILE *fp = tmpfile();
-  ferror(fp); // stdargs-warning{{should not be NULL}}
+  ferror(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_fileno(void) {
   FILE *fp = tmpfile();
-  fileno(fp); // stdargs-warning{{should not be NULL}}
+  fileno(fp); // stdargs-warning{{should be not NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
Index: clang/test/Analysis/stream-note.c
===================================================================
--- clang/test/Analysis/stream-note.c
+++ clang/test/Analysis/stream-note.c
@@ -88,8 +88,8 @@
     fclose(F);
     return;
   }
-  fclose(F); // stdargs-warning {{The 1st argument to 'fclose' should not be NULL}}
-             // stdargs-note@-1 {{The 1st argument to 'fclose' should not be NULL}}
+  fclose(F); // stdargs-warning {{The 1st argument to 'fclose' is NULL that is out of the accepted range}}
+             // stdargs-note@-1 {{The 1st argument to 'fclose' is NULL that is out of the accepted range}}
 }
 
 void check_eof_notes_feof_after_feof(void) {
Index: clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
+++ clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
@@ -14,5 +14,5 @@
 
 void test_arg_constraint_on_fun_with_default_param() {
   __defaultparam(nullptr); // \
-  // expected-warning{{The 1st argument to '__defaultparam' should not be NULL}}
+  // expected-warning{{The 1st argument to '__defaultparam' is NULL that is out of the accepted range; It should be not NULL}}
 }
Index: clang/test/Analysis/std-c-library-functions-arg-constraints.c
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -30,9 +30,9 @@
 
 void test_alnum_concrete(int v) {
   int ret = isalnum(256); // \
-  // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
-  // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
-  // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}}
+  // report-warning{{The 1st argument to 'isalnum' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'isalnum' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'isalnum' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
   (void)ret;
 }
 
@@ -55,9 +55,9 @@
     // bugpath-note{{Taking true branch}}
 
     int ret = isalnum(x); // \
-    // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
-    // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
-    // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}}
+    // report-warning{{The 1st argument to 'isalnum' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'isalnum' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'isalnum' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
 
     (void)ret;
   }
@@ -67,9 +67,9 @@
 
 void test_toupper_concrete(int v) {
   int ret = toupper(256); // \
-  // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
-  // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
-  // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}}
+  // report-warning{{The 1st argument to 'toupper' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'toupper' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'toupper' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
   (void)ret;
 }
 
@@ -91,9 +91,9 @@
     // bugpath-note{{Taking true branch}}
 
     int ret = toupper(x); // \
-    // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
-    // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
-    // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}}
+    // report-warning{{The 1st argument to 'toupper' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'toupper' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'toupper' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
 
     (void)ret;
   }
@@ -103,9 +103,9 @@
 
 void test_tolower_concrete(int v) {
   int ret = tolower(256); // \
-  // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
-  // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
-  // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}}
+  // report-warning{{The 1st argument to 'tolower' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'tolower' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'tolower' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
   (void)ret;
 }
 
@@ -127,9 +127,9 @@
     // bugpath-note{{Taking true branch}}
 
     int ret = tolower(x); // \
-    // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
-    // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
-    // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}}
+    // report-warning{{The 1st argument to 'tolower' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'tolower' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'tolower' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
 
     (void)ret;
   }
@@ -139,9 +139,9 @@
 
 void test_toascii_concrete(int v) {
   int ret = toascii(256); // \
-  // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
-  // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
-  // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}}
+  // report-warning{{The 1st argument to 'toascii' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'toascii' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'toascii' is 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
   (void)ret;
 }
 
@@ -163,9 +163,9 @@
     // bugpath-note{{Taking true branch}}
 
     int ret = toascii(x); // \
-    // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
-    // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
-    // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}}
+    // report-warning{{The 1st argument to 'toascii' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'toascii' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'toascii' is >= 256 that is out of the accepted range; It should be an unsigned char value or EOF}}
 
     (void)ret;
   }
@@ -176,9 +176,9 @@
 size_t fread(void *restrict, size_t, size_t, FILE *restrict);
 void test_notnull_concrete(FILE *fp) {
   fread(0, sizeof(int), 10, fp); // \
-  // report-warning{{The 1st argument to 'fread' should not be NULL}} \
-  // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \
-  // bugpath-note{{The 1st argument to 'fread' should not be NULL}}
+  // report-warning{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-warning{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-note{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}}
 }
 void test_notnull_symbolic(FILE *fp, int *buf) {
   fread(buf, sizeof(int), 10, fp);
@@ -192,9 +192,9 @@
   if (!buf)                          // bugpath-note{{Assuming 'buf' is null}} \
             // bugpath-note{{Taking true branch}}
     fread(buf, sizeof(int), 10, fp); // \
-    // report-warning{{The 1st argument to 'fread' should not be NULL}} \
-    // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \
-    // bugpath-note{{The 1st argument to 'fread' should not be NULL}}
+    // report-warning{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+    // bugpath-warning{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+    // bugpath-note{{The 1st argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}}
 }
 void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
   if (fp) // \
@@ -202,9 +202,9 @@
   // bugpath-note{{Taking false branch}}
     return;
   size_t ret = fread(buf, size, n, fp); // \
-  // report-warning{{The 4th argument to 'fread' should not be NULL}} \
-  // bugpath-warning{{The 4th argument to 'fread' should not be NULL}} \
-  // bugpath-note{{The 4th argument to 'fread' should not be NULL}}
+  // report-warning{{The 4th argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-warning{{The 4th argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-note{{The 4th argument to 'fread' is NULL that is out of the accepted range; It should be not NULL}}
   clang_analyzer_warnIfReached(); // not reachable
 }
 
@@ -220,9 +220,9 @@
   // The 3rd parameter should be the number of elements to read, not
   // the size in bytes.
   fread(wbuf, size, nitems, file); // \
-  // report-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
+  // report-warning{{The 1st argument to 'fread' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+  // bugpath-warning{{The 1st argument to 'fread' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+  // bugpath-note{{The 1st argument to 'fread' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
 }
 
 int __two_constrained_args(int, int);
@@ -255,18 +255,18 @@
 int __variadic(void *stream, const char *format, ...);
 void test_arg_constraint_on_variadic_fun(void) {
   __variadic(0, "%d%d", 1, 2); // \
-  // report-warning{{The 1st argument to '__variadic' should not be NULL}} \
-  // bugpath-warning{{The 1st argument to '__variadic' should not be NULL}} \
-  // bugpath-note{{The 1st argument to '__variadic' should not be NULL}}
+  // report-warning{{The 1st argument to '__variadic' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-warning{{The 1st argument to '__variadic' is NULL that is out of the accepted range; It should be not NULL}} \
+  // bugpath-note{{The 1st argument to '__variadic' is NULL that is out of the accepted range; It should be not NULL}}
 }
 
 int __buf_size_arg_constraint(const void *, size_t);
 void test_buf_size_concrete(void) {
   char buf[3];                       // bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint(buf, 4); // \
-  // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
-  // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
-  // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}}
 }
 void test_buf_size_symbolic(int s) {
   char buf[3];
@@ -291,9 +291,9 @@
 void test_buf_size_concrete_with_multiplication(void) {
   short buf[3];                                         // bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
-  // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
 }
 void test_buf_size_symbolic_with_multiplication(size_t s) {
   short buf[3];
@@ -317,7 +317,7 @@
 void test_min_buf_size(void) {
   char buf[9];// bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint_concrete(buf); // \
-  // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \
-  // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \
-  // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10}}
 }
Index: clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
+++ clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
@@ -16,8 +16,8 @@
   char buf[3];                       // bugpath-note{{'buf' initialized here}}
   int s = 4;                         // bugpath-note{{'s' initialized to 4}}
   __buf_size_arg_constraint(buf, s); // \
-  // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
-  // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}}
 }
 
 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
@@ -26,6 +26,6 @@
   int s1 = 4;                                 // bugpath-note{{'s1' initialized to 4}}
   int s2 = sizeof(short);                     // bugpath-note{{'s2' initialized to}}
   __buf_size_arg_constraint_mul(buf, s1, s2); // \
-  // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
 }
Index: clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
+++ clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
@@ -15,7 +15,7 @@
 int __not_null(int *);
 void test_not_null(int *x) {
   __not_null(nullptr); // \
-  // expected-warning{{The 1st argument to '__not_null' should not be NULL}}
+  // expected-warning{{The 1st argument to '__not_null' is NULL that is out of the accepted range; It should be not NULL [}}
 }
 
 // Check the BufferSizeConstraint violation notes.
@@ -28,19 +28,19 @@
   case 1: {
     char buf[9];
     __buf_size_arg_constraint_concrete(buf); // \
-    // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
+    // expected-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10 [}}
     break;
   }
   case 2: {
     char buf[3];
     __buf_size_arg_constraint(buf, 4); // \
-    // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
+    // expected-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}}
     break;
   }
   case 3: {
     char buf[3];
     __buf_size_arg_constraint_mul(buf, 4, 2); // \
-    // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
+    // expected-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
     break;
   }
   }
@@ -78,34 +78,36 @@
 int __range_out_1_2__4_6(int); // [1, 2], [4, 6]
 int __range_out_1_2__4_inf(int); // [1, 2], [4, inf]
 
+int __test_case_range_1_2__4_6(int);
+
 void test_range_values(int x) {
   switch (x) {
   case 0:
-    __single_val_0(1); // expected-warning{{should be zero}}
+    __single_val_0(1); // expected-warning{{is 1 that is out of the accepted range; It should be zero}}
     break;
   case 1:
-    __single_val_1(2); // expected-warning{{should be 1}}
+    __single_val_1(2); // expected-warning{{is 2 that is out of the accepted range; It should be 1}}
     break;
   case 2:
-    __range_1_2(3); // expected-warning{{should be 1 or 2}}
+    __range_1_2(3); // expected-warning{{is 3 that is out of the accepted range; It should be 1 or 2}}
     break;
   case 3:
-    __range_m1_1(3); // expected-warning{{should be between -1 and 1}}
+    __range_m1_1(3); // expected-warning{{is 3 that is out of the accepted range; It should be between -1 and 1}}
     break;
   case 4:
-    __range_m2_m1(1); // expected-warning{{should be -2 or -1}}
+    __range_m2_m1(1); // expected-warning{{is 1 that is out of the accepted range; It should be -2 or -1}}
     break;
   case 5:
-    __range_m10_10(11); // expected-warning{{should be between -10 and 10}}
+    __range_m10_10(11); // expected-warning{{is 11 that is out of the accepted range; It should be between -10 and 10}}
     break;
   case 6:
-    __range_m10_10(-11); // expected-warning{{should be between -10 and 10}}
+    __range_m10_10(-11); // expected-warning{{is -11 that is out of the accepted range; It should be between -10 and 10}}
     break;
   case 7:
-    __range_1_2__4_6(3); // expected-warning{{should be 1 or 2 or 4, 5 or 6}}
+    __range_1_2__4_6(3); // expected-warning{{is 3 that is out of the accepted range; It should be 1 or 2 or between 4 and 6}}
     break;
   case 8:
-    __range_1_2__4_inf(3); // expected-warning{{should be 1 or 2 or >= 4}}
+    __range_1_2__4_inf(3); // expected-warning{{is 3 that is out of the accepted range; It should be 1 or 2 or >= 4}}
     break;
   }
 }
@@ -113,22 +115,22 @@
 void test_range_values_inf(int x) {
   switch (x) {
   case 1:
-    __range_m1_inf(-2); // expected-warning{{should be >= -1}}
+    __range_m1_inf(-2); // expected-warning{{is -2 that is out of the accepted range; It should be >= -1}}
     break;
   case 2:
-    __range_0_inf(-1); // expected-warning{{should be >= 0}}
+    __range_0_inf(-1); // expected-warning{{is -1 that is out of the accepted range; It should be >= 0}}
     break;
   case 3:
-    __range_1_inf(0); // expected-warning{{should be > 0}}
+    __range_1_inf(0); // expected-warning{{is 0 that is out of the accepted range; It should be > 0}}
     break;
   case 4:
-    __range_minf_m1(0); // expected-warning{{should be < 0}}
+    __range_minf_m1(0); // expected-warning{{is 0 that is out of the accepted range; It should be < 0}}
     break;
   case 5:
-    __range_minf_0(1); // expected-warning{{should be <= 0}}
+    __range_minf_0(1); // expected-warning{{is 1 that is out of the accepted range; It should be <= 0}}
     break;
   case 6:
-    __range_minf_1(2); // expected-warning{{should be <= 1}}
+    __range_minf_1(2); // expected-warning{{is 2 that is out of the accepted range; It should be <= 1}}
     break;
   }
 }
@@ -136,28 +138,28 @@
 void test_range_values_out(int x) {
   switch (x) {
   case 0:
-    __single_val_out_0(0); // expected-warning{{should be nonzero}}
+    __single_val_out_0(0); // expected-warning{{is 0 that is out of the accepted range; It should be nonzero}}
     break;
   case 1:
-    __single_val_out_1(1); // expected-warning{{should be not equal to 1}}
+    __single_val_out_1(1); // expected-warning{{is 1 that is out of the accepted range; It should be not equal to 1}}
     break;
   case 2:
-    __range_out_1_2(2); // expected-warning{{should be not 1 and not 2}}
+    __range_out_1_2(2); // expected-warning{{is 2 that is out of the accepted range; It should be not 1 and not 2}}
     break;
   case 3:
-    __range_out_m1_1(-1); // expected-warning{{should be not between -1 and 1}}
+    __range_out_m1_1(-1); // expected-warning{{is -1 that is out of the accepted range; It should be not between -1 and 1}}
     break;
   case 4:
-    __range_out_m2_m1(-2); // expected-warning{{should be not -2 and not -1}}
+    __range_out_m2_m1(-2); // expected-warning{{is -2 that is out of the accepted range; It should be not -2 and not -1}}
     break;
   case 5:
-    __range_out_m10_10(0); // expected-warning{{should be not between -10 and 10}}
+    __range_out_m10_10(0); // expected-warning{{is 0 that is out of the accepted range; It should be not between -10 and 10}}
     break;
   case 6:
-    __range_out_1_2__4_6(1); // expected-warning{{should be not 1 and not 2 and not between 4 and 6}}
+    __range_out_1_2__4_6(1); // expected-warning{{is 1 that is out of the accepted range; It should be not 1 and not 2 and not between 4 and 6}}
     break;
   case 7:
-    __range_out_1_2__4_inf(4); // expected-warning{{should be not 1 and not 2 and < 4}}
+    __range_out_1_2__4_inf(4); // expected-warning{{is 4 that is out of the accepted range; It should be not 1 and not 2 and < 4}}
     break;
   }
 }
@@ -165,22 +167,71 @@
 void test_range_values_out_inf(int x) {
   switch (x) {
   case 1:
-    __range_out_minf_m1(-1); // expected-warning{{should be >= 0}}
+    __range_out_minf_m1(-1); // expected-warning{{is -1 that is out of the accepted range; It should be >= 0}}
     break;
   case 2:
-    __range_out_minf_0(0); // expected-warning{{should be > 0}}
+    __range_out_minf_0(0); // expected-warning{{is 0 that is out of the accepted range; It should be > 0}}
     break;
   case 3:
-    __range_out_minf_1(1); // expected-warning{{should be > 1}}
+    __range_out_minf_1(1); // expected-warning{{is 1 that is out of the accepted range; It should be > 1}}
     break;
   case 4:
-    __range_out_m1_inf(-1); // expected-warning{{should be < -1}}
+    __range_out_m1_inf(-1); // expected-warning{{is -1 that is out of the accepted range; It should be < -1}}
     break;
   case 5:
-    __range_out_0_inf(0); // expected-warning{{should be < 0}}
+    __range_out_0_inf(0); // expected-warning{{is 0 that is out of the accepted range; It should be < 0}}
     break;
   case 6:
-    __range_out_1_inf(1); // expected-warning{{should be <= 0}}
+    __range_out_1_inf(1); // expected-warning{{is 1 that is out of the accepted range; It should be <= 0}}
     break;
   }
 }
+
+void test_explanation(int x, int y) {
+  switch (y) {
+  case 1:
+    if (x > 0)
+      __single_val_0(x); // expected-warning{{is > 0 that is out of the accepted range; It should be zero [}}
+    return;
+  case 2:
+    if (x < 0)
+      __single_val_0(x); // expected-warning{{is < 0 that is out of the accepted range; It should be zero [}}
+    return;
+  case 3:
+    if (x < -1)
+      __single_val_0(x); // expected-warning{{is < 0 that is out of the accepted range; It should be zero [}}
+    return;
+  case 4:
+    if (x != 0)
+      __single_val_0(x); // expected-warning{{is out of the accepted range; It should be zero [}}
+    return;
+  case 5:
+    if (x == 3)
+      __range_1_2__4_6(x); // expected-warning{{is 3 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 6:
+    if (x > 6)
+      __range_1_2__4_6(x); // expected-warning{{is >= 7 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 7:
+    if (x < 1)
+      __range_1_2__4_6(x); // expected-warning{{is <= 0 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 8:
+    if (__test_case_range_1_2__4_6(x) == 1)
+      __range_1_2__4_6(x); // expected-warning{{is 3 or <= 0 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 9:
+    if (__test_case_range_1_2__4_6(x) == 2)
+      __range_1_2__4_6(x); // expected-warning{{is 3 or >= 7 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 10:
+    if (__test_case_range_1_2__4_6(x) == 3)
+      __range_1_2__4_6(x); // expected-warning{{is <= 0 or >= 7 that is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  case 11:
+    if (__test_case_range_1_2__4_6(x) == 4)
+      __range_1_2__4_6(x); // expected-warning{{is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
+    return;
+  }
+}
Index: clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
+++ clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
@@ -19,7 +19,7 @@
 // Check NotNullConstraint assumption notes.
 int __not_null(int *);
 int test_not_null_note(int *x, int y) {
-  __not_null(x);      // expected-note{{Assuming the 1st argument to '__not_null' is not NULL}}
+  __not_null(x);      // expected-note{{Assuming that the 1st argument to '__not_null' is not NULL}}
   if (x)              // expected-note{{'x' is non-null}} \
                       // expected-note{{Taking true branch}}
     if (!y)           // expected-note{{Assuming 'y' is 0}} \
@@ -33,7 +33,7 @@
 // Check the RangeConstraint assumption notes.
 int __single_val_0(int);      // [0, 0]
 int test_range_constraint_note(int x, int y) {
-  __single_val_0(x);  // expected-note{{Assuming the 1st argument to '__single_val_0' is zero}}
+  __single_val_0(x);  // expected-note{{Assuming that the 1st argument to '__single_val_0' is zero}}
   return y / x;       // expected-warning{{Division by zero}} \
                       // expected-note{{Division by zero}}
 }
@@ -41,7 +41,7 @@
 // Check the BufferSizeConstraint assumption notes.
 int __buf_size_arg_constraint_concrete(const void *buf); // size of buf must be >= 10
 void test_buffer_size_note(char *buf, int y) {
-  __buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming the size of the 1st argument to '__buf_size_arg_constraint_concrete' is equal to or greater than 10}}
+  __buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming that the 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size equal to or greater than 10}}
   clang_analyzer_eval(clang_analyzer_getExtent(buf) >= 10); // expected-warning{{TRUE}} \
                                                             // expected-note{{TRUE}}
 
Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -102,21 +102,19 @@
   /// Special argument number for specifying the return value.
   static const ArgNo Ret;
 
-  using DescString = SmallString<96>;
-
-  /// Returns the string representation of an argument index.
+  /// Get a string representation of an argument index.
   /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
-  static SmallString<8> getArgDesc(ArgNo);
-  /// Append textual description of a numeric range [RMin,RMax] to the string
+  static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
+  /// Append textual description of a numeric range [RMin,RMax] to
   /// \p Out.
   static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
                                     QualType ArgT, BasicValueFactory &BVF,
-                                    DescString &Out);
-  /// Append textual description of a numeric range out of [RMin,RMax] to the
-  /// string \p Out.
+                                    llvm::raw_ostream &Out);
+  /// Append textual description of a numeric range out of [RMin,RMax] to
+  /// \p Out.
   static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
                                    QualType ArgT, BasicValueFactory &BVF,
-                                   DescString &Out);
+                                   llvm::raw_ostream &Out);
 
   class ValueConstraint;
 
@@ -150,23 +148,12 @@
                                   const Summary &Summary,
                                   CheckerContext &C) const = 0;
 
-    /// Represents that in which context do we require a description of the
-    /// constraint.
-    enum class DescriptionKind {
-      /// The constraint is violated.
-      Violation,
-      /// We assume that the constraint is satisfied.
-      /// This can be used when a precondition is satisfied, or when a summary
-      /// case is applied.
-      Assumption
-    };
-
     /// Give a description that explains the constraint to the user. Used when
     /// a bug is reported or when the constraint is applied and displayed as a
     /// note.
-    virtual std::string describe(DescriptionKind DK, const CallEvent &Call,
-                                 ProgramStateRef State,
-                                 const Summary &Summary) const {
+    virtual void describe(const CallEvent &Call, ProgramStateRef State,
+                          const Summary &Summary,
+                          llvm::raw_ostream &Out) const {
       // There are some descendant classes that are not used as argument
       // constraints, e.g. ComparisonConstraint. In that case we can safely
       // ignore the implementation of this function.
@@ -174,6 +161,29 @@
           "Description not implemented for summary case constraints");
     }
 
+    /// This function is called when the current constraint represents the
+    /// opposite of a constraint that was not satisfied in a given state, but
+    /// the opposite is satisfied. In this case the available information in the
+    /// program state and this constraint can be used to get a more detailed
+    /// description about the original constraint violation. This can be get by
+    /// try to narrow the current constraint while it remains satisfied in the
+    /// given program state. If useful information is found it is put into
+    /// \p Out, but it is possible to produce no output. If anything is added to
+    /// \p Out it should look like " but is ...", the string is added to the bug
+    /// report about a constraint violation.
+    virtual bool describeArgumentValue(const CallEvent &Call,
+                                       ProgramStateRef State,
+                                       const Summary &Summary,
+                                       llvm::raw_ostream &Out) const {
+      if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
+        if (const llvm::APSInt *Int = N->getAsInteger()) {
+          Out << *Int;
+          return true;
+        }
+      }
+      return false;
+    }
+
     /// Return those arguments that should be tracked when we report a bug about
     /// argument constraint violation. By default it is the argument that is
     /// constrained, however, in some special cases we need to track other
@@ -254,9 +264,13 @@
                           const Summary &Summary,
                           CheckerContext &C) const override;
 
-    std::string describe(DescriptionKind DK, const CallEvent &Call,
-                         ProgramStateRef State,
-                         const Summary &Summary) const override;
+    void describe(const CallEvent &Call, ProgramStateRef State,
+                  const Summary &Summary,
+                  llvm::raw_ostream &Out) const override;
+
+    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
+                               const Summary &Summary,
+                               llvm::raw_ostream &Out) const override;
 
     ValueConstraintPtr negate() const override {
       RangeConstraint Tmp(*this);
@@ -342,9 +356,13 @@
                           const Summary &Summary,
                           CheckerContext &C) const override;
 
-    std::string describe(DescriptionKind DK, const CallEvent &Call,
-                         ProgramStateRef State,
-                         const Summary &Summary) const override;
+    void describe(const CallEvent &Call, ProgramStateRef State,
+                  const Summary &Summary,
+                  llvm::raw_ostream &Out) const override;
+
+    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
+                               const Summary &Summary,
+                               llvm::raw_ostream &Out) const override;
 
     ValueConstraintPtr negate() const override {
       NotNullConstraint Tmp(*this);
@@ -396,9 +414,9 @@
                           const Summary &Summary,
                           CheckerContext &C) const override;
 
-    std::string describe(DescriptionKind DK, const CallEvent &Call,
-                         ProgramStateRef State,
-                         const Summary &Summary) const override;
+    void describe(const CallEvent &Call, ProgramStateRef State,
+                  const Summary &Summary,
+                  llvm::raw_ostream &Out) const override;
 
     std::vector<ArgNo> getArgsToTrack() const override {
       std::vector<ArgNo> Result{ArgN};
@@ -773,8 +791,20 @@
       return;
     assert(Call.getDecl() &&
            "Function found in summary must have a declaration available");
-    std::string Msg = VC->describe(ValueConstraint::DescriptionKind::Violation,
-                                   Call, C.getState(), Summary);
+    SmallString<256> Msg;
+    llvm::raw_svector_ostream MsgOs(Msg);
+
+    MsgOs << "The ";
+    printArgDesc(VC->getArgNo(), MsgOs);
+    MsgOs << " to '" << getFunctionName(Call) << "' is ";
+    bool ValuesPrinted =
+        NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
+    if (ValuesPrinted)
+      MsgOs << " that is out of the accepted range; It should be ";
+    else
+      MsgOs << "out of the accepted range; It should be ";
+    VC->describe(Call, C.getState(), Summary, MsgOs);
+    // NegatedVC->describeBug1(Call, N->getState(), Summary, MsgOs);
     Msg[0] = toupper(Msg[0]);
     if (!BT_InvalidArg)
       BT_InvalidArg = std::make_unique<BugType>(
@@ -816,55 +846,37 @@
 
 } // end of anonymous namespace
 
-SmallString<8>
-StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
-  SmallString<8> Result;
-  Result += std::to_string(ArgN + 1);
-  Result += llvm::getOrdinalSuffix(ArgN + 1);
-  Result += " argument";
-  return Result;
+void StdLibraryFunctionsChecker::printArgDesc(
+    StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
+  Out << std::to_string(ArgN + 1);
+  Out << llvm::getOrdinalSuffix(ArgN + 1);
+  Out << " argument";
 }
 
 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
                                                        llvm::APSInt RMax,
                                                        QualType ArgT,
                                                        BasicValueFactory &BVF,
-                                                       DescString &Out) {
+                                                       llvm::raw_ostream &Out) {
   if (RMin.isZero() && RMax.isZero())
-    Out.append("zero");
+    Out << "zero";
   else if (RMin == RMax)
-    RMin.toString(Out);
+    Out << RMin;
   else if (RMin == BVF.getMinValue(ArgT)) {
     if (RMax == -1)
-      Out.append("< 0");
-    else {
-      Out.append("<= ");
-      RMax.toString(Out);
-    }
+      Out << "< 0";
+    else
+      Out << "<= " << RMax;
   } else if (RMax == BVF.getMaxValue(ArgT)) {
     if (RMin.isOne())
-      Out.append("> 0");
-    else {
-      Out.append(">= ");
-      RMin.toString(Out);
-    }
+      Out << "> 0";
+    else
+      Out << ">= " << RMin;
   } else if (RMin.isNegative() == RMax.isNegative() &&
              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
-    RMin.toString(Out);
-    Out.append(" or ");
-    RMax.toString(Out);
-  } else if (RMin.isNegative() == RMax.isNegative() &&
-             RMin.getLimitedValue() == RMax.getLimitedValue() - 2) {
-    RMin.toString(Out);
-    Out.append(", ");
-    (RMin + 1).toString(Out, 10, RMin.isSigned());
-    Out.append(" or ");
-    RMax.toString(Out);
+    Out << RMin << " or " << RMax;
   } else {
-    Out.append("between ");
-    RMin.toString(Out);
-    Out.append(" and ");
-    RMax.toString(Out);
+    Out << "between " << RMin << " and " << RMax;
   }
 }
 
@@ -872,37 +884,26 @@
                                                       llvm::APSInt RMax,
                                                       QualType ArgT,
                                                       BasicValueFactory &BVF,
-                                                      DescString &Out) {
+                                                      llvm::raw_ostream &Out) {
   if (RMin.isZero() && RMax.isZero())
-    Out.append("nonzero");
+    Out << "nonzero";
   else if (RMin == RMax) {
-    Out.append("not equal to ");
-    RMin.toString(Out);
+    Out << "not equal to " << RMin;
   } else if (RMin == BVF.getMinValue(ArgT)) {
     if (RMax == -1)
-      Out.append(">= 0");
-    else {
-      Out.append("> ");
-      RMax.toString(Out);
-    }
+      Out << ">= 0";
+    else
+      Out << "> " << RMax;
   } else if (RMax == BVF.getMaxValue(ArgT)) {
     if (RMin.isOne())
-      Out.append("<= 0");
-    else {
-      Out.append("< ");
-      RMin.toString(Out);
-    }
+      Out << "<= 0";
+    else
+      Out << "< " << RMin;
   } else if (RMin.isNegative() == RMax.isNegative() &&
              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
-    Out.append("not ");
-    RMin.toString(Out);
-    Out.append(" and not ");
-    RMax.toString(Out);
+    Out << "not " << RMin << " and not " << RMax;
   } else {
-    Out.append("not between ");
-    RMin.toString(Out);
-    Out.append(" and ");
-    RMax.toString(Out);
+    Out << "not between " << RMin << " and " << RMax;
   }
 }
 
@@ -981,42 +982,74 @@
   return State;
 }
 
-std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
-    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
-    const Summary &Summary) const {
+void StdLibraryFunctionsChecker::RangeConstraint::describe(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
 
   BasicValueFactory &BVF = getBVF(State);
   QualType T = Summary.getArgType(getArgNo());
-  DescString Result;
-  const auto Violation = ValueConstraint::DescriptionKind::Violation;
-
-  Result += "the ";
-  Result += getArgDesc(ArgN);
-  Result += " to '";
-  Result += getFunctionName(Call);
-  Result += DK == Violation ? "' should be " : "' is ";
+
   if (!Description.empty()) {
-    Result += Description;
+    Out << Description;
   } else {
     unsigned I = Ranges.size();
     if (Kind == WithinRange) {
       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
         appendInsideRangeDesc(BVF.getValue(R.first, T),
-                              BVF.getValue(R.second, T), T, BVF, Result);
+                              BVF.getValue(R.second, T), T, BVF, Out);
         if (--I > 0)
-          Result += " or ";
+          Out << " or ";
       }
     } else {
       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
         appendOutOfRangeDesc(BVF.getValue(R.first, T),
-                             BVF.getValue(R.second, T), T, BVF, Result);
+                             BVF.getValue(R.second, T), T, BVF, Out);
         if (--I > 0)
-          Result += " and ";
+          Out << " and ";
       }
     }
   }
+}
+
+bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
+  unsigned int NRanges = 0;
+  bool HaveAllRanges = true;
+
+  ProgramStateManager &Mgr = State->getStateManager();
+  BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
+  ConstraintManager &CM = Mgr.getConstraintManager();
+  SVal V = getArgSVal(Call, getArgNo());
 
-  return Result.c_str();
+  if (auto N = V.getAs<NonLoc>()) {
+    if (const llvm::APSInt *Int = N->getAsInteger()) {
+      Out << *Int;
+      return true;
+    }
+    QualType T = Summary.getArgType(getArgNo());
+    SmallString<128> MoreInfo;
+    llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
+    auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
+      if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
+        if (NRanges > 0)
+          MoreInfoOs << " or ";
+        appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
+        ++NRanges;
+      } else {
+        HaveAllRanges = false;
+      }
+      return true;
+    };
+
+    applyOnRange(Kind, BVF, T, ApplyF);
+    assert(NRanges > 0);
+    if (!HaveAllRanges || NRanges == 1) {
+      Out << MoreInfo;
+      return true;
+    }
+  }
+  return false;
 }
 
 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
@@ -1055,17 +1088,20 @@
   return State->assume(L, CannotBeNull);
 }
 
-std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
-    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
-    const Summary &Summary) const {
-  SmallString<48> Result;
-  const auto Violation = ValueConstraint::DescriptionKind::Violation;
-  Result += "the ";
-  Result += getArgDesc(ArgN);
-  Result += " to '";
-  Result += getFunctionName(Call);
-  Result += DK == Violation ? "' should not be NULL" : "' is not NULL";
-  return Result.c_str();
+void StdLibraryFunctionsChecker::NotNullConstraint::describe(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
+  assert(CannotBeNull &&
+         "Describe should not be used when the value must be NULL");
+  Out << "not NULL";
+}
+
+bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
+  assert(!CannotBeNull && "This function is used when the value is NULL");
+  Out << "NULL";
+  return true;
 }
 
 ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
@@ -1110,28 +1146,20 @@
   llvm_unreachable("Size argument or the dynamic size is Undefined");
 }
 
-std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
-    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
-    const Summary &Summary) const {
-  SmallString<96> Result;
-  const auto Violation = ValueConstraint::DescriptionKind::Violation;
-  Result += "the size of the ";
-  Result += getArgDesc(ArgN);
-  Result += " to '";
-  Result += getFunctionName(Call);
-  Result += DK == Violation ? "' should be " : "' is ";
-  Result += "equal to or greater than ";
+void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
+  Out << "a buffer with size equal to or greater than ";
   if (ConcreteSize) {
-    ConcreteSize->toString(Result);
+    Out << *ConcreteSize;
   } else if (SizeArgN) {
-    Result += "the value of the ";
-    Result += getArgDesc(*SizeArgN);
+    Out << "the value of the ";
+    printArgDesc(*SizeArgN, Out);
     if (SizeMultiplierArgN) {
-      Result += " times the ";
-      Result += getArgDesc(*SizeMultiplierArgN);
+      Out << " times the ";
+      printArgDesc(*SizeMultiplierArgN, Out);
     }
   }
-  return Result.c_str();
 }
 
 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
@@ -1164,10 +1192,14 @@
     assert(SuccessSt);
     NewState = SuccessSt;
     if (NewState != State) {
-      SmallString<64> Msg;
-      Msg += "Assuming ";
-      Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
-                                  Call, NewState, Summary);
+      SmallString<128> Msg;
+      llvm::raw_svector_ostream Os(Msg);
+      Os << "Assuming that the ";
+      printArgDesc(Constraint->getArgNo(), Os);
+      Os << " to '";
+      Os << getFunctionName(Call);
+      Os << "' is ";
+      Constraint->describe(Call, NewState, Summary, Os);
       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
       NewNode = C.addTransition(
           NewState, NewNode,
@@ -3471,6 +3503,27 @@
                   ErrnoIrrelevant, "Function returns 0")
             .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
                   ErrnoIrrelevant, "Function returns 1"));
+    addToFunctionSummaryMap(
+        "__test_case_range_1_2__4_6",
+        Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .Case({ArgumentCondition(0U, WithinRange,
+                                     IntRangeVector{{IntMin, 0}, {3, 3}}),
+                   ReturnValueCondition(WithinRange, SingleValue(1))},
+                  ErrnoIrrelevant)
+            .Case({ArgumentCondition(0U, WithinRange,
+                                     IntRangeVector{{3, 3}, {7, IntMax}}),
+                   ReturnValueCondition(WithinRange, SingleValue(2))},
+                  ErrnoIrrelevant)
+            .Case({ArgumentCondition(0U, WithinRange,
+                                     IntRangeVector{{IntMin, 0}, {7, IntMax}}),
+                   ReturnValueCondition(WithinRange, SingleValue(3))},
+                  ErrnoIrrelevant)
+            .Case({ArgumentCondition(
+                       0U, WithinRange,
+                       IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
+                   ReturnValueCondition(WithinRange, SingleValue(4))},
+                  ErrnoIrrelevant));
   }
 
   SummariesInitialized = true;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to