martong created this revision.
martong added reviewers: NoQ, Szelethus, balazske.
Herald added subscribers: cfe-commits, ASDenysPetrov, uenoku, steakhal, 
Charusso, gamesh411, dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, rnkovacs, 
szepet, baloghadamsoftware, xazax.hun, whisperity.
Herald added a reviewer: jdoerfert.
Herald added a reviewer: sstefan1.
Herald added a reviewer: uenoku.
Herald added a project: clang.
martong marked an inline comment as done.
martong added inline comments.
martong marked an inline comment as not done.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp:570
+llvm::Optional<const FunctionDecl *>
+lookupGlobalCFunction(StringRef Name, const ASTContext &ACtx) {
+  IdentifierInfo &II = ACtx.Idents.get(Name);
----------------
Ups, this function is unused I'll remove.


Currently we map function summaries to names (i.e. strings). We can
associate more summaries with different signatures to one name, this way
we support overloading. During a call event we check whether the
signature of the summary matches the signature of the callee and we
apply the summary only in that case.

In this patch we change this mapping to associate a summary to a
FunctionDecl. We do lookup operations when the summary map is
initialized. We lookup the given name and we match the signature of the
given summary against the lookup results. If the summary matches the
FunctionDecl (got from the lookup result) then we add that to the
summary map. During a call event we compare FunctionDecl pointers.
Advantages of this new refactor:

- Cleaner mapping and structure for the checker.
- Possibly way more efficient handling of call events.
- A summary is added only if that is relevant for the given TU.
- We can get the concrete FunctionDecl by the time when we create the summary, 
this opens up possibilities of further sanity checks regarding the summary 
cases and argument constraints.
- Opens up to future work when we'd like to store summaries from IR to a 
FunctionDecl (or from the Attributor results of the given FunctionDecl).

Note, we cannot support old C functions without prototypes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77641

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

Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -266,21 +266,15 @@
       return T;
     }
 
-    /// Try our best to figure out if the call expression is the call of
+    /// Try our best to figure out if the summary's signature matches
     /// *the* library function to which this specification applies.
-    bool matchesCall(const FunctionDecl *FD) const;
+    bool matchesSignature(const FunctionDecl *FD) const;
   };
 
-  // The same function (as in, function identifier) may have different
-  // summaries assigned to it, with different argument and return value types.
-  // 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 different definitions on different platforms.
-  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.
-  mutable llvm::StringMap<Summaries> FunctionSummaryMap;
+  using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
+  mutable FunctionSummaryMapType FunctionSummaryMap;
 
   mutable std::unique_ptr<BugType> BT_InvalidArg;
 
@@ -289,14 +283,6 @@
   static QualType getArgType(const Summary &Summary, ArgNo ArgN) {
     return Summary.getArgType(ArgN);
   }
-  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, ArgNo ArgN) {
-    return ArgN == Ret ? CE->getType().getCanonicalType()
-                       : CE->getArg(ArgN)->getType().getCanonicalType();
-  }
   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
   }
@@ -440,7 +426,7 @@
   BinaryOperator::Opcode Op = getOpcode();
   ArgNo OtherArg = getOtherArgNo();
   SVal OtherV = getArgSVal(Call, OtherArg);
-  QualType OtherT = getArgType(Call, OtherArg);
+  QualType OtherT = getArgType(Summary, OtherArg);
   // Note: we avoid integral promotion for comparison.
   OtherV = SVB.evalCast(OtherV, T, OtherT);
   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
@@ -530,7 +516,7 @@
   llvm_unreachable("Unknown invalidation kind!");
 }
 
-bool StdLibraryFunctionsChecker::Summary::matchesCall(
+bool StdLibraryFunctionsChecker::Summary::matchesSignature(
     const FunctionDecl *FD) const {
   // Check number of arguments:
   if (FD->param_size() != ArgTys.size())
@@ -565,28 +551,10 @@
 
   initFunctionSummaries(C);
 
-  IdentifierInfo *II = FD->getIdentifier();
-  if (!II)
-    return None;
-  StringRef Name = II->getName();
-  if (Name.empty() || !C.isCLibraryFunction(FD, Name))
-    return None;
-
-  auto FSMI = FunctionSummaryMap.find(Name);
+  auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
   if (FSMI == FunctionSummaryMap.end())
     return None;
-
-  // Verify that function signature matches the spec in advance.
-  // Otherwise we might be modeling the wrong function.
-  // Strict checking is important because we will be conducting
-  // very integral-type-sensitive operations on arguments and
-  // return values.
-  const Summaries &SpecVariants = FSMI->second;
-  for (const Summary &Spec : SpecVariants)
-    if (Spec.matchesCall(FD))
-      return Spec;
-
-  return None;
+  return FSMI->second;
 }
 
 Optional<StdLibraryFunctionsChecker::Summary>
@@ -598,6 +566,21 @@
   return findFunctionSummary(FD, C);
 }
 
+llvm::Optional<const FunctionDecl *>
+lookupGlobalCFunction(StringRef Name, const ASTContext &ACtx) {
+  IdentifierInfo &II = ACtx.Idents.get(Name);
+  auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
+  if (LookupRes.size() == 0)
+    return None;
+
+  assert(LookupRes.size() == 1 && "In C, identifiers should be unique");
+  Decl *D = LookupRes.front()->getCanonicalDecl();
+  auto *FD = dyn_cast<FunctionDecl>(D);
+  if (!FD)
+    return None;
+  return FD->getCanonicalDecl();
+}
+
 void StdLibraryFunctionsChecker::initFunctionSummaries(
     CheckerContext &C) const {
   if (!FunctionSummaryMap.empty())
@@ -652,6 +635,38 @@
     return -1;
   }();
 
+  // Auxiliary class to aid adding summaries to the summary map.
+  struct AddToFunctionSummaryMap {
+    const ASTContext &ACtx;
+    FunctionSummaryMapType &Map;
+    AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM)
+        : ACtx(ACtx), Map(FSM) {}
+    // Add a summary to a FunctionDecl found by lookup. The lookup is performed
+    // by the given Name, and in the global scope. The summary will be attached
+    // to the found FunctionDecl only if the signatures match.
+    void operator()(StringRef Name, const Summary &S) {
+      IdentifierInfo &II = ACtx.Idents.get(Name);
+      auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
+      if (LookupRes.size() == 0)
+        return;
+      for (Decl *D : LookupRes) {
+        if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+          if (S.matchesSignature(FD)) {
+            auto Res = Map.insert({FD->getCanonicalDecl(), S});
+            assert(Res.second && "Function already has a summary set!");
+            (void)Res;
+            return;
+          }
+        }
+      }
+    }
+    // Add several summaries for the given name.
+    void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
+      for (const Summary &S : Summaries)
+        operator()(Name, S);
+    }
+  } addToFunctionSummaryMap(ACtx, FunctionSummaryMap);
+
   // We are finally ready to define specifications for all supported functions.
   //
   // The signature needs to have the correct number of arguments.
@@ -677,7 +692,6 @@
   // return value, however the correct range is [-1, 10].
   //
   // Please update the list of functions in the header after editing!
-  //
 
   // Below are helpers functions to create the summaries.
   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
@@ -739,238 +753,186 @@
         .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
   };
 
-  FunctionSummaryMap = {
-      // The isascii() family of functions.
-      // The behavior is undefined if the value of the argument is not
-      // representable as unsigned char or is not equal to EOF. See e.g. C99
-      // 7.4.1.2 The isalpha function (p: 181-182).
-      {
-          "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, UCharRangeMax}})})
-                  .Case({ArgumentCondition(0U, OutOfRange,
-                                           {{'0', '9'},
-                                            {'A', 'Z'},
-                                            {'a', 'z'},
-                                            {128, UCharRangeMax}}),
-                         ReturnValueCondition(WithinRange, SingleValue(0))})
-                  .ArgConstraint(ArgumentCondition(
-                      0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))},
-      },
-      {
-          "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, UCharRangeMax}})})
-                  .Case({ArgumentCondition(
-                             0U, OutOfRange,
-                             {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
-                         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, UCharRangeMax}})})
-                  // Is not an unsigned char.
-                  .Case({ArgumentCondition(0U, OutOfRange,
-                                           Range(0, UCharRangeMax)),
-                         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, UCharRangeMax}})})
-                  .Case({ArgumentCondition(
-                             0U, OutOfRange,
-                             {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
-                         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, UCharRangeMax}})})
-                  // Other.
-                  .Case({ArgumentCondition(0U, OutOfRange,
-                                           {{'A', 'Z'}, {128, UCharRangeMax}}),
-                         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)
+  // The isascii() family of functions.
+  // The behavior is undefined if the value of the argument is not
+  // representable as unsigned char or is not equal to EOF. See e.g. C99
+  // 7.4.1.2 The isalpha function (p: 181-182).
+  addToFunctionSummaryMap(
+      "isalnum",
+      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, UCharRangeMax}})})
+          .Case(
+              {ArgumentCondition(
+                   0U, OutOfRange,
+                   {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
+               ReturnValueCondition(WithinRange, SingleValue(0))})
+          .ArgConstraint(ArgumentCondition(
+              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+  addToFunctionSummaryMap(
+      "isalpha",
+      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, UCharRangeMax}})})
+          .Case({ArgumentCondition(
+                     0U, OutOfRange,
+                     {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
+                 ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "isascii",
+      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))}));
+  addToFunctionSummaryMap(
+      "isblank",
+      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))}));
+  addToFunctionSummaryMap(
+      "iscntrl",
+      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))}));
+  addToFunctionSummaryMap(
+      "isdigit",
+      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))}));
+  addToFunctionSummaryMap(
+      "isgraph",
+      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))}));
+  addToFunctionSummaryMap(
+      "islower",
+      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, UCharRangeMax}})})
+          // Is not an unsigned char.
+          .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
+                 ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "isprint",
+      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))}));
+  addToFunctionSummaryMap(
+      "ispunct",
+      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+          .Case({ArgumentCondition(
+                     0U, WithinRange,
+                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
+                 ReturnValueCondition(OutOfRange, SingleValue(0))})
+          .Case({ArgumentCondition(
+                     0U, OutOfRange,
+                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
+                 ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "isspace",
+      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, UCharRangeMax}})})
+          .Case({ArgumentCondition(0U, OutOfRange,
+                                   {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
+                 ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "isupper",
+      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, UCharRangeMax}})})
+          // Other.
+          .Case({ArgumentCondition(0U, OutOfRange,
+                                   {{'A', 'Z'}, {128, UCharRangeMax}}),
+                 ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "isxdigit",
+      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.
+  addToFunctionSummaryMap("getc", Getc());
+  addToFunctionSummaryMap("fgetc", Getc());
+  addToFunctionSummaryMap(
+      "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
                      .Case({ReturnValueCondition(
-                         WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})})}},
-
-      // 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{Fwrite()}},
-      // 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)}},
-  };
+                         WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}));
+
+  // 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.
+  addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax),
+                                   Read(LongLongTy, LongLongMax)});
+  addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax),
+                                    Read(LongLongTy, LongLongMax)});
+  addToFunctionSummaryMap("fread", Fread());
+  addToFunctionSummaryMap("fwrite", Fwrite());
+  // getline()-like functions either fail or read at least the delimiter.
+  addToFunctionSummaryMap("getline",
+                          {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
+                           Getline(LongLongTy, LongLongMax)});
+  addToFunctionSummaryMap("getdelim",
+                          {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
+                           Getline(LongLongTy, LongLongMax)});
 
   // Functions for testing.
   if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
-    llvm::StringMap<Summaries> TestFunctionSummaryMap = {
-        {"__two_constrained_args",
-         Summaries{
-             Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
-                 .ArgConstraint(
-                     ArgumentCondition(0U, WithinRange, SingleValue(1)))
-                 .ArgConstraint(
-                     ArgumentCondition(1U, WithinRange, SingleValue(1)))}},
-        {"__arg_constrained_twice",
-         Summaries{Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
-                       .ArgConstraint(
-                           ArgumentCondition(0U, OutOfRange, SingleValue(1)))
-                       .ArgConstraint(
-                           ArgumentCondition(0U, OutOfRange, SingleValue(2)))}},
-        {"__defaultparam", Summaries{Summary(ArgTypes{Irrelevant, IntTy},
-                                             RetType{IntTy}, EvalCallAsPure)
-                                         .ArgConstraint(NotNull(ArgNo(0)))}},
-        {"__variadic", Summaries{Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
-                                         RetType{IntTy}, EvalCallAsPure)
-                                     .ArgConstraint(NotNull(ArgNo(0)))
-                                     .ArgConstraint(NotNull(ArgNo(1)))}}};
-    for (auto &E : TestFunctionSummaryMap) {
-      auto InsertRes =
-          FunctionSummaryMap.insert({std::string(E.getKey()), E.getValue()});
-      assert(InsertRes.second &&
-             "Test functions must not clash with modeled functions");
-      (void)InsertRes;
-    }
+    addToFunctionSummaryMap(
+        "__two_constrained_args",
+        Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
+            .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
+    addToFunctionSummaryMap(
+        "__arg_constrained_twice",
+        Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
+            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
+    addToFunctionSummaryMap(
+        "__defaultparam",
+        Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure)
+            .ArgConstraint(NotNull(ArgNo(0))));
+    addToFunctionSummaryMap("__variadic",
+                            Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
+                                    RetType{IntTy}, EvalCallAsPure)
+                                .ArgConstraint(NotNull(ArgNo(0)))
+                                .ArgConstraint(NotNull(ArgNo(1))));
   }
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to