[clang] ce1fb03 - [clang][analyzer] Improve bug reports of StdLibraryFunctionsChecker.

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 12 01:25:43 PDT 2023


Author: Balázs Kéri
Date: 2023-04-12T10:24:55+02:00
New Revision: ce1fb03db8174ca63fedc6e3aebdd6fb2c4fcfdf

URL: https://github.com/llvm/llvm-project/commit/ce1fb03db8174ca63fedc6e3aebdd6fb2c4fcfdf
DIFF: https://github.com/llvm/llvm-project/commit/ce1fb03db8174ca63fedc6e3aebdd6fb2c4fcfdf.diff

LOG: [clang][analyzer] Improve bug reports of StdLibraryFunctionsChecker.

Add an additional explanation of what is wrong if a constraint is
not satisfied, in some cases.
Additionally the bug report generation is changed to use raw_ostream.

Reviewed By: Szelethus, NoQ

Differential Revision: https://reviews.llvm.org/D144003

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 98f5540cef709..4e3ea0934b6f1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -102,21 +102,19 @@ class StdLibraryFunctionsChecker
   /// 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 @@ class StdLibraryFunctionsChecker
 
     /// 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 @@ class StdLibraryFunctionsChecker
           "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 @@ class StdLibraryFunctionsChecker
                           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 @@ class StdLibraryFunctionsChecker
                           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 @@ class StdLibraryFunctionsChecker
                           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 @@ class StdLibraryFunctionsChecker
       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 @@ static BasicValueFactory &getBVF(ProgramStateRef State) {
 
 } // 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 @@ void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
                                                       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 @@ ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
   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 @@ ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
   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 @@ ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
   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 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
     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 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
                   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;

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
index 2ddcf7a3136fb..f9d901fca9da1 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
@@ -19,7 +19,7 @@ int clang_analyzer_getExtent(void *);
 // 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 @@ int test_not_null_note(int *x, int y) {
 // 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 @@ int test_range_constraint_note(int x, int y) {
 // 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}}
 

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
index 2a9b4821b8fdb..a1b956e009f40 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
+++ b/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 @@ void test_buffer_size(int x) {
   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_minf_1(int); // [-inf, 1]
 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(int x) {
 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_inf(int x) {
 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(int x) {
 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;
+  }
+}

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
index 38b5f03e46551..b2377363dbb63 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
@@ -16,8 +16,8 @@ void test_buf_size_concrete(void) {
   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 @@ void test_buf_size_concrete_with_multiplication(void) {
   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}}
 }

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
index cff435d627530..83666f3fe91e9 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -30,9 +30,9 @@ int isalnum(int);
 
 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 @@ void test_alnum_symbolic2(int x) {
     // 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 @@ int toupper(int);
 
 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 @@ void test_toupper_symbolic2(int x) {
     // 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 @@ int tolower(int);
 
 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 @@ void test_tolower_symbolic2(int x) {
     // 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 @@ int toascii(int);
 
 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 @@ void test_toascii_symbolic2(int x) {
     // 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 @@ typedef typeof(sizeof(int)) size_t;
 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 @@ void test_notnull_symbolic2(FILE *fp, int *buf) {
   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 @@ void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
   // 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 @@ void ARR38_C_F(FILE *file) {
   // 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 @@ void test_multiple_constraints_on_same_arg(int x) {
 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 @@ int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
 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 @@ int __buf_size_arg_constraint_concrete(const void *);
 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}}
 }

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
index 86fa98bf4f10c..48060bf052737 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
@@ -14,5 +14,5 @@ int __defaultparam(void *, int y = 3);
 
 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}}
 }

diff  --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c
index cd711bc27711a..199d208cbde82 100644
--- a/clang/test/Analysis/stream-note.c
+++ b/clang/test/Analysis/stream-note.c
@@ -88,8 +88,8 @@ void check_track_null(void) {
     fclose(F);
     return;
   }
-  fclose(F); // stdargs-warning {{The 1st argument to 'fclose' should not be NULL}}
-             // stdargs-note at -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 at -1 {{The 1st argument to 'fclose' is NULL but should not be NULL}}
 }
 
 void check_eof_notes_feof_after_feof(void) {

diff  --git a/clang/test/Analysis/stream-stdlibraryfunctionargs.c b/clang/test/Analysis/stream-stdlibraryfunctionargs.c
index 9d1b9244f0f24..6b4a6d10a8f61 100644
--- a/clang/test/Analysis/stream-stdlibraryfunctionargs.c
+++ b/clang/test/Analysis/stream-stdlibraryfunctionargs.c
@@ -42,7 +42,7 @@ void test_freopen(void) {
 
 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_fread(void) {
 
 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}}


        


More information about the cfe-commits mailing list