steakhal added a comment.

Great progress.
Now, moving to the docs.
Have you checked that the docs compile without errors and look as you would 
expect? Please post how it looks.

Please make a note about this new checker in the clang's release docs, as we 
usually announce new checkers and major changes there.



================
Comment at: clang/docs/analyzer/checkers.rst:58-64
+ int basic_examples(int a, int b) {
+   if (b < 0) {
+     return a >> b; // warn: right argument is negative
+   } else if (b >= 32) {
+     return a << b; // warn: right argument >= capacity
+   }
+ }
----------------
else after return


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:272
+  if (const auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>()) {
+    const std::int64_t RHS = ConcreteRight->getValue().getExtValue();
+    assert(RHS > MaximalAllowedShift);
----------------
`getExtValue()`, I believe, asserts that it "fits", thus the concrete int is at 
most 64 bits wide. Does it work for `_BigInt`s? (or whatever we have like that 
:D)


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:299-303
+      if (Side == OperandSide::Left) {
+        NonNegOperands |= NonNegLeft;
+      } else {
+        NonNegOperands |= NonNegRight;
+      }
----------------
When I see something like this I always think of using a ternary.
Have you also considered?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:335-339
+    auto R =
+        std::make_unique<PathSensitiveBugReport>(BT, ShortMsg, Msg, ErrNode);
+    bugreporter::trackExpressionValue(ErrNode, Op->getLHS(), *R);
+    bugreporter::trackExpressionValue(ErrNode, Op->getRHS(), *R);
+    return R;
----------------
AHA! Now I got you. You also call this `R`.
Just use `R` at the callsite as well. Job done.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:355-357
+    if (!BTPtr)
+      BTPtr = std::make_unique<BugType>(this, "Bitwise shift",
+                                        "Suspicious operation");
----------------
How about eagerly inline initializing this field? And avoiding `mutable` as 
well.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:367-369
+
+  const AnalyzerOptions &Opts = Mgr.getAnalyzerOptions();
+
----------------



================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:53
+class BitwiseShiftValidator {
+  // Primary mutable state:
+  CheckerContext &Ctx;
----------------
donat.nagy wrote:
> steakhal wrote:
> > Where does this comment corresponds to?
> The two data members (`Ctx` and `State`) that are directly below the comment.
> 
> I tried to split the list of data members into three groups (primary mutable 
> state, secondary mutable state, `const`  members), but now I reconsider this 
> I feel that these header comments are actually superfluous.
> 
> I'll return to a variant of the earlier layout where I put 
> `NonNegFlags`/`UpperBound` to the end and comment that they are only used for 
> note tag creation; but don't emphasize the (immediately visible) `const`ness 
> / non-`const`-ness of other members with comments.
One way to emphasize this is by choosing names like `FoldedState`, or anything 
else that has something to do with "motion" or "change".
Given that if we have `ProgramStateRefs` in helper classes they usually remain 
still. Think of BugReportVisitors for example. Consequently,it's important to 
raise awareness when it's not like that. A different name would achieve this.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:57-59
+  // Secondary mutable state, used only for note tag creation:
+  enum { NonNegLeft = 1, NonNegRight = 2 };
+  unsigned NonNegFlags = 0;
----------------
donat.nagy wrote:
> donat.nagy wrote:
> > steakhal wrote:
> > > How about using the same enum type for these two? It would signify that 
> > > these are used together.
> > > Also, by only looking at the possible values, it's not apparent that 
> > > these are bitflag values. A suffix might help the reader.
> > Using the enum type is a good idea, however I'd probably put the `Flag` 
> > suffix into the name of the type:
> > ```
> > enum SignednessFlags : unsigned { NonNegLeft = 1, NonNegRight = 2 };
> > SignednessFlags NonNegOperands = 0;
> > ```
> I rename the member `NonNegFlags` to `NonNegOperands` but its type remains a 
> plain `unsigned` because otherwise using the or-assign operator like 
> `NonNegOperands |= NonNegLeft` produces the error
> > Assigning to 'enum SignednessFlags' from incompatible type 'unsigned int' 
> > (clang typecheck_convert_incompatible)
> (note that both operands were from the same enum type).
Okay, indeed one would need to define the `operator|(SignednessStatus, 
SignednessStatus)` and `operato&|(SignednessStatus, SignednessStatus)` as well.
It probably doesn't worth it. Such a pity that we can't have nice things in C++.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:60-63
+  // If there is an upper bound, it is <= the size of a primitive type
+  // (expressed in bits), so this is a very safe sentinel value:
+  enum { NoUpperBound = 999 };
+  unsigned UpperBound = NoUpperBound;
----------------
donat.nagy wrote:
> steakhal wrote:
> > Have you considered using `std::optional`?
> > Given that the dimension of this variable is "bits", I think it would be 
> > great to have that in its name.
> I considered using `std::optional`, but using this "old-school" solution 
> ensures that `NoUpperBound` is comparable to and larger than the "real" upper 
> bound values, which lets me avoid some ugly boolean logic. I'll update the 
> comment and probably also the variable name.
What "ugly boolean logic" are you referring to?
I thought one can always use `value_or(999)` anyway. To me, that means that the 
option approach is a refinement of yours. But depending on the situation, it 
might be possible to avoid the extrema value 999 altogether.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:106-109
+  if (auto BRP = checkOvershift()) {
+    Ctx.emitReport(std::move(BRP));
+    return;
+  }
----------------
donat.nagy wrote:
> steakhal wrote:
> > I'd prefer `BR` or `Report`. Since we know already that we are in the 
> > path-sensitive domain, `P` has less value there.
> > I'd apply this concept everywhere in the patch.
> The `P` stands for the "Ptr" in the name of the type alias `BugReportPtr`; 
> but your comment clearly highlights that this variable name is confusing ;).
> 
> I'll probably avoid the `auto` and use `BugReportPtr Bug = ...` to remind the 
> reader that this is a pointer (that can be null) and if it's non-null, then 
> we found a bug.
Oh I see. To me, it's fairly obvious now that bugreports are just 
smart-pointers.
So I implicitly looked for some other reason. But just look at other checker, 
and call it the same way how they do, for consistency. That's all I wanted.
There are two/three common options I believe: `B` or `BR`, and maybe `Report`.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:190-191
+  std::string Msg =
+      llvm::formatv("The result of {0} shift is undefined because the right "
+                    "operand{1} is not smaller than {2}, the capacity of 
'{3}'",
+                    isLeftShift() ? "left" : "right", RightOpStr, LHSBitWidth,
----------------
donat.nagy wrote:
> steakhal wrote:
> > 
> This is an important distinction, I use "not smaller than {2}" as a shorter 
> synonym of "larger than or equal to {2}". I can choose some other wording if 
> you feel that this is not clear enough.
No, I have not strong feelings. Feel free to use the one you like more.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:218
+                                       Side == OperandSide::Left ? "Left" : 
"Right",
+                                       isLeftShift() ? "left" : "right")
+                             .str();
----------------
donat.nagy wrote:
> steakhal wrote:
> > The `isLeftShift() ? "left" : "right"` expression appears 4 times in total.
> > I'd also recommend to not distinguish the capitalized "left" and "right" 
> > strings, and just post-process the messages to ensure that the first 
> > character is capitalized inside the `createBugReport()`.
> > 
> > Also note that you can reuse the same placeholder, so you would only need 
> > to pass the `side()` only once.
> > ```lang=C++
> > static void capitalizeBeginning(std::string &Str) {
> >   if (Str.empty())
> >     return;
> >   Str[0] = llvm::toUpper(Str[0]);
> > }
> > 
> > StringRef side() const {
> >   return isLeftShift() ? "left" : "right";
> > }
> > ```
> I introduced a method for `isLeftShift() ? "left" : "right"` (which is indeed 
> repeated several times), but I didn't define `capitalizeBeginning` because 
> that would've been used only once.
> 
> Your remark that [with the capitalization function] "you can reuse the same 
> placeholder, so you would only need to pass the side() only once" seems to be 
> incorrect, because `Side == OperandSide::Left ? "Left" : "Right"` (which 
> operand are we talking about?) and `isLeftShift() ? "left" : "right"` (what 
> kind of shift operator are we talking about?) are two independent values.
Makes sense. It was so tempting though.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:315
+    default:
+      llvm_unreachable("this checker does not use other comparison operators");
+  }
----------------
donat.nagy wrote:
> steakhal wrote:
> > 
> I'd say that the current wording is correct because the the checker "use"s 
> the comparison operators (in its implementation) instead of "accept"ing them 
> from outside; but I can replace the message with e.g. "this //function// does 
> not accept other comparison operators" if you'd prefer that.
No strong feelings :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156312

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

Reply via email to