balazske updated this revision to Diff 510816.
balazske marked 3 inline comments as done.
balazske added a comment.

I decided to add back `DescriptionKind` and make possible to use a message like
"should not be NULL". Now all generated strings in functions `describe` and
`describeArgumentValue` start with "should be" or "is" to make this consistent.
The messages are now in form "is ... but should be ..." which sounds at some 
times
too trivial but acceptable as generated message.


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
@@ -42,7 +42,7 @@
 
 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 but should not be NULL}}
   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 but should not be NULL}}
   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}}
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 but should not be NULL}}
+             // stdargs-note@-1 {{The 1st argument to 'fclose' is NULL but should not be NULL}}
 }
 
 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 but should not be 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 but should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'isalnum' is 256 but should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'isalnum' is 256 but 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 but should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'isalnum' is >= 256 but should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'isalnum' is >= 256 but 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 but should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'toupper' is 256 but should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'toupper' is 256 but 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 but should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'toupper' is >= 256 but should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'toupper' is >= 256 but 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 but should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'tolower' is 256 but should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'tolower' is 256 but 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 but should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'tolower' is >= 256 but should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'tolower' is >= 256 but 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 but should be an unsigned char value or EOF}} \
+  // bugpath-warning{{The 1st argument to 'toascii' is 256 but should be an unsigned char value or EOF}} \
+  // bugpath-note{{The 1st argument to 'toascii' is 256 but 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 but should be an unsigned char value or EOF}} \
+    // bugpath-warning{{The 1st argument to 'toascii' is >= 256 but should be an unsigned char value or EOF}} \
+    // bugpath-note{{The 1st argument to 'toascii' is >= 256 but 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 but should not be NULL}} \
+  // bugpath-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
+  // bugpath-note{{The 1st argument to 'fread' is NULL but should not be 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 but should not be NULL}} \
+    // bugpath-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
+    // bugpath-note{{The 1st argument to 'fread' is NULL but should not be 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 but should not be NULL}} \
+  // bugpath-warning{{The 4th argument to 'fread' is NULL but should not be NULL}} \
+  // bugpath-note{{The 4th argument to 'fread' is NULL but should not be 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 but should not be NULL}} \
+  // bugpath-warning{{The 1st argument to '__variadic' is NULL but should not be NULL}} \
+  // bugpath-note{{The 1st argument to '__variadic' is NULL but should not be 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 but should not be 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 but should be zero}}
     break;
   case 1:
-    __single_val_1(2); // expected-warning{{should be 1}}
+    __single_val_1(2); // expected-warning{{is 2 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but should be >= -1}}
     break;
   case 2:
-    __range_0_inf(-1); // expected-warning{{should be >= 0}}
+    __range_0_inf(-1); // expected-warning{{is -1 but should be >= 0}}
     break;
   case 3:
-    __range_1_inf(0); // expected-warning{{should be > 0}}
+    __range_1_inf(0); // expected-warning{{is 0 but should be > 0}}
     break;
   case 4:
-    __range_minf_m1(0); // expected-warning{{should be < 0}}
+    __range_minf_m1(0); // expected-warning{{is 0 but should be < 0}}
     break;
   case 5:
-    __range_minf_0(1); // expected-warning{{should be <= 0}}
+    __range_minf_0(1); // expected-warning{{is 1 but should be <= 0}}
     break;
   case 6:
-    __range_minf_1(2); // expected-warning{{should be <= 1}}
+    __range_minf_1(2); // expected-warning{{is 2 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but 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 but should be zero [}}
+    return;
+  case 2:
+    if (x < 0)
+      __single_val_0(x); // expected-warning{{is < 0 but should be zero [}}
+    return;
+  case 3:
+    if (x < -1)
+      __single_val_0(x); // expected-warning{{is < 0 but 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 but 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 but 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 but 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 but 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 but 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 but 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;
 
@@ -152,21 +150,25 @@
 
     /// Represents that in which context do we require a description of the
     /// constraint.
-    enum class DescriptionKind {
-      /// The constraint is violated.
+    enum DescriptionKind {
+      /// Describe a constraint that was violated.
+      /// Description should start with something like "should be".
       Violation,
-      /// We assume that the constraint is satisfied.
+      /// Describe a constraint that was assumed to be true.
       /// This can be used when a precondition is satisfied, or when a summary
       /// case is applied.
+      /// Description should start with something like "is".
       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 {
+    /// note. The description should not mention the argument (getArgNo).
+    /// See StdLibraryFunctionsChecker::reportBug about how this function is
+    /// used (this function is used not only there).
+    virtual void describe(DescriptionKind DK, 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 +176,31 @@
           "Description not implemented for summary case constraints");
     }
 
+    /// Give a description that explains the actual argument value (where the
+    /// current ValueConstraint applies to) to the user. This function should be
+    /// called only when the current constraint is satisfied by the argument.
+    /// It should produce a more precise description than the constraint itself.
+    /// The actual value of the argument and the program state can be used to
+    /// make the description more precise. In the most simple case, if the
+    /// argument has a fixed known value this value can be printed into \p Out,
+    /// this is done by default.
+    /// The function should return true if a description was printed to \p Out,
+    /// otherwise false.
+    /// See StdLibraryFunctionsChecker::reportBug about how this function is
+    /// used.
+    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 +281,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(DescriptionKind DK, 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 +373,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(DescriptionKind DK, 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 +431,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(DescriptionKind DK, 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 +808,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) << "' ";
+    bool ValuesPrinted =
+        NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
+    if (ValuesPrinted)
+      MsgOs << " but ";
+    else
+      MsgOs << "is out of the accepted range; It ";
+    VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
+                 MsgOs);
     Msg[0] = toupper(Msg[0]);
     if (!BT_InvalidArg)
       BT_InvalidArg = std::make_unique<BugType>(
@@ -816,55 +863,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 +901,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 +999,77 @@
   return State;
 }
 
-std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
+void StdLibraryFunctionsChecker::RangeConstraint::describe(
     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
-    const Summary &Summary) const {
+    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 ";
+
+  Out << ((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 << "is ";
+      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 << "is ";
+      Out << MoreInfo;
+      return true;
+    }
+  }
+  return false;
 }
 
 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
@@ -1055,17 +1108,23 @@
   return State->assume(L, CannotBeNull);
 }
 
-std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
+void 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();
+    const Summary &Summary, llvm::raw_ostream &Out) const {
+  assert(CannotBeNull &&
+         "Describe should not be used when the value must be NULL");
+  if (DK == Violation)
+    Out << "should not be NULL";
+  else
+    Out << "is 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 << "is NULL";
+  return true;
 }
 
 ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
@@ -1110,28 +1169,21 @@
   llvm_unreachable("Size argument or the dynamic size is Undefined");
 }
 
-std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
+void 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 ";
+    const Summary &Summary, llvm::raw_ostream &Out) const {
+  Out << ((DK == Violation) ? "should be " : "is ");
+  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 +1216,15 @@
     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 << "' ";
+      Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
+                           Os);
       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
       NewNode = C.addTransition(
           NewState, NewNode,
@@ -3471,6 +3528,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