[PATCH] D103094: [analyzer] Implemented RangeSet::Factory::castTo function to perform promotions, truncations and conversions

Gabor Marton via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 13 02:58:37 PDT 2022


martong added a comment.

Thanks for you patience Denys! Finally I had some time for the review. Nice work!



================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:242
+    ///
+    /// This function optimized for each of the six cast cases:
+    /// - noop
----------------



================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:358
+  assert(!isEmpty());
+  return begin()->From().isUnsigned();
+}
----------------
Probably it is unrelated to this patch, but
Could it happen that `(++begin())->From().isUnsigned()` gives a different signedness? Or we had a separate assertion when we  added the second `Range`? The same question applies to the below two functions as well. Seems like in `unite` we don't have such validity check...


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:687
+
+  if (IsConversion && (!IsPromotion || !What.isUnsigned()))
+    return makePersistent(convertTo(What, Ty));
----------------
Could you please explain why do we need the `|| !What.isUnsigned()` part of the condition?

This would make much more sense to me:
```
if (IsConversion && !IsPromotion)
    return makePersistent(convertTo(What, Ty));
```


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:690
+
+  // Promotion from unsigneds to signeds/unsigneds left.
+
----------------
martong wrote:
> I think it would be more consistent with the other operations (truncate and convert) if we had this logic in its own separate function: `promoteTo`. And this function should be called only if `isPromotion` is set (?)
This comment is confusing, since we can get here also if
`isConversion` is false and
`isPromotion` is false 


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:690-711
+  // Promotion from unsigneds to signeds/unsigneds left.
+
+  using llvm::APInt;
+  using llvm::APSInt;
+  ContainerType Result;
+  // We definitely know the size of the result set.
+  Result.reserve(What.size());
----------------
I think it would be more consistent with the other operations (truncate and convert) if we had this logic in its own separate function: `promoteTo`. And this function should be called only if `isPromotion` is set (?)


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:740-741
+    uint64_t CurrentRangeSize = (ToInt - FromInt).getZExtValue();
+    // This is an optimization for specific case when we are enough to cover
+    // the whole range.
+    Dummy.clear();
----------------
?


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:773
+  ContainerType Result;
+  ContainerType Dummy;
+  // Divide the cast into two phases (presented as loops here).
----------------
We could certainly have a better name for this. E.g. `SecondHalf`. (And `FirstHalf` instead of `Result`?)


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:774-791
+  // Divide the cast into two phases (presented as loops here).
+  // First phase(loop) works when casted values go in ascending order.
+  // E.g. char{1,3,5,127} -> uint{1,3,5,127}
+  // Interrupt the first phase and go to second one when casted values start
+  // go in descending order. That means that we crossed over the middle of
+  // the type value set (aka 0 for signeds and MAX/2+1 for unsigneds).
+  // For instance:
----------------
I think this comment would be better positioned as a header comment for the entire function.


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:792
+  //    unite -> uchar(-2, 1)
+  auto CastRange = [Ty, &VF = ValueFactory](const Range &R) -> Bounds {
+    // Get bounds of the given range.
----------------
Why not `-> Range`?


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:802
+  // Phase 1. Fill the first array.
+  APSInt LastFromInt = Ty.getMinValue();
+  const auto *It = What.begin();
----------------
Would it be a better name:`LastConvertedInt`? The naming `From` is confusing because that suggests the value we cast from, however, this variable refers to the casted to values, isn't it?


================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:812-814
+    if (NewBounds.first > NewBounds.second) {
+      Dummy.emplace_back(ValueFactory.getMinValue(Ty), NewBounds.second);
+      Result.emplace_back(NewBounds.first, ValueFactory.getMaxValue(Ty));
----------------
I think this case (wrap) deserves a comment.


================
Comment at: clang/unittests/StaticAnalyzer/RangeSetTest.cpp:728
+
+  using TV = TestValues<T>;
+  constexpr auto MIN = TV::MIN;
----------------
It doesn't matter, becasue `T` and `F` are equal here, but for consistency with the other tests.


================
Comment at: clang/unittests/StaticAnalyzer/RangeSetTest.cpp:827
+  if (is_signed_v<F>) {
+    this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
+    this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MID}});
----------------
I am getting lost. Why don't you check against `ToMIN` and `ToMAX` here? Could you explain e.g. with int16->int8?

It is confusing that at many places you test against `MIN`, `MAX`, `A`, ... and the conversion is happening automatically by the `checkCastTo` template. Would it be more explicit to use everywhere `ToMIN`, `ToA`, `ToB`, ... and check against them?


================
Comment at: clang/unittests/StaticAnalyzer/RangeSetTest.cpp:874-879
+  constexpr auto FromA = TV::FromA;
+  constexpr auto ToA = TV::ToA;
+  constexpr auto FromB = TV::FromB;
+  constexpr auto ToB = TV::ToB;
+  this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}},
+                                   {{FromA, ToA}});
----------------
Could you please elaborate what do we test here?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103094/new/

https://reviews.llvm.org/D103094



More information about the cfe-commits mailing list