[clang] ddc5d40 - [clang][analyzer] Make messages of StdCLibraryFunctionsChecker user-friendly

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 15 00:23:41 PST 2023


Author: Balázs Kéri
Date: 2023-02-15T09:22:48+01:00
New Revision: ddc5d40dd285d6422dc66b9aa25064502af3218b

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

LOG: [clang][analyzer] Make messages of StdCLibraryFunctionsChecker user-friendly

Warnings and notes of checker alpha.unix.StdLibraryFunctionArgs are
improved. Previously one warning and one note was emitted for every
finding, now one warning is emitted only that contains a detailed
description of the found issue.

Reviewed By: Szelethus

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

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 49b3db560843d..b36f72f2653c7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -84,9 +84,20 @@ class StdLibraryFunctionsChecker
   typedef uint32_t ArgNo;
   static const ArgNo Ret;
 
+  using DescString = SmallString<96>;
   /// Returns the 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
+  /// '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 'Out'.
+  static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
+                                   QualType ArgT, BasicValueFactory &BVF,
+                                   DescString &Out);
 
   class ValueConstraint;
 
@@ -101,6 +112,12 @@ class StdLibraryFunctionsChecker
   /// (or return value) of a function. Derived classes implement 
diff erent kind
   /// of constraints, e.g range constraints or correlation between two
   /// arguments.
+  /// These are used as argument constraints (preconditions) of functions, in
+  /// which case a bug report may be emitted if the constraint is not satisfied.
+  /// Another use is as conditions for summary cases, to create 
diff erent
+  /// classes of behavior for a function. In this case no description of the
+  /// constraint is needed because the summary cases have an own (not generated)
+  /// description string.
   class ValueConstraint {
   public:
     ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
@@ -114,9 +131,9 @@ class StdLibraryFunctionsChecker
       llvm_unreachable("Not implemented");
     };
 
-    // Check whether the constraint is malformed or not. It is malformed if the
-    // specified argument has a mismatch with the given FunctionDecl (e.g. the
-    // arg number is out-of-range of the function's argument list).
+    /// Check whether the constraint is malformed or not. It is malformed if the
+    /// specified argument has a mismatch with the given FunctionDecl (e.g. the
+    /// arg number is out-of-range of the function's argument list).
     bool checkValidity(const FunctionDecl *FD) const {
       const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
       assert(ValidArg && "Arg out of range!");
@@ -127,31 +144,34 @@ class StdLibraryFunctionsChecker
     }
     ArgNo getArgNo() const { return ArgN; }
 
-    // Return those arguments that should be tracked when we report a bug. By
-    // default it is the argument that is constrained, however, in some special
-    // cases we need to track other arguments as well. E.g. a buffer size might
-    // be encoded in another argument.
+    /// Return those arguments that should be tracked when we report a bug. By
+    /// default it is the argument that is constrained, however, in some special
+    /// cases we need to track other arguments as well. E.g. a buffer size might
+    /// be encoded in another argument.
     virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
 
     virtual StringRef getName() const = 0;
 
-    // Represents that in which context do we require a description of the
-    // constraint.
+    /// Represents that in which context do we require a description of the
+    /// constraint.
     enum class DescriptionKind {
-      // The constraint is violated.
+      /// The constraint is violated.
       Violation,
-      // We assume that the constraint is satisfied.
+      /// We assume that the constraint is satisfied.
       Assumption
     };
 
-    // Give a description that explains the constraint to the user. Used when
-    // the bug is reported.
-    virtual std::string describe(DescriptionKind DK, ProgramStateRef State,
+    /// 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 {
       // 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.
-      llvm_unreachable("Not implemented");
+      llvm_unreachable(
+          "Description not implemented for summary case constraints");
     }
 
   protected:
@@ -178,13 +198,19 @@ class StdLibraryFunctionsChecker
     // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
     // is default initialized to be empty.
     IntRangeVector Ranges;
+    // A textual description of this constraint for the specific case where the
+    // constraint is used. If empty a generated description will be used.
+    StringRef Description;
 
   public:
     StringRef getName() const override { return "Range"; }
-    RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
-        : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
+    RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
+                    StringRef Desc = "")
+        : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
+    }
 
-    std::string describe(DescriptionKind DK, ProgramStateRef State,
+    std::string describe(DescriptionKind DK, const CallEvent &Call,
+                         ProgramStateRef State,
                          const Summary &Summary) const override;
 
     const IntRangeVector &getRanges() const { return Ranges; }
@@ -256,7 +282,8 @@ class StdLibraryFunctionsChecker
   public:
     NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
         : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
-    std::string describe(DescriptionKind DK, ProgramStateRef State,
+    std::string describe(DescriptionKind DK, const CallEvent &Call,
+                         ProgramStateRef State,
                          const Summary &Summary) const override;
     StringRef getName() const override { return "NonNull"; }
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -328,7 +355,8 @@ class StdLibraryFunctionsChecker
       return Result;
     }
 
-    std::string describe(DescriptionKind DK, ProgramStateRef State,
+    std::string describe(DescriptionKind DK, const CallEvent &Call,
+                         ProgramStateRef State,
                          const Summary &Summary) const override;
 
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -698,6 +726,11 @@ class StdLibraryFunctionsChecker
   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
   }
+  static std::string getFunctionName(const CallEvent &Call) {
+    assert(Call.getDecl() &&
+           "Call was found by a summary, should have declaration");
+    return cast<NamedDecl>(Call.getDecl())->getNameAsString();
+  }
 
 public:
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -729,28 +762,22 @@ class StdLibraryFunctionsChecker
                  CheckerContext &C) const {
     if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
       return;
-    std::string Msg =
-        (Twine("Function argument constraint is not satisfied, constraint: ") +
-         VC->getName().data())
-            .str();
+    assert(Call.getDecl() &&
+           "Function found in summary must have a declaration available");
+    std::string Msg = VC->describe(ValueConstraint::DescriptionKind::Violation,
+                                   Call, C.getState(), Summary);
+    Msg[0] = toupper(Msg[0]);
     if (!BT_InvalidArg)
       BT_InvalidArg = std::make_unique<BugType>(
           CheckNames[CK_StdCLibraryFunctionArgsChecker],
-          "Unsatisfied argument constraints", categories::LogicError);
+          "Function call with invalid argument", categories::LogicError);
     auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
 
-    for (ArgNo ArgN : VC->getArgsToTrack())
+    for (ArgNo ArgN : VC->getArgsToTrack()) {
       bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
-
-    // Highlight the range of the argument that was violated.
-    R->addRange(Call.getArgSourceRange(VC->getArgNo()));
-
-    // Describe the argument constraint violation in a note.
-    std::string Descr = VC->describe(
-        ValueConstraint::DescriptionKind::Violation, C.getState(), Summary);
-    // Capitalize the first letter b/c we want a full sentence.
-    Descr[0] = toupper(Descr[0]);
-    R->addNote(Descr, R->getLocation(), Call.getArgSourceRange(VC->getArgNo()));
+      // All tracked arguments are important, highlight them.
+      R->addRange(Call.getArgSourceRange(ArgN));
+    }
 
     C.emitReport(std::move(R));
   }
@@ -772,82 +799,170 @@ int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
     std::numeric_limits<ArgNo>::max();
 
-} // end of anonymous namespace
-
 static BasicValueFactory &getBVF(ProgramStateRef State) {
   ProgramStateManager &Mgr = State->getStateManager();
   SValBuilder &SVB = Mgr.getSValBuilder();
   return SVB.getBasicValueFactory();
 }
 
+} // 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::appendInsideRangeDesc(llvm::APSInt RMin,
+                                                       llvm::APSInt RMax,
+                                                       QualType ArgT,
+                                                       BasicValueFactory &BVF,
+                                                       DescString &Out) {
+  if (RMin.isZero() && RMax.isZero())
+    Out.append("zero");
+  else if (RMin == RMax)
+    RMin.toString(Out);
+  else if (RMin == BVF.getMinValue(ArgT)) {
+    if (RMax == -1)
+      Out.append("< 0");
+    else {
+      Out.append("<= ");
+      RMax.toString(Out);
+    }
+  } else if (RMax == BVF.getMaxValue(ArgT)) {
+    if (RMin.isOne())
+      Out.append("> 0");
+    else {
+      Out.append(">= ");
+      RMin.toString(Out);
+    }
+  } 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);
+  } else {
+    Out.append("between ");
+    RMin.toString(Out);
+    Out.append(" and ");
+    RMax.toString(Out);
+  }
+}
+
+void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
+                                                      llvm::APSInt RMax,
+                                                      QualType ArgT,
+                                                      BasicValueFactory &BVF,
+                                                      DescString &Out) {
+  if (RMin.isZero() && RMax.isZero())
+    Out.append("nonzero");
+  else if (RMin == RMax) {
+    Out.append("not equal to ");
+    RMin.toString(Out);
+  } else if (RMin == BVF.getMinValue(ArgT)) {
+    if (RMax == -1)
+      Out.append(">= 0");
+    else {
+      Out.append("> ");
+      RMax.toString(Out);
+    }
+  } else if (RMax == BVF.getMaxValue(ArgT)) {
+    if (RMin.isOne())
+      Out.append("<= 0");
+    else {
+      Out.append("< ");
+      RMin.toString(Out);
+    }
+  } else if (RMin.isNegative() == RMax.isNegative() &&
+             RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
+    Out.append("not ");
+    RMin.toString(Out);
+    Out.append(" and not ");
+    RMax.toString(Out);
+  } else {
+    Out.append("not between ");
+    RMin.toString(Out);
+    Out.append(" and ");
+    RMax.toString(Out);
+  }
+}
+
 std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
-    DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+    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 += DK == Violation ? " should not be NULL" : " is not NULL";
+  Result += " to '";
+  Result += getFunctionName(Call);
+  Result += DK == Violation ? "' should not be NULL" : "' is not NULL";
   return Result.c_str();
 }
 
 std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
-    DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
+    const Summary &Summary) const {
 
   BasicValueFactory &BVF = getBVF(State);
 
   QualType T = Summary.getArgType(getArgNo());
-  SmallString<48> Result;
+  DescString Result;
   const auto Violation = ValueConstraint::DescriptionKind::Violation;
   Result += "the ";
   Result += getArgDesc(ArgN);
-  Result += DK == Violation ? " should be " : " is ";
-
-  // Range kind as a string.
-  Kind == OutOfRange ? Result += "out of" : Result += "within";
-
-  // Get the range values as a string.
-  Result += " the range ";
-  if (Ranges.size() > 1)
-    Result += "[";
-  unsigned I = Ranges.size();
-  for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
-    Result += "[";
-    const llvm::APSInt &Min = BVF.getValue(R.first, T);
-    const llvm::APSInt &Max = BVF.getValue(R.second, T);
-    Min.toString(Result);
-    Result += ", ";
-    Max.toString(Result);
-    Result += "]";
-    if (--I > 0)
-      Result += ", ";
+  Result += " to '";
+  Result += getFunctionName(Call);
+  Result += DK == Violation ? "' should be " : "' is ";
+  if (!Description.empty()) {
+    Result += 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);
+        if (--I > 0)
+          Result += " or ";
+      }
+    } else {
+      for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
+        appendOutOfRangeDesc(BVF.getValue(R.first, T),
+                             BVF.getValue(R.second, T), T, BVF, Result);
+        if (--I > 0)
+          Result += " and ";
+      }
+    }
   }
-  if (Ranges.size() > 1)
-    Result += "]";
 
   return Result.c_str();
 }
 
-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;
-}
-
 std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
-    DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+    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 += DK == Violation ? " should be " : " is ";
-  Result += "equal to or greater than the value of ";
+  Result += " to '";
+  Result += getFunctionName(Call);
+  Result += DK == Violation ? "' should be " : "' is ";
+  Result += "equal to or greater than ";
   if (ConcreteSize) {
     ConcreteSize->toString(Result);
   } else if (SizeArgN) {
-    Result += "the ";
+    Result += "the value of the ";
     Result += getArgDesc(*SizeArgN);
     if (SizeMultiplierArgN) {
       Result += " times the ";
@@ -998,7 +1113,7 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
       SmallString<64> Msg;
       Msg += "Assuming ";
       Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
-                                  NewState, Summary);
+                                  Call, NewState, Summary);
       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
       NewNode = C.addTransition(
           NewState, NewNode,
@@ -1358,9 +1473,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
 
   // Below are helpers functions to create the summaries.
-  auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
-                              IntRangeVector Ranges) {
-    return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
+  auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
+                              StringRef Desc = "") {
+    return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
   };
   auto BufferSize = [](auto... Args) {
     return std::make_shared<BufferSizeConstraint>(Args...);
@@ -1443,8 +1558,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
                ReturnValueCondition(WithinRange, SingleValue(0))},
               ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
-          .ArgConstraint(ArgumentCondition(
-              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+          .ArgConstraint(ArgumentCondition(0U, WithinRange,
+                                           {{EOFv, EOFv}, {0, UCharRangeMax}},
+                                           "an unsigned char value or EOF")));
   addToFunctionSummaryMap(
       "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
       Summary(EvalCallAsPure)
@@ -1603,18 +1719,21 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   addToFunctionSummaryMap(
       "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
       Summary(EvalCallAsPure)
-          .ArgConstraint(ArgumentCondition(
-              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+          .ArgConstraint(ArgumentCondition(0U, WithinRange,
+                                           {{EOFv, EOFv}, {0, UCharRangeMax}},
+                                           "an unsigned char value or EOF")));
   addToFunctionSummaryMap(
       "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
       Summary(EvalCallAsPure)
-          .ArgConstraint(ArgumentCondition(
-              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+          .ArgConstraint(ArgumentCondition(0U, WithinRange,
+                                           {{EOFv, EOFv}, {0, UCharRangeMax}},
+                                           "an unsigned char value or EOF")));
   addToFunctionSummaryMap(
       "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
       Summary(EvalCallAsPure)
-          .ArgConstraint(ArgumentCondition(
-              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+          .ArgConstraint(ArgumentCondition(0U, WithinRange,
+                                           {{EOFv, EOFv}, {0, UCharRangeMax}},
+                                           "an unsigned char value or EOF")));
 
   // The getc() family of functions that returns either a char or an EOF.
   addToFunctionSummaryMap(
@@ -3097,11 +3216,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
 
   // Functions for testing.
   if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
+    const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
+
     addToFunctionSummaryMap(
         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
 
-    // Test range values.
+    // Test inside range constraints.
     addToFunctionSummaryMap(
         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
         Summary(EvalCallAsPure)
@@ -3114,11 +3235,124 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
         Summary(EvalCallAsPure)
             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
-    addToFunctionSummaryMap("__range_1_2__4_5",
+    addToFunctionSummaryMap(
+        "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
+    addToFunctionSummaryMap(
+        "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
+    addToFunctionSummaryMap(
+        "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
+    addToFunctionSummaryMap("__range_m1_inf",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range(-1, IntMax))));
+    addToFunctionSummaryMap("__range_0_inf",
                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
                             Summary(EvalCallAsPure)
                                 .ArgConstraint(ArgumentCondition(
-                                    0U, WithinRange, Range({1, 2}, {4, 5}))));
+                                    0U, WithinRange, Range(0, IntMax))));
+    addToFunctionSummaryMap("__range_1_inf",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range(1, IntMax))));
+    addToFunctionSummaryMap("__range_minf_m1",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range(IntMin, -1))));
+    addToFunctionSummaryMap("__range_minf_0",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range(IntMin, 0))));
+    addToFunctionSummaryMap("__range_minf_1",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range(IntMin, 1))));
+    addToFunctionSummaryMap("__range_1_2__4_6",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, WithinRange, Range({1, 2}, {4, 6}))));
+    addToFunctionSummaryMap(
+        "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, WithinRange,
+                                             Range({1, 2}, {4, IntMax}))));
+
+    // Test out of range constraints.
+    addToFunctionSummaryMap(
+        "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
+    addToFunctionSummaryMap(
+        "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
+    addToFunctionSummaryMap(
+        "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
+    addToFunctionSummaryMap(
+        "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
+    addToFunctionSummaryMap(
+        "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
+    addToFunctionSummaryMap(
+        "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
+    addToFunctionSummaryMap("__range_out_m1_inf",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(-1, IntMax))));
+    addToFunctionSummaryMap("__range_out_0_inf",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(0, IntMax))));
+    addToFunctionSummaryMap("__range_out_1_inf",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(1, IntMax))));
+    addToFunctionSummaryMap("__range_out_minf_m1",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(IntMin, -1))));
+    addToFunctionSummaryMap("__range_out_minf_0",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(IntMin, 0))));
+    addToFunctionSummaryMap("__range_out_minf_1",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range(IntMin, 1))));
+    addToFunctionSummaryMap("__range_out_1_2__4_6",
+                            Signature(ArgTypes{IntTy}, RetType{IntTy}),
+                            Summary(EvalCallAsPure)
+                                .ArgConstraint(ArgumentCondition(
+                                    0U, OutOfRange, Range({1, 2}, {4, 6}))));
+    addToFunctionSummaryMap(
+        "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+        Summary(EvalCallAsPure)
+            .ArgConstraint(
+                ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
 
     // Test range kind.
     addToFunctionSummaryMap(

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 50e07d39cd5be..2ddcf7a3136fb 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 is not NULL}}
+  __not_null(x);      // expected-note{{Assuming 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 is within the range [0, 0]}}
+  __single_val_0(x);  // expected-note{{Assuming 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 is equal to or greater than the value of 10}}
+  __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}}
   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 7481a015e5580..2a9b4821b8fdb 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,8 +15,7 @@
 int __not_null(int *);
 void test_not_null(int *x) {
   __not_null(nullptr); // \
-  // expected-note{{The 1st argument should not be NULL}} \
-  // expected-warning{{}}
+  // expected-warning{{The 1st argument to '__not_null' should not be NULL}}
 }
 
 // Check the BufferSizeConstraint violation notes.
@@ -29,66 +28,159 @@ void test_buffer_size(int x) {
   case 1: {
     char buf[9];
     __buf_size_arg_constraint_concrete(buf); // \
-    // expected-note{{The size of the 1st argument should be equal to or greater than the value of 10}} \
-    // expected-warning{{}}
+    // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
     break;
   }
   case 2: {
     char buf[3];
     __buf_size_arg_constraint(buf, 4); // \
-    // expected-note{{The size of the 1st argument should be equal to or greater than the value of the 2nd arg}} \
-    // expected-warning{{}}
+    // 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}}
     break;
   }
   case 3: {
     char buf[3];
     __buf_size_arg_constraint_mul(buf, 4, 2); // \
-    // expected-note{{The size of the 1st argument should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
-    // expected-warning{{}}
+    // 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}}
     break;
   }
   }
 }
 
 // Check the RangeConstraint violation notes.
-int __single_val_1(int);      // [1, 1]
-int __range_1_2(int);         // [1, 2]
-int __range_1_2__4_5(int);    // [1, 2], [4, 5]
-void test_range(int x) {
-    __single_val_1(2); // \
-    // expected-note{{The 1st argument should be within the range [1, 1]}} \
-    // expected-warning{{}}
-}
-// Do more specific check against the range strings.
+
+int __single_val_0(int); // [0, 0]
+int __single_val_1(int); // [1, 1]
+int __range_1_2(int); // [1, 2]
+int __range_m1_1(int); // [-1, 1]
+int __range_m2_m1(int); // [-2, -1]
+int __range_m10_10(int); // [-10, 10]
+int __range_m1_inf(int); // [-1, inf]
+int __range_0_inf(int); // [0, inf]
+int __range_1_inf(int); // [1, inf]
+int __range_minf_m1(int); // [-inf, -1]
+int __range_minf_0(int); // [-inf, 0]
+int __range_minf_1(int); // [-inf, 1]
+int __range_1_2__4_6(int); // [1, 2], [4, 6]
+int __range_1_2__4_inf(int); // [1, 2], [4, inf]
+
+int __single_val_out_0(int); // [0, 0]
+int __single_val_out_1(int); // [1, 1]
+int __range_out_1_2(int); // [1, 2]
+int __range_out_m1_1(int); // [-1, 1]
+int __range_out_m2_m1(int); // [-2, -1]
+int __range_out_m10_10(int); // [-10, 10]
+int __range_out_m1_inf(int); // [-1, inf]
+int __range_out_0_inf(int); // [0, inf]
+int __range_out_1_inf(int); // [1, inf]
+int __range_out_minf_m1(int); // [-inf, -1]
+int __range_out_minf_0(int); // [-inf, 0]
+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]
+
 void test_range_values(int x) {
   switch (x) {
-    case 1:
-      __single_val_1(2);      // expected-note{{[1, 1]}} \
-                              // expected-warning{{}}
-      break;
-    case 2:
-      __range_1_2(3);         // expected-note{{[1, 2]}} \
-                              // expected-warning{{}}
-      break;
-    case 3:
-      __range_1_2__4_5(3);    // expected-note{{[[1, 2], [4, 5]]}} \
-                              // expected-warning{{}}
-      break;
+  case 0:
+    __single_val_0(1); // expected-warning{{should be zero}}
+    break;
+  case 1:
+    __single_val_1(2); // expected-warning{{should be 1}}
+    break;
+  case 2:
+    __range_1_2(3); // expected-warning{{should be 1 or 2}}
+    break;
+  case 3:
+    __range_m1_1(3); // expected-warning{{should be between -1 and 1}}
+    break;
+  case 4:
+    __range_m2_m1(1); // expected-warning{{should be -2 or -1}}
+    break;
+  case 5:
+    __range_m10_10(11); // expected-warning{{should be between -10 and 10}}
+    break;
+  case 6:
+    __range_m10_10(-11); // expected-warning{{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}}
+    break;
+  case 8:
+    __range_1_2__4_inf(3); // expected-warning{{should be 1 or 2 or >= 4}}
+    break;
   }
 }
-// Do more specific check against the range kinds.
-int __within(int);       // [1, 1]
-int __out_of(int);       // [1, 1]
-void test_range_kind(int x) {
+
+void test_range_values_inf(int x) {
   switch (x) {
-    case 1:
-      __within(2);       // expected-note{{within}} \
-                         // expected-warning{{}}
-      break;
-    case 2:
-      __out_of(1);       // expected-note{{out of}} \
-                         // expected-warning{{}}
-      break;
+  case 1:
+    __range_m1_inf(-2); // expected-warning{{should be >= -1}}
+    break;
+  case 2:
+    __range_0_inf(-1); // expected-warning{{should be >= 0}}
+    break;
+  case 3:
+    __range_1_inf(0); // expected-warning{{should be > 0}}
+    break;
+  case 4:
+    __range_minf_m1(0); // expected-warning{{should be < 0}}
+    break;
+  case 5:
+    __range_minf_0(1); // expected-warning{{should be <= 0}}
+    break;
+  case 6:
+    __range_minf_1(2); // expected-warning{{should be <= 1}}
+    break;
   }
 }
 
+void test_range_values_out(int x) {
+  switch (x) {
+  case 0:
+    __single_val_out_0(0); // expected-warning{{should be nonzero}}
+    break;
+  case 1:
+    __single_val_out_1(1); // expected-warning{{should be not equal to 1}}
+    break;
+  case 2:
+    __range_out_1_2(2); // expected-warning{{should be not 1 and not 2}}
+    break;
+  case 3:
+    __range_out_m1_1(-1); // expected-warning{{should be not between -1 and 1}}
+    break;
+  case 4:
+    __range_out_m2_m1(-2); // expected-warning{{should be not -2 and not -1}}
+    break;
+  case 5:
+    __range_out_m10_10(0); // expected-warning{{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}}
+    break;
+  case 7:
+    __range_out_1_2__4_inf(4); // expected-warning{{should be not 1 and not 2 and < 4}}
+    break;
+  }
+}
+
+void test_range_values_out_inf(int x) {
+  switch (x) {
+  case 1:
+    __range_out_minf_m1(-1); // expected-warning{{should be >= 0}}
+    break;
+  case 2:
+    __range_out_minf_0(0); // expected-warning{{should be > 0}}
+    break;
+  case 3:
+    __range_out_minf_1(1); // expected-warning{{should be > 1}}
+    break;
+  case 4:
+    __range_out_m1_inf(-1); // expected-warning{{should be < -1}}
+    break;
+  case 5:
+    __range_out_0_inf(0); // expected-warning{{should be < 0}}
+    break;
+  case 6:
+    __range_out_1_inf(1); // expected-warning{{should be <= 0}}
+    break;
+  }
+}

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 afdff5b2ffac0..38b5f03e46551 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,9 +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{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 
 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
@@ -27,7 +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{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }

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 1e9165321232d..cff435d627530 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -30,11 +30,9 @@ int isalnum(int);
 
 void test_alnum_concrete(int v) {
   int ret = isalnum(256); // \
-  // report-warning{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
   (void)ret;
 }
 
@@ -57,11 +55,9 @@ void test_alnum_symbolic2(int x) {
     // bugpath-note{{Taking true branch}}
 
     int ret = isalnum(x); // \
-    // report-warning{{Function argument constraint is not satisfied}} \
-    // report-note{{}} \
-    // bugpath-warning{{Function argument constraint is not satisfied}} \
-    // bugpath-note{{}} \
-    // bugpath-note{{Function argument constraint is not satisfied}}
+    // 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}}
 
     (void)ret;
   }
@@ -71,11 +67,9 @@ int toupper(int);
 
 void test_toupper_concrete(int v) {
   int ret = toupper(256); // \
-  // report-warning{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
   (void)ret;
 }
 
@@ -97,11 +91,9 @@ void test_toupper_symbolic2(int x) {
     // bugpath-note{{Taking true branch}}
 
     int ret = toupper(x); // \
-    // report-warning{{Function argument constraint is not satisfied}} \
-    // report-note{{}} \
-    // bugpath-warning{{Function argument constraint is not satisfied}} \
-    // bugpath-note{{}} \
-    // bugpath-note{{Function argument constraint is not satisfied}}
+    // 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}}
 
     (void)ret;
   }
@@ -111,11 +103,9 @@ int tolower(int);
 
 void test_tolower_concrete(int v) {
   int ret = tolower(256); // \
-  // report-warning{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
   (void)ret;
 }
 
@@ -137,11 +127,9 @@ void test_tolower_symbolic2(int x) {
     // bugpath-note{{Taking true branch}}
 
     int ret = tolower(x); // \
-    // report-warning{{Function argument constraint is not satisfied}} \
-    // report-note{{}} \
-    // bugpath-warning{{Function argument constraint is not satisfied}} \
-    // bugpath-note{{}} \
-    // bugpath-note{{Function argument constraint is not satisfied}}
+    // 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}}
 
     (void)ret;
   }
@@ -151,11 +139,9 @@ int toascii(int);
 
 void test_toascii_concrete(int v) {
   int ret = toascii(256); // \
-  // report-warning{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
   (void)ret;
 }
 
@@ -177,11 +163,9 @@ void test_toascii_symbolic2(int x) {
     // bugpath-note{{Taking true branch}}
 
     int ret = toascii(x); // \
-    // report-warning{{Function argument constraint is not satisfied}} \
-    // report-note{{}} \
-    // bugpath-warning{{Function argument constraint is not satisfied}} \
-    // bugpath-note{{}} \
-    // bugpath-note{{Function argument constraint is not satisfied}}
+    // 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}}
 
     (void)ret;
   }
@@ -192,11 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 void test_notnull_symbolic(FILE *fp, int *buf) {
   fread(buf, sizeof(int), 10, fp);
@@ -210,11 +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{{Function argument constraint is not satisfied}} \
-    // report-note{{}} \
-    // bugpath-warning{{Function argument constraint is not satisfied}} \
-    // bugpath-note{{}} \
-    // bugpath-note{{Function argument constraint is not satisfied}}
+    // 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}}
 }
 void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
   if (fp) // \
@@ -222,11 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
   clang_analyzer_warnIfReached(); // not reachable
 }
 
@@ -242,11 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 
 int __two_constrained_args(int, int);
@@ -279,22 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 
 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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 void test_buf_size_symbolic(int s) {
   char buf[3];
@@ -319,11 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }
 void test_buf_size_symbolic_with_multiplication(size_t s) {
   short buf[3];
@@ -347,9 +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{{Function argument constraint is not satisfied}} \
-  // report-note{{}} \
-  // bugpath-warning{{Function argument constraint is not satisfied}} \
-  // bugpath-note{{}} \
-  // bugpath-note{{Function argument constraint is not satisfied}}
+  // 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}}
 }

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 2e646dc2574a8..86fa98bf4f10c 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
@@ -14,6 +14,5 @@ int __defaultparam(void *, int y = 3);
 
 void test_arg_constraint_on_fun_with_default_param() {
   __defaultparam(nullptr); // \
-  // expected-warning{{Function argument constraint is not satisfied}} \
-  // expected-note{{}}
+  // expected-warning{{The 1st argument to '__defaultparam' should not be NULL}}
 }

diff  --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c
index 42e46d45601d7..cd711bc27711a 100644
--- a/clang/test/Analysis/stream-note.c
+++ b/clang/test/Analysis/stream-note.c
@@ -88,9 +88,8 @@ void check_track_null(void) {
     fclose(F);
     return;
   }
-  fclose(F); // stdargs-warning {{Function argument constraint is not satisfied}}
-             // stdargs-note at -1 {{Function argument constraint is not satisfied}}
-             // stdargs-note at -2 {{The 1st argument should not be NULL}}
+  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}}
 }
 
 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 469d40b456914..9d1b9244f0f24 100644
--- a/clang/test/Analysis/stream-stdlibraryfunctionargs.c
+++ b/clang/test/Analysis/stream-stdlibraryfunctionargs.c
@@ -18,37 +18,31 @@ size_t n;
 void test_fopen(void) {
   FILE *fp = fopen("path", "r");
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
-  fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  fclose(fp); // stdargs-warning{{should not be NULL}}
 }
 
 void test_tmpfile(void) {
   FILE *fp = tmpfile();
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
-  fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  fclose(fp); // stdargs-warning{{should not be NULL}}
 }
 
 void test_fclose(void) {
   FILE *fp = tmpfile();
-  fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  fclose(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
 }
 
 void test_freopen(void) {
   FILE *fp = tmpfile();
-  fp = freopen("file", "w", fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                                 // stdargs-note{{The 3rd argument should not be NULL}}
-  fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  fp = freopen("file", "w", fp); // stdargs-warning{{should not be NULL}}
+  fclose(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
 }
 
 void test_fread(void) {
   FILE *fp = tmpfile();
-  size_t ret = fread(buf, size, n, fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                                        // stdargs-note{{The 4th argument should not be NULL}}
+  size_t ret = fread(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fread' 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}}
@@ -58,8 +52,7 @@ void test_fread(void) {
 
 void test_fwrite(void) {
   FILE *fp = tmpfile();
-  size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                                        // stdargs-note{{The 4th argument should not be NULL}}
+  size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fwrite' 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}}
@@ -69,24 +62,21 @@ void test_fwrite(void) {
 
 void test_fseek(void) {
   FILE *fp = tmpfile();
-  fseek(fp, 0, 0); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                   // stdargs-note{{The 1st argument should not be NULL}}
+  fseek(fp, 0, 0); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_ftell(void) {
   FILE *fp = tmpfile();
-  ftell(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-             // stdargs-note{{The 1st argument should not be NULL}}
+  ftell(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_rewind(void) {
   FILE *fp = tmpfile();
-  rewind(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  rewind(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
@@ -94,8 +84,7 @@ void test_rewind(void) {
 void test_fgetpos(void) {
   FILE *fp = tmpfile();
   fpos_t pos;
-  fgetpos(fp, &pos); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                     // stdargs-note{{The 1st argument should not be NULL}}
+  fgetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
@@ -103,40 +92,35 @@ void test_fgetpos(void) {
 void test_fsetpos(void) {
   FILE *fp = tmpfile();
   fpos_t pos;
-  fsetpos(fp, &pos); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                     // stdargs-note{{The 1st argument should not be NULL}}
+  fsetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_clearerr(void) {
   FILE *fp = tmpfile();
-  clearerr(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-                // stdargs-note{{The 1st argument should not be NULL}}
+  clearerr(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_feof(void) {
   FILE *fp = tmpfile();
-  feof(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-            // stdargs-note{{The 1st argument should not be NULL}}
+  feof(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_ferror(void) {
   FILE *fp = tmpfile();
-  ferror(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  ferror(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }
 
 void test_fileno(void) {
   FILE *fp = tmpfile();
-  fileno(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
-              // stdargs-note{{The 1st argument should not be NULL}}
+  fileno(fp); // stdargs-warning{{should not be NULL}}
   clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
   fclose(fp);
 }


        


More information about the cfe-commits mailing list