Author: Gabor Marton
Date: 2020-02-10T16:45:33+01:00
New Revision: f5086b3803ac2f908a734bbb2c7a50018fb3cd8c

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

LOG: [analyzer] StdLibraryFunctionsChecker refactor: remove macros

Reviewers: NoQ

Tags: #clang

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

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 2cdee8da375e..e8668775ab85 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -9,7 +9,7 @@
 // This checker improves modeling of a few simple library functions.
 // It does not generate warnings.
 //
-// This checker provides a specification format - `FunctionSummaryTy' - and
+// This checker provides a specification format - `Summary' - and
 // contains descriptions of some library functions in this format. Each
 // specification contains a list of branches for splitting the program state
 // upon call, and range constraints on argument and return-value symbols that
@@ -21,7 +21,7 @@
 // consider standard C function `ispunct(int x)', which returns a non-zero 
value
 // iff `x' is a punctuation character, that is, when `x' is in range
 //   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].
-// `FunctionSummaryTy' provides only two branches for this function. However,
+// `Summary' provides only two branches for this function. However,
 // any attempt to describe this range with if-statements in the body farm
 // would result in many more branches. Because each branch needs to be analyzed
 // independently, this significantly reduces performance. Additionally,
@@ -30,13 +30,13 @@
 // which may lead to false positives because considering this particular path
 // was not consciously intended, and therefore it might have been unreachable.
 //
-// This checker uses eval::Call for modeling "pure" functions, for which
-// their `FunctionSummaryTy' is a precise model. This avoids unnecessary
-// invalidation passes. Conflicts with other checkers are unlikely because
-// if the function has no other effects, other checkers would probably never
-// want to improve upon the modeling done by this checker.
+// This checker uses eval::Call for modeling pure functions (functions without
+// side effets), for which their `Summary' is a precise model. This avoids
+// unnecessary invalidation passes. Conflicts with other checkers are unlikely
+// because if the function has no other effects, other checkers would probably
+// never want to improve upon the modeling done by this checker.
 //
-// Non-"pure" functions, for which only partial improvement over the default
+// Non-pure functions, for which only partial improvement over the default
 // behavior is expected, are modeled via check::PostCall, non-intrusively.
 //
 // The following standard C functions are currently supported:
@@ -64,49 +64,48 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
   /// Below is a series of typedefs necessary to define function specs.
   /// We avoid nesting types here because each additional qualifier
   /// would need to be repeated in every function spec.
-  struct FunctionSummaryTy;
+  struct Summary;
 
   /// Specify how much the analyzer engine should entrust modeling this 
function
   /// to us. If he doesn't, he performs additional invalidations.
-  enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
+  enum InvalidationKind { NoEvalCall, EvalCallAsPure };
 
-  /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
+  /// A pair of ValueRangeKind and IntRangeVector would describe a range
   /// imposed on a particular argument or return value symbol.
   ///
   /// Given a range, should the argument stay inside or outside this range?
   /// The special `ComparesToArgument' value indicates that we should
   /// impose a constraint that involves other argument or return value symbols.
-  enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
+  enum ValueRangeKind { OutOfRange, WithinRange, ComparesToArgument };
 
   // The universal integral type to use in value range descriptions.
   // Unsigned to make sure overflows are well-defined.
-  typedef uint64_t RangeIntTy;
+  typedef uint64_t RangeInt;
 
   /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
   /// a non-negative integer, which less than 5 and not equal to 2. For
   /// `ComparesToArgument', holds information about how exactly to compare to
   /// the argument.
-  typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
+  typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
 
   /// A reference to an argument or return value by its number.
   /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
   /// obviously uint32_t should be enough for all practical purposes.
-  typedef uint32_t ArgNoTy;
-  static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
+  typedef uint32_t ArgNo;
+  static const ArgNo Ret = std::numeric_limits<ArgNo>::max();
 
   /// Incapsulates a single range on a single symbol within a branch.
   class ValueRange {
-    ArgNoTy ArgNo; // Argument to which we apply the range.
-    ValueRangeKindTy Kind; // Kind of range definition.
-    IntRangeVectorTy Args; // Polymorphic arguments.
+    ArgNo ArgN;          // Argument to which we apply the range.
+    ValueRangeKind Kind; // Kind of range definition.
+    IntRangeVector Args; // Polymorphic arguments.
 
   public:
-    ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
-               const IntRangeVectorTy &Args)
-        : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
+    ValueRange(ArgNo ArgN, ValueRangeKind Kind, const IntRangeVector &Args)
+        : ArgN(ArgN), Kind(Kind), Args(Args) {}
 
-    ArgNoTy getArgNo() const { return ArgNo; }
-    ValueRangeKindTy getKind() const { return Kind; }
+    ArgNo getArgNo() const { return ArgN; }
+    ValueRangeKind getKind() const { return Kind; }
 
     BinaryOperator::Opcode getOpcode() const {
       assert(Kind == ComparesToArgument);
@@ -118,13 +117,13 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
       return Op;
     }
 
-    ArgNoTy getOtherArgNo() const {
+    ArgNo getOtherArgNo() const {
       assert(Kind == ComparesToArgument);
       assert(Args.size() == 1);
-      return static_cast<ArgNoTy>(Args[0].second);
+      return static_cast<ArgNo>(Args[0].second);
     }
 
-    const IntRangeVectorTy &getRanges() const {
+    const IntRangeVector &getRanges() const {
       assert(Kind != ComparesToArgument);
       return Args;
     }
@@ -132,19 +131,19 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
     // We avoid creating a virtual apply() method because
     // it makes initializer lists harder to write.
   private:
-    ProgramStateRef
-    applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
-                      const FunctionSummaryTy &Summary) const;
-    ProgramStateRef
-    applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
-                       const FunctionSummaryTy &Summary) const;
-    ProgramStateRef
-    applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
-                              const FunctionSummaryTy &Summary) const;
+    ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
+                                      const CallEvent &Call,
+                                      const Summary &Summary) const;
+    ProgramStateRef applyAsWithinRange(ProgramStateRef State,
+                                       const CallEvent &Call,
+                                       const Summary &Summary) const;
+    ProgramStateRef applyAsComparesToArgument(ProgramStateRef State,
+                                              const CallEvent &Call,
+                                              const Summary &Summary) const;
 
   public:
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
-                          const FunctionSummaryTy &Summary) const {
+                          const Summary &Summary) const {
       switch (Kind) {
       case OutOfRange:
         return applyAsOutOfRange(State, Call, Summary);
@@ -160,15 +159,27 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
   /// The complete list of ranges that defines a single branch.
   typedef std::vector<ValueRange> ValueRangeSet;
 
+  using ArgTypes = std::vector<QualType>;
+  using Ranges = std::vector<ValueRangeSet>;
+
   /// Includes information about function prototype (which is necessary to
   /// ensure we're modeling the right function and casting values properly),
   /// approach to invalidation, and a list of branches - essentially, a list
   /// of list of ranges - essentially, a list of lists of lists of segments.
-  struct FunctionSummaryTy {
-    const std::vector<QualType> ArgTypes;
-    const QualType RetType;
-    const InvalidationKindTy InvalidationKind;
-    const std::vector<ValueRangeSet> Ranges;
+  struct Summary {
+    const ArgTypes ArgTys;
+    const QualType RetTy;
+    const InvalidationKind InvalidationKd;
+    Ranges Cases;
+    ValueRangeSet ArgConstraints;
+
+    Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd)
+        : ArgTys(ArgTys), RetTy(RetTy), InvalidationKd(InvalidationKd) {}
+
+    Summary &Case(ValueRangeSet VRS) {
+      Cases.push_back(VRS);
+      return *this;
+    }
 
   private:
     static void assertTypeSuitableForSummary(QualType T) {
@@ -182,8 +193,8 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
     }
 
   public:
-    QualType getArgType(ArgNoTy ArgNo) const {
-      QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
+    QualType getArgType(ArgNo ArgN) const {
+      QualType T = (ArgN == Ret) ? RetTy : ArgTys[ArgN];
       assertTypeSuitableForSummary(T);
       return T;
     }
@@ -198,28 +209,27 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
   // We call these "variants" of the function. This can be useful for handling
   // C++ function overloads, and also it can be used when the same function
   // may have 
diff erent definitions on 
diff erent platforms.
-  typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
+  typedef std::vector<Summary> Summaries;
 
   // The map of all functions supported by the checker. It is initialized
   // lazily, and it doesn't change after initialization.
-  typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
-  mutable FunctionSummaryMapTy FunctionSummaryMap;
+  mutable llvm::StringMap<Summaries> FunctionSummaryMap;
 
-  // Auxiliary functions to support ArgNoTy within all structures
+  // Auxiliary functions to support ArgNo within all structures
   // in a unified manner.
-  static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
-    return Summary.getArgType(ArgNo);
+  static QualType getArgType(const Summary &Summary, ArgNo ArgN) {
+    return Summary.getArgType(ArgN);
   }
-  static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
-    return ArgNo == Ret ? Call.getResultType().getCanonicalType()
-                        : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
+  static QualType getArgType(const CallEvent &Call, ArgNo ArgN) {
+    return ArgN == Ret ? Call.getResultType().getCanonicalType()
+                       : Call.getArgExpr(ArgN)->getType().getCanonicalType();
   }
-  static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
-    return ArgNo == Ret ? CE->getType().getCanonicalType()
-                        : CE->getArg(ArgNo)->getType().getCanonicalType();
+  static QualType getArgType(const CallExpr *CE, ArgNo ArgN) {
+    return ArgN == Ret ? CE->getType().getCanonicalType()
+                       : CE->getArg(ArgN)->getType().getCanonicalType();
   }
-  static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
-    return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
+  static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
+    return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
   }
 
 public:
@@ -227,9 +237,9 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
 
 private:
-  Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
-                                          const CallExpr *CE,
-                                          CheckerContext &C) const;
+  Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
+                                        const CallExpr *CE,
+                                        CheckerContext &C) const;
 
   void initFunctionSummaries(BasicValueFactory &BVF) const;
 };
@@ -237,7 +247,7 @@ class StdLibraryFunctionsChecker : public 
Checker<check::PostCall, eval::Call> {
 
 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
     ProgramStateRef State, const CallEvent &Call,
-    const FunctionSummaryTy &Summary) const {
+    const Summary &Summary) const {
 
   ProgramStateManager &Mgr = State->getStateManager();
   SValBuilder &SVB = Mgr.getSValBuilder();
@@ -247,7 +257,7 @@ ProgramStateRef 
StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
   SVal V = getArgSVal(Call, getArgNo());
 
   if (auto N = V.getAs<NonLoc>()) {
-    const IntRangeVectorTy &R = getRanges();
+    const IntRangeVector &R = getRanges();
     size_t E = R.size();
     for (size_t I = 0; I != E; ++I) {
       const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
@@ -262,10 +272,9 @@ ProgramStateRef 
StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
   return State;
 }
 
-ProgramStateRef
-StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
+ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
     ProgramStateRef State, const CallEvent &Call,
-    const FunctionSummaryTy &Summary) const {
+    const Summary &Summary) const {
 
   ProgramStateManager &Mgr = State->getStateManager();
   SValBuilder &SVB = Mgr.getSValBuilder();
@@ -278,7 +287,7 @@ StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
   // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
   // and then cut away all holes in R one by one.
   if (auto N = V.getAs<NonLoc>()) {
-    const IntRangeVectorTy &R = getRanges();
+    const IntRangeVector &R = getRanges();
     size_t E = R.size();
 
     const llvm::APSInt &MinusInf = BVF.getMinValue(T);
@@ -316,7 +325,7 @@ StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
 ProgramStateRef
 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
     ProgramStateRef State, const CallEvent &Call,
-    const FunctionSummaryTy &Summary) const {
+    const Summary &Summary) const {
 
   ProgramStateManager &Mgr = State->getStateManager();
   SValBuilder &SVB = Mgr.getSValBuilder();
@@ -325,7 +334,7 @@ 
StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
   SVal V = getArgSVal(Call, getArgNo());
 
   BinaryOperator::Opcode Op = getOpcode();
-  ArgNoTy OtherArg = getOtherArgNo();
+  ArgNo OtherArg = getOtherArgNo();
   SVal OtherV = getArgSVal(Call, OtherArg);
   QualType OtherT = getArgType(Call, OtherArg);
   // Note: we avoid integral promotion for comparison.
@@ -346,15 +355,16 @@ void StdLibraryFunctionsChecker::checkPostCall(const 
CallEvent &Call,
   if (!CE)
     return;
 
-  Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
+  Optional<Summary> FoundSummary = findFunctionSummary(FD, CE, C);
   if (!FoundSummary)
     return;
 
   // Now apply ranges.
-  const FunctionSummaryTy &Summary = *FoundSummary;
+  const Summary &Summary = *FoundSummary;
   ProgramStateRef State = C.getState();
 
-  for (const auto &VRS: Summary.Ranges) {
+  // Apply case/branch specifications.
+  for (const auto &VRS : Summary.Cases) {
     ProgramStateRef NewState = State;
     for (const auto &VR: VRS) {
       NewState = VR.apply(NewState, Call, Summary);
@@ -377,12 +387,12 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent 
&Call,
   if (!CE)
     return false;
 
-  Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
+  Optional<Summary> FoundSummary = findFunctionSummary(FD, CE, C);
   if (!FoundSummary)
     return false;
 
-  const FunctionSummaryTy &Summary = *FoundSummary;
-  switch (Summary.InvalidationKind) {
+  const Summary &Summary = *FoundSummary;
+  switch (Summary.InvalidationKd) {
   case EvalCallAsPure: {
     ProgramStateRef State = C.getState();
     const LocationContext *LC = C.getLocationContext();
@@ -400,19 +410,19 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent 
&Call,
   llvm_unreachable("Unknown invalidation kind!");
 }
 
-bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
+bool StdLibraryFunctionsChecker::Summary::matchesCall(
     const CallExpr *CE) const {
   // Check number of arguments:
-  if (CE->getNumArgs() != ArgTypes.size())
+  if (CE->getNumArgs() != ArgTys.size())
     return false;
 
   // Check return type if relevant:
-  if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
+  if (!RetTy.isNull() && RetTy != CE->getType().getCanonicalType())
     return false;
 
   // Check argument types when relevant:
-  for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
-    QualType FormalT = ArgTypes[I];
+  for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
+    QualType FormalT = ArgTys[I];
     // Null type marks irrelevant arguments.
     if (FormalT.isNull())
       continue;
@@ -428,7 +438,7 @@ bool 
StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
   return true;
 }
 
-Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
+Optional<StdLibraryFunctionsChecker::Summary>
 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
                                                 const CallExpr *CE,
                                                 CheckerContext &C) const {
@@ -459,8 +469,8 @@ StdLibraryFunctionsChecker::findFunctionSummary(const 
FunctionDecl *FD,
   // Strict checking is important because we will be conducting
   // very integral-type-sensitive operations on arguments and
   // return values.
-  const FunctionVariantsTy &SpecVariants = FSMI->second;
-  for (const FunctionSummaryTy &Spec : SpecVariants)
+  const Summaries &SpecVariants = FSMI->second;
+  for (const Summary &Spec : SpecVariants)
     if (Spec.matchesCall(CE))
       return Spec;
 
@@ -487,9 +497,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   QualType LongLongTy = ACtx.LongLongTy;
   QualType SizeTy = ACtx.getSizeType();
 
-  RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
-  RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
-  RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
+  RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
+  RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
+  RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
 
   // We are finally ready to define specifications for all supported functions.
   //
@@ -517,538 +527,237 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   //
   // Please update the list of functions in the header after editing!
   //
-  // The format is as follows:
-  //
-  //{ "function name",
-  //  { spec:
-  //    { argument types list, ... },
-  //    return type, purity, { range set list:
-  //      { range list:
-  //        { argument index, within or out of, {{from, to}, ...} },
-  //        { argument index, compares to argument, {{how, which}} },
-  //        ...
-  //      }
-  //    }
-  //  }
-  //}
-
-#define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
-#define END_SUMMARY_WITH_VARIANTS }},
-#define VARIANT(argument_types, return_type, invalidation_approach)            
\
-  { argument_types, return_type, invalidation_approach, {
-#define END_VARIANT } },
-#define SUMMARY(identifier, argument_types, return_type,                       
\
-                invalidation_approach)                                         
\
-  { #identifier, { { argument_types, return_type, invalidation_approach, {
-#define END_SUMMARY } } } },
-#define ARGUMENT_TYPES(...) { __VA_ARGS__ }
-#define RETURN_TYPE(x) x
-#define INVALIDATION_APPROACH(x) x
-#define CASE {
-#define END_CASE },
-#define ARGUMENT_CONDITION(argument_number, condition_kind)                    
\
-  { argument_number, condition_kind, {
-#define END_ARGUMENT_CONDITION }},
-#define RETURN_VALUE_CONDITION(condition_kind)                                 
\
-  { Ret, condition_kind, {
-#define END_RETURN_VALUE_CONDITION }},
-#define ARG_NO(x) x##U
-#define RANGE(x, y) { x, y },
-#define SINGLE_VALUE(x) RANGE(x, x)
-#define IS_LESS_THAN(arg) { BO_LE, arg }
+
+  // Below are helper functions to create the summaries.
+  auto ArgumentCondition = [](ArgNo ArgN, ValueRangeKind Kind,
+                              IntRangeVector Ranges) -> ValueRange {
+    ValueRange VR{ArgN, Kind, Ranges};
+    return VR;
+  };
+  auto ReturnValueCondition = [](ValueRangeKind Kind,
+                                 IntRangeVector Ranges) -> ValueRange {
+    ValueRange VR{Ret, Kind, Ranges};
+    return VR;
+  };
+  auto Range = [](RangeInt b, RangeInt e) {
+    return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
+  };
+  auto SingleValue = [](RangeInt v) {
+    return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
+  };
+  auto IsLessThan = [](ArgNo ArgN) { return IntRangeVector{{BO_LE, ArgN}}; };
+
+  using RetType = QualType;
+
+  // Templates for summaries that are reused by many functions.
+  auto Getc = [&]() {
+    return Summary(ArgTypes{Irrelevant}, RetType{IntTy}, NoEvalCall)
+        .Case({ReturnValueCondition(WithinRange, Range(-1, 255))});
+  };
+  auto Read = [&](RetType R, RangeInt Max) {
+    return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
+                   NoEvalCall)
+        .Case({ReturnValueCondition(ComparesToArgument, IsLessThan(2)),
+               ReturnValueCondition(WithinRange, Range(-1, Max))});
+  };
+  auto Fread = [&]() {
+    return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy, Irrelevant},
+                   RetType{SizeTy}, NoEvalCall)
+        .Case({
+            ReturnValueCondition(ComparesToArgument, IsLessThan(2)),
+        });
+  };
+  auto Getline = [&](RetType R, RangeInt Max) {
+    return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R},
+                   NoEvalCall)
+        .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
+  };
 
   FunctionSummaryMap = {
-    // The isascii() family of functions.
-    SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Boils down to isupper() or islower() or isdigit()
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('0', '9')
-          RANGE('A', 'Z')
-          RANGE('a', 'z')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // The locale-specific range.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-        // No post-condition. We are completely unaware of
-        // locale-specific return values.
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('0', '9')
-          RANGE('A', 'Z')
-          RANGE('a', 'z')
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('A', 'Z')
-          RANGE('a', 'z')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // The locale-specific range.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-      END_CASE
-      CASE // Other.
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('A', 'Z')
-          RANGE('a', 'z')
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Is ASCII.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(0, 127)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(0, 127)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          SINGLE_VALUE('\t')
-          SINGLE_VALUE(' ')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          SINGLE_VALUE('\t')
-          SINGLE_VALUE(' ')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // 0..31 or 127
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(0, 32)
-          SINGLE_VALUE(127)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(0, 32)
-          SINGLE_VALUE(127)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Is a digit.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('0', '9')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('0', '9')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(33, 126)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(33, 126)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Is certainly lowercase.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('a', 'z')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // Is ascii but not lowercase.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(0, 127)
-        END_ARGUMENT_CONDITION
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('a', 'z')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // The locale-specific range.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-      END_CASE
-      CASE // Is not an unsigned char.
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(0, 255)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(32, 126)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(32, 126)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('!', '/')
-          RANGE(':', '@')
-          RANGE('[', '`')
-          RANGE('{', '~')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('!', '/')
-          RANGE(':', '@')
-          RANGE('[', '`')
-          RANGE('{', '~')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Space, '\f', '\n', '\r', '\t', '\v'.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(9, 13)
-          SINGLE_VALUE(' ')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // The locale-specific range.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE(9, 13)
-          SINGLE_VALUE(' ')
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE // Is certainly uppercase.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('A', 'Z')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE // The locale-specific range.
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-      END_CASE
-      CASE // Other.
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('A', 'Z') RANGE(128, 255)
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(EvalCallAsPure))
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
-          RANGE('0', '9')
-          RANGE('A', 'F')
-          RANGE('a', 'f')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(OutOfRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-      CASE
-        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
-          RANGE('0', '9')
-          RANGE('A', 'F')
-          RANGE('a', 'f')
-        END_ARGUMENT_CONDITION
-        RETURN_VALUE_CONDITION(WithinRange)
-          SINGLE_VALUE(0)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-
-    // The getc() family of functions that returns either a char or an EOF.
-    SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(NoEvalCall))
-      CASE // FIXME: EOF is assumed to be defined as -1.
-        RETURN_VALUE_CONDITION(WithinRange)
-          RANGE(-1, 255)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(NoEvalCall))
-      CASE // FIXME: EOF is assumed to be defined as -1.
-        RETURN_VALUE_CONDITION(WithinRange)
-          RANGE(-1, 255)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
-            INVALIDATION_APPROACH(NoEvalCall))
-      CASE // FIXME: EOF is assumed to be defined as -1.
-        RETURN_VALUE_CONDITION(WithinRange)
-          RANGE(-1, 255)
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-
-    // read()-like functions that never return more than buffer size.
-    // We are not sure how ssize_t is defined on every platform, so we provide
-    // three variants that should cover common cases.
-    SUMMARY_WITH_VARIANTS(read)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, IntMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, LongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, LongLongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-    END_SUMMARY_WITH_VARIANTS
-    SUMMARY_WITH_VARIANTS(write)
-      // Again, due to elusive nature of ssize_t, we have duplicate
-      // our summaries to cover 
diff erent variants.
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, IntMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, LongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
-              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
-          END_RETURN_VALUE_CONDITION
-          RETURN_VALUE_CONDITION(WithinRange)
-            RANGE(-1, LongLongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-    END_SUMMARY_WITH_VARIANTS
-    SUMMARY(fread,
-            ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
-            RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
-      CASE
-        RETURN_VALUE_CONDITION(ComparesToArgument)
-          IS_LESS_THAN(ARG_NO(2))
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-    SUMMARY(fwrite,
-            ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
-            RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
-      CASE
-        RETURN_VALUE_CONDITION(ComparesToArgument)
-          IS_LESS_THAN(ARG_NO(2))
-        END_RETURN_VALUE_CONDITION
-      END_CASE
-    END_SUMMARY
-
-    // getline()-like functions either fail or read at least the delimiter.
-    SUMMARY_WITH_VARIANTS(getline)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
-              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, IntMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
-              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, LongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
-              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, LongLongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-    END_SUMMARY_WITH_VARIANTS
-    SUMMARY_WITH_VARIANTS(getdelim)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
-            RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, IntMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
-            RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, LongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
-            RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
-        CASE
-          RETURN_VALUE_CONDITION(WithinRange)
-            SINGLE_VALUE(-1)
-            RANGE(1, LongLongMax)
-          END_RETURN_VALUE_CONDITION
-        END_CASE
-      END_VARIANT
-    END_SUMMARY_WITH_VARIANTS
+      // The isascii() family of functions.
+      {
+          "isalnum",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  // Boils down to isupper() or islower() or isdigit().
+                  .Case(
+                      {ArgumentCondition(0U, WithinRange,
+                                         {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
+                       ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  // The locale-specific range.
+                  // No post-condition. We are completely unaware of
+                  // locale-specific return values.
+                  .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})})
+                  .Case({ArgumentCondition(
+                             0U, OutOfRange,
+                             {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, 255}}),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isalpha",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange,
+                                           {{'A', 'Z'}, {'a', 'z'}}),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  // The locale-specific range.
+                  .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})})
+                  .Case(
+                      {ArgumentCondition(0U, OutOfRange,
+                                         {{'A', 'Z'}, {'a', 'z'}, {128, 255}}),
+                       ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isascii",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isblank",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange,
+                                           {{'\t', '\t'}, {' ', ' '}}),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(0U, OutOfRange,
+                                           {{'\t', '\t'}, {' ', ' '}}),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "iscntrl",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange,
+                                           {{0, 32}, {127, 127}}),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case(
+                      {ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 
127}}),
+                       ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isdigit",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isgraph",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "islower",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  // Is certainly lowercase.
+                  .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  // Is ascii but not lowercase.
+                  .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
+                         ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})
+                  // The locale-specific range.
+                  .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})})
+                  // Is not an unsigned char.
+                  .Case({ArgumentCondition(0U, OutOfRange, Range(0, 255)),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isprint",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "ispunct",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case({ArgumentCondition(
+                             0U, WithinRange,
+                             {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case({ArgumentCondition(
+                             0U, OutOfRange,
+                             {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isspace",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  // Space, '\f', '\n', '\r', '\t', '\v'.
+                  .Case({ArgumentCondition(0U, WithinRange,
+                                           {{9, 13}, {' ', ' '}}),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  // The locale-specific range.
+                  .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})})
+                  .Case({ArgumentCondition(0U, OutOfRange,
+                                           {{9, 13}, {' ', ' '}, {128, 255}}),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isupper",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  // Is certainly uppercase.
+                  .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
+                         ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  // The locale-specific range.
+                  .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})})
+                  // Other.
+                  .Case({ArgumentCondition(0U, OutOfRange,
+                                           {{'A', 'Z'}, {128, 255}}),
+                         ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+      {
+          "isxdigit",
+          Summaries{
+              Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                  .Case(
+                      {ArgumentCondition(0U, WithinRange,
+                                         {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
+                       ReturnValueCondition(OutOfRange, SingleValue(0))})
+                  .Case(
+                      {ArgumentCondition(0U, OutOfRange,
+                                         {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
+                       ReturnValueCondition(WithinRange, SingleValue(0))})},
+      },
+
+      // The getc() family of functions that returns either a char or an EOF.
+      {"getc", Summaries{Getc()}},
+      {"fgetc", Summaries{Getc()}},
+      {"getchar", Summaries{Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
+                                .Case({ReturnValueCondition(WithinRange,
+                                                            Range(-1, 
255))})}},
+
+      // read()-like functions that never return more than buffer size.
+      // We are not sure how ssize_t is defined on every platform, so we
+      // provide three variants that should cover common cases.
+      {"read", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax),
+                         Read(LongLongTy, LongLongMax)}},
+      {"write", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax),
+                          Read(LongLongTy, LongLongMax)}},
+      {"fread", Summaries{Fread()}},
+      {"fwrite", Summaries{Fread()}},
+      // getline()-like functions either fail or read at least the delimiter.
+      {"getline", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax),
+                            Getline(LongLongTy, LongLongMax)}},
+      {"getdelim", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax),
+                             Getline(LongLongTy, LongLongMax)}},
   };
 }
 


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to