[clang] f5086b3 - [analyzer] StdLibraryFunctionsChecker refactor: remove macros
Gabor Marton via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 10 07:53:20 PST 2020
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)}},
};
}
More information about the cfe-commits
mailing list