aaron.ballman added inline comments.

================
Comment at: lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp:96
+  // Get the value of the expression to cast.
+  const auto ValueToCastOptional =
+      C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
----------------
NoQ wrote:
> aaron.ballman wrote:
> > NoQ wrote:
> > > aaron.ballman wrote:
> > > > Szelethus wrote:
> > > > > Szelethus wrote:
> > > > > > ZaMaZaN4iK wrote:
> > > > > > > lebedev.ri wrote:
> > > > > > > > ZaMaZaN4iK wrote:
> > > > > > > > > lebedev.ri wrote:
> > > > > > > > > > ZaMaZaN4iK wrote:
> > > > > > > > > > > lebedev.ri wrote:
> > > > > > > > > > > > ZaMaZaN4iK wrote:
> > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > `const auto *`
> > > > > > > > > > > > > Why do we need this change here? If I understand 
> > > > > > > > > > > > > correctly, with `const auto*` we also need change 
> > > > > > > > > > > > > initializer to 
> > > > > > > > > > > > > `C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>().getPointer()`.
> > > > > > > > > > > > >  But I don't understand why we need this.
> > > > > > > > > > > > Is `ValueToCastOptional` a pointer, a reference, or 
> > > > > > > > > > > > just an actual `DefinedOrUnknownSVal`? I can't tell.
> > > > > > > > > > > > (sidenote: would be great to have a clang-tidy check 
> > > > > > > > > > > > for this.)
> > > > > > > > > > > `ValueToCastOptional` is 
> > > > > > > > > > > `llvm::Optional<DefinedOrUnknownSVal>`
> > > > > > > > > > See, all my guesses were wrong. That is why it should not 
> > > > > > > > > > be `auto` at all.
> > > > > > > > > I don't agree with you for this case. Honestly it's like a 
> > > > > > > > > yet another holywar question. If we are talking only about 
> > > > > > > > > this case - here you can see `getAs<DefinedOrUnknownSVal>` 
> > > > > > > > > part of the expression. this means clearly (at least for me) 
> > > > > > > > > that we get something like `DefinedOrUnknownSVal`. What we 
> > > > > > > > > get? I just press hotkey in my favourite IDE/text editor and 
> > > > > > > > > see that `getAs` returns 
> > > > > > > > > `llvm::Optional<DefinedOrUnknownSVal>`. From my point of view 
> > > > > > > > > it's clear enough here.
> > > > > > > > > 
> > > > > > > > > If we are talking more generally about question "When should 
> > > > > > > > > we use `auto` at all? " - we can talk, but not here, I think 
> > > > > > > > > :)
> > > > > > > > https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable
> > > > > > > >  comes to mind.
> > > > > > > > > What we get? I just press hotkey in my favourite IDE/text 
> > > > > > > > > editor and see that getAs returns 
> > > > > > > > > llvm::Optional<DefinedOrUnknownSVal>
> > > > > > > > Which hotkey do i need to press to see this here, in the 
> > > > > > > > phabricator?
> > > > > > > > 
> > > > > > > > This really shouldn't be `auto`, if you have to explain that in 
> > > > > > > > the variable's name, justify it in review comments.
> > > > > > > Ok, didn't know about such LLVM coding standard. Of course, with 
> > > > > > > this information I will fix using `auto` here. Thank you.
> > > > > > Actually, I disagree. In the Static Analyzer we use `auto` if the 
> > > > > > return type is in the name of the expression, and `getAs` may fail, 
> > > > > > so it returns an `Optional`. In the case where a nullptr may be 
> > > > > > returned to signal failure, `auto *` is used, so I believe that 
> > > > > > `auto` is appropriate here.
> > > > > But don't change it back now, it doesn't matter a whole lot :D
> > > > > Actually, I disagree. In the Static Analyzer we use auto if the 
> > > > > return type is in the name of the expression, and getAs may fail, so 
> > > > > it returns an Optional. 
> > > > 
> > > > The static analyzer should be following the same coding standard as the 
> > > > rest of the project. This is new code, so it's not matching 
> > > > inappropriate styles from older code, so there's really no reason to 
> > > > not match the coding standard.
> > > > 
> > > > > In the case where a nullptr may be returned to signal failure, auto * 
> > > > > is used, so I believe that auto is appropriate here.
> > > > 
> > > > I disagree that `auto` is appropriate here. The amount of confusion 
> > > > about the type demonstrates why.
> > > I confirm the strong local tradition of preferring `auto` for optional 
> > > `SVal`s in new code, and i believe it's well-justified from the overall 
> > > coding guideline's point of view. Even if you guys didn't get it right 
> > > from the start, the amount of Analyzer-specific experience required to 
> > > understand that it's an optional is very minimal and people get used to 
> > > it very quickly when they start actively working on the codebase.
> > > 
> > > On one hand, being a class that combines LLVM custom RTTI with 
> > > pass-by-value semantics (i.e., it's like `QualType` when it comes to 
> > > passing it around and like `Type` when it comes to casting), optionals 
> > > are inevitable for representing `SVal` dynamic cast results.
> > > 
> > > On the other hand, `SVal` is one of the most common classes of objects in 
> > > the Static Analyzer (like, maybe, `Stmt` in Clang; i think a lot of 
> > > people who are interested in Static Analyzer more than in the rest of 
> > > Clang learn about `SVal`s earlier than about `Stmt`s), and in particular 
> > > `SVal` casts are extremely common (around 3-4 `SVal::getAs<T>()` casts 
> > > per a path-sensitive checker, not counting `castAs`, ~2x more common than 
> > > arithmetic operations over `SVal`s, only ~3x less common than all sorts 
> > > of `dyn_cast` in all checkers, including path-insensitive checkers), so 
> > > it's something you get used to really quickly.
> > > 
> > > Writing `Optional<DefinedOrUnknownSVal> DV = 
> > > V.getAs<DefinedOrUnknownSVal>();` in a lot of checker callbacks is 
> > > annoying for pretty much all checker developers from day 1. This clutters 
> > > the most important parts of the checker's logic: transfer functions and 
> > > the definition of the error state. Most bugs are in *that* part of the 
> > > code, and those bugs are *not* due to using `auto` for casts. Not using 
> > > `auto` almost doubles the amount of code you need to write to perform a 
> > > simple run-time type check. With a more verbose variable name or a bit 
> > > more code around it, it also causes a line break.
> > > 
> > > And it only provides information that most of the readers either already 
> > > know ("`SVal` is a value-type, so it uses optionals"), or memorize 
> > > immediately after encountering this pattern once on their first day, or 
> > > barely even care (optionals are used like pointers anyway). Being finally 
> > > allowed to replace it with just `auto` after migration to C++11 was 
> > > divine.
> > > 
> > > So i'm still strongly in favor of keeping this pattern included in the 
> > > list of //"places where the type is already obvious from the context"//. 
> > > This is the top-1 source of annoying boilerplate in Static Analyzer, and 
> > > it's as easy to remember as it is to learn that `dyn_cast<T>(S)` returns 
> > > a pointer (or a reference? - you need to look up the definition of `S` to 
> > > figure this out, unlike `V.getAs<T>()` that is always an optional for 
> > > `SVal`s).
> > > 
> > > P.S. Though i admit that coming up with a less annoying API is also a 
> > > good idea :)
> > > P.P.S. I guess some sort of `Optional<auto>` would have made everybody 
> > > happy. But it's not a thing unfortunately :(
> > Thank you for the explanation. However, I'm still not convinced this is 
> > supported by the coding style guideline. The point to "places where the 
> > type is already obvious from the context" has (in my estimation) only 
> > covered places where the type truly is obvious. i.e., it's either spelled 
> > out explicitly (`dyn_cast<>`, `getAs<>`, etc) or it's entirely immaterial 
> > for understanding (iterators). Whether a value is optional strikes me as 
> > highly pertinent information for code reviewers or maintainers to 
> > understand because it conveys information about the validity of a value. To 
> > me, this is just as important as the distinction between `auto`, `auto *`, 
> > and `auto &`, which we make the user spell out in the case of pointers and 
> > references. From what I can tell, we also spell out `Optional` pretty 
> > consistently elsewhere in the product.
> > 
> > The rationale that this is a common idiom makes the push-back 
> > understandable, but at the same time, use of `auto` where the type is not 
> > immediately obvious makes the static analyzer more hostile to get into, 
> > especially for people who only stray into this part of the code base 
> > periodically (which is one major motivation for having a style guide in the 
> > first place).
> > 
> > I also don't do a ton of work in the static analyzer, so take this feedback 
> > with a grain of salt. I certainly don't expect to change the static 
> > analyzer's decision here. However, this is also the second time this week 
> > I've run into "we don't do that in the static analyzer" and both times have 
> > been in response to common review feedback that applies elsewhere in the 
> > product and both times have consumed review time from multiple people in 
> > order to resolve.
> > 
> > Ultimately, a style guide is just that -- a guide, not a mandate. It may 
> > also be that deviation from the guide here is reasonable, but it does come 
> > at a cost. That said, this ship may have already sailed; churning the code 
> > to remove use of `auto` comes with its own costs that may not be worth 
> > paying.
> Like, i mean, until now i always thought of using `auto` for casts, including 
> casts of value-types, as of something that the coding guideline explicitly 
> asks for, and didn't even consider that it might be a deviation, and that's 
> the first time i hear this concern raised. Though now that you point this 
> out, the problem with highlighting that it's //the// `llvm::Optional` is 
> indeed an unclear situation.
> 
> For me as a maintainer, pure `auto` is definitely much easier to read and 
> review when used with `getAs`. For a casual reader - i don't know, i accept 
> that it might be harder than i imagine.
> 
> As usual, i'm happy to be proven wrong and/or accept any decision on that 
> matter. To me coding guidelines are definitely above personal preferences.
> 
> > conveys information about the validity of a value
> 
> This is conveyed via the choice between `getAs` and `castAs`.
> Though now that you point this out, the problem with highlighting that it's 
> the llvm::Optional is indeed an unclear situation.

Yup!

> This is conveyed via the choice between getAs and castAs.

That's a fair point, but in the rest of the code base, `getAs<>` returns a 
pointer. What started off this discussion was me asking for `const auto *` to 
clarify that it was a pointer to constant data when it really wasn't one (at 
least directly). So while it does convey the semantics, it still is a bit 
confusing.

However, I think you're right. The difference between `getAs<>` and `castAs<>` 
may be sufficient once you know the static analyzer a bit better.


https://reviews.llvm.org/D33672



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

Reply via email to