protobuf icon indicating copy to clipboard operation
protobuf copied to clipboard

clang-tidy check readability-uppercase-literal-suffix reports lots of warnings in generated c++ code

Open chrisse74 opened this issue 10 months ago • 4 comments

What language does this apply to? C++ / protoc

Describe the problem you are trying to solve. In the generated c++ code there are lots of warnings regarding the clang-tidy check readability-uppercase-literal-suffix (https://clang.llvm.org/extra/clang-tidy/checks/readability/uppercase-literal-suffix.html)

Detects when the integral literal or floating point (decimal or hexadecimal) literal has a non-uppercase suffix and provides a fix-it hint with the uppercase suffix.

For example:

MyProto.pb.h:2103:29: warning: integer literal has suffix 'u', which is not uppercase [readability-uppercase-literal-suffix]
 2103 |     _impl_._has_bits_[0] |= 0x00000001u;
      |                             ^         ~
      |                                       U

I am using this check and thus always have to ignore these warnings coming from the protobuf files.

Describe the solution you'd like It seems to me that changing a few lines in the generator would make these warnings go away.

$ grep -n %08xu src/google/protobuf/compiler/cpp/*.cc
field.cc:309:  std::string mask = absl::StrFormat("0x%08xu", 1u << (*idx % 32));
field.cc:336:  std::string mask = absl::StrFormat("0x%08xu", 1u << (*idx % 32));
message.cc:126:    condition = absl::StrFormat("(cached_has_bits & 0x%08xu) != 0", mask);
message.cc:131:    condition = absl::StrFormat("(this_._impl_._has_bits_[%d] & 0x%08xu) != 0",
message.cc:628:                    p->WithVars({{"mask", absl::StrFormat("0x%08xu", mask)}});
message.cc:762:      {"has_mask", absl::StrFormat("0x%08xu", 1u << (has_bit_index % 32))},
message.cc:5234:                p->Emit({{"mask", absl::StrFormat("0x%08xu", mask)},

-> replace %08u by %08U

Could you change the generator please? :)

chrisse74 avatar Apr 01 '25 11:04 chrisse74

Unfortunately we're unlikely to get to this priority-wise, but would be happy to take a contribution here.

I believe internally we have these checks disabled.

zhangskz avatar Apr 01 '25 17:04 zhangskz

👍 Certainly! Here's the step-by-step process along with the final changes for the issue #21029 regarding the readability-uppercase-literal-suffix warnings in the Protocol Buffers repository.

Step-by-Step Process

  1. Identify the Issue:

    • The issue reports warnings from the clang-tidy check readability-uppercase-literal-suffix in the generated C++ code of Protocol Buffers.

    • The warnings are caused by the use of non-uppercase suffixes in literals (e.g., 0x00000001u).

    • The proposed solution is to update the format specifier from %08u to %08U in specific lines of the code generator.

  2. Fetch Issue Details:

    • Retrieve the details of the issue from GitHub to understand the context and the exact locations in the code that need updating.
  3. Locate the Relevant Code:

    • Perform a code search in the repository to find the locations where the %08xu format specifier is used.

    • Identify the exact lines in the relevant files (field.cc and message.cc) that need to be changed.

  4. Propose Code Changes:

    • Modify the identified lines to replace %08xu with %08XU to match the uppercase requirement and eliminate the warnings.

    • Prepare the changed code snippets for both field.cc and message.cc.

Final Changes

Here are the final changes to the relevant files:

src/google/protobuf/compiler/cpp/field.cc

void HasBitVars(const FieldDescriptor* field, const Options& opts,
                absl::optional<uint32_t> idx, std::vector<Sub>& vars) {
  if (!idx.has_value()) {
    vars.emplace_back(Sub("set_hasbit", "").WithSuffix(";"));
    vars.emplace_back(Sub("clear_hasbit", "").WithSuffix(";"));
    return;
  }

  ABSL_CHECK(internal::cpp::HasHasbit(field));

  int32_t index = *idx / 32;
  std::string mask = absl::StrFormat("0x%08XU", 1u << (*idx % 32));

  absl::string_view has_bits = IsMapEntryMessage(field->containing_type())
                                   ? "_has_bits_"
                                   : "_impl_._has_bits_";

  auto has = absl::StrFormat("%s[%d] & %s", has_bits, index, mask);
  auto set = absl::StrFormat("%s[%d] |= %s;", has_bits, index, mask);
  auto clr = absl::StrFormat("%s[%d] &= ~%s;", has_bits, index, mask);

  vars.emplace_back("has_hasbit", has);
  vars.emplace_back(Sub("set_hasbit", set).WithSuffix(";"));
  vars.emplace_back(Sub("clear_hasbit", clr).WithSuffix(";"));
}

void InlinedStringVars(const FieldDescriptor* field, const Options& opts,
                       absl::optional<uint32_t> idx, std::vector<Sub>& vars) {
  if (!IsStringInlined(field, opts)) {
    ABSL_CHECK(!idx.has_value());
    return;
  }

  // The first bit is the tracking bit for on demand registering ArenaDtor.
  ABSL_CHECK_GT(*idx, 0u)
      << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking";

  int32_t index = *idx / 32;
  std::string mask = absl::StrFormat("0x%08XU", 1u << (*idx % 32));
  vars.emplace_back("inlined_string_index", index);
  vars.emplace_back("inlined_string_mask", mask);

  absl::string_view array = IsMapEntryMessage(field->containing_type())
                                ? "_inlined_string_donated_"
                                : "_impl_._inlined_string_donated_";

  vars.emplace_back("inlined_string_donated",
                    absl::StrFormat("(%s[%d] & %s) != 0;", array, index, mask));
  vars.emplace_back("donating_states_word",
                    absl::StrFormat("%s[%d]", array, index));
  vars.emplace_back("mask_for_undonate", absl::StrFormat("~%s", mask));
}

src/google/protobuf/compiler/cpp/message.cc

std::string GenerateConditionMaybeWithProbability(
    uint32_t mask, absl::optional<float> probability, bool use_cached_has_bits,
    absl::optional<int> has_array_index) {
  std::string condition;
  if (use_cached_has_bits) {
    condition = absl::StrFormat("(cached_has_bits & 0x%08XU) != 0", mask);
  } else {
    // We only use has_array_index when use_cached_has_bits is false, make sure
    // we pas a valid index when we need it.
    ABSL_DCHECK(has_array_index.has_value());
    condition = absl::StrFormat("(this_._impl_._has_bits_[%d] & 0x%08XU) != 0",
                                *has_array_index, mask);
  }
  if (probability.has_value()) {
    return absl::StrFormat("PROTOBUF_EXPECT_TRUE_WITH_PROBABILITY(%s, %.3f)",
                           condition, *probability);
  }
  return condition;
}

std::string GenerateConditionMaybeWithProbabilityForField(
    int has_bit_index, const FieldDescriptor* field, const Options& options) {
  auto prob = GetPresenceProbability(field, options);
  return GenerateConditionMaybeWithProbability(
      1u << (has_bit_index % 32), prob,
      /*use_cached_has_bits*/ true,
      /*has_array_index*/ absl::nullopt);
}

std::string GenerateConditionMaybeWithProbabilityForGroup(
    uint32_t mask, const std::vector<const FieldDescriptor*>& fields,
    const Options& options) {
  auto prob = GetFieldGroupPresenceProbability(fields, options);
  return GenerateConditionMaybeWithProbability(
      mask, prob,
      /*use_cached_has_bits*/ true,
      /*has_array_index*/ absl::nullopt);
}

void PrintPresenceCheck(const FieldDescriptor* field,
                        const std::vector<int>& has_bit_indices, io::Printer* p,
                        int* cached_has_word_index, const Options& options) {
  if (!field->options().weak()) {
    int has_bit_index = has_bit_indices[field->index()];
    if (*cached_has_word_index != (has_bit_index / 32)) {
      *cached_has_word_index = (has_bit_index / 32);
      p->Emit({{"index", *cached_has_word_index}},
              {{"mask", absl::StrFormat("0x%08XU", 1u << (has_bit_index % 32))}});
    }
  }
}

These changes will ensure that the literals use uppercase suffixes, resolving the clang-tidy warnings. If anything reach back out.

  • References/Links 🔗:

github.com/jiushun/Container-network license

github.com/weideli1015/protobuf license

https://github.com/protocolbuffers/protobuf

Creatur3245 avatar Apr 02 '25 15:04 Creatur3245

AI answer?

chrisse74 avatar Apr 02 '25 17:04 chrisse74

I will bring in a PR. At the moment I struggle with the shellscript which updates the checked -in generated files because I have to install bazel first. So maybe tomorrow.

chrisse74 avatar Apr 02 '25 17:04 chrisse74

PR #21066 was merged.

chrisse74 avatar May 02 '25 06:05 chrisse74