This is an archive of the discontinued LLVM Phabricator instance.

hicpp-signed-bitwise - Return location of the operand (and not of the operator beginning)
ClosedPublic

Authored by vladimir.plyashkun on Aug 11 2022, 7:01 AM.

Details

Summary

Hello!
Currently, the "hicpp/signed-bitwise" check returns the beginning of the binary/unary operator as location, which sometimes confuses users in the IDE due to incorrect highlighting.
Yes, the offset from Ranges can be used for this particular check, but i suppose better solution is to return begin location of the problematic operand instead of operator.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptAug 11 2022, 7:01 AM
vladimir.plyashkun requested review of this revision.Aug 11 2022, 7:01 AM
njames93 added inline comments.Aug 11 2022, 7:22 AM
clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
100

Seems pretty useless to pass the begin location of the Unary/Binary operator here.
The only source locations that are of interest is the operator location and the whole range of the SignedOperand.
Based on the issues with jetbrains rendering, I also imagine clangd would have the same issue, We'd likely want to have the diag locations as the SignedOperand begin(like this patch). Then pass the whole source range of the signed operand(like it currently is).
I'm either way on whether we would need to pass the location of the operator (BinaryOp|UnaryOp)->getOperatorLoc()

Hi @vladimir.plyashkun !

I looked at the screenshot in the link you posted. What is the type of value?

Consider that if value is an uint8_t, as per the integer promotion rules, it will be promoted to (signed) int before running the bitwise operation. Therefore clang-tidy is right to point out the problem with value. Check it out:

https://godbolt.org/z/8EMcPd6rd

`-DeclStmt <line:6:5, col:22>
  `-VarDecl <col:5, col:18> col:10 y 'int':'int' cinit
    `-BinaryOperator <col:14, col:18> 'int' '&'
      |-ImplicitCastExpr <col:14> 'int' <IntegralCast>
      | `-ImplicitCastExpr <col:14> 'std::uint8_t':'unsigned char' <LValueToRValue>
      |   `-DeclRefExpr <col:14> 'std::uint8_t':'unsigned char' lvalue Var 0x55db629e40e8 'x' 'std::uint8_t':'unsigned char'
      `-IntegerLiteral <col:18> 'int' 255

On the other hand, if the 0xFF becomes 0xFFu, then Clang performs an integer promotion to unsigned int instead of int, and that's why clang-tidy no longer complains.

I'm not sure that's correct behavior, however:

If int can represent the entire range of values of the original type (or the range of values of the original bit field), the value is converted to type int. Otherwise the value is converted to unsigned int.

https://en.cppreference.com/w/c/language/conversion

In this case, an int can represent fully all values of an uint8_t.

vladimir.plyashkun added a comment.EditedAug 11 2022, 7:55 AM

Hi @carlosgalvezp
Yes, sorry, maybe screenshot and example from issue in our bugtracker is not the best one.
You can check it on this sample from clang-tidy tests:
The "hicpp-signed-bitwise" will point to

URes = UValue & -1;

[UValue] instead of -1, which looks confusing.

clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
100

My initial point was to preserve current behaviour as much as possible, but i agree that (BinaryOp|UnaryOp)->getOperatorLoc() is much better in this case.

The pre-merge bot is failing because clang-format hasn't been run. Can you please update the diff by running git clang-format first.

Hi @carlosgalvezp
Yes, sorry, maybe screenshot and example from issue in our bugtracker is not the best one.
You can check it on this sample from clang-tidy tests:
The "hicpp-signed-bitwise" will point to

URes = UValue & -1;

[UValue] instead of -1, which looks confusing.

Ah, yes that seems off, thanks for the clarification! :)

  • Executed clang-format after changes
  • Return operator location (in additional range)
njames93 added inline comments.Aug 15 2022, 9:15 AM
clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
102

We still need the source range of the operand

[build]   Value <<= diagTest(1, 2, 3);
[build]         ~~~ ^

Vs

[build]   Value <<= diagTest(1, 2, 3);
[build]         ~~~ ^~~~~~~~~~~~~~~~~
vladimir.plyashkun updated this revision to Diff 452936.EditedAug 16 2022, 3:02 AM
  • return operand source range too
njames93 accepted this revision.Aug 17 2022, 3:43 AM

Would you like me to commit it on your behalf again?

This revision is now accepted and ready to land.Aug 17 2022, 3:43 AM
vladimir.plyashkun marked an inline comment as done.Aug 17 2022, 3:49 AM

Would you like me to commit it on your behalf again?

Yes, the email is the same - vladimir.plyashkun@jetbrains.com