Merge branch 'main' into protowire-options-range

This commit is contained in:
esrauchg 2026-08-09 13:02:02 -04:00 committed by GitHub
commit a3d24a95ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
118 changed files with 4000 additions and 1890 deletions

View file

@ -94,7 +94,7 @@ jobs:
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "bazel-tests"
bazel: test //bazel/...

View file

@ -37,25 +37,25 @@ jobs:
- { name: No-RTTI, flags: --cxxopt=-fno-rtti, continuous-only: true }
include:
# Set defaults
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
- targets: //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
# Override cases with custom images
- config: { name: "Bazel8", flags: --cxxopt="-Wno-self-assign-overloaded" }
cache_key: Bazel8
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "Bazel9", flags: "--cxxopt=-Wno-self-assign-overloaded" }
cache_key: Bazel9
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "TCMalloc" }
cache_key: TcMalloc
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12"
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 "
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "aarch64", flags: "--platforms=//build_defs:linux-aarch_64" }
cache_key: aarch64-bazel8
targets: "//src/... //src/google/protobuf/compiler:protoc_aarch64_test //third_party/utf8_range/..."
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-aarch64-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12"
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-aarch64-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 "
name: ${{ matrix.config.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.config.name }}
runs-on: ${{ matrix.config.runner || 'ubuntu-latest' }}
steps:
@ -64,6 +64,15 @@ jobs:
uses: protocolbuffers/protobuf-ci/checkout@v5
with:
ref: ${{ inputs.safe-checkout }}
- name: Prime the cache
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: ${{ matrix.image }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: cpp_linux/${{ matrix.cache_key }}
bazel: fetch ${{ matrix.targets }} ${{ matrix.config.flags }}
exclude-targets: ${{ matrix.exclude-targets }}
- name: Run tests
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
@ -78,7 +87,7 @@ jobs:
strategy:
fail-fast: false # Don't cancel all jobs if one fails.
matrix:
version: ['10.4', '13.1']
version: ['10.5', '13.4']
name: ${{ matrix.config.continuous-only && inputs.continuous-prefix || '' }} Linux GCC ${{ matrix.version }}
runs-on: ubuntu-latest
steps:
@ -87,11 +96,19 @@ jobs:
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
with:
ref: ${{ inputs.safe-checkout }}
- name: Prime the cache
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: cpp_linux/gcc-${{ matrix.version }}
bazel: fetch //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-${{ matrix.version }}-e78301df86b3e4c46ec9ac4d98be00e19305d8f3
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: cpp_linux/gcc-${{ matrix.version }}
bazel: test //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
@ -125,7 +142,7 @@ jobs:
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-${{ matrix.arch }}
- name: Check disk space after cross compile
@ -146,7 +163,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-${{ matrix.arch }}-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-${{ matrix.arch }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
entrypoint: bash
command: >
@ -386,7 +403,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-168f9c9d015a0fa16611e1e9eede796fe9bfbb69
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
entrypoint: bash
command: >-
@ -608,7 +625,7 @@ jobs:
if: ${{ inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-7932bf8b25fb76a111e7257d151a6a58d5c3c671
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: cpp_linux/abseil_head
bazel: test //src/... --override_module=abseil-cpp=abseil-cpp-head

View file

@ -27,7 +27,7 @@ jobs:
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.2.0-3.1.415-8.0.100-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
entrypoint: /bin/bash
command: >-
@ -43,7 +43,7 @@ jobs:
- name: Run conformance tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.2.0-3.1.415-8.0.100-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: csharp_linux
bazel: test //csharp:conformance_test --action_env=PATH --action_env=DOTNET_CLI_TELEMETRY_OPTOUT=1 --test_env=DOTNET_CLI_HOME=/home/bazel

View file

@ -22,7 +22,7 @@ jobs:
include:
- targets: "//hpb/... //hpb_generator/..."
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
- bazel_cmd: "test"
name: Linux ${{ matrix.config.name }}

View file

@ -30,27 +30,27 @@ jobs:
include:
- name: OpenJDK 8
cache_key: '8'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
# TODO: b/318555165 - enable the layering check. Currently it does
# not work correctly with the toolchain in this Docker image.
targets: //java/... //java/internal:java_version --features=-layering_check
flags: --java_language_version=8
- name: OpenJDK 11
cache_key: '11'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
targets: //java/... //java/internal:java_version //compatibility/...
continuous-only: true
- name: OpenJDK 17
cache_key: '17'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-17-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-17-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
targets: //java/... //java/internal:java_version //compatibility/...
- name: OpenJDK 21 bazel 8
cache_key: 'bazel8'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8.6.0-21-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8.7.0-21-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
targets: //java/... //java/internal:java_version //compatibility/...
- name: OpenJDK 21
cache_key: '21'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-21-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-21-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
targets: //java/... //java/internal:java_version //compatibility/...
# TODO: b/395623141 - restore this test once runtime uses / emulates aarch64.
# - name: aarch64
@ -105,7 +105,7 @@ jobs:
- name: Generate maven artifacts with bazel and install using maven
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: java_linux/11
bash: |

View file

@ -65,7 +65,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:9.0.0-${{ matrix.version }}-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:9.2.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: php_linux/${{ matrix.version }}
bash: |
@ -115,7 +115,7 @@ jobs:
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-i386
@ -147,7 +147,7 @@ jobs:
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64

View file

@ -50,7 +50,7 @@ jobs:
targets: //python/... //python:aarch64_test
# TODO Enable this once conformance tests are fixed.
flags: --define=use_fast_cpp_protos=true --test_tag_filters=-conformance
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-aarch64-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-aarch64-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.type }} ${{ matrix.version }} ${{ matrix.nobzlmod && 'No Bzlmod' || '' }}
runs-on: ubuntu-latest
@ -64,7 +64,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:9.0.0-{0}-7932bf8b25fb76a111e7257d151a6a58d5c3c671', matrix.version) }}
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.version) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: python_linux/${{ matrix.type }}_${{ matrix.version }}
bazel: test ${{ matrix.targets }} ${{ matrix.flags }} ${{ matrix.nobzlmod && '--noenable_bzlmod' || '' }} --test_env=KOKORO_PYTHON_VERSION

View file

@ -36,12 +36,12 @@ jobs:
- { name: Ruby 3.4, ruby: ruby-3.4.1, continuous-only: true }
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: NATIVE }
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: FFI }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: NATIVE }
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: FFI }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.name }} ${{ matrix.ffi == 'FFI' && ' FFI' || '' }}
runs-on: ubuntu-latest
@ -55,7 +55,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.0.0-{0}-9fc33a0c378b5affd3c85d3f5ae4f330993048f7', matrix.ruby) }}
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.ruby) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: ruby_linux/${{ matrix.ruby }}
bazel: test //ruby/... //ruby/tests:ruby_version --test_env=KOKORO_RUBY_VERSION --test_env=BAZEL=true ${{ matrix.ffi == 'FFI' && '--//ruby:ffi=enabled --test_env=PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI' || '' }}
@ -81,7 +81,7 @@ jobs:
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-i386
@ -114,7 +114,7 @@ jobs:
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64
@ -192,12 +192,12 @@ jobs:
- { name: Ruby 3.4, ruby: ruby-3.4.1, continuous-only: true }
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: NATIVE }
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: FFI }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: NATIVE }
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: FFI, continuous-only: true }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Install ${{ matrix.name }}${{ matrix.ffi == 'FFI' && ' FFI' || '' }}
runs-on: ubuntu-latest
steps:
@ -210,7 +210,7 @@ jobs:
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.0.0-{0}-9fc33a0c378b5affd3c85d3f5ae4f330993048f7', matrix.ruby) }}
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.ruby) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: ruby_install/${{ matrix.ruby }}_${{ matrix.bazel }}
bash: >

View file

@ -24,7 +24,7 @@ jobs:
include:
- targets: "//rust/... //src/google/protobuf/compiler/rust/..."
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
- bazel_cmd: "test"
# Override cases with custom images

View file

@ -30,8 +30,8 @@ jobs:
config:
- { name: "Fastbuild" }
- { name: "Optimized", flags: "-c opt", continuous-only: true }
- { name: "GCC Optimized", flags: "-c opt --force_pic --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac" }
- { name: "GCC Static", flags: "-c opt --dynamic_mode=off --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac", continuous-only: true }
- { name: "GCC Optimized", flags: "-c opt --force_pic --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\" --copt=\"-Wno-error=deprecated-declarations\" --copt=\"-Wno-error=array-bounds\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 " }
- { name: "GCC Static", flags: "-c opt --dynamic_mode=off --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\" --copt=\"-Wno-error=deprecated-declarations\" --copt=\"-Wno-error=array-bounds\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ", continuous-only: true }
- { name: "ASAN", flags: "--config=asan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/...", runner: ubuntu-22-4core }
- { name: "UBSAN", flags: "--config=ubsan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/... -//lua/...", continuous-only: true }
- { name: "32-bit", flags: "--copt=-m32 --linkopt=-m32", exclude-targets: "-//benchmarks:benchmark -//python/..." }
@ -51,7 +51,7 @@ jobs:
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: ${{ matrix.config.image || 'us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12' }}
image: ${{ matrix.config.image || 'us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: upb-bazel
bazel: test //benchmarks/... //lua/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}

View file

@ -35,6 +35,7 @@ google/protobuf/compiler/php/names.h
google/protobuf/compiler/plugin.h
google/protobuf/compiler/plugin.pb.h
google/protobuf/compiler/plugin.proto
google/protobuf/compiler/python/names.h
google/protobuf/compiler/retention.h
google/protobuf/compiler/scc.h
google/protobuf/compiler/subprocess.h
@ -111,6 +112,7 @@ google/protobuf/metadata.h
google/protobuf/metadata_lite.h
google/protobuf/micro_string.h
google/protobuf/naming_style.h
google/protobuf/offset_ptr.h
google/protobuf/option_interpreter.h
google/protobuf/os_macros_restore.inc
google/protobuf/os_macros_undef.inc
@ -244,6 +246,7 @@ upb/wire/decode_fast/combinations.h
upb/wire/decode_fast/data.h
upb/wire/decode_fast/select.h
upb/wire/encode.h
upb/wire/encode_extension.h
upb/wire/eps_copy_input_stream.h
upb/wire/reader.h
upb/wire/types.h

View file

@ -499,6 +499,64 @@ void BinaryAndJsonConformanceSuite::RunMessageSetTests() {
})pb"
// clang-format on
);
// [type_id, value, type_id (different)] -> first type_id and value honored.
RunValidBinaryProtobufTest<TestAllTypesProto2>(
absl::StrCat("ValidMessageSetEncoding.DuplicateDifferentTypeId"),
RECOMMENDED,
len(500,
group(
1,
absl::StrCat(
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
field(2, WireFormatLite::WIRETYPE_VARINT, varint(1547769))))),
// clang-format off
R"pb(message_set_correct: {
[protobuf_test_messages.proto2
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
})pb"
// clang-format on
);
// [type_id, value, value] -> first value honored, no merge.
RunValidBinaryProtobufTest<TestAllTypesProto2>(
absl::StrCat("ValidMessageSetEncoding.DuplicateValue"), RECOMMENDED,
len(500,
group(
1,
absl::StrCat(
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
len(3,
field(9, WireFormatLite::WIRETYPE_VARINT, varint(88)))))),
// clang-format off
R"pb(message_set_correct: {
[protobuf_test_messages.proto2
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
})pb"
// clang-format on
);
// [value, type_id, value] -> first value honored, no merge.
RunValidBinaryProtobufTest<TestAllTypesProto2>(
absl::StrCat("ValidMessageSetEncoding.DuplicateValueOutOfOrder"),
RECOMMENDED,
len(500,
group(
1,
absl::StrCat(
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
len(3,
field(9, WireFormatLite::WIRETYPE_VARINT, varint(88)))))),
// clang-format off
R"pb(message_set_correct: {
[protobuf_test_messages.proto2
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
})pb"
// clang-format on
);
}
void BinaryAndJsonConformanceSuite::RunRecursionLimitTests() {

View file

@ -70,3 +70,6 @@ Required.*.ProtobufInput.BadTag_OverlongVarint
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message

View file

@ -15,3 +15,4 @@ Recommended.Editions.ProtobufInput.RejectInvalidUtf8.String.Extension
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message

View file

@ -175,3 +175,6 @@ Required.*.JsonInput.TimestampJsonInputNonLeapFeb29
Required.*.JsonInput.TimestampJsonInputSecondTooLarge # Should have failed to parse, but didn't.
Required.*.JsonInput.TimestampJsonInputYearTooLong # Should have failed to parse, but didn't.
Required.*.JsonInput.TimestampJsonInputYearTooShort # Should have failed to parse, but didn't.
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message

View file

@ -3,4 +3,3 @@
#
# By listing them here we can keep tabs on which ones are failing and be sure
# that we don't introduce regressions in other tests.
Recommended.Proto2.ProtobufInput.EnforceDepthLimit.MessageSetExtension # Should have failed to parse, but didn't.

View file

@ -35,3 +35,6 @@ Recommended.Proto3.ProtobufInput.RejectInvalidUtf8.String.Singular
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message

View file

@ -598,3 +598,8 @@ about your project (name and website) so we can add an entry for you.
* Website: https://protowire.org
* Extensions: 1314-1363
1. Flyte
* Website: https://github.com/flyteorg/flyte
* Extensions: 1364-1373

View file

@ -929,6 +929,15 @@ public final class Descriptors {
return parent;
}
/**
* Checks whether this message type is defined in {@code descriptor.proto}.
*
* <p>For example, it returns true for {@code MessageOptions}, {@code FieldOptions}, etc.
*/
boolean isDescriptorProtoType() {
return getFile() == DescriptorProtos.getDescriptor();
}
public boolean isPlaceholder() {
return placeholder;
}

View file

@ -1070,7 +1070,10 @@ class MessageReflection {
Message defaultInstance)
throws IOException {
if (!field.isRepeated()) {
boolean isLazyField = ExtensionRegistryLite.lazyExtensionEnabled() && field.isExtension();
boolean isLazyField =
ExtensionRegistryLite.lazyExtensionEnabled()
&& field.isExtension()
&& !field.getContainingType().isDescriptorProtoType();
if (hasField(field)) {
InternalLazyField lazyField = extensions.getLazyField(field);
if (isLazyField && lazyField != null) {

View file

@ -12,6 +12,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import com.google.protobuf.ExtensionRegistryLite.LazyExtensionMode;
import proto2_unittest.UnittestCustomOptions;
import proto2_unittest.UnittestOptimizeFor;
import proto2_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import proto2_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
@ -459,4 +460,31 @@ public class ParserTest {
assertThat(builder.getExtension(TestParsingMerge.optionalExt).getOptionalInt32()).isEqualTo(2);
}
// Test that custom options are eagerly parsed by verifying that an invalid tag in the extension
// payload throws an exception.
@Test
public void testCustomOptionEagerlyParsed() throws Exception {
LazyExtensionMode originalMode = ExtensionRegistryLite.getLazyExtensionMode();
ExtensionRegistryLite.setLazyExtensionMode(LazyExtensionMode.LAZY_VERIFY_ON_ACCESS);
int fieldNumber = UnittestCustomOptions.complexOpt1.getNumber();
int extensionTag = (fieldNumber << 3) | 2; // WireFormat.WIRETYPE_LENGTH_DELIMITED
ByteArrayOutputStream output = new ByteArrayOutputStream();
CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeUInt32NoTag(extensionTag);
codedOutput.writeUInt32NoTag(1); // Length = 1 byte
codedOutput.writeRawByte((byte) 0); // 0 is an invalid varint tag in protobuf payload
codedOutput.flush();
byte[] invalidPayload = output.toByteArray();
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
registry.add(UnittestCustomOptions.complexOpt1);
Throwable thrown =
assertThrows(
InvalidProtocolBufferException.class,
() -> DescriptorProtos.MessageOptions.parseFrom(invalidPayload, registry));
assertThat(thrown).hasMessageThat().contains("invalid tag");
ExtensionRegistryLite.setLazyExtensionMode(originalMode);
}
}

View file

@ -36,7 +36,7 @@ class DslListTest {
@Test
fun dslListIsNotMutable() {
val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
assertThat(dslList is MutableList<*>).isFalse()
assertThat((dslList as Any) is MutableList<*>).isFalse()
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")

View file

@ -35,7 +35,7 @@ class DslMapTest {
@Test
fun dslMapIsNotMutable() {
val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
assertThat(dslMap is MutableMap<*, *>).isFalse()
assertThat((dslMap as Any) is MutableMap<*, *>).isFalse()
}
@Test

View file

@ -47,7 +47,7 @@ class ExtensionListTest {
TestProto.repeatedExtension,
mutableListOf(1, 2, 3),
)
assertThat(extensionList is MutableList<*>).isFalse()
assertThat((extensionList as Any) is MutableList<*>).isFalse()
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")

View file

@ -389,6 +389,29 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t
return self;
}
- (instancetype)initWithData:(NSData *)data parentRecursionDepth:(NSUInteger)parentDepth {
if ((self = [self initWithData:data])) {
// The parent stream had already entered `parentDepth` nested parses; we
// are about to begin one more level in this child stream, so seed the
// depth accordingly and verify the limit before parsing starts. This
// matches the convention used by the C++ ParseContext spawn helper,
// which increments and checks the depth before recursing into a payload
// that has been read into a fresh buffer.
state_.recursionDepth = parentDepth + 1;
@try {
CheckRecursionLimit(&state_);
} @catch (NSException *exception) {
// If CheckRecursionLimit raises an exception (when recursion depth exceeds
// kDefaultRecursionLimit), `self` will not be returned to the caller.
// Explicitly release `self` here to avoid a memory leak before re-throwing.
[self release];
self = nil;
@throw;
}
}
return self;
}
- (void)dealloc {
[buffer_ release];
[super dealloc];

View file

@ -33,6 +33,16 @@ typedef struct GPBCodedInputStreamState {
NSData *buffer_;
}
// Initializes a new stream over `data` whose initial recursion depth is one
// deeper than `parentDepth`. Used when a parser needs to spawn a fresh
// CodedInputStream to decode a payload that has already been read into a
// separate buffer (e.g. MessageSet items), so that the native call stack
// growth is still bounded by kDefaultRecursionLimit. The initializer raises
// GPBCodedInputStreamErrorRecursionDepthExceeded if `parentDepth` is already
// at the limit. Mirrors the depth-inheritance done by the C++ ParseContext
// spawn helper.
- (instancetype)initWithData:(NSData *)data parentRecursionDepth:(NSUInteger)parentDepth;
// Group support is deprecated, so we hide this interface from users, but
// support for older data.
- (void)readGroup:(int32_t)fieldNumber

View file

@ -2444,7 +2444,16 @@ void GPBClearMessageAutocreator(GPBMessage *self) {
[self setExtension:extension value:targetMessage];
[targetMessage release];
}
GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
// Parsing the MessageSet item payload requires a fresh CodedInputStream
// because the payload bytes are read into a separate buffer before the
// item's type-id and payload tags are correlated. Carry the parent
// stream's recursion depth across to the child stream so that nested
// MessageSet items (which would otherwise reset the depth to 0 on every
// hop) remain bounded by kDefaultRecursionLimit. This mirrors the
// depth-inheritance behavior of the C++ ParseContext spawn helper.
GPBCodedInputStream *newInput =
[[GPBCodedInputStream alloc] initWithData:rawBytes
parentRecursionDepth:input->state_.recursionDepth];
@try {
[targetMessage mergeFromCodedInputStream:newInput
extensionRegistry:extensionRegistry

View file

@ -428,4 +428,81 @@ const int kUnknownTypeId2 = 1550056;
}
}
static NSData* MessageSetDataWithLayers(NSUInteger layers) {
MSetMessage* innermost = [MSetMessage message];
MSetMessageExtension1* innermostExt = [MSetMessageExtension1 message];
innermostExt.i = 1;
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
[innermost setExtension:MSetMessageExtension1_extension_MessageSetExtension() value:innermostExt];
#else
[innermost setExtension:[MSetMessageExtension1 messageSetExtension] value:innermostExt];
#endif
MSetMessage* current = innermost;
for (NSUInteger i = 1; i < layers; ++i) {
MSetMessageExtension1* ext = [MSetMessageExtension1 message];
ext.recursive = current;
MSetMessage* parent = [MSetMessage message];
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
[parent setExtension:MSetMessageExtension1_extension_MessageSetExtension() value:ext];
#else
[parent setExtension:[MSetMessageExtension1 messageSetExtension] value:ext];
#endif
current = parent;
}
return [current data];
}
- (void)testParseMessageSetRecursionDepthCarriedFromParent {
// Each MSetMessage carries a single MSetMessageExtension1, whose
// `recursive` field is again a MSetMessage. Chaining N of these produces
// a MessageSet-of-MessageSet payload nested N levels deep. The parser
// for each MessageSet item allocates a fresh CodedInputStream, so depth
// tracking has to be inherited across those streams for the documented
// kDefaultRecursionLimit (100) to actually apply.
//
// Each layer increases recursion depth by 2 (+1 for the child CodedInputStream
// in parseMessageSet:, +1 for the `recursive` message field in readMessage:).
// 50 layers reaches depth 100 (kDefaultRecursionLimit), which must parse successfully.
// 51 layers attempts to reach depth 101 (kDefaultRecursionLimit + 1), which must fail
// with GPBCodedInputStreamErrorRecursionDepthExceeded rather than silently parsing.
const NSUInteger kPassLayers = 50;
NSData* passData = MessageSetDataWithLayers(kPassLayers);
XCTAssertNotNil(passData);
NSError* error = nil;
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
MSetMessage* passParsed =
[MSetMessage parseFromData:passData
extensionRegistry:MSet_Objc_Protobuf_Tests_Mset_MSetUnittestMsetRoot_Registry()
error:&error];
#else
MSetMessage* passParsed = [MSetMessage parseFromData:passData
extensionRegistry:[MSetUnittestMsetRoot extensionRegistry]
error:&error];
#endif
XCTAssertNotNil(passParsed);
XCTAssertNil(error);
const NSUInteger kFailLayers = 51;
NSData* failData = MessageSetDataWithLayers(kFailLayers);
XCTAssertNotNil(failData);
error = nil;
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
MSetMessage* failParsed =
[MSetMessage parseFromData:failData
extensionRegistry:MSet_Objc_Protobuf_Tests_Mset_MSetUnittestMsetRoot_Registry()
error:&error];
#else
MSetMessage* failParsed = [MSetMessage parseFromData:failData
extensionRegistry:[MSetUnittestMsetRoot extensionRegistry]
error:&error];
#endif
XCTAssertNil(failParsed);
XCTAssertNotNil(error);
XCTAssertEqualObjects(error.domain, GPBCodedInputStreamErrorDomain);
XCTAssertEqual(error.code, GPBCodedInputStreamErrorRecursionDepthExceeded);
}
@end

View file

@ -6413,6 +6413,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
/* Create lazily, since it's only needed for Any */
if (!e->arena) {
e->arena = upb_Arena_New();
if (!e->arena) {
jsonenc_err(e, "Out of memory");
}
}
return e->arena;
}
@ -6730,6 +6733,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
upb_Arena* arena = jsonenc_arena(e);
upb_Message* any = upb_Message_New(any_layout, arena);
if (!any) {
jsonenc_err(e, "Out of memory");
return;
}
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
kUpb_DecodeStatus_Ok) {
@ -9112,26 +9119,6 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
in->size = size;
}
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg,
upb_StringView* data,
uintptr_t* iter,
upb_Arena* arena) {
upb_MessageUnknown unknown;
unknown.type = kUpb_MessageUnknownType_StringView;
unknown.value.bytes = *data;
upb_Message_DeleteUnknownStatus res =
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
if (res == kUpb_DeleteUnknown_IterUpdated ||
res == kUpb_DeleteUnknown_DeletedLast) {
// the unknown data remains the same on the result of
// kUpb_DeleteUnknown_AllocFail.
*data = unknown.value.bytes;
}
return res;
}
size_t upb_Message_ExtensionCount(const upb_Message* msg) {
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
if (!in) return 0;
@ -9352,6 +9339,25 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
: kUpb_DeleteUnknown_DeletedLast;
}
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
struct upb_Message* msg, upb_StringView* data, uintptr_t* iter,
struct upb_Arena* arena) {
upb_MessageUnknown unknown;
unknown.type = kUpb_MessageUnknownType_StringView;
unknown.value.bytes = *data;
upb_Message_DeleteUnknownStatus res =
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
if (res == kUpb_DeleteUnknown_IterUpdated ||
res == kUpb_DeleteUnknown_DeletedLast) {
// the unknown data remains the same on the result of
// kUpb_DeleteUnknown_AllocFail.
*data = unknown.value.bytes;
}
return res;
}
#include <stddef.h>
#include <stdint.h>
@ -10287,12 +10293,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
upb_TaggedAuxType tag) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
// For Canonical Extensions, we check whether the extension has already been
// set. If we find an extension with the same pointer and tag, we reuse it to
// prevent duplicate entries for the same extension.
//
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
// accumulates.
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
upb_Extension* ext =
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
}
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
if (!ext) return NULL;
memset(ext, 0, sizeof(upb_Extension));
ext->ext = e;
@ -11382,6 +11397,7 @@ done:
#endif
upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size);
upb_MdDecoder_CheckOutOfMemory(&decoder->base, ret);
memcpy(ret, &decoder->table, sizeof(*ret));
#if UPB_FASTTABLE
@ -18340,6 +18356,49 @@ const char* upb_EncodeStatus_String(upb_EncodeStatus status) {
}
#include <setjmp.h>
#include <stddef.h>
// Must be last.
static upb_EncodeStatus upb_DoEncodeExtension(upb_encstate* encoder, char* ptr,
const struct upb_Extension* ext,
bool is_message_set,
upb_StringView* view,
int encode_options) {
if (UPB_SETJMP(*encoder->err) == 0) {
char* buf = ptr;
size_t size = 0;
UPB_PRIVATE(_upb_Encode_Extension)(encoder, ext->ext, ext->data,
is_message_set, &buf, &size,
encode_options);
view->data = buf;
view->size = size;
} else {
UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
upb_BackAlloc_Abort(&encoder->alloc);
view->data = NULL;
view->size = 0;
}
UPB_PRIVATE(_upb_encstate_destroy)(encoder);
return encoder->status;
}
upb_EncodeStatus upb_EncodeExtension(const struct upb_Extension* ext,
struct upb_Arena* arena,
upb_StringView* view, int encode_options) {
const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(ext->ext);
bool is_message_set =
extendee != NULL && upb_MiniTable_IsMessageSet(extendee);
upb_encstate e;
jmp_buf err;
char* ptr = UPB_PRIVATE(_upb_encstate_init)(&e, &err, arena);
return upb_DoEncodeExtension(&e, ptr, ext, is_message_set, view,
encode_options);
}
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@ -19026,9 +19085,12 @@ static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg,
if (e->options & kUpb_EncodeOption_Deterministic) {
_upb_sortedmap sorted;
_upb_mapsorter_pushmap(
&e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
map, &sorted);
if (!_upb_mapsorter_pushmap(
&e->sorter,
layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), map,
&sorted)) {
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
}
upb_MapEntry ent;
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
ptr = encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent);
@ -19164,7 +19226,7 @@ static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m,
if (e->options & kUpb_EncodeOption_Deterministic) {
_upb_sortedmap sorted;
if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) {
// TODO: b/378744096 - handle alloc failure
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
}
const upb_Extension* ext;
while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {

View file

@ -5711,139 +5711,6 @@ UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map);
#include <stdint.h>
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
struct upb_Extension;
typedef enum {
kUpb_MessageUnknownType_StringView,
kUpb_MessageUnknownType_NonCanonicalExtension,
} upb_MessageUnknownType;
// Represents an unknown field in a message, whether it's in a serialized
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
typedef struct upb_MessageUnknown {
uint8_t type;
union {
upb_StringView bytes;
const upb_Extension* extension;
} value;
} upb_MessageUnknown;
// Support iteration over unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
struct upb_MessageUnknown* data,
uintptr_t* iter) {
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
size_t i = *iter;
if (in) {
while (i < in->size) {
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
*iter = i;
return true;
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
data->value.extension =
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
*iter = i;
return true;
}
}
}
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes.size = 0;
data->value.bytes.data = NULL;
*iter = i;
return false;
}
typedef enum {
kUpb_FindUnknown_Ok,
kUpb_FindUnknown_NotPresent,
kUpb_FindUnknown_ParseError,
} upb_FindUnknown_Status;
typedef struct {
upb_FindUnknown_Status status;
struct upb_MessageUnknown unknown;
uintptr_t iter;
} upb_FindUnknownRet2;
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
// message, including unknown upb_StringView and non-canonical extensions
// (upb_Extension*).
//
// If multiple matching entries exist for the same field number (e.g. both a
// raw unknown upb_StringView and a non-canonical extension), this function
// returns the one encountered first in internal iteration order (which follows
// the order they were added or parsed).
//
// A depth_limit of zero means to just use the upb default depth limit.
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
uint32_t field_number,
int depth_limit);
typedef enum {
kUpb_DeleteUnknown_DeletedLast,
kUpb_DeleteUnknown_IterUpdated,
kUpb_DeleteUnknown_AllocFail,
} upb_Message_DeleteUnknownStatus;
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_MessageUnknown data;
// // Iterate chunks
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// Support deletion of unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
struct upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
// Must be last.
typedef struct upb_Message upb_Message;
@ -5889,39 +5756,6 @@ UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg) {
return false;
}
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_StringView data;
// // Iterate chunks
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
// case kUpb_Message_DeleteUnknown_DeletedLast: return ok;
// case kUpb_Message_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// TODO: b/510055656 - Legacy API that works with messages that only have
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
// messages that may have non-canonical extensions.
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
upb_Message* msg, upb_StringView* data, uintptr_t* iter, upb_Arena* arena);
// Returns the number of extensions present in this message.
size_t upb_Message_ExtensionCount(const upb_Message* msg);
@ -16890,6 +16724,170 @@ bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
kUpb_MessageUnknownType_StringView,
kUpb_MessageUnknownType_NonCanonicalExtension,
} upb_MessageUnknownType;
// Represents an unknown field in a message, whether it's in a serialized
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
typedef struct upb_MessageUnknown {
uint8_t type;
union {
upb_StringView bytes;
const upb_Extension* extension;
} value;
} upb_MessageUnknown;
// Support iteration over unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
struct upb_MessageUnknown* data,
uintptr_t* iter) {
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
size_t i = *iter;
if (in) {
while (i < in->size) {
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
*iter = i;
return true;
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
data->value.extension =
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
*iter = i;
return true;
}
}
}
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes.size = 0;
data->value.bytes.data = NULL;
*iter = i;
return false;
}
typedef enum {
kUpb_FindUnknown_Ok,
kUpb_FindUnknown_NotPresent,
kUpb_FindUnknown_ParseError,
} upb_FindUnknown_Status;
typedef struct {
upb_FindUnknown_Status status;
struct upb_MessageUnknown unknown;
uintptr_t iter;
} upb_FindUnknownRet2;
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
// message, including unknown upb_StringView and non-canonical extensions
// (upb_Extension*).
//
// If multiple matching entries exist for the same field number (e.g. both a
// raw unknown upb_StringView and a non-canonical extension), this function
// returns the one encountered first in internal iteration order (which follows
// the order they were added or parsed).
//
// A depth_limit of zero means to just use the upb default depth limit.
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
uint32_t field_number,
int depth_limit);
typedef enum {
kUpb_DeleteUnknown_DeletedLast,
kUpb_DeleteUnknown_IterUpdated,
kUpb_DeleteUnknown_AllocFail,
} upb_Message_DeleteUnknownStatus;
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_StringView data;
// // Iterate chunks
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
// TODO: b/510055656 - Legacy API that works with messages that only have
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
// messages that may have non-canonical extensions.
UPB_NODISCARD upb_Message_DeleteUnknownStatus
upb_Message_DeleteUnknown(struct upb_Message* msg, upb_StringView* data,
uintptr_t* iter, struct upb_Arena* arena);
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_MessageUnknown data;
// // Iterate chunks
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// Support deletion of unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
struct upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
@ -19476,6 +19474,33 @@ void _upb_Decoder_AddEnumValueToUnknown(upb_Decoder* d, upb_Message* msg,
#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */
#ifndef UPB_WIRE_ENCODE_EXTENSION_H_
#define UPB_WIRE_ENCODE_EXTENSION_H_
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
struct upb_Extension;
// Encodes an extension (`upb_Extension*`) to bytes.
//
// This can be used to encode an extension into the provided arena.
// Returns `kUpb_EncodeStatus_Ok` on success.
UPB_NODISCARD upb_EncodeStatus
upb_EncodeExtension(const struct upb_Extension* ext, struct upb_Arena* arena,
upb_StringView* view, int encode_options);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_WIRE_ENCODE_EXTENSION_H_ */
#ifndef GOOGLE_UPB_UPB_WIRE_WRITER_H__
#define GOOGLE_UPB_UPB_WIRE_WRITER_H__

View file

@ -222,6 +222,7 @@ cc_dist_library(
"//src/google/protobuf/compiler/java:names",
"//src/google/protobuf/compiler/objectivec:names",
"//src/google/protobuf/compiler/php:names",
"//src/google/protobuf/compiler/python:names",
],
)
@ -242,6 +243,7 @@ cc_dist_library(
"//upb/util:def_to_proto",
"//upb/util:required_fields",
"//upb/wire:byte_size",
"//upb/wire:encode_extension",
"//upb/wire/decode_fast:select",
],
)

View file

@ -28,7 +28,12 @@ static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) {
memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str));
ret.data = ptr;
} else {
// Data is only needed temporarily (within map lookup).
// Alias the Ruby String's bytes instead of copying them. Only valid when
// the result is consumed before anything can allocate: Convert_RubyToUpb
// may have converted `str` to a temporary that nothing else references, so
// any GC between here and the read can free or move it. The map lookup
// paths (Map_index, Map_has_key, Map_delete) satisfy this; insertion paths
// must pass an arena.
ret.data = RSTRING_PTR(str);
}
ret.size = RSTRING_LEN(str);

View file

@ -434,8 +434,13 @@ static VALUE Map_index(VALUE _self, VALUE key) {
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
Map* self = ruby_to_Map(_self);
upb_Arena* arena = Arena_get(self->arena);
// The key must be copied into the arena, not aliased. Converting the value
// below can allocate a Ruby object and therefore trigger GC, which may free
// or move the String the key would otherwise point into. Passing NULL here is
// only safe when the key is consumed before any allocation, as in the lookup
// paths (Map_index, Map_has_key, Map_delete).
upb_MessageValue key_upb =
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
upb_MessageValue val_upb =
Convert_RubyToUpb(val, "", self->value_type_info, arena);

View file

@ -527,7 +527,10 @@ typedef struct {
static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
MapInit* map_init = (MapInit*)_self;
upb_MessageValue k, v;
k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
// Copy the key into the arena rather than aliasing it: building the value
// below allocates, which can trigger GC and free or move the String the key
// would otherwise point into.
k = Convert_RubyToUpb(key, "", map_init->key_type, map_init->arena);
if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
const upb_MiniTable* t =

View file

@ -5166,6 +5166,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
/* Create lazily, since it's only needed for Any */
if (!e->arena) {
e->arena = upb_Arena_New();
if (!e->arena) {
jsonenc_err(e, "Out of memory");
}
}
return e->arena;
}
@ -5483,6 +5486,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
upb_Arena* arena = jsonenc_arena(e);
upb_Message* any = upb_Message_New(any_layout, arena);
if (!any) {
jsonenc_err(e, "Out of memory");
return;
}
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
kUpb_DecodeStatus_Ok) {
@ -7865,26 +7872,6 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
in->size = size;
}
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg,
upb_StringView* data,
uintptr_t* iter,
upb_Arena* arena) {
upb_MessageUnknown unknown;
unknown.type = kUpb_MessageUnknownType_StringView;
unknown.value.bytes = *data;
upb_Message_DeleteUnknownStatus res =
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
if (res == kUpb_DeleteUnknown_IterUpdated ||
res == kUpb_DeleteUnknown_DeletedLast) {
// the unknown data remains the same on the result of
// kUpb_DeleteUnknown_AllocFail.
*data = unknown.value.bytes;
}
return res;
}
size_t upb_Message_ExtensionCount(const upb_Message* msg) {
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
if (!in) return 0;
@ -8105,6 +8092,25 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
: kUpb_DeleteUnknown_DeletedLast;
}
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
struct upb_Message* msg, upb_StringView* data, uintptr_t* iter,
struct upb_Arena* arena) {
upb_MessageUnknown unknown;
unknown.type = kUpb_MessageUnknownType_StringView;
unknown.value.bytes = *data;
upb_Message_DeleteUnknownStatus res =
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
if (res == kUpb_DeleteUnknown_IterUpdated ||
res == kUpb_DeleteUnknown_DeletedLast) {
// the unknown data remains the same on the result of
// kUpb_DeleteUnknown_AllocFail.
*data = unknown.value.bytes;
}
return res;
}
#include <stddef.h>
#include <stdint.h>
@ -9040,12 +9046,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
upb_TaggedAuxType tag) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
// For Canonical Extensions, we check whether the extension has already been
// set. If we find an extension with the same pointer and tag, we reuse it to
// prevent duplicate entries for the same extension.
//
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
// accumulates.
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
upb_Extension* ext =
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
}
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
if (!ext) return NULL;
memset(ext, 0, sizeof(upb_Extension));
ext->ext = e;
@ -10135,6 +10150,7 @@ done:
#endif
upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size);
upb_MdDecoder_CheckOutOfMemory(&decoder->base, ret);
memcpy(ret, &decoder->table, sizeof(*ret));
#if UPB_FASTTABLE
@ -17803,6 +17819,49 @@ const char* upb_EncodeStatus_String(upb_EncodeStatus status) {
}
#include <setjmp.h>
#include <stddef.h>
// Must be last.
static upb_EncodeStatus upb_DoEncodeExtension(upb_encstate* encoder, char* ptr,
const struct upb_Extension* ext,
bool is_message_set,
upb_StringView* view,
int encode_options) {
if (UPB_SETJMP(*encoder->err) == 0) {
char* buf = ptr;
size_t size = 0;
UPB_PRIVATE(_upb_Encode_Extension)(encoder, ext->ext, ext->data,
is_message_set, &buf, &size,
encode_options);
view->data = buf;
view->size = size;
} else {
UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
upb_BackAlloc_Abort(&encoder->alloc);
view->data = NULL;
view->size = 0;
}
UPB_PRIVATE(_upb_encstate_destroy)(encoder);
return encoder->status;
}
upb_EncodeStatus upb_EncodeExtension(const struct upb_Extension* ext,
struct upb_Arena* arena,
upb_StringView* view, int encode_options) {
const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(ext->ext);
bool is_message_set =
extendee != NULL && upb_MiniTable_IsMessageSet(extendee);
upb_encstate e;
jmp_buf err;
char* ptr = UPB_PRIVATE(_upb_encstate_init)(&e, &err, arena);
return upb_DoEncodeExtension(&e, ptr, ext, is_message_set, view,
encode_options);
}
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@ -18489,9 +18548,12 @@ static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg,
if (e->options & kUpb_EncodeOption_Deterministic) {
_upb_sortedmap sorted;
_upb_mapsorter_pushmap(
&e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
map, &sorted);
if (!_upb_mapsorter_pushmap(
&e->sorter,
layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), map,
&sorted)) {
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
}
upb_MapEntry ent;
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
ptr = encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent);
@ -18627,7 +18689,7 @@ static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m,
if (e->options & kUpb_EncodeOption_Deterministic) {
_upb_sortedmap sorted;
if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) {
// TODO: b/378744096 - handle alloc failure
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
}
const upb_Extension* ext;
while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {

View file

@ -5711,139 +5711,6 @@ UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map);
#include <stdint.h>
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
struct upb_Extension;
typedef enum {
kUpb_MessageUnknownType_StringView,
kUpb_MessageUnknownType_NonCanonicalExtension,
} upb_MessageUnknownType;
// Represents an unknown field in a message, whether it's in a serialized
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
typedef struct upb_MessageUnknown {
uint8_t type;
union {
upb_StringView bytes;
const upb_Extension* extension;
} value;
} upb_MessageUnknown;
// Support iteration over unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
struct upb_MessageUnknown* data,
uintptr_t* iter) {
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
size_t i = *iter;
if (in) {
while (i < in->size) {
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
*iter = i;
return true;
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
data->value.extension =
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
*iter = i;
return true;
}
}
}
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes.size = 0;
data->value.bytes.data = NULL;
*iter = i;
return false;
}
typedef enum {
kUpb_FindUnknown_Ok,
kUpb_FindUnknown_NotPresent,
kUpb_FindUnknown_ParseError,
} upb_FindUnknown_Status;
typedef struct {
upb_FindUnknown_Status status;
struct upb_MessageUnknown unknown;
uintptr_t iter;
} upb_FindUnknownRet2;
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
// message, including unknown upb_StringView and non-canonical extensions
// (upb_Extension*).
//
// If multiple matching entries exist for the same field number (e.g. both a
// raw unknown upb_StringView and a non-canonical extension), this function
// returns the one encountered first in internal iteration order (which follows
// the order they were added or parsed).
//
// A depth_limit of zero means to just use the upb default depth limit.
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
uint32_t field_number,
int depth_limit);
typedef enum {
kUpb_DeleteUnknown_DeletedLast,
kUpb_DeleteUnknown_IterUpdated,
kUpb_DeleteUnknown_AllocFail,
} upb_Message_DeleteUnknownStatus;
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_MessageUnknown data;
// // Iterate chunks
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// Support deletion of unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
struct upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
// Must be last.
typedef struct upb_Message upb_Message;
@ -5889,39 +5756,6 @@ UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg) {
return false;
}
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_StringView data;
// // Iterate chunks
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
// case kUpb_Message_DeleteUnknown_DeletedLast: return ok;
// case kUpb_Message_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// TODO: b/510055656 - Legacy API that works with messages that only have
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
// messages that may have non-canonical extensions.
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
upb_Message* msg, upb_StringView* data, uintptr_t* iter, upb_Arena* arena);
// Returns the number of extensions present in this message.
size_t upb_Message_ExtensionCount(const upb_Message* msg);
@ -16604,6 +16438,170 @@ bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
kUpb_MessageUnknownType_StringView,
kUpb_MessageUnknownType_NonCanonicalExtension,
} upb_MessageUnknownType;
// Represents an unknown field in a message, whether it's in a serialized
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
typedef struct upb_MessageUnknown {
uint8_t type;
union {
upb_StringView bytes;
const upb_Extension* extension;
} value;
} upb_MessageUnknown;
// Support iteration over unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
struct upb_MessageUnknown* data,
uintptr_t* iter) {
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
size_t i = *iter;
if (in) {
while (i < in->size) {
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
*iter = i;
return true;
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
data->value.extension =
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
*iter = i;
return true;
}
}
}
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes.size = 0;
data->value.bytes.data = NULL;
*iter = i;
return false;
}
typedef enum {
kUpb_FindUnknown_Ok,
kUpb_FindUnknown_NotPresent,
kUpb_FindUnknown_ParseError,
} upb_FindUnknown_Status;
typedef struct {
upb_FindUnknown_Status status;
struct upb_MessageUnknown unknown;
uintptr_t iter;
} upb_FindUnknownRet2;
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
// message, including unknown upb_StringView and non-canonical extensions
// (upb_Extension*).
//
// If multiple matching entries exist for the same field number (e.g. both a
// raw unknown upb_StringView and a non-canonical extension), this function
// returns the one encountered first in internal iteration order (which follows
// the order they were added or parsed).
//
// A depth_limit of zero means to just use the upb default depth limit.
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
uint32_t field_number,
int depth_limit);
typedef enum {
kUpb_DeleteUnknown_DeletedLast,
kUpb_DeleteUnknown_IterUpdated,
kUpb_DeleteUnknown_AllocFail,
} upb_Message_DeleteUnknownStatus;
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_StringView data;
// // Iterate chunks
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
// TODO: b/510055656 - Legacy API that works with messages that only have
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
// messages that may have non-canonical extensions.
UPB_NODISCARD upb_Message_DeleteUnknownStatus
upb_Message_DeleteUnknown(struct upb_Message* msg, upb_StringView* data,
uintptr_t* iter, struct upb_Arena* arena);
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_MessageUnknown data;
// // Iterate chunks
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
// case kUpb_DeleteUnknown_DeletedLast: return ok;
// case kUpb_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// Support deletion of unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
struct upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
@ -19300,6 +19298,33 @@ void _upb_Decoder_AddEnumValueToUnknown(upb_Decoder* d, upb_Message* msg,
#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */
#ifndef UPB_WIRE_ENCODE_EXTENSION_H_
#define UPB_WIRE_ENCODE_EXTENSION_H_
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
struct upb_Extension;
// Encodes an extension (`upb_Extension*`) to bytes.
//
// This can be used to encode an extension into the provided arena.
// Returns `kUpb_EncodeStatus_Ok` on success.
UPB_NODISCARD upb_EncodeStatus
upb_EncodeExtension(const struct upb_Extension* ext, struct upb_Arena* arena,
upb_StringView* view, int encode_options);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_WIRE_ENCODE_EXTENSION_H_ */
#ifndef GOOGLE_UPB_UPB_WIRE_WRITER_H__
#define GOOGLE_UPB_UPB_WIRE_WRITER_H__

View file

@ -104,4 +104,57 @@ class GCTest < Test::Unit::TestCase
GC.stress = old_gc
puts "passed"
end
# Regression test: the map key must be copied into the arena, not aliased.
#
# Convert_RubyToUpb returns a *temporary* String for a key that is a Symbol or
# is not already tagged UTF-8. Converting the value afterwards allocates, which
# can trigger GC and free that temporary before upb_Map_Set copies the key --
# leaving a silently corrupted key holding unrelated heap bytes.
def assert_map_keys_survive_gc(&builder)
old_gc = GC.stress
GC.stress = true
begin
100.times do
# Non-UTF-8 key and value: the key conversion allocates a temporary, and
# the value conversion allocates again, opening the window.
key = ("K" * 5000).dup.force_encoding("ISO-8859-1") +
"\xE9".dup.force_encoding("ISO-8859-1")
value = ("V" * 5000).dup.force_encoding("ISO-8859-1") +
"\xE9".dup.force_encoding("ISO-8859-1")
assert_equal [key.encode("UTF-8")], builder.call(key, value).keys
end
ensure
GC.stress = old_gc
end
end
def test_map_string_key_not_corrupted_by_gc
assert_map_keys_survive_gc do |key, value|
map = Google::Protobuf::Map.new(:string, :string)
map[key] = value
map
end
end
def test_map_symbol_key_not_corrupted_by_gc
old_gc = GC.stress
GC.stress = true
begin
100.times do
map = Google::Protobuf::Map.new(:string, :string)
map[:some_symbol_key] = :some_symbol_value
assert_equal ["some_symbol_key"], map.keys
end
ensure
GC.stress = old_gc
end
end
def test_map_field_kwarg_key_not_corrupted_by_gc
assert_map_keys_survive_gc do |key, value|
A::B::C::TestMessage.new(:map_string_string => { key => value })
.map_string_string
end
end
end

View file

@ -38,6 +38,18 @@ rust_library(
"//conditions:default": ["--cfg=cpp_kernel"],
}),
visibility = ["//visibility:public"],
deps = [":protobuf_lite"],
)
rust_library(
name = "protobuf_lite",
srcs = ["protobuf_lite.rs"],
edition = "2024",
rustc_flags = select({
":use_upb_kernel": ["--cfg=upb_kernel"],
"//conditions:default": ["--cfg=cpp_kernel"],
}),
visibility = ["//visibility:public"],
deps = select({
":use_upb_kernel": [":protobuf_upb"],
"//conditions:default": [":protobuf_cpp"],
@ -83,6 +95,7 @@ ALL_RUST_SRCS = PROTOBUF_SHARED + [
"gtest_matchers.rs",
"gtest_matchers_impl.rs",
"protobuf.rs",
"protobuf_lite.rs",
"upb_kernel/conversions.rs",
"upb_kernel/extension.rs",
"upb_kernel/interop.rs",
@ -146,15 +159,26 @@ rust_test(
# This provides an identical set of re-exports as `:protobuf` with `:use_upb_kernel` active.
# This is only used for tests shared between runtimes.
rust_library(
name = "protobuf_upb_export",
name = "protobuf_upb_lite_export",
testonly = True,
srcs = ["protobuf.rs"],
srcs = ["protobuf_lite.rs"],
edition = "2024",
rustc_flags = ["--cfg=upb_kernel"],
visibility = [":protobuf_internal"],
deps = [":protobuf_upb"],
)
rust_library(
name = "protobuf_upb_export",
testonly = True,
srcs = ["protobuf.rs"],
aliases = {"//rust:protobuf_upb_lite_export": "protobuf_lite"},
edition = "2024",
rustc_flags = ["--cfg=upb_kernel"],
visibility = [":protobuf_internal"],
deps = [":protobuf_upb_lite_export"],
)
# The Rust Protobuf runtime using the cpp kernel.
#
# `rust_cpp_proto_library` implicitly depends on this target. This target cannot depend on
@ -204,15 +228,26 @@ rust_test(
# This provides an identical set of re-exports as `:protobuf` with `:use_upb_kernel` inactive.
# This is only used for tests shared between runtimes.
rust_library(
name = "protobuf_cpp_export",
name = "protobuf_cpp_lite_export",
testonly = True,
srcs = ["protobuf.rs"],
srcs = ["protobuf_lite.rs"],
edition = "2024",
rustc_flags = ["--cfg=cpp_kernel"],
visibility = [":protobuf_internal"],
deps = [":protobuf_cpp"],
)
rust_library(
name = "protobuf_cpp_export",
testonly = True,
srcs = ["protobuf.rs"],
aliases = {"//rust:protobuf_cpp_lite_export": "protobuf_lite"},
edition = "2024",
rustc_flags = ["--cfg=cpp_kernel"],
visibility = [":protobuf_internal"],
deps = [":protobuf_cpp_lite_export"],
)
cc_library(
name = "cpp_api",
srcs = [

View file

@ -1,34 +1,13 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. All rights reserved.
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//! Rust Protobuf Runtime
//! Rust Protobuf Full Runtime
//!
//! This file exists as the public entry point for the Rust Protobuf runtime. It
//! is a thin re-export of the `shared.rs` file but is needed for two reasons:
//! - To create a single `protobuf` crate name for either cpp and upb kernels
//! from user code (toggled at compile time).
//! - Blocks the __internal module from being re-exported to application code,
//! unless they use one of our visibility-restricted targets (gencode does
//! have access to them).
//! This crate re-exports the `protobuf` lite runtime and (in the future) adds reflection
//! traits and heavy APIs (like text formatting) that are banned in `lite` mode.
#[cfg(cpp_kernel)]
use protobuf_cpp as kernel;
#[cfg(upb_kernel)]
use protobuf_upb as kernel;
/// Block these two mods from being re-exported by the `pub use`
/// below (glob use automatically only adds things that aren't otherwise
/// defined).
///
/// By creating a const instead of an empty mod it is easier to have a test
/// that confirms this targeted 'blocking' is working as intended.
#[doc(hidden)]
#[allow(non_upper_case_globals)]
pub const __internal: () = ();
pub use kernel::*;
pub use protobuf_lite::*;

34
rust/protobuf_lite.rs Normal file
View file

@ -0,0 +1,34 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2026 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//! Rust Protobuf Runtime
//!
//! This file exists as the public entry point for the Rust Protobuf runtime. It
//! is a thin re-export of the `shared.rs` file but is needed for two reasons:
//! - To create a single `protobuf` crate name for either cpp and upb kernels
//! from user code (toggled at compile time).
//! - Blocks the __internal module from being re-exported to application code,
//! unless they use one of our visibility-restricted targets (gencode does
//! have access to them).
#[cfg(cpp_kernel)]
use protobuf_cpp as kernel;
#[cfg(upb_kernel)]
use protobuf_upb as kernel;
/// Block these two mods from being re-exported by the `pub use`
/// below (glob use automatically only adds things that aren't otherwise
/// defined).
///
/// By creating a const instead of an empty mod it is easier to have a test
/// that confirms this targeted 'blocking' is working as intended.
#[doc(hidden)]
#[allow(non_upper_case_globals)]
pub const __internal: () = ();
pub use kernel::*;

View file

@ -74,6 +74,7 @@ set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/option_interpreter.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/port.cc
@ -188,6 +189,7 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.h
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style.h
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.h
${protobuf_SOURCE_DIR}/src/google/protobuf/option_interpreter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_restore.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_undef.inc
@ -259,6 +261,7 @@ set(libprotobuf_lite_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/port.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/raw_ptr.cc
@ -307,6 +310,7 @@ set(libprotobuf_lite_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/message_traits.h
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.h
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.h
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_restore.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_undef.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.h
@ -349,6 +353,7 @@ set(libprotoc_public_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/versions.cc
@ -379,6 +384,7 @@ set(libprotoc_public_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/scc.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.h
@ -493,6 +499,7 @@ set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/helpers.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/names.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/rbs_generator.cc
@ -644,6 +651,7 @@ set(libprotoc_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/helpers.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/names.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/rbs_generator.h
@ -744,6 +752,7 @@ set(libupb_srcs
${protobuf_SOURCE_DIR}/upb/wire/decode.c
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/select.c
${protobuf_SOURCE_DIR}/upb/wire/encode.c
${protobuf_SOURCE_DIR}/upb/wire/encode_extension.c
${protobuf_SOURCE_DIR}/upb/wire/eps_copy_input_stream.c
${protobuf_SOURCE_DIR}/upb/wire/internal/back_alloc.c
${protobuf_SOURCE_DIR}/upb/wire/internal/decoder.c
@ -874,6 +883,7 @@ set(libupb_hdrs
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/data.h
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/select.h
${protobuf_SOURCE_DIR}/upb/wire/encode.h
${protobuf_SOURCE_DIR}/upb/wire/encode_extension.h
${protobuf_SOURCE_DIR}/upb/wire/eps_copy_input_stream.h
${protobuf_SOURCE_DIR}/upb/wire/internal/back_alloc.h
${protobuf_SOURCE_DIR}/upb/wire/internal/constants.h
@ -1291,6 +1301,7 @@ set(protobuf_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/no_field_presence_map_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/no_field_presence_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/port_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/preserve_unknown_enum_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_lite_unittest.cc

View file

@ -726,6 +726,7 @@ cc_library(
"inlined_string_field.cc",
"map.cc",
"message_lite.cc",
"offset_ptr.cc",
"parse_context.cc",
"raw_ptr.cc",
"repeated_field.cc",
@ -759,6 +760,7 @@ cc_library(
"map_type_handler.h",
"message_lite.h",
"metadata_lite.h",
"offset_ptr.h",
"parse_context.h",
"raw_ptr.h",
"repeated_field.h",
@ -988,6 +990,17 @@ cc_test(
],
)
cc_test(
name = "offset_ptr_test",
srcs = ["offset_ptr_test.cc"],
deps = [
":cc_test_protos",
":protobuf_lite",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
# This target exposes the headers for the protobuf runtime, and additionally
# depends on the C++ well-known types and some other miscellaneous utilities.
# The purpose is to preserve compatibility with projects that do not yet comply

View file

@ -211,7 +211,6 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
p->Emit(R"cc(
inline void $Msg$::set_$name$(const ::absl::Cord& value) {
$WeakDescriptorSelfPin$;
$PrepareSplitMessageForWrite$;
_internal_set_$name_internal$(value);
$annotate_set$;
// @@protoc_insertion_point(field_set:$full_name$)
@ -220,7 +219,6 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
p->Emit(R"cc(
inline void $Msg$::set_$name$(::absl::string_view value) {
$WeakDescriptorSelfPin$;
$PrepareSplitMessageForWrite$;
$set_hasbit$;
$field_$ = value;
$annotate_set$;

View file

@ -238,7 +238,6 @@ void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
)cc");
p->Emit(R"cc(
inline $Map$* $nonnull$ $Msg$::_internal_mutable_$name_internal$() {
$PrepareSplitMessageForWrite$;
$TsanDetectConcurrentMutation$;
return $field_$.MutableMap();
}

View file

@ -3693,6 +3693,10 @@ MessageGenerator::NewOpRequirements MessageGenerator::GetNewOp() const {
// We can't skip the ArenaDtor for these messages.
op.needs_to_run_constructor = true;
}
if (descriptor_->extension_range_count() > 0) {
// Extensions are not zero-initializable.
op.needs_memcpy = true;
}
for (const FieldDescriptor* field : internal::FieldRange(descriptor_)) {
if (ShouldSplit(field, options_)) {

View file

@ -49,11 +49,9 @@ struct MockZeroFieldsBase : public MockMessageBase {
ABSL_CHECK_MESSAGE_SIZE(MockZeroFieldsBase, 24);
struct MockExtensionSet {
int16_t capacity; // 4 bytes
int16_t size; // 4 bytes
void* data; // 8 bytes
};
ABSL_CHECK_MESSAGE_SIZE(MockExtensionSet, 16);
ABSL_CHECK_MESSAGE_SIZE(MockExtensionSet, 8);
struct MockRepeatedPtrField {
int current_size; // 4 bytes
@ -95,12 +93,12 @@ TEST(GeneratedMessageTest, ReservedSize) {
TEST(GeneratedMessageTest, EmptyMessageWithExtensionsSize) {
struct MockGenerated : public MockMessageBase { // 16 bytes
MockExtensionSet extensions; // 24 bytes
MockExtensionSet extensions; // 8 bytes
int cached_size; // 4 bytes
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
// + 0-4 bytes of padding
};
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 40);
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 32);
EXPECT_EQ(sizeof(proto2_unittest::TestEmptyMessageWithExtensions),
sizeof(MockGenerated));
}
@ -288,7 +286,7 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
struct MockGenerated : public MockMessageBase { // 16 bytes
int has_bits[1]; // 4 bytes
int cached_size; // 4 bytes
MockExtensionSet extensions; // 24 bytes
MockExtensionSet extensions; // 8 bytes
void* my_string; // 8 bytes
void* optional_nested_message; // 8 bytes
int64_t my_int; // 8 bytes
@ -296,12 +294,12 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
// + 0-4 bytes padding
};
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 72);
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 64);
struct MockGeneratedExperiments : public MockMessageBase { // 16 bytes
int has_bits[1]; // 4 bytes
int cached_size; // 4 bytes
MockExtensionSet extensions; // 24 bytes
MockExtensionSet extensions; // 8 bytes
std::string my_string; // sizeof(std::string)
MockLazy optional_nested_message; // lazy, see above.
int64_t my_int; // 8 bytes
@ -309,17 +307,17 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
// + 0-4 bytes padding
};
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedExperiments, 80 + sizeof(MockLazy));
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedExperiments, 72 + sizeof(MockLazy));
struct MockGeneratedSplit : public MockMessageBase { // 16 bytes
int has_bits[1]; // 4 bytes
int cached_size; // 4 bytes
MockExtensionSet extensions; // 24 bytes
MockExtensionSet extensions; // 8 bytes
void* split; // 8 bytes
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
// + 0-4 bytes padding
};
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedSplit, 48);
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedSplit, 40);
#ifndef PROTOBUF_FORCE_SPLIT
// Make sure both or none are on for this test.

View file

@ -40,9 +40,8 @@ namespace {
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
void SetEnumVariables(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, const FieldGeneratorInfo* info,
ClassNameResolver* name_resolver,
const FieldDescriptor* descriptor, int bit_index,
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
absl::flat_hash_map<absl::string_view, std::string>* variables,
Context* context) {
SetCommonFieldVariables(descriptor, info, variables);
@ -75,27 +74,26 @@ void SetEnumVariables(
// For singular messages and builders, one bit is used for the hasField bit.
// Note that these have a trailing ";".
(*variables)["set_has_field_bit_to_local"] =
GenerateSetBitToLocal(message_bit_index);
(*variables)["is_field_present_message"] =
GenerateGetBit(message_bit_index);
GenerateSetBitToLocal(bit_index);
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
} else {
(*variables)["set_has_field_bit_to_local"] = "";
variables->insert({"is_field_present_message",
variables->insert({"is_field_present",
absl::StrCat((*variables)["name"], "_ != ",
(*variables)["default"], ".getNumber()")});
}
// Always track the presence of a field explicitly in the builder, regardless
// of syntax.
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index);
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builder_bit_index);
GenerateGetBitFromLocal(bit_index);
// Note that these have a trailing ";".
(*variables)["set_has_field_bit_builder"] =
absl::StrCat(GenerateSetBit(builder_bit_index), ";");
(*variables)["clear_has_field_bit_builder"] =
absl::StrCat(GenerateClearBit(builder_bit_index), ";");
(*variables)["set_has_field_bit"] =
absl::StrCat(GenerateSetBit(bit_index), ";");
(*variables)["clear_has_field_bit"] =
absl::StrCat(GenerateClearBit(bit_index), ";");
(*variables)["unknown"] =
SupportUnknownEnumValue(descriptor)
@ -108,21 +106,16 @@ void SetEnumVariables(
// ===================================================================
ImmutableEnumFieldGenerator::ImmutableEnumFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, message_bit_index, builder_bit_index,
context) {
SetEnumVariables(descriptor, message_bit_index, builder_bit_index,
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, bit_index, context) {
SetEnumVariables(descriptor, bit_index,
context->GetFieldGeneratorInfo(descriptor), name_resolver_,
&variables_, context);
}
ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() = default;
int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
return HasHasbit(descriptor_) ? 1 : 0;
}
void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
void ImmutableEnumFieldGenerator::GenerateInterfaceHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -130,30 +123,48 @@ void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
}
}
void ImmutableEnumFieldGenerator::GenerateInterfaceGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$int get$capitalized_name$Value();\n");
}
}
void ImmutableEnumFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
}
void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
PrintExtraFieldInfo(variables_, printer);
void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceHasMethod(printer);
GenerateInterfaceGetValueMethod(printer);
GenerateInterfaceGetMethod(printer);
}
void ImmutableEnumFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
printer->Print(variables_,
"@java.lang.Override $deprecation$public boolean "
"${$has$capitalized_name$$}$() {\n"
" return $is_field_present_message$;\n"
" return $is_field_present$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumFieldGenerator::GenerateGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
@ -164,6 +175,10 @@ void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -175,19 +190,30 @@ void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetValueMethod(printer);
GenerateGetMethod(printer);
}
void ImmutableEnumFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
printer->Print(variables_,
"@java.lang.Override $deprecation$public boolean "
"${$has$capitalized_name$$}$() {\n"
" return $get_has_field_bit_builder$;\n"
" return $get_has_field_bit$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumFieldGenerator::GenerateBuilderGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
@ -197,6 +223,12 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumFieldGenerator::GenerateBuilderSetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -204,12 +236,16 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
"$deprecation$public Builder "
"${$set$capitalized_name$Value$}$(int value) {\n"
" $name$_ = value;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" onChanged();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableEnumFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -219,6 +255,10 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return result == null ? $unknown$ : result;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -226,19 +266,23 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
"$deprecation$public Builder "
"${$set$capitalized_name$$}$($type$ value) {\n"
" $null_check$\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $name$_ = value.getNumber();\n"
" onChanged();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableEnumFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit_builder$\n"
" $clear_has_field_bit$\n"
" $name$_ = $default_number$;\n"
" onChanged();\n"
" return this;\n"
@ -246,6 +290,17 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
GenerateBuilderHasMethod(printer);
GenerateBuilderGetValueMethod(printer);
GenerateBuilderSetValueMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
}
void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for enums
@ -286,7 +341,7 @@ void ImmutableEnumFieldGenerator::GenerateBuildingCode(
printer->Print(variables_,
"if ($get_has_field_bit_from_local$) {\n"
" result.$name$_ = $name$_;\n");
if (GetNumBitsForMessage() > 0) {
if (GetNumBits() > 0) {
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
}
printer->Print("}\n");
@ -297,7 +352,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(variables_,
"$name$_ = input.readEnum();\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
} else {
printer->Print(variables_,
"int tmpRaw = input.readEnum();\n"
@ -307,7 +362,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
" mergeUnknownVarintField($number$, tmpRaw);\n"
"} else {\n"
" $name$_ = tmpRaw;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
"}\n");
}
}
@ -315,7 +370,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
void ImmutableEnumFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" output.writeEnum($number$, $name$_);\n"
"}\n");
}
@ -323,7 +378,7 @@ void ImmutableEnumFieldGenerator::GenerateSerializationCode(
void ImmutableEnumFieldGenerator::GenerateSerializedSizeCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .computeEnumSize($number$, $name$_);\n"
"}\n");
@ -347,10 +402,8 @@ std::string ImmutableEnumFieldGenerator::GetBoxedType() const {
// ===================================================================
ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context)
: ImmutableEnumFieldGenerator(descriptor, message_bit_index,
builder_bit_index, context) {
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableEnumFieldGenerator(descriptor, bit_index, context) {
const OneofGeneratorInfo* info =
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
SetCommonOneofVariables(descriptor, info, &variables_);
@ -358,9 +411,8 @@ ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator(
ImmutableEnumOneofFieldGenerator::~ImmutableEnumOneofFieldGenerator() = default;
void ImmutableEnumOneofFieldGenerator::GenerateMembers(
void ImmutableEnumOneofFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
@ -369,7 +421,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumOneofFieldGenerator::GenerateGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
@ -383,6 +438,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumOneofFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -397,7 +456,15 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
void ImmutableEnumOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetValueMethod(printer);
GenerateGetMethod(printer);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -408,7 +475,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
@ -422,6 +492,12 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
" return $default_number$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderSetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -435,6 +511,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -448,7 +528,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
" return $default$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -462,7 +545,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -479,6 +565,16 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
GenerateBuilderHasMethod(printer);
GenerateBuilderGetValueMethod(printer);
GenerateBuilderSetValueMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
}
void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearCode(
io::Printer* printer) const {
// No-op: Enum fields in oneofs are correctly cleared by clearing the oneof
@ -573,39 +669,51 @@ void ImmutableEnumOneofFieldGenerator::GenerateHashCode(
// ===================================================================
RepeatedImmutableEnumFieldGenerator::RepeatedImmutableEnumFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context)
: ImmutableEnumFieldGenerator(descriptor, message_bit_index,
builder_bit_index, context) {}
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableEnumFieldGenerator(descriptor, bit_index, context) {}
RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() =
default;
int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(
variables_,
"$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(variables_,
"$deprecation$int get$capitalized_name$Count();\n");
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$$type$ get$capitalized_name$(int index);\n");
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetValueListMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$java.util.List<java.lang.Integer>\n"
"get$capitalized_name$ValueList();\n");
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
@ -613,6 +721,85 @@ void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceGetListMethod(printer);
GenerateInterfaceGetCountMethod(printer);
GenerateInterfaceGetMethod(printer);
GenerateInterfaceGetValueListMethod(printer);
GenerateInterfaceGetValueMethod(printer);
}
void RepeatedImmutableEnumFieldGenerator::GenerateGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.IntListAdapter<\n"
" $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateGetValueListMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<java.lang.Integer>\n"
"${$get$capitalized_name$ValueList$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public int "
"${$get$capitalized_name$Value$}$(int index) {\n"
" return $name$_.getInt(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(
@ -631,64 +818,19 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
" }\n"
" };\n");
PrintExtraFieldInfo(variables_, printer);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.IntListAdapter<\n"
" $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<java.lang.Integer>\n"
"${$get$capitalized_name$ValueList$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldEnumValueAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public int "
"${$get$capitalized_name$Value$}$(int index) {\n"
" return $name$_.getInt(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
GenerateGetListMethod(printer);
GenerateGetCountMethod(printer);
GenerateGetMethod(printer);
GenerateGetValueListMethod(printer);
GenerateGetValueMethod(printer);
if (descriptor_->is_packed()) {
printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n");
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
void RepeatedImmutableEnumFieldGenerator::GenerateEnsureIsMutableMethod(
io::Printer* printer) const {
// We use one method and pass -1 when capacity is unknown to control class
// size.
printer->Print(
variables_,
"private $field_list_type$ $name$_ = $empty_list$;\n"
@ -696,23 +838,26 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" if (!$name$_.isModifiable()) {\n"
" $name$_ = makeMutableCopy($name$_, capacity);\n"
" }\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
"}\n");
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(
variables_,
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.IntListAdapter<\n"
" $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
@ -721,6 +866,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
@ -729,6 +878,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
context_->options(),
/* builder */ true);
@ -742,6 +895,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
context_->options(),
/* builder */ true);
@ -755,6 +912,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddAllMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
context_->options(),
/* builder */ true);
@ -769,6 +930,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -776,12 +941,15 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_has_field_bit_builder$\n"
" $clear_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetValueListMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
@ -792,6 +960,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
@ -800,6 +974,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return $name$_.getInt(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderSetValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(
printer, descriptor_, LIST_INDEXED_SETTER, context_->options(),
/* builder */ true);
@ -813,6 +993,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER,
context_->options(),
/* builder */ true);
@ -825,6 +1011,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddAllValueMethod(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
LIST_MULTI_ADDER, context_->options(),
/* builder */ true);
@ -843,6 +1035,23 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
}
}
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
GenerateEnsureIsMutableMethod(printer);
GenerateBuilderGetListMethod(printer);
GenerateBuilderGetCountMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderAddMethod(printer);
GenerateBuilderAddAllMethod(printer);
GenerateBuilderClearMethod(printer);
GenerateBuilderGetValueListMethod(printer);
GenerateBuilderGetValueMethod(printer);
GenerateBuilderSetValueMethod(printer);
GenerateBuilderAddValueMethod(printer);
GenerateBuilderAddAllValueMethod(printer);
}
void RepeatedImmutableEnumFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for enums
@ -870,7 +1079,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMergingCode(
" if ($name$_.isEmpty()) {\n"
" $name$_ = other.$name$_;\n"
" $name_make_immutable$;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" } else {\n"
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
" $name$_.addAll(other.$name$_);\n"

View file

@ -38,8 +38,7 @@ namespace java {
class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
public:
explicit ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableEnumFieldGenerator(const ImmutableEnumFieldGenerator&) = delete;
ImmutableEnumFieldGenerator& operator=(const ImmutableEnumFieldGenerator&) =
delete;
@ -47,7 +46,7 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
// implements ImmutableFieldGenerator
// ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -65,14 +64,27 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
std::string GetBoxedType() const override;
protected:
private:
void GenerateInterfaceHasMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetValueMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
};
class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
public:
ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableEnumOneofFieldGenerator(const ImmutableEnumOneofFieldGenerator&) =
delete;
ImmutableEnumOneofFieldGenerator& operator=(
@ -89,13 +101,25 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const override;
void GenerateEqualsCode(io::Printer* printer) const override;
void GenerateHashCode(io::Printer* printer) const override;
private:
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetValueMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderParserMethod(io::Printer* printer) const;
};
class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
public:
explicit RepeatedImmutableEnumFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex,
int builderBitIndex, Context* context);
const FieldDescriptor* descriptor, int bit_index, Context* context);
RepeatedImmutableEnumFieldGenerator(
const RepeatedImmutableEnumFieldGenerator&) = delete;
RepeatedImmutableEnumFieldGenerator& operator=(
@ -103,7 +127,6 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
~RepeatedImmutableEnumFieldGenerator() override;
// implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -122,6 +145,33 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
void GenerateHashCode(io::Printer* printer) const override;
std::string GetBoxedType() const override;
private:
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueListMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueMethod(io::Printer* printer) const;
void GenerateGetListMethod(io::Printer* printer) const;
void GenerateGetCountMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateGetValueListMethod(io::Printer* printer) const;
void GenerateGetValueMethod(io::Printer* printer) const;
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
void GenerateBuilderGetListMethod(io::Printer* printer) const;
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderAddMethod(io::Printer* printer) const;
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderGetValueListMethod(io::Printer* printer) const;
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
void GenerateBuilderAddValueMethod(io::Printer* printer) const;
void GenerateBuilderAddAllValueMethod(io::Printer* printer) const;
};
} // namespace java

View file

@ -9,11 +9,9 @@ namespace compiler {
namespace java {
ImmutableFieldGenerator::ImmutableFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
const FieldDescriptor* descriptor, int bit_index, Context* context)
: descriptor_(descriptor),
message_bit_index_(messageBitIndex),
builder_bit_index_(builderBitIndex),
bit_index_(bit_index),
context_(context),
name_resolver_(context->GetNameResolver()) {}

View file

@ -18,16 +18,13 @@ class ClassNameResolver; // name_resolver.h
class ImmutableFieldGenerator : public FieldGenerator {
public:
explicit ImmutableFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableFieldGenerator(const ImmutableFieldGenerator&) = delete;
ImmutableFieldGenerator& operator=(const ImmutableFieldGenerator&) = delete;
~ImmutableFieldGenerator() override = default;
int GetMessageBitIndex() const { return message_bit_index_; }
int GetBuilderBitIndex() const { return builder_bit_index_; }
virtual int GetNumBitsForMessage() const = 0;
constexpr int GetNumBitsForBuilder() const { return 1; }
int GetBitIndex() const { return bit_index_; }
constexpr int GetNumBits() const { return 1; }
virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
virtual void GenerateMembers(io::Printer* printer) const = 0;
virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
@ -52,8 +49,7 @@ class ImmutableFieldGenerator : public FieldGenerator {
protected:
const FieldDescriptor* descriptor_;
int message_bit_index_;
int builder_bit_index_;
int bit_index_;
Context* context_;
ClassNameResolver* name_resolver_;
absl::flat_hash_map<absl::string_view, std::string> variables_;

View file

@ -31,58 +31,57 @@ namespace java {
namespace {
std::unique_ptr<ImmutableFieldGenerator> MakeImmutableGenerator(
const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
Context* context) {
const FieldDescriptor* field, int bit_index, Context* context) {
if (field->is_repeated()) {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
if (IsMapEntry(field->message_type())) {
return std::make_unique<ImmutableMapFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
return std::make_unique<ImmutableMapFieldGenerator>(field, bit_index,
context);
} else {
return std::make_unique<RepeatedImmutableMessageFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
}
case JAVATYPE_ENUM:
return std::make_unique<RepeatedImmutableEnumFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
case JAVATYPE_STRING:
return std::make_unique<RepeatedImmutableStringFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
default:
return std::make_unique<RepeatedImmutablePrimitiveFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
}
} else {
if (IsRealOneof(field)) {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
return std::make_unique<ImmutableMessageOneofFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
case JAVATYPE_ENUM:
return std::make_unique<ImmutableEnumOneofFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
case JAVATYPE_STRING:
return std::make_unique<ImmutableStringOneofFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
default:
return std::make_unique<ImmutablePrimitiveOneofFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
}
} else {
switch (GetJavaType(field)) {
case JAVATYPE_MESSAGE:
return std::make_unique<ImmutableMessageFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
case JAVATYPE_ENUM:
return std::make_unique<ImmutableEnumFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
return std::make_unique<ImmutableEnumFieldGenerator>(field, bit_index,
context);
case JAVATYPE_STRING:
return std::make_unique<ImmutableStringFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
default:
return std::make_unique<ImmutablePrimitiveFieldGenerator>(
field, messageBitIndex, builderBitIndex, context);
field, bit_index, context);
}
}
}
@ -94,15 +93,12 @@ FieldGeneratorMap<ImmutableFieldGenerator> MakeImmutableFieldGenerators(
const Descriptor* descriptor, Context* context) {
// Construct all the FieldGenerators and assign them bit indices for their
// bit fields.
int messageBitIndex = 0;
int builderBitIndex = 0;
int bit_index = 0;
FieldGeneratorMap<ImmutableFieldGenerator> ret(descriptor);
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
auto generator = MakeImmutableGenerator(field, messageBitIndex,
builderBitIndex, context);
messageBitIndex += generator->GetNumBitsForMessage();
builderBitIndex += generator->GetNumBitsForBuilder();
auto generator = MakeImmutableGenerator(field, bit_index, context);
bit_index += generator->GetNumBits();
ret.Add(field, std::move(generator));
}
return ret;

View file

@ -52,10 +52,8 @@ std::string WireType(const FieldDescriptor* field) {
} // namespace
ImmutableMapFieldGenerator::ImmutableMapFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
context) {
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, bit_index, context) {
SetMessageVariables(context->GetFieldGeneratorInfo(descriptor));
}
@ -164,28 +162,34 @@ void ImmutableMapFieldGenerator::SetMessageVariables(
variables_["descriptor"] = absl::StrCat(
name_resolver->GetImmutableClassName(descriptor_->file()), ".internal_",
UniqueFileScopeIdentifier(descriptor_->message_type()), "_descriptor, ");
variables_["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index_);
variables_["get_has_field_bit"] = GenerateGetBit(bit_index_);
variables_["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builder_bit_index_);
variables_["set_has_field_bit_builder"] =
absl::StrCat(GenerateSetBit(builder_bit_index_), ";");
variables_["clear_has_field_bit_builder"] =
absl::StrCat(GenerateClearBit(builder_bit_index_), ";");
GenerateGetBitFromLocal(bit_index_);
variables_["set_has_field_bit"] =
absl::StrCat(GenerateSetBit(bit_index_), ";");
variables_["clear_has_field_bit"] =
absl::StrCat(GenerateClearBit(bit_index_), ";");
}
int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { return 0; }
void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
void ImmutableMapFieldGenerator::GenerateInterfaceGetCountMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$int ${$get$capitalized_name$Count$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableMapFieldGenerator::GenerateInterfaceContainsMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetMapMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
if (google::protobuf::internal::IsOss()) {
@ -204,49 +208,6 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
"$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
"${$get$capitalized_name$Map$}$();\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$$value_enum_type_pass_through_nullness$ "
"${$get$capitalized_name$OrDefault$}$(\n"
" $key_type$ key,\n"
" $value_enum_type_pass_through_nullness$ "
" defaultValue);\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
" * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"java.util.Map<$type_parameters$>\n"
"${$get$capitalized_name$Value$}$();\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
"${$get$capitalized_name$ValueMap$}$();\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$$value_type_pass_through_nullness$ "
"${$get$capitalized_name$ValueOrDefault$}$(\n"
" $key_type$ key,\n"
" $value_type_pass_through_nullness$ defaultValue);\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
}
} else {
if (google::protobuf::internal::IsOss()) {
printer->Print(variables_,
@ -263,6 +224,22 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
"$deprecation$java.util.Map<$type_parameters$>\n"
"${$get$capitalized_name$Map$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetOrDefaultMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$$value_enum_type_pass_through_nullness$ "
"${$get$capitalized_name$OrDefault$}$(\n"
" $key_type$ key,\n"
" $value_enum_type_pass_through_nullness$ "
" defaultValue);\n");
printer->Annotate("{", "}", descriptor_);
} else {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$$value_type_pass_through_nullness$ "
@ -270,6 +247,20 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
" $key_type$ key,\n"
" $value_type_pass_through_nullness$ defaultValue);\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetOrThrowMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
} else {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
@ -279,6 +270,65 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueMapMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
printer->Print(variables_,
"/**\n"
" * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"java.util.Map<$type_parameters$>\n"
"${$get$capitalized_name$Value$}$();\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
"${$get$capitalized_name$ValueMap$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueOrDefaultMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$$value_type_pass_through_nullness$ "
"${$get$capitalized_name$ValueOrDefault$}$(\n"
" $key_type$ key,\n"
" $value_type_pass_through_nullness$ defaultValue);\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueOrThrowMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceGetCountMethod(printer);
GenerateInterfaceContainsMethod(printer);
GenerateInterfaceGetMapMethod(printer);
GenerateInterfaceGetOrDefaultMethod(printer);
GenerateInterfaceGetOrThrowMethod(printer);
GenerateInterfaceGetValueMapMethod(printer);
GenerateInterfaceGetValueOrDefaultMethod(printer);
GenerateInterfaceGetValueOrThrowMethod(printer);
}
void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
@ -328,6 +378,183 @@ void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const {
GenerateMapGetters(printer);
}
void ImmutableMapFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .clear();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateBuilderRemoveMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
" $key_type$ key) {\n"
" $key_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .remove(key);\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateBuilderPutMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit$\n"
" return internalGetAdapted$capitalized_name$Map(\n"
" internalGetMutable$capitalized_name$().getMutableMap());\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_enum_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, $name$ValueConverter.doBackward(value));\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
} else {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$type_parameters$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit$\n"
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, value);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableMapFieldGenerator::GenerateBuilderPutAllMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
" internalGetAdapted$capitalized_name$Map(\n"
" internalGetMutable$capitalized_name$().getMutableMap())\n"
" .putAll(values);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
} else {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$type_parameters$> values) {\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .putAll(values);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableMapFieldGenerator::GenerateBuilderPutValueMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"${$getMutable$capitalized_name$Value$}$() {\n"
" $set_has_field_bit$\n"
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, value);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableMapFieldGenerator::GenerateBuilderPutAllValueMethod(
io::Printer* printer) const {
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n"
" java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .putAll(values);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
}
void ImmutableMapFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
if (GetJavaType(MapValueField(descriptor_)) == JAVATYPE_MESSAGE) {
@ -354,162 +581,17 @@ void ImmutableMapFieldGenerator::GenerateBuilderMembers(
" if (!$name$_.isMutable()) {\n"
" $name$_ = $name$_.copy();\n"
" }\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return $name$_;\n"
"}\n");
GenerateMapGetters(printer);
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit_builder$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .clear();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
" $key_type$ key) {\n"
" $key_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .remove(key);\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
const FieldDescriptor* value = MapValueField(descriptor_);
if (GetJavaType(value) == JAVATYPE_ENUM) {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit_builder$\n"
" return internalGetAdapted$capitalized_name$Map(\n"
" internalGetMutable$capitalized_name$().getMutableMap());\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_enum_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, $name$ValueConverter.doBackward(value));\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
" internalGetAdapted$capitalized_name$Map(\n"
" internalGetMutable$capitalized_name$().getMutableMap())\n"
" .putAll(values);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
if (SupportUnknownEnumValue(value)) {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"${$getMutable$capitalized_name$Value$}$() {\n"
" $set_has_field_bit_builder$\n"
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, value);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n"
" java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .putAll(values);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
} else {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$type_parameters$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit_builder$\n"
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .put(key, value);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$type_parameters$> values) {\n"
" internalGetMutable$capitalized_name$().getMutableMap()\n"
" .putAll(values);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
GenerateBuilderClearMethod(printer);
GenerateBuilderRemoveMethod(printer);
GenerateBuilderPutMethod(printer);
GenerateBuilderPutAllMethod(printer);
GenerateBuilderPutValueMethod(printer);
GenerateBuilderPutAllValueMethod(printer);
}
void ImmutableMapFieldGenerator::GenerateMapGetters(
@ -701,6 +783,108 @@ void ImmutableMapFieldGenerator::GenerateMapGetters(
}
}
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderClearMethod(
io::Printer* printer) const {
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit$\n"
" internalGetMutable$capitalized_name$().clear();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderRemoveMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
" $key_type$ key) {\n"
" $key_null_check$\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .remove(key);\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderPutMethod(
io::Printer* printer) const {
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$type_parameters$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit$\n"
" return internalGetMutable$capitalized_name$().ensureMessageMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .put(key, value);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderPutAllMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$type_parameters$> values) {\n"
" for (java.util.Map.Entry<$type_parameters$> e : values.entrySet()) {\n"
" java.util.Objects.requireNonNull(e.getKey());\n"
" java.util.Objects.requireNonNull(e.getValue());\n"
" }\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .putAll(values);\n"
" $set_has_field_bit$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::
GenerateMessageMapBuilderPutBuilderIfAbsentMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public $value_builder_type$ "
"${$put$capitalized_name$BuilderIfAbsent$}$(\n"
" $key_type$ key) {\n"
" java.util.Map<$boxed_key_type$, $value_interface_type$> builderMap = "
"internalGetMutable$capitalized_name$().ensureBuilderMap();\n"
" $value_interface_type$ entry = builderMap.get(key);\n"
" if (entry == null) {\n"
" entry = $value_type$.newBuilder();\n"
" builderMap.put(key, entry);\n"
" }\n"
" if (entry instanceof $value_type$) {\n"
" entry = (($value_type$) entry).toBuilder();\n"
" builderMap.put(key, entry);\n"
" }\n"
" return ($value_builder_type$) entry;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderMembers(
io::Printer* printer) const {
printer->Print(
@ -761,96 +945,16 @@ void ImmutableMapFieldGenerator::GenerateMessageMapBuilderMembers(
" $name$_ = new "
"com.google.protobuf.MapFieldBuilder<>($name$Converter);\n"
" }\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return $name$_;\n"
"}\n");
GenerateMessageMapGetters(printer);
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit_builder$\n"
" internalGetMutable$capitalized_name$().clear();\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
" $key_type$ key) {\n"
" $key_null_check$\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .remove(key);\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
if (google::protobuf::internal::IsOss()) {
printer->Print(
variables_,
"/**\n"
" * Use alternate mutation accessors instead.\n"
" */\n"
"@java.lang.Deprecated\n"
"public java.util.Map<$type_parameters$>\n"
" ${$getMutable$capitalized_name$$}$() {\n"
" $set_has_field_bit_builder$\n"
" return internalGetMutable$capitalized_name$().ensureMessageMap();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
" $key_type$ key,\n"
" $value_type$ value) {\n"
" $key_null_check$\n"
" $value_null_check$\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .put(key, value);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
" java.util.Map<$type_parameters$> values) {\n"
" for (java.util.Map.Entry<$type_parameters$> e : values.entrySet()) {\n"
" java.util.Objects.requireNonNull(e.getKey());\n"
" java.util.Objects.requireNonNull(e.getValue());\n"
" }\n"
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
" .putAll(values);\n"
" $set_has_field_bit_builder$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(
variables_,
"$deprecation$public $value_builder_type$ "
"${$put$capitalized_name$BuilderIfAbsent$}$(\n"
" $key_type$ key) {\n"
" java.util.Map<$boxed_key_type$, $value_interface_type$> builderMap = "
"internalGetMutable$capitalized_name$().ensureBuilderMap();\n"
" $value_interface_type$ entry = builderMap.get(key);\n"
" if (entry == null) {\n"
" entry = $value_type$.newBuilder();\n"
" builderMap.put(key, entry);\n"
" }\n"
" if (entry instanceof $value_type$) {\n"
" entry = (($value_type$) entry).toBuilder();\n"
" builderMap.put(key, entry);\n"
" }\n"
" return ($value_builder_type$) entry;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
GenerateMessageMapBuilderClearMethod(printer);
GenerateMessageMapBuilderRemoveMethod(printer);
GenerateMessageMapBuilderPutMethod(printer);
GenerateMessageMapBuilderPutAllMethod(printer);
GenerateMessageMapBuilderPutBuilderIfAbsentMethod(printer);
}
void ImmutableMapFieldGenerator::GenerateMessageMapGetters(
@ -948,7 +1052,7 @@ void ImmutableMapFieldGenerator::GenerateMergingCode(
printer->Print(variables_,
"internalGetMutable$capitalized_name$().mergeFrom(\n"
" other.internalGet$capitalized_name$());\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
}
void ImmutableMapFieldGenerator::GenerateBuildingCode(
@ -981,7 +1085,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
" $default_entry$.getParserForType(), extensionRegistry);\n"
"internalGetMutable$capitalized_name$().ensureBuilderMap().put(\n"
" $name$__.getKey(), $name$__.getValue());\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
return;
}
if (!SupportUnknownEnumValue(value) && type == JAVATYPE_ENUM) {
@ -995,7 +1099,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
"} else {\n"
" internalGetMutable$capitalized_name$().getMutableMap().put(\n"
" $name$__.getKey(), $name$__.getValue());\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
"}\n");
return;
}
@ -1005,7 +1109,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
" $default_entry$.getParserForType(), extensionRegistry);\n"
"internalGetMutable$capitalized_name$().getMutableMap().put(\n"
" $name$__.getKey(), $name$__.getValue());\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
}
void ImmutableMapFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {

View file

@ -21,12 +21,11 @@ namespace java {
class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
public:
explicit ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
~ImmutableMapFieldGenerator() override = default;
// implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -49,6 +48,29 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
void GenerateMapGetters(io::Printer* printer) const;
void GenerateMessageMapBuilderMembers(io::Printer* printer) const;
void GenerateMessageMapGetters(io::Printer* printer) const;
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
void GenerateInterfaceContainsMethod(io::Printer* printer) const;
void GenerateInterfaceGetMapMethod(io::Printer* printer) const;
void GenerateInterfaceGetOrDefaultMethod(io::Printer* printer) const;
void GenerateInterfaceGetOrThrowMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueMapMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueOrDefaultMethod(io::Printer* printer) const;
void GenerateInterfaceGetValueOrThrowMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderRemoveMethod(io::Printer* printer) const;
void GenerateBuilderPutMethod(io::Printer* printer) const;
void GenerateBuilderPutAllMethod(io::Printer* printer) const;
void GenerateBuilderPutValueMethod(io::Printer* printer) const;
void GenerateBuilderPutAllValueMethod(io::Printer* printer) const;
void GenerateMessageMapBuilderClearMethod(io::Printer* printer) const;
void GenerateMessageMapBuilderRemoveMethod(io::Printer* printer) const;
void GenerateMessageMapBuilderPutMethod(io::Printer* printer) const;
void GenerateMessageMapBuilderPutAllMethod(io::Printer* printer) const;
void GenerateMessageMapBuilderPutBuilderIfAbsentMethod(
io::Printer* printer) const;
};
} // namespace java

View file

@ -380,8 +380,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
// Integers for bit fields.
int totalBits = 0;
for (int i = 0; i < descriptor_->field_count(); i++) {
totalBits +=
field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
totalBits += field_generators_.get(descriptor_->field(i)).GetNumBits();
}
int totalInts = (totalBits + 31) / 32;
for (int i = 0; i < totalInts; i++) {

View file

@ -188,8 +188,7 @@ void MessageBuilderGenerator::Generate(io::Printer* printer) {
// Integers for bit fields.
int totalBits = 0;
for (int i = 0; i < descriptor_->field_count(); i++) {
totalBits +=
field_generators_.get(descriptor_->field(i)).GetNumBitsForBuilder();
totalBits += field_generators_.get(descriptor_->field(i)).GetNumBits();
}
int totalInts = (totalBits + 31) / 32;
for (int i = 0; i < totalInts; i++) {
@ -720,7 +719,7 @@ int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
for (; bit < 32 && next < descriptor_->field_count(); ++next) {
const ImmutableFieldGenerator& field =
field_generators_.get(descriptor_->field(next));
bit += field.GetNumBitsForBuilder();
bit += field.GetNumBits();
// Skip oneof fields that are handled separately
if (IsRealOneof(descriptor_->field(next))) {
@ -733,13 +732,13 @@ int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
continue;
}
// Skip fields without presence bits in the builder
if (field.GetNumBitsForBuilder() == 0) {
if (field.GetNumBits() == 0) {
continue;
}
// Track message bits if necessary
if (field.GetNumBitsForMessage() > 0) {
int to_bitfield = field.GetMessageBitIndex() / 32;
if (field.GetNumBits() > 0) {
int to_bitfield = field.GetBitIndex() / 32;
if (declared_to_bitfields.count(to_bitfield) == 0) {
printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name",
GetBitFieldName(to_bitfield));

View file

@ -20,6 +20,7 @@
#include "google/protobuf/compiler/java/doc_comment.h"
#include "google/protobuf/compiler/java/field_common.h"
#include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/full/field_generator.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
@ -37,7 +38,7 @@ namespace {
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
void SetMessageVariables(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
const FieldDescriptor* descriptor, int bit_index,
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
absl::flat_hash_map<absl::string_view, std::string>* variables,
Context* context) {
@ -59,27 +60,27 @@ void SetMessageVariables(
// For singular messages and builders, one bit is used for the hasField bit.
// Note that these have a trailing ";".
(*variables)["set_has_field_bit_to_local"] =
GenerateSetBitToLocal(messageBitIndex);
GenerateSetBitToLocal(bit_index);
(*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
} else {
(*variables)["set_has_field_bit_to_local"] = "";
variables->insert({"is_field_present_message",
absl::StrCat((*variables)["name"], "_ != null")});
variables->insert(
{"is_field_present", absl::StrCat((*variables)["name"], "_ != null")});
}
// For repeated builders, one bit is used for whether the array is immutable.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(bit_index);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(bit_index);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(bit_index);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_has_field_bit_builder"] =
absl::StrCat(GenerateSetBit(builderBitIndex), ";");
(*variables)["clear_has_field_bit_builder"] =
absl::StrCat(GenerateClearBit(builderBitIndex), ";");
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
(*variables)["set_has_field_bit"] =
absl::StrCat(GenerateSetBit(bit_index), ";");
(*variables)["clear_has_field_bit"] =
absl::StrCat(GenerateClearBit(bit_index), ";");
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
GenerateGetBitFromLocal(bit_index);
(*variables)["tag_size"] = absl::StrCat(
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
@ -90,21 +91,15 @@ void SetMessageVariables(
// ===================================================================
ImmutableMessageFieldGenerator::ImmutableMessageFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
context) {
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, bit_index, context) {
SetMessageVariables(descriptor, bit_index,
context->GetFieldGeneratorInfo(descriptor),
name_resolver_, &variables_, context);
}
ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() = default;
int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
return HasHasbit(descriptor_) ? 1 : 0;
}
void ImmutableMessageFieldGenerator::GenerateInterfaceHasMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -126,7 +121,6 @@ void ImmutableMessageFieldGenerator::GenerateInterfaceGetOrBuilderMethod(
variables_,
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
}
void ImmutableMessageFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
// TODO: In the future, consider having a method specific to the
@ -145,7 +139,7 @@ void ImmutableMessageFieldGenerator::GenerateHasMethod(
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $is_field_present_message$;\n"
" return $is_field_present$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
@ -224,7 +218,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderHasMethod(
context_->options());
printer->Print(variables_,
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $get_has_field_bit_builder$;\n"
" return $get_has_field_bit$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
@ -253,7 +247,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderSetMethod(
"$name$Builder_.setMessage(value);\n",
"$set_has_field_bit_builder$\n"
"$set_has_field_bit$\n"
"$on_changed$\n"
"return this;\n",
Semantic::kSet);
@ -279,7 +273,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMergeMethod(
PrintNestedBuilderFunction(
printer,
"$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)",
"if ($get_has_field_bit_builder$ &&\n"
"if ($get_has_field_bit$ &&\n"
" $name$_ != null &&\n"
" $name$_ != $type$.getDefaultInstance()) {\n"
" get$capitalized_name$Builder().mergeFrom(value);\n"
@ -290,7 +284,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMergeMethod(
"$name$Builder_.mergeFrom(value);\n",
"if ($name$_ != null) {\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
"}\n"
"return this;\n",
@ -304,7 +298,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderClearMethod(
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit_builder$\n"
" $clear_has_field_bit$\n"
" $name$_ = null;\n"
" if ($name$Builder_ != null) {\n"
" $name$Builder_.dispose();\n"
@ -323,7 +317,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderGetBuilderMethod(
printer->Print(variables_,
"$deprecation$public $type$.Builder "
"${$get$capitalized_name$Builder$}$() {\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return "
"internalGet$capitalized_name$FieldBuilder().getBuilder();\n"
@ -392,7 +386,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderParseMethod(
" $name$_ = input.readGroup($number$, $type$.parser(),\n"
" extensionRegistry);\n"
"}\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
} else {
printer->Print(
variables_,
@ -404,7 +398,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderParseMethod(
"} else {\n"
" $name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"
"}\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
}
printer->Outdent();
printer->Print("}\n");
@ -470,7 +464,7 @@ void ImmutableMessageFieldGenerator::GenerateBuildingCode(
" result.$name$_ = $name$Builder_ == null\n"
" ? $name$_\n"
" : $name$Builder_.build();\n");
if (GetNumBitsForMessage() > 0) {
if (GetNumBits() > 0) {
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
}
printer->Print("}\n");
@ -486,7 +480,7 @@ void ImmutableMessageFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
printer->Print(
variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" output.write$group_or_message$($number$, get$capitalized_name$());\n"
"}\n");
}
@ -495,7 +489,7 @@ void ImmutableMessageFieldGenerator::GenerateSerializedSizeCode(
io::Printer* printer) const {
printer->Print(
variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
"}\n");
@ -522,10 +516,8 @@ std::string ImmutableMessageFieldGenerator::GetBoxedType() const {
// ===================================================================
ImmutableMessageOneofFieldGenerator::ImmutableMessageOneofFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableMessageFieldGenerator(descriptor, messageBitIndex,
builderBitIndex, context) {
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableMessageFieldGenerator(descriptor, bit_index, context) {
const OneofGeneratorInfo* info =
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
SetCommonOneofVariables(descriptor, info, &variables_);
@ -850,18 +842,12 @@ void ImmutableMessageOneofFieldGenerator::GenerateSerializedSizeCode(
// ===================================================================
RepeatedImmutableMessageFieldGenerator::RepeatedImmutableMessageFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableMessageFieldGenerator(descriptor, messageBitIndex,
builderBitIndex, context) {}
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableMessageFieldGenerator(descriptor, bit_index, context) {}
RepeatedImmutableMessageFieldGenerator::
~RepeatedImmutableMessageFieldGenerator() = default;
int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
void RepeatedImmutableMessageFieldGenerator::GenerateInterfaceGetListMethod(
io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_, context_->options());

View file

@ -37,9 +37,7 @@ namespace java {
class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
public:
explicit ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableMessageFieldGenerator(const ImmutableMessageFieldGenerator&) =
delete;
ImmutableMessageFieldGenerator& operator=(
@ -48,7 +46,7 @@ class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
// implements ImmutableFieldGenerator
// ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -102,8 +100,7 @@ class ImmutableMessageOneofFieldGenerator
: public ImmutableMessageFieldGenerator {
public:
ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableMessageOneofFieldGenerator(
const ImmutableMessageOneofFieldGenerator&) = delete;
ImmutableMessageOneofFieldGenerator& operator=(
@ -139,8 +136,7 @@ class RepeatedImmutableMessageFieldGenerator
: public ImmutableMessageFieldGenerator {
public:
explicit RepeatedImmutableMessageFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex,
int builderBitIndex, Context* context);
const FieldDescriptor* descriptor, int bit_index, Context* context);
RepeatedImmutableMessageFieldGenerator(
const RepeatedImmutableMessageFieldGenerator&) = delete;
RepeatedImmutableMessageFieldGenerator& operator=(
@ -148,7 +144,6 @@ class RepeatedImmutableMessageFieldGenerator
~RepeatedImmutableMessageFieldGenerator() override;
// implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;

View file

@ -59,9 +59,8 @@ void AddPrimitiveVariableForThisAndOther(
}
void SetPrimitiveVariables(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, const FieldGeneratorInfo* info,
ClassNameResolver* name_resolver,
const FieldDescriptor* descriptor, int bit_index,
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
absl::flat_hash_map<absl::string_view, std::string>* variables,
Context* context) {
SetCommonFieldVariables(descriptor, info, variables);
@ -131,17 +130,16 @@ void SetPrimitiveVariables(
// For singular messages and builders, one bit is used for the hasField bit.
// Note that these have a trailing ";".
(*variables)["set_has_field_bit_to_local"] =
absl::StrCat(GenerateSetBitToLocal(message_bit_index), ";");
(*variables)["is_field_present_message"] =
GenerateGetBit(message_bit_index);
(*variables)["is_other_field_present_message"] =
absl::StrCat(GenerateSetBitToLocal(bit_index), ";");
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
(*variables)["is_other_field_present"] =
absl::StrCat("other.has", (*variables)["capitalized_name"], "()");
} else {
(*variables)["set_has_field_bit_to_local"] = "";
switch (descriptor->type()) {
case FieldDescriptor::TYPE_BYTES:
AddPrimitiveVariableForThisAndOther(
"is_field_present_message", "is_other_field_present_message",
"is_field_present", "is_other_field_present",
[](absl::string_view value) {
return absl::StrCat("!", value, ".isEmpty()");
},
@ -149,7 +147,7 @@ void SetPrimitiveVariables(
break;
case FieldDescriptor::TYPE_FLOAT:
AddPrimitiveVariableForThisAndOther(
"is_field_present_message", "is_other_field_present_message",
"is_field_present", "is_other_field_present",
[](absl::string_view value) {
return absl::StrCat("java.lang.Float.floatToRawIntBits(", value,
") != 0");
@ -158,7 +156,7 @@ void SetPrimitiveVariables(
break;
case FieldDescriptor::TYPE_DOUBLE:
AddPrimitiveVariableForThisAndOther(
"is_field_present_message", "is_other_field_present_message",
"is_field_present", "is_other_field_present",
[](absl::string_view value) {
return absl::StrCat("java.lang.Double.doubleToRawLongBits(",
value, ") != 0");
@ -167,7 +165,7 @@ void SetPrimitiveVariables(
break;
default:
AddPrimitiveVariableForThisAndOther(
"is_field_present_message", "is_other_field_present_message",
"is_field_present", "is_other_field_present",
[variables](absl::string_view value) {
return absl::StrCat(value, " != ", (*variables)["default"]);
},
@ -178,13 +176,13 @@ void SetPrimitiveVariables(
// Always track the presence of a field explicitly in the builder, regardless
// of syntax.
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index);
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builder_bit_index);
(*variables)["set_has_field_bit_builder"] =
absl::StrCat(GenerateSetBit(builder_bit_index), ";");
(*variables)["clear_has_field_bit_builder"] =
absl::StrCat(GenerateClearBit(builder_bit_index), ";");
GenerateGetBitFromLocal(bit_index);
(*variables)["set_has_field_bit"] =
absl::StrCat(GenerateSetBit(bit_index), ";");
(*variables)["clear_has_field_bit"] =
absl::StrCat(GenerateClearBit(bit_index), ";");
}
} // namespace
@ -192,21 +190,16 @@ void SetPrimitiveVariables(
// ===================================================================
ImmutablePrimitiveFieldGenerator::ImmutablePrimitiveFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, message_bit_index, builder_bit_index,
context) {
SetPrimitiveVariables(descriptor, message_bit_index, builder_bit_index,
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, bit_index, context) {
SetPrimitiveVariables(descriptor, bit_index,
context->GetFieldGeneratorInfo(descriptor),
name_resolver_, &variables_, context);
}
ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() = default;
int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
return HasHasbit(descriptor_) ? 1 : 0;
}
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -214,15 +207,58 @@ void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
}
}
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
}
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceHasMethod(printer);
GenerateInterfaceGetMethod(printer);
}
void ImmutablePrimitiveFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $is_field_present$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutablePrimitiveFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(variables_, "private $field_type$ $name$_ = $default$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetMethod(printer);
}
void ImmutablePrimitiveFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
@ -230,11 +266,14 @@ void ImmutablePrimitiveFieldGenerator::GenerateMembers(
variables_,
"@java.lang.Override\n"
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $is_field_present_message$;\n"
" return $get_has_field_bit$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutablePrimitiveFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -245,31 +284,8 @@ void ImmutablePrimitiveFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
void ImmutablePrimitiveFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $get_has_field_bit_builder$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -278,19 +294,22 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
"${$set$capitalized_name$$}$($type$ value) {\n"
" $null_check$\n"
" $name$_ = value;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $clear_has_field_bit_builder$\n");
" $clear_has_field_bit$\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
JavaType type = GetJavaType(descriptor_);
if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
@ -308,6 +327,15 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
"}\n");
}
void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
GenerateBuilderHasMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
}
void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for primitives
@ -329,7 +357,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode(
void ImmutablePrimitiveFieldGenerator::GenerateMergingCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_other_field_present_message$) {\n"
"if ($is_other_field_present$) {\n"
" set$capitalized_name$(other.get$capitalized_name$());\n"
"}\n");
}
@ -339,7 +367,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
printer->Print(variables_,
"if ($get_has_field_bit_from_local$) {\n"
" result.$name$_ = $name$_;\n");
if (GetNumBitsForMessage() > 0) {
if (GetNumBits() > 0) {
printer->Print(variables_, " $set_has_field_bit_to_local$\n");
}
printer->Print("}\n");
@ -349,13 +377,13 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = input.read$capitalized_type$();\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
}
void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" output.write$capitalized_type$($number$, $name$_);\n"
"}\n");
}
@ -363,7 +391,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
void ImmutablePrimitiveFieldGenerator::GenerateSerializedSizeCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .compute$capitalized_type$Size($number$, $name$_);\n"
"}\n");
@ -470,10 +498,8 @@ std::string ImmutablePrimitiveFieldGenerator::GetBoxedType() const {
// ===================================================================
ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context)
: ImmutablePrimitiveFieldGenerator(descriptor, message_bit_index,
builder_bit_index, context) {
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutablePrimitiveFieldGenerator(descriptor, bit_index, context) {
const OneofGeneratorInfo* info =
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
SetCommonOneofVariables(descriptor, info, &variables_);
@ -482,9 +508,8 @@ ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator(
ImmutablePrimitiveOneofFieldGenerator::
~ImmutablePrimitiveOneofFieldGenerator() = default;
void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
void ImmutablePrimitiveOneofFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
@ -494,7 +519,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -508,7 +536,14 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetMethod(printer);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -518,7 +553,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -529,7 +567,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
" return $default$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -543,7 +584,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -560,6 +604,14 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
GenerateBuilderHasMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
}
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearCode(
io::Printer* printer) const {
// No-Op: When a primitive field is in a oneof, clearing the oneof clears that
@ -623,36 +675,81 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateSerializedSizeCode(
RepeatedImmutablePrimitiveFieldGenerator::
RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
int message_bit_index,
int builder_bit_index,
Context* context)
: ImmutablePrimitiveFieldGenerator(descriptor, message_bit_index,
builder_bit_index, context) {}
int bit_index, Context* context)
: ImmutablePrimitiveFieldGenerator(descriptor, bit_index, context) {}
RepeatedImmutablePrimitiveFieldGenerator::
~RepeatedImmutablePrimitiveFieldGenerator() = default;
int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$java.util.List<$boxed_type$> "
"get$capitalized_name$List();\n");
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(variables_,
"$deprecation$int get$capitalized_name$Count();\n");
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$$type$ get$capitalized_name$(int index);\n");
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceGetListMethod(printer);
GenerateInterfaceGetCountMethod(printer);
GenerateInterfaceGetMethod(printer);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$boxed_type$>\n"
" ${$get$capitalized_name$List$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
variables_,
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $repeated_get$(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(variables_,
@ -660,31 +757,9 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
"private $field_list_type$ $name$_ =\n"
" $empty_list$;\n");
PrintExtraFieldInfo(variables_, printer);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$boxed_type$>\n"
" ${$get$capitalized_name$List$}$() {\n"
" return $name$_;\n" // note: unmodifiable list
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
variables_,
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $repeated_get$(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
GenerateGetListMethod(printer);
GenerateGetCountMethod(printer);
GenerateGetMethod(printer);
if (descriptor_->is_packed()) {
printer->Print(variables_,
@ -692,16 +767,8 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
}
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
void RepeatedImmutablePrimitiveFieldGenerator::GenerateEnsureIsMutableMethod(
io::Printer* printer) const {
// We use a ProtobufArrayList because it starts as a mutable list that can be
// switched to immutable when references are handed out. This allows copy-free
// sharing. A bit in the bitfield tracks whether there are any items in the
// list. The presence bit allows us to skip work on blocks of 32 fields by
// by checking if the entire bit-field int == 0 (none of the fields are
// present).
// We use one method and pass -1 when capacity is unknown to control class
// size.
printer->Print(
variables_,
"private $field_list_type$ $name$_ = $empty_list$;\n"
@ -709,13 +776,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" if (!$name$_.isModifiable()) {\n"
" $name$_ = makeMutableCopy($name$_, capacity);\n"
" }\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
"}\n");
}
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
@ -725,6 +791,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
@ -733,6 +803,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
@ -741,6 +815,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" return $repeated_get$(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
context_->options(),
/* builder */ true);
@ -750,11 +828,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" $null_check$\n"
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
" $repeated_set$(index, value);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderAddMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
context_->options(),
/* builder */ true);
@ -764,11 +846,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" $null_check$\n"
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
" $repeated_add$(value);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderAddAllMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
context_->options(),
/* builder */ true);
@ -778,11 +864,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
" com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
" values, $name$_);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -790,13 +880,25 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_has_field_bit_builder$\n"
" $clear_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
GenerateEnsureIsMutableMethod(printer);
GenerateBuilderGetListMethod(printer);
GenerateBuilderGetCountMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderAddMethod(printer);
GenerateBuilderAddAllMethod(printer);
GenerateBuilderClearMethod(printer);
}
void RepeatedImmutablePrimitiveFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
@ -824,7 +926,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMergingCode(
" if ($name$_.isEmpty()) {\n"
" $name$_ = other.$name$_;\n"
" $name_make_immutable$;\n"
" $set_has_field_bit_builder$\n");
" $set_has_field_bit$\n");
printer->Print(variables_,
" } else {\n"
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"

View file

@ -36,9 +36,7 @@ namespace java {
class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
public:
explicit ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
int message_bit_index,
int builder_bit_index,
Context* context);
int bit_index, Context* context);
ImmutablePrimitiveFieldGenerator(const ImmutablePrimitiveFieldGenerator&) =
delete;
ImmutablePrimitiveFieldGenerator& operator=(
@ -47,7 +45,7 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
// implements ImmutableFieldGenerator
// ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -65,16 +63,24 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
std::string GetBoxedType() const override;
protected:
private:
void GenerateInterfaceHasMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
};
class ImmutablePrimitiveOneofFieldGenerator
: public ImmutablePrimitiveFieldGenerator {
public:
ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
int message_bit_index,
int builder_bit_index,
Context* context);
int bit_index, Context* context);
ImmutablePrimitiveOneofFieldGenerator(
const ImmutablePrimitiveOneofFieldGenerator&) = delete;
ImmutablePrimitiveOneofFieldGenerator& operator=(
@ -89,14 +95,22 @@ class ImmutablePrimitiveOneofFieldGenerator
void GenerateBuilderParsingCode(io::Printer* printer) const override;
void GenerateSerializationCode(io::Printer* printer) const override;
void GenerateSerializedSizeCode(io::Printer* printer) const override;
private:
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
};
class RepeatedImmutablePrimitiveFieldGenerator
: public ImmutablePrimitiveFieldGenerator {
public:
explicit RepeatedImmutablePrimitiveFieldGenerator(
const FieldDescriptor* descriptor, int message_bit_index,
int builder_bit_index, Context* context);
const FieldDescriptor* descriptor, int bit_index, Context* context);
RepeatedImmutablePrimitiveFieldGenerator(
const RepeatedImmutablePrimitiveFieldGenerator&) = delete;
RepeatedImmutablePrimitiveFieldGenerator& operator=(
@ -104,7 +118,6 @@ class RepeatedImmutablePrimitiveFieldGenerator
~RepeatedImmutablePrimitiveFieldGenerator() override;
// implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -123,6 +136,24 @@ class RepeatedImmutablePrimitiveFieldGenerator
void GenerateHashCode(io::Printer* printer) const override;
std::string GetBoxedType() const override;
private:
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateGetListMethod(io::Printer* printer) const;
void GenerateGetCountMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
void GenerateBuilderGetListMethod(io::Printer* printer) const;
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderAddMethod(io::Printer* printer) const;
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
};
} // namespace java

View file

@ -39,7 +39,7 @@ using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
namespace {
void SetPrimitiveVariables(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
const FieldDescriptor* descriptor, int bit_index,
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
absl::flat_hash_map<absl::string_view, std::string>* variables,
Context* context) {
@ -75,29 +75,24 @@ void SetPrimitiveVariables(
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["set_has_field_bit_to_local"] =
GenerateSetBitToLocal(messageBitIndex);
GenerateSetBitToLocal(bit_index);
// Note that these have a trailing ";".
(*variables)["set_has_field_bit_message"] =
absl::StrCat(GenerateSetBit(messageBitIndex), ";");
(*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
} else {
(*variables)["set_has_field_bit_to_local"] = "";
(*variables)["set_has_field_bit_message"] = "";
variables->insert({"is_field_present_message",
absl::StrCat("!", (*variables)["isStringEmpty"], "(",
(*variables)["name"], "_)")});
variables->insert(
{"is_field_present", absl::StrCat("!", (*variables)["isStringEmpty"],
"(", (*variables)["name"], "_)")});
}
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_builder"] =
absl::StrCat(GenerateSetBit(builderBitIndex), ";");
(*variables)["clear_has_field_bit_builder"] =
absl::StrCat(GenerateClearBit(builderBitIndex), ";");
GenerateGetBitFromLocal(bit_index);
(*variables)["set_has_field_bit"] =
absl::StrCat(GenerateSetBit(bit_index), ";");
(*variables)["clear_has_field_bit"] =
absl::StrCat(GenerateClearBit(bit_index), ";");
}
} // namespace
@ -105,20 +100,15 @@ void SetPrimitiveVariables(
// ===================================================================
ImmutableStringFieldGenerator::ImmutableStringFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
context) {
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableFieldGenerator(descriptor, bit_index, context) {
SetPrimitiveVariables(descriptor, bit_index,
context->GetFieldGeneratorInfo(descriptor),
name_resolver_, &variables_, context);
}
ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() = default;
int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
return HasHasbit(descriptor_) ? 1 : 0;
}
// A note about how strings are handled. This code used to just store a String
// in the Message. This had two issues:
//
@ -150,7 +140,7 @@ int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
//
// For single fields, the logic for this is done inside the generated code. For
// repeated fields, the logic is done in LazyStringArrayList.
void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
void ImmutableStringFieldGenerator::GenerateInterfaceHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -158,10 +148,18 @@ void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
}
}
void ImmutableStringFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$java.lang.String get$capitalized_name$();\n");
}
void ImmutableStringFieldGenerator::GenerateInterfaceGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -169,13 +167,15 @@ void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
" get$capitalized_name$Bytes();\n");
}
void ImmutableStringFieldGenerator::GenerateMembers(
void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
printer->Print(variables_,
"@SuppressWarnings(\"serial\")\n"
"private volatile java.lang.Object $name$_ = $default$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateInterfaceHasMethod(printer);
GenerateInterfaceGetMethod(printer);
GenerateInterfaceGetBytesMethod(printer);
}
void ImmutableStringFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
@ -183,11 +183,14 @@ void ImmutableStringFieldGenerator::GenerateMembers(
variables_,
"@java.lang.Override\n"
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $is_field_present_message$;\n"
" return $is_field_present$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableStringFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(
@ -216,6 +219,10 @@ void ImmutableStringFieldGenerator::GenerateMembers(
" return s;\n"
" }\n"
"}\n");
}
void ImmutableStringFieldGenerator::GenerateGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -236,21 +243,33 @@ void ImmutableStringFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringFieldGenerator::GenerateBuilderMembers(
void ImmutableStringFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(variables_,
"private java.lang.Object $name$_ $default_init$;\n");
"@SuppressWarnings(\"serial\")\n"
"private volatile java.lang.Object $name$_ = $default$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetMethod(printer);
GenerateGetBytesMethod(printer);
}
void ImmutableStringFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
printer->Print(
variables_,
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
" return $get_has_field_bit_builder$;\n"
" return $get_has_field_bit$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
}
void ImmutableStringFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(
@ -276,7 +295,10 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
" return (java.lang.String) ref;\n"
" }\n"
"}\n");
}
void ImmutableStringFieldGenerator::GenerateBuilderGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -294,7 +316,10 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
" }\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -303,11 +328,15 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
" java.lang.String value) {\n"
" $null_check$\n"
" $name$_ = value;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableStringFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -315,16 +344,17 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
// The default value is not a simple literal so we want to avoid executing
// it multiple times. Instead, get the default out of the default instance.
printer->Print(variables_,
" $name$_ = getDefaultInstance().get$capitalized_name$();\n");
printer->Print(variables_,
" $clear_has_field_bit_builder$\n"
" $clear_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
}
void ImmutableStringFieldGenerator::GenerateBuilderSetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -339,12 +369,24 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
}
printer->Print(variables_,
" $name$_ = value;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
}
void ImmutableStringFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
printer->Print(variables_,
"private java.lang.Object $name$_ $default_init$;\n");
GenerateBuilderHasMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderGetBytesMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
GenerateBuilderSetBytesMethod(printer);
}
void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for primitives
@ -368,14 +410,14 @@ void ImmutableStringFieldGenerator::GenerateMergingCode(
printer->Print(variables_,
"if (other.has$capitalized_name$()) {\n"
" $name$_ = other.$name$_;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
"}\n");
} else {
printer->Print(variables_,
"if (!other.get$capitalized_name$().isEmpty()) {\n"
" $name$_ = other.$name$_;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
"}\n");
}
@ -386,7 +428,7 @@ void ImmutableStringFieldGenerator::GenerateBuildingCode(
printer->Print(variables_,
"if ($get_has_field_bit_from_local$) {\n"
" result.$name$_ = $name$_;\n");
if (GetNumBitsForMessage() > 0) {
if (GetNumBits() > 0) {
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
}
printer->Print("}\n");
@ -398,18 +440,18 @@ void ImmutableStringFieldGenerator::GenerateBuilderParsingCode(
printer->Print(variables_,
"$name$_ = "
"input.readStringRequireUtf8();\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
} else {
printer->Print(variables_,
"$name$_ = input.readBytes();\n"
"$set_has_field_bit_builder$\n");
"$set_has_field_bit$\n");
}
}
void ImmutableStringFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" $writeString$(output, $number$, $name$_);\n"
"}\n");
}
@ -417,7 +459,7 @@ void ImmutableStringFieldGenerator::GenerateSerializationCode(
void ImmutableStringFieldGenerator::GenerateSerializedSizeCode(
io::Printer* printer) const {
printer->Print(variables_,
"if ($is_field_present_message$) {\n"
"if ($is_field_present$) {\n"
" size += $computeStringSize$($number$, $name$_);\n"
"}\n");
}
@ -443,10 +485,8 @@ std::string ImmutableStringFieldGenerator::GetBoxedType() const {
// ===================================================================
ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableStringFieldGenerator(descriptor, messageBitIndex,
builderBitIndex, context) {
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableStringFieldGenerator(descriptor, bit_index, context) {
const OneofGeneratorInfo* info =
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
SetCommonOneofVariables(descriptor, info, &variables_);
@ -455,9 +495,8 @@ ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator(
ImmutableStringOneofFieldGenerator::~ImmutableStringOneofFieldGenerator() =
default;
void ImmutableStringOneofFieldGenerator::GenerateMembers(
void ImmutableStringOneofFieldGenerator::GenerateHasMethod(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
context_->options());
@ -466,7 +505,10 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringOneofFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(
@ -495,6 +537,10 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
" return s;\n"
" }\n"
"}\n");
}
void ImmutableStringOneofFieldGenerator::GenerateGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
@ -519,7 +565,15 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
void ImmutableStringOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
GenerateHasMethod(printer);
GenerateGetMethod(printer);
GenerateGetBytesMethod(printer);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderHasMethod(
io::Printer* printer) const {
ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
@ -530,7 +584,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
" return $has_oneof_case_message$;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(
@ -560,7 +617,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
" return (java.lang.String) ref;\n"
" }\n"
"}\n");
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
context_->options());
printer->Print(variables_,
@ -583,7 +643,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
" }\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -597,6 +660,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -611,7 +678,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderSetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
context_->options(),
/* builder */ true);
@ -632,6 +702,16 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
"}\n");
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
GenerateBuilderHasMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderGetBytesMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderClearMethod(printer);
GenerateBuilderSetBytesMethod(printer);
}
void ImmutableStringOneofFieldGenerator::GenerateBuilderClearCode(
io::Printer* printer) const {
// No-Op: String fields in oneofs are correctly cleared by clearing the oneof
@ -687,41 +767,41 @@ void ImmutableStringOneofFieldGenerator::GenerateSerializedSizeCode(
// ===================================================================
RepeatedImmutableStringFieldGenerator::RepeatedImmutableStringFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
Context* context)
: ImmutableStringFieldGenerator(descriptor, messageBitIndex,
builderBitIndex, context) {}
const FieldDescriptor* descriptor, int bit_index, Context* context)
: ImmutableStringFieldGenerator(descriptor, bit_index, context) {}
RepeatedImmutableStringFieldGenerator::
~RepeatedImmutableStringFieldGenerator() = default;
int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(
variables_,
// NOTE: the same method in the implementation class actually returns
// com.google.protobuf.ProtocolStringList (a subclass of List). It's
// changed between protobuf 2.5.0 release and protobuf 2.6.1 release.
// To retain binary compatibility with both 2.5.0 and 2.6.1 generated
// code, we make this interface method return List so both methods
// with different return types exist in the compiled byte code.
"$deprecation$java.util.List<java.lang.String>\n"
" get$capitalized_name$List();\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(variables_,
"$deprecation$int get$capitalized_name$Count();\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(
variables_,
"$deprecation$java.lang.String get$capitalized_name$(int index);\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
@ -729,6 +809,62 @@ void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
" get$capitalized_name$Bytes(int index);\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
GenerateInterfaceGetListMethod(printer);
GenerateInterfaceGetCountMethod(printer);
GenerateInterfaceGetMethod(printer);
GenerateInterfaceGetBytesMethod(printer);
}
void RepeatedImmutableStringFieldGenerator::GenerateGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
" ${$get$capitalized_name$List$}$() {\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$public java.lang.String "
"${$get$capitalized_name$$}$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ByteString\n"
" ${$get$capitalized_name$Bytes$}$(int index) {\n"
" return $name$_.getByteString(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(variables_,
@ -736,14 +872,39 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
" $empty_list$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateGetListMethod(printer);
GenerateGetCountMethod(printer);
GenerateGetMethod(printer);
GenerateGetBytesMethod(printer);
}
void RepeatedImmutableStringFieldGenerator::GenerateEnsureIsMutableMethod(
io::Printer* printer) const {
printer->Print(
variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$name$_.isModifiable()) {\n"
" $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
" }\n"
" $set_has_field_bit$\n"
"}\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetListMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
" ${$get$capitalized_name$List$}$() {\n"
" return $name$_;\n" // note: unmodifiable list
" $name$_.makeImmutable();\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetCountMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
@ -752,6 +913,10 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(variables_,
@ -760,6 +925,10 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
" return $name$_.get(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
@ -770,67 +939,8 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
printer->Annotate("{", "}", descriptor_);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
void RepeatedImmutableStringFieldGenerator::GenerateBuilderSetMethod(
io::Printer* printer) const {
// One field is the list and the bit field keeps track of whether the
// list is immutable. If it's immutable, the invariant is that it must
// either an instance of Collections.emptyList() or it's an ArrayList
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
// a reference to the underlying ArrayList. This invariant allows us to
// share instances of lists between protocol buffers avoiding expensive
// memory allocations. Note, immutable is a strong guarantee here -- not
// just that the list cannot be modified via the reference but that the
// list can never be modified.
printer->Print(variables_,
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
" $empty_list$;\n");
printer->Print(
variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$name$_.isModifiable()) {\n"
" $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
" }\n"
" $set_has_field_bit_builder$\n"
"}\n");
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
" ${$get$capitalized_name$List$}$() {\n"
" $name$_.makeImmutable();\n"
" return $name$_;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
printer->Print(
variables_,
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
" return $name$_.size();\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
context_->options());
printer->Print(variables_,
"$deprecation$public java.lang.String "
"${$get$capitalized_name$$}$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldStringBytesAccessorDocComment(
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ByteString\n"
" ${$get$capitalized_name$Bytes$}$(int index) {\n"
" return $name$_.getByteString(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
context_->options(),
/* builder */ true);
@ -840,11 +950,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
" $null_check$\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.set(index, value);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
context_->options(),
/* builder */ true);
@ -854,11 +968,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
" $null_check$\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddAllMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
context_->options(),
/* builder */ true);
@ -868,11 +986,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
" ensure$capitalized_name$IsMutable();\n"
" com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
" values, $name$_);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderClearMethod(
io::Printer* printer) const {
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
context_->options(),
/* builder */ true);
@ -881,12 +1003,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $name$_ =\n"
" $empty_list$;\n"
" $clear_has_field_bit_builder$;\n"
" $clear_has_field_bit$;\n"
" $on_changed$\n"
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddBytesMethod(
io::Printer* printer) const {
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER,
context_->options(),
/* builder */ true);
@ -902,12 +1027,29 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
printer->Print(variables_,
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return this;\n"
"}\n");
}
void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
printer->Print(variables_,
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
" $empty_list$;\n");
GenerateEnsureIsMutableMethod(printer);
GenerateBuilderGetListMethod(printer);
GenerateBuilderGetCountMethod(printer);
GenerateBuilderGetMethod(printer);
GenerateBuilderGetBytesMethod(printer);
GenerateBuilderSetMethod(printer);
GenerateBuilderAddMethod(printer);
GenerateBuilderAddAllMethod(printer);
GenerateBuilderClearMethod(printer);
GenerateBuilderAddBytesMethod(printer);
}
void RepeatedImmutableStringFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
@ -938,7 +1080,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateMergingCode(
"if (!other.$name$_.isEmpty()) {\n"
" if ($name$_.isEmpty()) {\n"
" $name$_ = other.$name$_;\n"
" $set_has_field_bit_builder$\n"
" $set_has_field_bit$\n"
" } else {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"

View file

@ -37,8 +37,7 @@ namespace java {
class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
public:
explicit ImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex, Context* context);
int bit_index, Context* context);
ImmutableStringFieldGenerator(const ImmutableStringFieldGenerator&) = delete;
ImmutableStringFieldGenerator& operator=(
const ImmutableStringFieldGenerator&) = delete;
@ -46,7 +45,7 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
// implements ImmutableFieldGenerator
// ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -64,22 +63,34 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
std::string GetBoxedType() const override;
protected:
private:
void GenerateInterfaceHasMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateInterfaceGetBytesMethod(io::Printer* printer) const;
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateGetBytesMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderSetBytesMethod(io::Printer* printer) const;
};
class ImmutableStringOneofFieldGenerator
: public ImmutableStringFieldGenerator {
public:
ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex, int builderBitIndex,
Context* context);
int bit_index, Context* context);
ImmutableStringOneofFieldGenerator(
const ImmutableStringOneofFieldGenerator&) = delete;
ImmutableStringOneofFieldGenerator& operator=(
const ImmutableStringOneofFieldGenerator&) = delete;
~ImmutableStringOneofFieldGenerator() override;
private:
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
void GenerateBuilderClearCode(io::Printer* printer) const override;
@ -88,14 +99,25 @@ class ImmutableStringOneofFieldGenerator
void GenerateBuilderParsingCode(io::Printer* printer) const override;
void GenerateSerializationCode(io::Printer* printer) const override;
void GenerateSerializedSizeCode(io::Printer* printer) const override;
private:
void GenerateHasMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateGetBytesMethod(io::Printer* printer) const;
void GenerateBuilderHasMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderSetBytesMethod(io::Printer* printer) const;
};
class RepeatedImmutableStringFieldGenerator
: public ImmutableStringFieldGenerator {
public:
explicit RepeatedImmutableStringFieldGenerator(
const FieldDescriptor* descriptor, int messageBitIndex,
int builderBitIndex, Context* context);
const FieldDescriptor* descriptor, int bit_index, Context* context);
RepeatedImmutableStringFieldGenerator(
const RepeatedImmutableStringFieldGenerator&) = delete;
RepeatedImmutableStringFieldGenerator& operator=(
@ -103,7 +125,6 @@ class RepeatedImmutableStringFieldGenerator
~RepeatedImmutableStringFieldGenerator() override;
// implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const override;
void GenerateInterfaceMembers(io::Printer* printer) const override;
void GenerateMembers(io::Printer* printer) const override;
void GenerateBuilderMembers(io::Printer* printer) const override;
@ -120,6 +141,28 @@ class RepeatedImmutableStringFieldGenerator
void GenerateHashCode(io::Printer* printer) const override;
std::string GetBoxedType() const override;
private:
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
void GenerateInterfaceGetMethod(io::Printer* printer) const;
void GenerateInterfaceGetBytesMethod(io::Printer* printer) const;
void GenerateGetListMethod(io::Printer* printer) const;
void GenerateGetCountMethod(io::Printer* printer) const;
void GenerateGetMethod(io::Printer* printer) const;
void GenerateGetBytesMethod(io::Printer* printer) const;
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
void GenerateBuilderGetListMethod(io::Printer* printer) const;
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
void GenerateBuilderGetMethod(io::Printer* printer) const;
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
void GenerateBuilderSetMethod(io::Printer* printer) const;
void GenerateBuilderAddMethod(io::Printer* printer) const;
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
void GenerateBuilderClearMethod(io::Printer* printer) const;
void GenerateBuilderAddBytesMethod(io::Printer* printer) const;
};
} // namespace java

View file

@ -739,6 +739,9 @@ bool Parser::ParseSyntaxIdentifier(const FileDescriptorProto* file,
bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
const LocationRecorder& root_location) {
// Maximum depth allowed by the DescriptorPool.
recursion_depth_ = internal::cpp::MaxMessageDeclarationNestingDepth();
if (TryConsumeEndOfDeclaration(";", nullptr)) {
// empty statement; ignore
return true;
@ -753,8 +756,6 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
LocationRecorder location(root_location,
FileDescriptorProto::kMessageTypeFieldNumber,
file->message_type_size());
// Maximum depth allowed by the DescriptorPool.
recursion_depth_ = internal::cpp::MaxMessageDeclarationNestingDepth();
return ParseMessageDefinition(file->add_message_type(), visibility,
location, file);
} else if (LookingAt("enum")) {
@ -1145,6 +1146,17 @@ bool Parser::ParseMessageFieldNoLabel(
field->set_type_name(group->name());
if (LookingAt("{")) {
const auto undo_depth = absl::MakeCleanup([&] {
if (limit_group_nesting_) ++recursion_depth_;
});
if (limit_group_nesting_) {
if (--recursion_depth_ <= 0) {
RecordError("Reached maximum recursion limit for nested messages.");
return false;
}
}
DO(ParseMessageBlock(group, group_location, containing_file));
} else {
RecordError("Missing group body.");

View file

@ -572,6 +572,7 @@ class PROTOBUF_EXPORT Parser final {
SourceLocationTable* source_location_table_; // legacy
bool had_errors_;
bool require_syntax_identifier_;
bool limit_group_nesting_ = false;
bool stop_after_syntax_identifier_;
std::string syntax_identifier_;
Edition edition_ = Edition::EDITION_UNKNOWN;

View file

@ -2293,6 +2293,54 @@ TEST_F(ParseErrorTest, NestingIsLimitedWithoutCrashing) {
ExpectHasErrors(input(), error);
}
TEST_F(ParseErrorTest, NestedMessagesInExtendGroupAreLimited) {
std::string start =
"syntax = \"proto2\";\n"
"message Extendable { extensions 1 to max; }\n"
"extend Extendable {\n"
" optional group Ext = 1 {\n";
std::string end = " }\n}\n";
const auto add = [&] {
absl::StrAppend(&start, "message M {");
absl::StrAppend(&end, "}");
};
const auto input = [&] { return absl::StrCat(start, end); };
// The first ones work correctly.
// We test up to MaxMessageDeclarationNestingDepth() - 2 to be portable
// between configurations (flag on/off, OSS/Google3).
for (int i = 1; i < internal::cpp::MaxMessageDeclarationNestingDepth() - 1;
++i) {
add();
const std::string str = input();
SetupParser(str);
FileDescriptorProto proto;
proto.set_name("foo.proto");
EXPECT_TRUE(parser_->Parse(input_.get(), &proto)) << input();
EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
ASSERT_EQ("", error_collector_.text_);
DescriptorPool pool;
ASSERT_TRUE(pool.BuildFile(proto));
}
// The rest have parsing errors but they don't crash no matter how deep we
// make them.
const auto error = testing::HasSubstr(
"Reached maximum recursion limit for nested messages.");
// Add enough levels to trigger error in all configurations.
for (int i = 0; i < 5; ++i) {
add();
}
ExpectHasErrors(input(), error);
for (int i = 0; i < 1000; ++i) {
add();
}
ExpectHasErrors(input(), error);
}
TEST_F(ParseErrorTest, MissingFieldNumber) {
ExpectHasErrors(
"message TestMessage {\n"

View file

@ -27,6 +27,22 @@ cc_binary(
],
)
cc_library(
name = "names",
srcs = ["names.cc"],
hdrs = ["names.h"],
copts = COPTS,
strip_include_prefix = "/src",
visibility = ["//visibility:public"],
deps = [
"//src/google/protobuf",
"//src/google/protobuf:port",
"//src/google/protobuf/compiler:code_generator",
"@abseil-cpp//absl/log:absl_check",
"@abseil-cpp//absl/strings",
],
)
cc_library(
name = "python",
srcs = [
@ -47,6 +63,7 @@ cc_library(
"@com_github_grpc_grpc//tools/distrib/python/grpcio_tools:__subpackages__",
],
deps = [
":names",
"//src/google/protobuf",
"//src/google/protobuf:port",
"//src/google/protobuf/compiler:code_generator",

View file

@ -44,6 +44,7 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/python/helpers.h"
#include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/compiler/python/pyi_generator.h"
#include "google/protobuf/compiler/retention.h"
#include "google/protobuf/compiler/versions.h"
@ -62,19 +63,6 @@ namespace compiler {
namespace python {
namespace {
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
std::string ModuleAlias(absl::string_view filename) {
std::string module_name = ModuleName(filename);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
absl::StrReplaceAll({{"_", "__"}}, &module_name);
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
return module_name;
}
// Name of the class attribute where we store the Python
// descriptor.Descriptor instance for the generated class.
@ -311,7 +299,7 @@ bool Generator::Generate(const FileDescriptor* file,
if (GeneratingDescriptorProto()) {
printer_->Outdent();
}
std::string module_name = ModuleName(file->name());
std::string module_name = ModuleName(file);
if (!opensource_runtime_) {
module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -396,8 +384,8 @@ void Generator::PrintTopBoilerplate() const {
printer_->Print("\n\n");
}
std::string Generator::ImportModuleName(absl::string_view filename) const {
std::string module_name = ModuleName(filename);
std::string Generator::ImportModuleName(const FileDescriptor* file) const {
std::string module_name = ModuleName(file);
if (!opensource_runtime_) {
module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -409,10 +397,8 @@ std::string Generator::ImportModuleName(absl::string_view filename) const {
void Generator::PrintImports() const {
bool has_importlib = false;
for (int i = 0; i < file_->dependency_count(); ++i) {
absl::string_view filename = file_->dependency(i)->name();
std::string module_name = ImportModuleName(filename);
std::string module_alias = ModuleAlias(filename);
std::string module_name = ImportModuleName(file_->dependency(i));
std::string module_alias = ModuleAlias(file_->dependency(i));
if (ContainsPythonKeyword(module_name)) {
// If the module path contains a Python keyword, we have to quote the
// module name and import it using importlib. Otherwise the usual kind of
@ -446,8 +432,7 @@ void Generator::PrintImports() const {
// Print public imports.
for (int i = 0; i < file_->public_dependency_count(); ++i) {
std::string module_name =
ImportModuleName(file_->public_dependency(i)->name());
std::string module_name = ImportModuleName(file_->public_dependency(i));
printer_->Print("from $module$ import *\n", "module", module_name);
}
printer_->Print("\n");
@ -601,7 +586,7 @@ void Generator::PrintFileDescriptor() const {
if (file_->dependency_count() != 0) {
printer_->Print(",\ndependencies=[");
for (int i = 0; i < file_->dependency_count(); ++i) {
std::string module_alias = ModuleAlias(file_->dependency(i)->name());
std::string module_alias = ModuleAlias(file_->dependency(i));
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
module_alias);
}
@ -610,8 +595,7 @@ void Generator::PrintFileDescriptor() const {
if (file_->public_dependency_count() > 0) {
printer_->Print(",\npublic_dependencies=[");
for (int i = 0; i < file_->public_dependency_count(); ++i) {
std::string module_alias =
ModuleAlias(file_->public_dependency(i)->name());
std::string module_alias = ModuleAlias(file_->public_dependency(i));
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
module_alias);
}
@ -741,7 +725,7 @@ void Generator::PrintDescriptorKeyAndModuleName(
std::string name = ModuleLevelServiceDescriptorName(descriptor);
printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key",
kDescriptorKey, "descriptor_name", name);
std::string module_name = ModuleName(file_->name());
std::string module_name = ModuleName(file_);
if (!opensource_runtime_) {
module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -937,7 +921,7 @@ void Generator::PrintMessage(const Descriptor& message_descriptor,
m["descriptor_key"] = kDescriptorKey;
m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n");
std::string module_name = ModuleName(file_->name());
std::string module_name = ModuleName(file_);
if (!opensource_runtime_) {
module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -1275,7 +1259,7 @@ std::string Generator::ModuleLevelDescriptorName(
// We now have the name relative to its own module. Also qualify with
// the module name iff this descriptor is from a different .proto file.
if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
}
return name;
}
@ -1288,7 +1272,7 @@ std::string Generator::ModuleLevelMessageName(
const Descriptor& descriptor) const {
std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
}
return name;
}
@ -1300,7 +1284,7 @@ std::string Generator::ModuleLevelServiceDescriptorName(
std::string name = absl::StrCat("_", descriptor.name());
absl::AsciiStrToUpper(&name);
if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
}
return name;
}
@ -1521,8 +1505,8 @@ void Generator::FixOptionsForMessage(const Descriptor& descriptor,
void Generator::CopyPublicDependenciesAliases(
absl::string_view copy_from, const FileDescriptor* file) const {
for (int i = 0; i < file->public_dependency_count(); ++i) {
std::string module_name = ModuleName(file->public_dependency(i)->name());
std::string module_alias = ModuleAlias(file->public_dependency(i)->name());
std::string module_name = ModuleName(file->public_dependency(i));
std::string module_alias = ModuleAlias(file->public_dependency(i));
// There's no module alias in the dependent file if it was generated by
// an old protoc (less than 3.0.0-alpha-1). Use module name in this
// situation.

View file

@ -82,7 +82,7 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
private:
GeneratorOptions ParseParameter(absl::string_view parameter,
std::string* error) const;
std::string ImportModuleName(absl::string_view filename) const;
std::string ImportModuleName(const FileDescriptor* file) const;
void PrintImports() const;
template <typename DescriptorT>
std::string GetResolvedFeatures(const DescriptorT& descriptor) const;

View file

@ -14,11 +14,12 @@
#include "absl/log/absl_check.h"
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
@ -27,18 +28,6 @@ namespace protobuf {
namespace compiler {
namespace python {
// Returns the Python module name expected for a given .proto filename.
std::string ModuleName(absl::string_view filename) {
std::string basename = StripProto(filename);
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
return absl::StrCat(basename, "_pb2");
}
std::string StrippedModuleName(absl::string_view filename) {
std::string module_name = ModuleName(filename);
return module_name;
}
// Keywords reserved by the Python language.
const char* const kKeywords[] = {
"False", "None", "True", "and", "as", "assert",
@ -74,7 +63,7 @@ std::string ResolveKeyword(absl::string_view name) {
std::string GetFileName(const FileDescriptor* file_des,
absl::string_view suffix) {
std::string module_name = ModuleName(file_des->name());
std::string module_name = ModuleName(file_des);
std::string filename = module_name;
absl::StrReplaceAll({{".", "/"}}, &filename);
absl::StrAppend(&filename, suffix);

View file

@ -10,18 +10,18 @@
#include <string>
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace python {
std::string ModuleName(absl::string_view filename);
std::string StrippedModuleName(absl::string_view filename);
bool ContainsPythonKeyword(absl::string_view module_name);
bool IsPythonKeyword(absl::string_view name);
std::string ResolveKeyword(absl::string_view name);
@ -40,4 +40,6 @@ std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__

View file

@ -0,0 +1,45 @@
#include "google/protobuf/compiler/python/names.h"
#include <string>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/code_generator.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace python {
// Returns the Python module name expected for a given .proto filename.
std::string ModuleName(const FileDescriptor* file) {
std::string basename = StripProto(file->name());
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
return absl::StrCat(basename, "_pb2");
}
std::string StrippedModuleName(const FileDescriptor* file) {
std::string module_name = ModuleName(file);
return module_name;
}
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
std::string ModuleAlias(const FileDescriptor* file) {
std::string module_name = ModuleName(file);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
absl::StrReplaceAll({{"_", "__"}}, &module_name);
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
return module_name;
}
} // namespace python
} // namespace compiler
} // namespace protobuf
} // namespace google

View file

@ -0,0 +1,36 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
#define GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
#include <string>
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
class FileDescriptor;
namespace compiler {
namespace python {
// Returns the Python module name expected for a given .proto filename.
PROTOC_EXPORT std::string ModuleName(const FileDescriptor* file);
// Returns the stripped Python module name expected for a given .proto filename.
PROTOC_EXPORT std::string StrippedModuleName(const FileDescriptor* file);
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
PROTOC_EXPORT std::string ModuleAlias(const FileDescriptor* file);
} // namespace python
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__

View file

@ -24,6 +24,7 @@
#include "absl/synchronization/mutex.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/python/helpers.h"
#include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
@ -45,7 +46,7 @@ std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
std::string module_alias;
const absl::string_view filename = descriptor.file()->name();
if (import_map_.find(filename) == import_map_.end()) {
std::string module_name = ModuleName(descriptor.file()->name());
std::string module_name = ModuleName(descriptor.file());
std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.');
module_alias = absl::StrCat("_", tokens.back());
} else {
@ -151,7 +152,7 @@ void PyiGenerator::PrintImportForDescriptor(
const FileDescriptor& desc, absl::flat_hash_set<std::string>* seen_aliases,
bool* has_importlib) const {
const absl::string_view filename = desc.name();
std::string module_name_owned = StrippedModuleName(filename);
std::string module_name_owned = StrippedModuleName(&desc);
absl::string_view module_name(module_name_owned);
size_t last_dot_pos = module_name.rfind('.');
std::string alias = absl::StrCat("_", module_name.substr(last_dot_pos + 1));
@ -296,7 +297,7 @@ void PyiGenerator::PrintImports() const {
// Public imports
for (int i = 0; i < file_->public_dependency_count(); ++i) {
const FileDescriptor* public_dep = file_->public_dependency(i);
std::string module_name = StrippedModuleName(public_dep->name());
std::string module_name = StrippedModuleName(public_dep);
// Top level messages in public imports
for (int i = 0; i < public_dep->message_type_count(); ++i) {
printer_->Print(
@ -404,7 +405,7 @@ std::string PyiGenerator::GetFieldType(
std::string name = ModuleLevelName(*field_des.message_type());
if ((containing_des.containing_type() != nullptr &&
name == containing_des.name())) {
std::string module = ModuleName(field_des.file()->name());
std::string module = ModuleName(field_des.file());
name = absl::StrCat(module, ".", name);
}
return name;

View file

@ -114,8 +114,7 @@ void GenerateRs(Context& ctx, const FieldDescriptor& extension,
}
} else {
std::string mini_descriptor =
pool.FindExtensionByName(std::string(extension.full_name()).c_str())
.MiniDescriptorEncode();
pool.FindExtensionByName(extension.full_name()).MiniDescriptorEncode();
std::string extendee = RsTypePath(ctx, *extension.containing_type());
std::string number = absl::StrCat(extension.number());

View file

@ -323,8 +323,7 @@ bool RustGenerator::Generate(const FileDescriptor* file,
for (int i = 0; i < file->enum_type_count(); ++i) {
auto& enum_ = *file->enum_type(i);
GenerateEnumDefinition(ctx, enum_,
pool.FindEnumByName(enum_.full_name().data()));
GenerateEnumDefinition(ctx, enum_, pool.FindEnumByName(enum_.full_name()));
ctx.printer().PrintRaw("\n");
if (ctx.is_cpp()) {

View file

@ -224,8 +224,7 @@ void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg,
if (scc.GetRepresentative() == &msg) {
for (const Descriptor* d : scc.descriptors) {
std::string mini_descriptor =
pool.FindMessageByName(d->full_name().data())
.MiniDescriptorEncode();
pool.FindMessageByName(d->full_name()).MiniDescriptorEncode();
ctx.Emit({{"name", RsTypePath(ctx, *d)},
{"minitable_symbol_name",
QualifiedUpbMiniTableName(ctx, *d)},
@ -237,8 +236,8 @@ void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg,
)rs");
}
for (const Descriptor* d : scc.descriptors) {
UpbMiniTableLinking(
ctx, *d, pool.FindMessageByName(d->full_name().data()), scc);
UpbMiniTableLinking(ctx, *d,
pool.FindMessageByName(d->full_name()), scc);
}
} else {
ctx.Emit(
@ -406,7 +405,7 @@ void GenerateRs(Context& ctx, const Descriptor& msg, const upb::DefPool& pool) {
return;
}
upb::MessageDefPtr upb_msg = pool.FindMessageByName(msg.full_name().data());
upb::MessageDefPtr upb_msg = pool.FindMessageByName(msg.full_name());
ctx.Emit(
{
// There's also ${$/$}$-style begin and end tokens, but those might

View file

@ -88,6 +88,7 @@
#include "google/protobuf/message.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/naming_style.h"
#include "google/protobuf/offset_ptr.h"
#include "google/protobuf/option_interpreter.h"
#include "google/protobuf/parse_context.h"
#include "google/protobuf/port.h"
@ -421,7 +422,7 @@ class FlatAllocatorImpl {
// TODO: Remove the NULL terminators to save memory and simplify
// the code.
absl::optional<internal::DescriptorNames> CreateDescriptorNames(
absl::optional<internal::DescriptorNames::Input> CreateDescriptorNames(
std::initializer_list<absl::string_view> bytes,
std::initializer_list<size_t> sizes) {
for (size_t size : sizes) {
@ -439,7 +440,7 @@ class FlatAllocatorImpl {
memcpy(out, b.data(), b.size());
out += b.size();
}
auto res = internal::DescriptorNames(out);
auto res = internal::DescriptorNames::Input{out};
for (size_t size : sizes) {
uint16_t size16 = static_cast<uint16_t>(size);
memcpy(out, &size16, sizeof(size16));
@ -452,7 +453,7 @@ class FlatAllocatorImpl {
PlanArray<char>(internal::DescriptorNames::AllocationSizeForSimpleNames(
full_name_size));
}
absl::optional<internal::DescriptorNames> AllocateEntityNames(
absl::optional<internal::DescriptorNames::Input> AllocateEntityNames(
absl::string_view scope, absl::string_view name) {
static constexpr absl::string_view kNullChar("\0", 1);
if (scope.empty()) {
@ -465,7 +466,7 @@ class FlatAllocatorImpl {
}
}
internal::DescriptorNames AllocatePlaceholderNames(
internal::DescriptorNames::Input AllocatePlaceholderNames(
absl::string_view full_name, size_t name_size) {
static constexpr absl::string_view kNullChar("\0", 1);
auto out = CreateDescriptorNames({full_name, kNullChar},
@ -533,7 +534,7 @@ class FlatAllocatorImpl {
PlanArray<char>(total_bytes);
}
absl::optional<internal::DescriptorNames> AllocateFieldNames(
absl::optional<internal::DescriptorNames::Input> AllocateFieldNames(
const absl::string_view name, const absl::string_view scope,
const std::string* opt_json_name) {
ABSL_CHECK(has_allocated());
@ -856,38 +857,11 @@ struct ParentNameQueryBase {
}
};
// A 32-bit "offset" based pointer used for hash tables below.
// The base pointer is the base of the FlatAllocation, which is the same for
// the objects in a single FileDescriptorTables (except the ones allocated later
// on demand, like unknown_enum_values_by_number_).
// This halves the size of the tables in 64-bit builds.
template <typename T>
struct OffsetT {
OffsetT(T* ptr, absl::string_view flat_buffer) {
ptrdiff_t diff = reinterpret_cast<const char*>(ptr) -
reinterpret_cast<const char*>(flat_buffer.data());
// Verify the pointer is actually in bounds of the buffer.
ABSL_DCHECK(static_cast<const void*>(ptr) >= flat_buffer.data() &&
static_cast<const void*>(ptr) <
flat_buffer.data() + flat_buffer.size());
ABSL_DCHECK_GE(diff, 0);
ABSL_DCHECK_LE(diff, std::numeric_limits<uint32_t>::max());
value = static_cast<uint32_t>(diff);
}
T* Resolve(const void* base_ptr) const {
return const_cast<T*>(reinterpret_cast<const T*>(
reinterpret_cast<const char*>(base_ptr) + value));
}
uint32_t value;
};
template <typename T>
const T& ResolveSymbol(const T& v, const void*) {
return v;
}
Symbol ResolveSymbol(OffsetT<const internal::SymbolBase> v,
Symbol ResolveSymbol(internal::BasePointer<const internal::SymbolBase, false> v,
const void* base_ptr) {
return Symbol(v.Resolve(base_ptr));
}
@ -916,7 +890,8 @@ struct SymbolByParentHash {
const void* base_ptr;
size_t operator()(OffsetT<const internal::SymbolBase> v) const {
size_t operator()(
internal::BasePointer<const internal::SymbolBase, false> v) const {
return (*this)(Symbol(v.Resolve(base_ptr)));
}
@ -930,8 +905,9 @@ struct SymbolByParentEq {
const void* base_ptr;
bool operator()(OffsetT<const internal::SymbolBase> offset,
const ParentNameFieldQuery& query) const {
bool operator()(
internal::BasePointer<const internal::SymbolBase, false> offset,
const ParentNameFieldQuery& query) const {
Symbol symbol = ResolveSymbol(offset, base_ptr);
const FieldDescriptor* field = symbol.field_descriptor();
return field != nullptr && !field->is_extension() &&
@ -945,9 +921,9 @@ struct SymbolByParentEq {
ResolveSymbol(b, base_ptr).parent_name_key();
}
};
using SymbolsByParentSet =
absl::flat_hash_set<OffsetT<const internal::SymbolBase>, SymbolByParentHash,
SymbolByParentEq>;
using SymbolsByParentSet = absl::flat_hash_set<
internal::BasePointer<const internal::SymbolBase, false>,
SymbolByParentHash, SymbolByParentEq>;
template <typename Projection>
struct ProjectedHash {
@ -1059,8 +1035,8 @@ using EnumValuesByNumberSet =
ParentNumberEq>;
template <typename T>
std::pair<const void*, int> ObjectToParentNumber(OffsetT<T> offset,
const void* base_ptr) {
std::pair<const void*, int> ObjectToParentNumber(
internal::BasePointer<T, false> offset, const void* base_ptr) {
return ObjectToParentNumber(offset.Resolve(base_ptr));
}
@ -1088,11 +1064,11 @@ struct ParentNumberEqOffsetPtr {
};
using EnumValuesByNumberSetOffsetPtr =
absl::flat_hash_set<OffsetT<const EnumValueDescriptor>,
absl::flat_hash_set<internal::BasePointer<const EnumValueDescriptor, false>,
ParentNumberHashOffsetPtr, ParentNumberEqOffsetPtr>;
using FieldsByNumberSet =
absl::flat_hash_set<OffsetT<const FieldDescriptor>,
absl::flat_hash_set<internal::BasePointer<const FieldDescriptor, false>,
ParentNumberHashOffsetPtr, ParentNumberEqOffsetPtr>;
// This is a map rather than a hash-map, since we use it to iterate
@ -1313,7 +1289,8 @@ class FileDescriptorTables {
const FileDescriptorTables* tables);
void FieldsByCamelcaseNamesLazyInitInternal() const;
Symbol Resolve(OffsetT<const internal::SymbolBase> v) const {
Symbol Resolve(
internal::BasePointer<const internal::SymbolBase, false> v) const {
return Symbol(v.Resolve(flat_buffer_.data()));
}
@ -1931,7 +1908,7 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
absl::StrCat(parent->full_name(), ".", enum_value_name));
result->number_ = number;
result->type_ = parent;
result->options_ = &EnumValueOptions::default_instance();
result->options_ = nullptr;
unknown_enum_values_by_number_.insert(result);
return result;
}
@ -1973,7 +1950,8 @@ bool FileDescriptorTables::AddAliasUnderParent(const void* parent,
ABSL_DCHECK_EQ(name, symbol.parent_name_key().second);
ABSL_DCHECK_EQ(parent, symbol.parent_name_key().first);
return symbols_by_parent_
.insert(OffsetT<const internal::SymbolBase>(symbol.ptr(), flat_buffer_))
.insert(internal::BasePointer<const internal::SymbolBase, false>(
symbol.ptr(), flat_buffer_.data()))
.second;
}
@ -2002,7 +1980,8 @@ bool FileDescriptorTables::AddFieldByNumber(FieldDescriptor* field) {
}
return fields_by_number_
.insert(OffsetT<const FieldDescriptor>(field, flat_buffer_))
.insert(internal::BasePointer<const FieldDescriptor, false>(
field, flat_buffer_.data()))
.second;
}
@ -2014,7 +1993,8 @@ bool FileDescriptorTables::AddEnumValueByNumber(EnumValueDescriptor* value) {
static_cast<int64_t>(base) + value->type()->sequential_value_limit_)
return true;
return enum_values_by_number_
.insert(OffsetT<const EnumValueDescriptor>(value, flat_buffer_))
.insert(internal::BasePointer<const EnumValueDescriptor, false>(
value, flat_buffer_.data()))
.second;
}
@ -2864,6 +2844,18 @@ bool DescriptorPool::TryFindExtensionInFallbackDatabase(
// ===================================================================
#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
const TYPE& CLASS::options() const { return *options_; }
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
bool FieldDescriptor::is_map_message_type() const {
return message_type()->options().map_entry();
}
@ -3436,9 +3428,10 @@ std::string FileDescriptor::DebugStringWithOptions(
comment_printer.AddPreComment(&contents);
absl::flat_hash_set<int> public_dependencies(
public_dependencies_, public_dependencies_ + public_dependency_count_);
public_dependencies_.get(),
public_dependencies_ + public_dependency_count_);
absl::flat_hash_set<int> weak_dependencies(
weak_dependencies_, weak_dependencies_ + weak_dependency_count_);
weak_dependencies_.get(), weak_dependencies_ + weak_dependency_count_);
for (int i = 0; i < dependency_count(); i++) {
if (public_dependencies.contains(i)) {
@ -4755,10 +4748,10 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
placeholder_enum->all_names_ = alloc.AllocatePlaceholderNames(
placeholder_full_name, placeholder_name.size());
placeholder_enum->all_names_.SetPayload(alloc.AllocatePlaceholderNames(
placeholder_full_name, placeholder_name.size()));
placeholder_enum->file_ = placeholder_file;
placeholder_enum->options_ = &EnumOptions::default_instance();
placeholder_enum->options_ = nullptr;
placeholder_enum->proto_features_ = &FeatureSet::default_instance();
placeholder_enum->merged_features_ = &FeatureSet::default_instance();
placeholder_enum->is_placeholder_ = true;
@ -4783,7 +4776,7 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
placeholder_value->number_ = 0;
placeholder_value->type_ = placeholder_enum;
placeholder_value->options_ = &EnumValueOptions::default_instance();
placeholder_value->options_ = nullptr;
return Symbol(placeholder_enum);
} else {
@ -4794,10 +4787,10 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
memset(static_cast<void*>(placeholder_message), 0,
sizeof(*placeholder_message));
placeholder_message->all_names_ = alloc.AllocatePlaceholderNames(
placeholder_full_name, placeholder_name.size());
placeholder_message->all_names_.SetPayload(alloc.AllocatePlaceholderNames(
placeholder_full_name, placeholder_name.size()));
placeholder_message->file_ = placeholder_file;
placeholder_message->options_ = &MessageOptions::default_instance();
placeholder_message->options_ = nullptr;
placeholder_message->proto_features_ = &FeatureSet::default_instance();
placeholder_message->merged_features_ = &FeatureSet::default_instance();
placeholder_message->is_placeholder_ = true;
@ -4844,7 +4837,7 @@ FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld(
placeholder->name_ = alloc.AllocateStrings(name);
placeholder->package_ = &internal::GetEmptyString();
placeholder->pool_ = this;
placeholder->options_ = &FileOptions::default_instance();
placeholder->options_ = nullptr;
placeholder->proto_features_ = &FeatureSet::default_instance();
placeholder->merged_features_ = &FeatureSet::default_instance();
placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
@ -5207,20 +5200,20 @@ void internal::DescriptorBuilder::PostProcessFieldFeatures(
if (field.options_->has_ctype()) {
field.legacy_proto_ctype_ = field.options_->ctype();
const_cast<FieldOptions*>( // NOLINT(google3-runtime-proto-const-cast)
field.options_)
field.options_.get())
->clear_ctype();
}
}
// A common pattern: We want to convert a repeated field in the descriptor
// to an array of values, calling some method to build each value.
#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \
OUTPUT->NAME##s_ = alloc.AllocateArray< \
typename std::remove_pointer<decltype(OUTPUT->NAME##s_)>::type>( \
INPUT.NAME##_size()); \
for (int i = 0; i < INPUT.NAME##_size(); i++) { \
METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc); \
#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \
OUTPUT->NAME##s_ = \
alloc.AllocateArray<decltype(OUTPUT->NAME##s_)::value_type>( \
INPUT.NAME##_size()); \
for (int i = 0; i < INPUT.NAME##_size(); i++) { \
METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc); \
}
PROTOBUF_NOINLINE void internal::DescriptorBuilder::AddRecursiveImportError(
@ -5840,9 +5833,8 @@ FileDescriptor* internal::DescriptorBuilder::BuildFileImpl(
auto cleanup = DisableTracking();
internal::VisitDescriptors(
*result, proto, [&](const auto& descriptor, const auto& proto) {
using OptionsT =
typename std::remove_const<typename std::remove_pointer<
decltype(descriptor.options_)>::type>::type;
using OptionsT = std::remove_const_t<
std::decay_t<decltype(*descriptor.options_)>>;
using DescriptorT =
typename std::remove_const<typename std::remove_reference<
decltype(descriptor)>::type>::type;
@ -5850,7 +5842,7 @@ FileDescriptor* internal::DescriptorBuilder::BuildFileImpl(
ResolveFeatures(
proto, const_cast<DescriptorT*>(&descriptor),
const_cast< // NOLINT(google3-runtime-proto-const-cast)
OptionsT*>(descriptor.options_),
OptionsT*>(+descriptor.options_),
alloc);
});
}
@ -6002,7 +5994,8 @@ void internal::DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
internal::FlatAllocator& alloc) {
const absl::string_view scope =
(parent == nullptr) ? file_->package() : parent->full_name();
result->all_names_ = AllocateNameStrings(scope, proto.name(), proto, alloc);
result->all_names_.SetPayload(
AllocateNameStrings(scope, proto.name(), proto, alloc));
ValidateSymbolName(proto.name(), result->full_name(), proto);
result->file_ = file_;
@ -6046,7 +6039,6 @@ void internal::DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
if (recursion_depth_ <= 0) {
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
"Reached maximum recursion limit for nested messages.");
result->nested_types_ = nullptr;
result->nested_type_count_ = 0;
return;
}
@ -6287,12 +6279,13 @@ void internal::DescriptorBuilder::BuildFieldOrExtension(
if (auto names = alloc.AllocateFieldNames(
proto.name(), scope,
proto.has_json_name() ? &proto.json_name() : nullptr)) {
result->all_names_ = *names;
result->all_names_.SetPayload(*names);
} else {
AddError(
scope.empty() ? proto.name() : absl::StrCat(scope, ".", proto.name()),
proto, DescriptorPool::ErrorCollector::NAME, "Name too long.");
result->all_names_ = alloc.AllocateEntityNames("", "unknown").value();
result->all_names_.SetPayload(
alloc.AllocateEntityNames("", "unknown").value());
}
ValidateSymbolName(proto.name(), result->full_name(), proto);
@ -6637,15 +6630,14 @@ void internal::DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
Descriptor* parent,
OneofDescriptor* result,
internal::FlatAllocator& alloc) {
result->all_names_ =
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc);
result->all_names_.SetPayload(
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc));
ValidateSymbolName(proto.name(), result->full_name(), proto);
result->containing_type_ = parent;
// We need to fill these in later.
result->field_count_ = 0;
result->fields_ = nullptr;
// Copy options.
AllocateOptions(proto, result, OneofDescriptorProto::kOptionsFieldNumber,
@ -6813,7 +6805,8 @@ void internal::DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
const absl::string_view scope =
(parent == nullptr) ? file_->package() : parent->full_name();
result->all_names_ = AllocateNameStrings(scope, proto.name(), proto, alloc);
result->all_names_.SetPayload(
AllocateNameStrings(scope, proto.name(), proto, alloc));
ValidateSymbolName(proto.name(), result->full_name(), proto);
result->file_ = file_;
result->containing_type_ = parent;
@ -6995,8 +6988,8 @@ void internal::DescriptorBuilder::BuildEnumValue(
void internal::DescriptorBuilder::BuildService(
const ServiceDescriptorProto& proto, const void* /* dummy */,
ServiceDescriptor* result, internal::FlatAllocator& alloc) {
result->all_names_ =
AllocateNameStrings(file_->package(), proto.name(), proto, alloc);
result->all_names_.SetPayload(
AllocateNameStrings(file_->package(), proto.name(), proto, alloc));
result->file_ = file_;
ValidateSymbolName(proto.name(), result->full_name(), proto);
@ -7014,8 +7007,8 @@ void internal::DescriptorBuilder::BuildMethod(
const MethodDescriptorProto& proto, const ServiceDescriptor* parent,
MethodDescriptor* result, internal::FlatAllocator& alloc) {
result->service_ = parent;
result->all_names_ =
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc);
result->all_names_.SetPayload(
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc));
ValidateSymbolName(proto.name(), result->full_name(), proto);

View file

@ -58,6 +58,7 @@
#include "absl/synchronization/mutex.h"
#include "google/protobuf/descriptor_lite.h" // IWYU pragma: export
#include "google/protobuf/extension_set.h"
#include "google/protobuf/offset_ptr.h"
#include "google/protobuf/port.h"
// Must be included last.
@ -267,7 +268,18 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED DescriptorNames {
public:
// Uninitialized, to support `= default` of descriptor types.
DescriptorNames() = default;
explicit DescriptorNames(const char* payload) : payload_(payload) {}
// We can't construct temporaries because of the offset_ptr, so avoid this.
#ifndef SWIG
DescriptorNames(const DescriptorNames&) = delete;
DescriptorNames& operator=(const DescriptorNames&) = delete;
#endif
struct Input {
const char* value;
};
void SetPayload(Input value) { payload_ = value.value; }
// The full name is just before `payload_`, and the name is the suffix of it.
// We don't need a special offset for them.
@ -309,7 +321,7 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED DescriptorNames {
return absl::string_view(payload_ - offset, size);
}
const char* payload_;
internal::NonnullOffsetPtr<const char> payload_;
};
class FlatAllocator;
@ -822,25 +834,20 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
// sequentially numbered fields in a message.
uint16_t sequential_field_limit_;
int field_count_;
internal::DescriptorNames all_names_;
const FileDescriptor* file_;
const Descriptor* containing_type_;
const MessageOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// These arrays are separated from their sizes to minimize padding on 64-bit.
FieldDescriptor* fields_;
OneofDescriptor* oneof_decls_;
Descriptor* nested_types_;
EnumDescriptor* enum_types_;
ExtensionRange* extension_ranges_;
FieldDescriptor* extensions_;
ReservedRange* reserved_ranges_;
const std::string** reserved_names_;
internal::NonnullOffsetPtr<const FileDescriptor> file_;
internal::NullableOffsetPtr<const Descriptor> containing_type_;
internal::OffsetProtoPtr<const MessageOptions> options_;
internal::NonnullOffsetPtr<FieldDescriptor> fields_;
internal::NonnullOffsetPtr<OneofDescriptor> oneof_decls_;
internal::NonnullOffsetPtr<Descriptor> nested_types_;
internal::NonnullOffsetPtr<EnumDescriptor> enum_types_;
internal::NonnullOffsetPtr<ExtensionRange> extension_ranges_;
internal::NonnullOffsetPtr<FieldDescriptor> extensions_;
internal::NonnullOffsetPtr<ReservedRange> reserved_ranges_;
internal::NonnullOffsetPtr<const std::string*> reserved_names_;
int field_count_;
int oneof_decl_count_;
int real_oneof_decl_count_;
int nested_type_count_;
@ -850,6 +857,9 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
int reserved_range_count_;
int reserved_name_count_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
// and update them to initialize the field.
@ -867,7 +877,8 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
friend class SymbolChecker;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 160);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 112);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor::ExtensionRange, 40);
// Describes a single field of a message. To get the descriptor for a given
// field, first get the Descriptor for the message in which it is defined,
@ -1273,6 +1284,9 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
CppRepeatedType CalculateCppRepeatedType() const;
static void TypeOnceInit(const FieldDescriptor* to_init);
void InternalTypeOnceInit() const;
bool has_default_value_ : 1;
bool proto3_optional_ : 1;
// Whether the user has specified the json_name field option in the .proto
@ -1308,25 +1322,32 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
// and its indices above.
int number_;
internal::DescriptorNames all_names_;
const FileDescriptor* file_;
internal::NonnullOffsetPtr<const FileDescriptor> file_;
union {
internal::NonnullOffsetPtr<const OneofDescriptor> containing_oneof;
internal::NullableOffsetPtr<const Descriptor> extension_scope;
} scope_;
internal::OffsetProtoPtr<const FieldOptions> options_;
// The once_flag is followed by a NUL terminated string for the type name and
// enum default value (or empty string if no default enum).
// Allocated separately, so no OffsetPtr.
absl::once_flag* type_once_;
static void TypeOnceInit(const FieldDescriptor* to_init);
void InternalTypeOnceInit() const;
// Extensions' containing type can be from a different file, so no OffsetPtr.
const Descriptor* containing_type_;
union {
const OneofDescriptor* containing_oneof;
const Descriptor* extension_scope;
} scope_;
union {
// Types can be from different files so no OffsetPtr.
mutable const Descriptor* message_type;
mutable const EnumDescriptor* enum_type;
} type_descriptor_;
const FieldOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
// descriptor.cc and update them to initialize the field.
@ -1362,7 +1383,7 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
friend class OneofDescriptor;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 88);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 72);
// Describes a oneof defined in a message type.
class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
@ -1451,11 +1472,12 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
int field_count_;
internal::DescriptorNames all_names_;
const Descriptor* containing_type_;
const OneofOptions* options_;
internal::NonnullOffsetPtr<const Descriptor> containing_type_;
internal::OffsetProtoPtr<const OneofOptions> options_;
internal::NonnullOffsetPtr<const FieldDescriptor> fields_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
const FieldDescriptor* fields_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
@ -1469,7 +1491,7 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
friend class Reflection;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 56);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 40);
// Describes an enum type defined in a .proto file. To get the EnumDescriptor
// for a generated enum type, call TypeName_descriptor(). Use DescriptorPool
@ -1663,20 +1685,20 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
// sequentially numbered labels in an enum.
int16_t sequential_value_limit_;
int value_count_;
internal::DescriptorNames all_names_;
const FileDescriptor* file_;
const Descriptor* containing_type_;
const EnumOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
EnumValueDescriptor* values_;
internal::NonnullOffsetPtr<const FileDescriptor> file_;
internal::NullableOffsetPtr<const Descriptor> containing_type_;
internal::OffsetProtoPtr<const EnumOptions> options_;
internal::NonnullOffsetPtr<EnumValueDescriptor> values_;
internal::NonnullOffsetPtr<EnumDescriptor::ReservedRange> reserved_ranges_;
internal::NonnullOffsetPtr<const std::string*> reserved_names_;
int value_count_;
int reserved_range_count_;
int reserved_name_count_;
EnumDescriptor::ReservedRange* reserved_ranges_;
const std::string** reserved_names_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<EnumDescriptor>() and AllocateArray<EnumDescriptor>() in
@ -1694,7 +1716,7 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
friend class Reflection;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 88);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 64);
// Describes an individual enum constant of a particular type. To get the
// EnumValueDescriptor for a given enum value, first get the EnumDescriptor
@ -1789,9 +1811,11 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
// We keep the old-style std::string payload to support `NameOfEnumAsString`
// Once we start migrating Enum_Name functions to string_view we can switch
// this too.
const std::string* all_names_;
internal::NonnullOffsetPtr<const std::string> all_names_;
internal::OffsetProtoPtr<const EnumValueOptions> options_;
// Type can be from a different allocation when creating enums via
// `FindEnumValueByNumberCreatingIfUnknown`.
const EnumDescriptor* type_;
const EnumValueOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// IMPORTANT: If you add a new field, make sure to search for all instances
@ -1807,7 +1831,7 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
friend class Reflection;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 48);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 40);
// Describes an RPC service. Use DescriptorPool to construct your own
// descriptors.
@ -1897,12 +1921,14 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
void GetLocationPath(std::vector<int>* output) const;
internal::DescriptorNames all_names_;
const FileDescriptor* file_;
const ServiceOptions* options_;
internal::NonnullOffsetPtr<const FileDescriptor> file_;
internal::OffsetProtoPtr<const ServiceOptions> options_;
internal::NonnullOffsetPtr<MethodDescriptor> methods_;
int method_count_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
MethodDescriptor* methods_;
int method_count_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<ServiceDescriptor>() and AllocateArray<ServiceDescriptor>() in
// descriptor.cc and update them to initialize the field.
@ -1914,7 +1940,7 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
friend class MethodDescriptor;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 64);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 40);
// Describes an individual service method. To obtain a MethodDescriptor given
// a service, first get its ServiceDescriptor, then call
@ -2007,10 +2033,13 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
bool client_streaming_;
bool server_streaming_;
internal::DescriptorNames all_names_;
const ServiceDescriptor* service_;
internal::NonnullOffsetPtr<const ServiceDescriptor> service_;
internal::OffsetProtoPtr<const MethodOptions> options_;
mutable internal::LazyDescriptor input_type_;
mutable internal::LazyDescriptor output_type_;
const MethodOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
// IMPORTANT: If you add a new field, make sure to search for all instances
@ -2023,7 +2052,7 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
friend class ServiceDescriptor;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 80);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 64);
// Describes a whole .proto file. To get the FileDescriptor for a compiled-in
// file, get the descriptor for something defined in that file and call
@ -2199,19 +2228,6 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
friend class FileDescriptorLegacy;
typedef FileOptions OptionsType;
bool is_placeholder_;
// Indicates the FileDescriptor is completed building. Used to verify
// that type accessor functions that can possibly build a dependent file
// aren't called during the process of building the file.
bool finished_building_;
// This one is here to fill the padding.
int extension_count_;
const std::string* name_;
const std::string* package_;
const DescriptorPool* pool_;
Edition edition_;
// Returns edition of this file. For legacy proto2/proto3 files, special
// EDITION_PROTO2 and EDITION_PROTO3 values are used.
Edition edition() const;
@ -2223,12 +2239,16 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
const FeatureSet& features() const { return *merged_features_; }
friend class internal::InternalFeatureHelper;
// dependencies_once_ contain a once_flag followed by N NUL terminated
// strings. Dependencies that do not need to be loaded will be empty. ie just
// {'\0'}
absl::once_flag* dependencies_once_;
static void DependenciesOnceInit(const FileDescriptor* to_init);
void InternalDependenciesOnceInit() const;
bool is_placeholder_;
// Indicates the FileDescriptor is completed building. Used to verify
// that type accessor functions that can possibly build a dependent file
// aren't called during the process of building the file.
bool finished_building_;
// This one is here to fill the padding.
int extension_count_;
internal::NonnullOffsetPtr<const std::string> name_;
Edition edition_;
// These are arranged to minimize padding on 64-bit.
int dependency_count_;
@ -2239,21 +2259,34 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
int enum_type_count_;
int service_count_;
mutable const FileDescriptor** dependencies_;
int* public_dependencies_;
int* weak_dependencies_;
absl::string_view* option_dependencies_;
internal::NonnullOffsetPtr<const FileDescriptor*> dependencies_;
internal::NonnullOffsetPtr<int> public_dependencies_;
internal::NonnullOffsetPtr<int> weak_dependencies_;
internal::NonnullOffsetPtr<absl::string_view> option_dependencies_;
internal::NonnullOffsetPtr<Descriptor> message_types_;
internal::NonnullOffsetPtr<EnumDescriptor> enum_types_;
internal::NonnullOffsetPtr<ServiceDescriptor> services_;
internal::NonnullOffsetPtr<FieldDescriptor> extensions_;
internal::OffsetProtoPtr<const FileOptions> options_;
internal::OffsetProtoPtr<const SourceCodeInfo> source_code_info_;
const std::string* package_;
// dependencies_once_ contain a once_flag followed by N NUL terminated
// strings. Dependencies that do not need to be loaded will be empty. ie just
// {'\0'}
absl::once_flag* dependencies_once_;
static void DependenciesOnceInit(const FileDescriptor* to_init);
void InternalDependenciesOnceInit() const;
const DescriptorPool* pool_;
Descriptor* message_types_;
EnumDescriptor* enum_types_;
ServiceDescriptor* services_;
FieldDescriptor* extensions_;
const FileOptions* options_;
const FeatureSet* proto_features_;
const FeatureSet* merged_features_;
const FileDescriptorTables* tables_;
const SourceCodeInfo* source_code_info_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
@ -2272,7 +2305,7 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
friend class ServiceDescriptor;
};
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 184);
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 136);
#ifndef SWIG
enum class ExtDeclEnforcementLevel : uint8_t {
@ -2903,9 +2936,6 @@ class PROTOBUF_EXPORT DescriptorPool {
return FIELD##s_ + index; \
}
#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
inline const TYPE& CLASS::options() const { return *options_; }
PROTOBUF_DEFINE_NAME_ACCESSOR(Descriptor)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
@ -2936,7 +2966,6 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range,
const Descriptor::ReservedRange*)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
PROTOBUF_DEFINE_NAME_ACCESSOR(FieldDescriptor)
@ -2944,7 +2973,6 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_json_name, bool)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32_t, int32_t)
@ -2960,7 +2988,6 @@ PROTOBUF_DEFINE_NAME_ACCESSOR(OneofDescriptor)
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(OneofDescriptor, field, const FieldDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
PROTOBUF_DEFINE_NAME_ACCESSOR(EnumDescriptor)
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
@ -2968,7 +2995,6 @@ PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
const EnumValueDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_range_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, reserved_range,
@ -2983,18 +3009,15 @@ inline absl::string_view EnumValueDescriptor::full_name() const {
}
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
PROTOBUF_DEFINE_NAME_ACCESSOR(ServiceDescriptor)
PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
const MethodDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
PROTOBUF_DEFINE_NAME_ACCESSOR(MethodDescriptor)
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
@ -3009,7 +3032,6 @@ PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
@ -3085,7 +3107,7 @@ inline absl::string_view FieldDescriptor::json_name() const {
inline const OneofDescriptor* FieldDescriptor::containing_oneof() const {
if (is_oneof_) {
auto* res = scope_.containing_oneof;
const OneofDescriptor* res = scope_.containing_oneof;
PROTOBUF_ASSUME(res != nullptr);
return res;
}

View file

@ -1372,7 +1372,7 @@ inline void* PROTOBUF_NONNULL FeatureSet::PlacementNew_(
return ::new (mem) FeatureSet(arena);
}
constexpr auto FeatureSet::InternalNewImpl_() {
return ::google::protobuf::internal::MessageCreator::ZeroInit(sizeof(FeatureSet), alignof(FeatureSet));
return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(FeatureSet), alignof(FeatureSet));
}
constexpr auto FeatureSet::InternalGenerateClassData_(
const MessageLite& prototype,

View file

@ -16361,114 +16361,7 @@ TEST_F(SourceLocationTest, GetSourceLocation) {
"rpc Method(A) returns (A.B);"));
}
TEST_F(SourceLocationTest, AggregateOptionSourceLocation) {
SourceLocation loc;
const FileDescriptor* file_desc =
ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
SourceCodePath base_path = {FileDescriptorProto::kServiceFieldNumber,
0,
ServiceDescriptorProto::kOptionsFieldNumber,
kCustomOptionFieldNumber,
0,
UninterpretedOption::kAggregateValueFieldNumber};
auto make_path = [&](std::initializer_list<int> sub) {
SourceCodePath path = base_path;
path.insert(path.end(), sub.begin(), sub.end());
return path;
};
// Verify what base_path matches directly (the entire aggregate block).
{
EXPECT_TRUE(file_desc->GetSourceLocation(base_path, &loc));
EXPECT_THAT(loc,
MatchesSubstring(kSourceLocationTestInput,
"{a:100, rep: [1, 2, 3], b_sub: {b: 200}}"));
}
// Path to "a" inside {a:100}
{
SourceCodePath path =
make_path({kAFieldNumber, UninterpretedOption::kNameFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "a"));
}
// Path to "100" inside {a:100}
{
SourceCodePath path = make_path(
{kAFieldNumber, UninterpretedOption::kPositiveIntValueFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "100"));
}
// Path to the name of the top-level option (test_svc_opt)
{
SourceCodePath path = {FileDescriptorProto::kServiceFieldNumber,
0,
ServiceDescriptorProto::kOptionsFieldNumber,
kCustomOptionFieldNumber,
0,
UninterpretedOption::kNameFieldNumber};
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc,
MatchesSubstring(kSourceLocationTestInput, "(test_svc_opt)"));
}
// Path to "1" inside {rep: [1, 2, 3]}
{
SourceCodePath path =
make_path({kRepFieldNumber, 0,
UninterpretedOption::kPositiveIntValueFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "1"));
}
// Path to "2" inside {rep: [1, 2, 3]}
{
SourceCodePath path =
make_path({kRepFieldNumber, 1,
UninterpretedOption::kPositiveIntValueFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "2"));
}
// Path to "3" inside {rep: [1, 2, 3]}
{
SourceCodePath path =
make_path({kRepFieldNumber, 2,
UninterpretedOption::kPositiveIntValueFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "3"));
}
// Path to "b_sub" inside {..., b_sub: {b: 200}}
{
SourceCodePath path =
make_path({kBSubFieldNumber, UninterpretedOption::kNameFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "b_sub"));
}
// Path to "b" inside {..., b_sub: {b: 200}}
{
SourceCodePath path = make_path(
{kBSubFieldNumber, UninterpretedOption::kAggregateValueFieldNumber,
kBFieldNumber, UninterpretedOption::kNameFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "b"));
}
// Path to "200" inside {..., b_sub: {b: 200}}
{
SourceCodePath path = make_path(
{kBSubFieldNumber, UninterpretedOption::kAggregateValueFieldNumber,
kBFieldNumber, UninterpretedOption::kDoubleValueFieldNumber});
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "200"));
}
}
// TODO: b/168903973 - Remove once we update the format.
TEST_F(SourceLocationTest, ExtensionSourceLocation) {
SourceLocation loc;
@ -16526,19 +16419,7 @@ TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
EXPECT_FALSE(file_desc->GetSourceLocation(unint, &loc));
SourceCodePath name_path = {FileDescriptorProto::kOptionsFieldNumber,
FileOptions::kJavaPackageFieldNumber,
UninterpretedOption::kNameFieldNumber};
EXPECT_TRUE(file_desc->GetSourceLocation(name_path, &loc));
EXPECT_THAT(loc,
MatchesSubstring(kSourceLocationTestInput, "java_package"));
SourceCodePath val_path = {FileDescriptorProto::kOptionsFieldNumber,
FileOptions::kJavaPackageFieldNumber,
UninterpretedOption::kStringValueFieldNumber};
EXPECT_TRUE(file_desc->GetSourceLocation(val_path, &loc));
EXPECT_THAT(loc,
MatchesSubstring(kSourceLocationTestInput, "\"com.foo.bar\""));
// TODO: b/168903973 - Remove once we update the format.
}
{
SourceCodePath path = {FileDescriptorProto::kOptionsFieldNumber,
@ -16551,18 +16432,7 @@ TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
EXPECT_FALSE(file_desc->GetSourceLocation(unint, &loc));
SourceCodePath name_path = {FileDescriptorProto::kOptionsFieldNumber,
kCustomOptionFieldNumber,
UninterpretedOption::kNameFieldNumber};
EXPECT_TRUE(file_desc->GetSourceLocation(name_path, &loc));
EXPECT_THAT(loc,
MatchesSubstring(kSourceLocationTestInput, "(test_file_opt)"));
SourceCodePath val_path = {FileDescriptorProto::kOptionsFieldNumber,
kCustomOptionFieldNumber,
UninterpretedOption::kStringValueFieldNumber};
EXPECT_TRUE(file_desc->GetSourceLocation(val_path, &loc));
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "\"foobar\""));
// TODO: b/168903973 - Remove once we update the format.
}
// Message option

View file

@ -185,39 +185,46 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
// ===================================================================
// Constructors and basic methods.
constexpr ExtensionSet::FlatItem ExtensionSet::kEmptyKeyValue = {0, 0, 0,
Extension()};
ExtensionSet::~ExtensionSet() {
// Deletes all allocated extensions.
if (IsCompletelyEmpty()) {
return;
}
ForEach([](int /* number */, Extension& ext) { ext.Free(); }, PrefetchNta{});
if (ABSL_PREDICT_FALSE(is_large())) {
delete map_.large;
} else {
DeleteFlatMap(map_.flat, flat_capacity_);
DeleteFlatMap(map_.flat, flat_capacity());
}
}
ExtensionSet::KeyValue* ExtensionSet::AllocateFlatMap(
ExtensionSet::FlatItem* ExtensionSet::AllocateFlatMap(
Arena* arena, uint16_t powerof2_flat_capacity) {
// It is important to allocate power-of-2 bytes in order to reuse
// allocated blocks in arena for ExtensionSet and RepeatedFields.
// ReturnArrayMemory is also more efficient with power-of-2 bytes, and
// sizeof(KeyValue) is a power-of-2 on 64-bit platforms.
static_assert(absl::has_single_bit(sizeof(KeyValue)) || sizeof(void*) != 8,
static_assert(absl::has_single_bit(sizeof(FlatItem)) || sizeof(void*) != 8,
"sizeof(KeyValue) must be a power of 2");
ABSL_DCHECK(absl::has_single_bit(powerof2_flat_capacity));
return Arena::CreateArray<ExtensionSet::KeyValue>(arena,
return Arena::CreateArray<ExtensionSet::FlatItem>(arena,
powerof2_flat_capacity);
}
void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
void ExtensionSet::DeleteFlatMap(const ExtensionSet::FlatItem* flat,
uint16_t flat_capacity) {
// Arena::CreateArray already requires a trivially destructible type, but
// ensure this constraint is not violated in the future.
static_assert(std::is_trivially_destructible_v<KeyValue>,
static_assert(std::is_trivially_destructible_v<FlatItem>,
"CreateArray requires a trivially destructible type");
// A const-cast is needed, but this is safe as we are about to deallocate the
// array.
internal::SizedArrayDelete(const_cast<KeyValue*>(flat),
internal::SizedArrayDelete(const_cast<FlatItem*>(flat),
sizeof(*flat) * flat_capacity);
}
@ -794,21 +801,23 @@ void ExtensionSet::MergeFrom(Arena* arena, const MessageLite* extendee,
ABSL_ATTRIBUTE_NOINLINE void ExtensionSet::InternalReduceSmallCapacity(
Arena* arena) {
ABSL_DCHECK_LE(flat_size_, kMaximumFlatCapacity);
ABSL_DCHECK_LE(flat_capacity_, kMaximumFlatCapacity);
ABSL_DCHECK_GT(flat_size_, 0);
ABSL_DCHECK_GE(flat_capacity_, flat_size_ * 2);
const size_t new_flat_capacity = absl::bit_ceil(flat_size_);
uint16_t current_size = flat_size();
uint16_t current_cap = flat_capacity();
ABSL_DCHECK_LE(current_size, kMaximumFlatCapacity);
ABSL_DCHECK_LE(current_cap, kMaximumFlatCapacity);
ABSL_DCHECK_GT(current_size, 0);
ABSL_DCHECK_GE(current_cap, current_size * 2);
const size_t new_flat_capacity = absl::bit_ceil(current_size);
auto* new_flat = AllocateFlatMap(arena, new_flat_capacity);
std::memcpy(new_flat, map_.flat, flat_size_ * sizeof(KeyValue));
std::memcpy(new_flat, map_.flat, current_size * sizeof(FlatItem));
auto* old_flat = map_.flat;
if (arena == nullptr) {
DeleteFlatMap(old_flat, flat_capacity_);
DeleteFlatMap(old_flat, current_cap);
} else {
arena->ReturnArrayMemory(old_flat, sizeof(KeyValue) * flat_capacity_);
arena->ReturnArrayMemory(old_flat, sizeof(FlatItem) * current_cap);
}
map_.flat = new_flat;
flat_capacity_ = new_flat_capacity;
set_flat_capacity_and_size(new_flat_capacity, current_size);
}
void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
@ -816,24 +825,22 @@ void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
const ExtensionSet& other,
Arena* other_arena) {
ABSL_DCHECK(!other.is_large());
// Compiler is complaining on potential side effects for `!other.is_large()`.
ABSL_ASSUME(static_cast<int16_t>(flat_size_) >= 0);
ABSL_DCHECK(IsCompletelyEmpty());
if (other.flat_size_ == 0) {
uint16_t new_size = other.flat_size();
if (new_size == 0) {
return;
}
flat_size_ = other.flat_size_;
KeyValue* dst_it = nullptr;
PROTOBUF_ASSUME(static_cast<int16_t>(new_size) > 0);
FlatItem* dst_it = nullptr;
other.ForEach(
[&](int number, const Extension& ext) {
if (ext.is_cleared) {
--flat_size_;
--new_size;
return;
}
if (dst_it == nullptr) {
InternalReserveSmallCapacityFromEmpty(arena, flat_size_);
InternalReserveSmallCapacityFromEmpty(arena, new_size);
dst_it = map_.flat;
}
dst_it->first = number;
@ -842,10 +849,11 @@ void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
++dst_it;
},
Prefetch{});
if (flat_capacity_ == 0) {
if (new_size == 0) {
return;
}
if (ABSL_PREDICT_FALSE(flat_capacity_ >= flat_size_ * 2)) {
set_flat_size(new_size);
if (ABSL_PREDICT_FALSE(flat_capacity() >= new_size * 2)) {
InternalReduceSmallCapacity(arena);
}
}
@ -860,8 +868,8 @@ void ExtensionSet::InternalMergeFromSlow(Arena* arena,
other.flat_begin(), other.flat_end()));
} else {
GrowCapacity(arena, SizeOfUnion(flat_begin(), flat_end(),
other.map_.large->begin(),
other.map_.large->end()));
other.map_.large->large.begin(),
other.map_.large->large.end()));
}
}
other.ForEach(
@ -940,6 +948,9 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena,
int number,
const Extension& other_extension,
Arena* other_arena) {
if (other_extension.is_cleared) {
return;
}
Extension* dst_extension;
bool is_new = MaybeNewExtension(arena, number, other_extension.descriptor,
&dst_extension);
@ -975,9 +986,6 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena,
return;
}
if (other_extension.is_cleared) {
return;
}
dst_extension->is_cleared = false;
switch (cpp_type(other_extension.type)) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
@ -1036,8 +1044,6 @@ void ExtensionSet::Swap(Arena* arena, const MessageLite* extendee,
void ExtensionSet::InternalSwap(ExtensionSet* other) {
using std::swap;
swap(flat_capacity_, other->flat_capacity_);
swap(flat_size_, other->flat_size_);
swap(map_, other->map_);
}
@ -1111,14 +1117,14 @@ bool ExtensionSet::IsInitialized(Arena* arena,
// Extensions are never required. However, we need to check that all
// embedded messages are initialized.
if (ABSL_PREDICT_FALSE(is_large())) {
for (const auto& kv : *map_.large) {
for (const auto& kv : map_.large->large) {
if (!kv.second.IsInitialized(this, extendee, kv.first, arena)) {
return false;
}
}
return true;
}
for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) {
for (const FlatItem* it = flat_begin(); it != flat_end(); ++it) {
if (!it->second.IsInitialized(this, extendee, it->first, arena)) {
return false;
}
@ -1164,8 +1170,8 @@ uint8_t* ExtensionSet::_InternalSerializeImpl(
return _InternalSerializeImplLarge(extendee, start_field_number,
end_field_number, target, stream);
}
const KeyValue* end = flat_end();
const KeyValue* it = flat_begin();
const FlatItem* end = flat_end();
const FlatItem* it = flat_begin();
while (it != end && it->first < start_field_number) ++it;
for (; it != end && it->first < end_field_number; ++it) {
target = it->second.InternalSerializeFieldWithCachedSizesToArray(
@ -1190,8 +1196,8 @@ uint8_t* ExtensionSet::_InternalSerializeImplLarge(
const MessageLite* extendee, int start_field_number, int end_field_number,
uint8_t* target, io::EpsCopyOutputStream* stream) const {
assert(is_large());
const auto& end = map_.large->end();
for (auto it = map_.large->lower_bound(start_field_number);
const auto& end = map_.large->large.end();
for (auto it = map_.large->large.lower_bound(start_field_number);
it != end && it->first < end_field_number; ++it) {
target = it->second.InternalSerializeFieldWithCachedSizesToArray(
extendee, this, it->first, target, stream);
@ -1526,7 +1532,7 @@ bool ExtensionSet::Extension::IsInitialized(const ExtensionSet* ext_set,
const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
if (flat_size_ == 0) {
if (IsCompletelyEmpty()) {
return nullptr;
} else if (ABSL_PREDICT_TRUE(!is_large())) {
for (auto it = flat_begin(), end = flat_end();
@ -1542,8 +1548,8 @@ const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
int key) const {
assert(is_large());
LargeMap::const_iterator it = map_.large->find(key);
if (it != map_.large->end()) {
LargeMap::const_iterator it = map_.large->large.find(key);
if (it != map_.large->large.end()) {
return &it->second;
}
return nullptr;
@ -1564,17 +1570,27 @@ ABSL_ATTRIBUTE_NOINLINE
std::pair<ExtensionSet::Extension*, bool>
ExtensionSet::InternalInsertIntoLargeMap(int key) {
ABSL_DCHECK(is_large());
auto maybe = map_.large->insert({key, Extension()});
auto maybe = map_.large->large.insert({key, Extension()});
return {&maybe.first->second, maybe.second};
}
std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(Arena* arena,
int key) {
if (IsCompletelyEmpty()) {
map_.flat = AllocateFlatMap(arena, 1);
map_.flat[0] = FlatItem{/*first=*/key,
/*flat_capacity=*/1,
/*flat_size=*/1,
/*second=*/Extension()};
return {&map_.flat[0].second, true};
}
if (ABSL_PREDICT_FALSE(is_large())) {
return InternalInsertIntoLargeMap(key);
}
uint16_t i = flat_size_;
KeyValue* flat = map_.flat;
uint16_t current_size = flat_size();
uint16_t current_cap = flat_capacity();
uint16_t i = current_size;
FlatItem* flat = map_.flat;
// Iterating from the back to benefit the case where the keys are inserted in
// increasing order.
for (; i > 0; --i) {
@ -1586,18 +1602,19 @@ std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(Arena* arena,
break;
}
}
if (flat_size_ == flat_capacity_) {
GrowCapacity(arena, flat_size_ + 1);
if (current_size == current_cap) {
GrowCapacity(arena, current_size + 1);
if (ABSL_PREDICT_FALSE(is_large())) {
return InternalInsertIntoLargeMap(key);
}
flat = map_.flat; // Reload flat pointer after GrowCapacity.
current_cap = flat_capacity();
}
std::copy_backward(flat + i, flat + flat_size_, flat + flat_size_ + 1);
++flat_size_;
std::copy_backward(flat + i, flat + current_size, flat + current_size + 1);
flat[i].first = key;
flat[i].second = Extension();
set_flat_capacity_and_size(current_cap, current_size + 1);
return {&flat[i].second, true};
}
@ -1605,62 +1622,66 @@ void ExtensionSet::GrowCapacity(Arena* arena, size_t minimum_new_capacity) {
if (ABSL_PREDICT_FALSE(is_large())) {
return; // LargeMap does not have a "reserve" method.
}
if (flat_capacity_ >= minimum_new_capacity) {
uint16_t current_cap = flat_capacity();
if (current_cap >= minimum_new_capacity) {
return;
}
auto new_flat_capacity = flat_capacity_;
size_t new_flat_capacity = current_cap;
do {
new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 4;
new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 2;
} while (new_flat_capacity < minimum_new_capacity);
KeyValue* begin = flat_begin();
KeyValue* end = flat_end();
FlatItem* begin = flat_begin();
FlatItem* end = flat_end();
uint16_t current_size = flat_size();
AllocatedData new_map;
if (new_flat_capacity > kMaximumFlatCapacity) {
new_map.large = Arena::Create<LargeMap>(arena);
LargeMap::iterator hint = new_map.large->begin();
for (const KeyValue* it = begin; it != end; ++it) {
hint = new_map.large->insert(hint, {it->first, it->second});
LargeRep* large_rep = Arena::Create<LargeRep>(arena);
LargeMap::iterator hint = large_rep->large.begin();
for (const FlatItem* it = begin; it != end; ++it) {
hint = large_rep->large.insert(hint, {it->first, it->second});
}
flat_size_ = static_cast<uint16_t>(-1);
ABSL_DCHECK(is_large());
new_map.large = large_rep;
} else {
new_map.flat = AllocateFlatMap(arena, new_flat_capacity);
std::copy(begin, end, new_map.flat);
SetFlatCapacityAndSize(*new_map.flat, new_flat_capacity, current_size);
}
if (flat_capacity_ > 0) {
if (current_cap > 0) {
if (arena == nullptr) {
DeleteFlatMap(begin, flat_capacity_);
DeleteFlatMap(begin, current_cap);
} else {
arena->ReturnArrayMemory(begin, sizeof(KeyValue) * flat_capacity_);
arena->ReturnArrayMemory(begin, sizeof(FlatItem) * current_cap);
}
}
flat_capacity_ = new_flat_capacity;
map_ = new_map;
}
void ExtensionSet::InternalReserveSmallCapacityFromEmpty(
Arena* arena, size_t minimum_new_capacity) {
ABSL_DCHECK(flat_capacity_ == 0);
ABSL_DCHECK(IsCompletelyEmpty());
ABSL_DCHECK(minimum_new_capacity <= kMaximumFlatCapacity);
ABSL_DCHECK(minimum_new_capacity > 0);
const size_t new_flat_capacity = absl::bit_ceil(minimum_new_capacity);
flat_capacity_ = new_flat_capacity;
map_.flat = AllocateFlatMap(arena, new_flat_capacity);
set_flat_capacity_and_size(new_flat_capacity, 0);
}
void ExtensionSet::Erase(int key) {
if (ABSL_PREDICT_FALSE(is_large())) {
map_.large->erase(key);
map_.large->large.erase(key);
return;
}
KeyValue* end = flat_end();
for (KeyValue* it = flat_begin(); it != end && it->first <= key; ++it) {
uint16_t current_cap = flat_capacity();
uint16_t current_size = flat_size();
FlatItem* end = flat_begin() + current_size;
for (FlatItem* it = flat_begin(); it != end && it->first <= key; ++it) {
if (it->first == key) {
std::copy(it + 1, end, it);
--flat_size_;
// We need to overwrite capacity in case we overwrote the first element.
set_flat_capacity_and_size(current_cap, current_size - 1);
return;
}
}

View file

@ -580,7 +580,7 @@ class PROTOBUF_EXPORT ExtensionSet {
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint8_t* _InternalSerialize(
const MessageLite* extendee, int start_field_number, int end_field_number,
uint8_t* target, io::EpsCopyOutputStream* stream) const {
if (flat_size_ == 0) {
if (flat_size() == 0) {
assert(!is_large());
return target;
}
@ -592,7 +592,7 @@ class PROTOBUF_EXPORT ExtensionSet {
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint8_t* _InternalSerializeAll(
const MessageLite* extendee, uint8_t* target,
io::EpsCopyOutputStream* stream) const {
if (flat_size_ == 0) {
if (flat_size() == 0) {
assert(!is_large());
return target;
}
@ -891,13 +891,40 @@ class PROTOBUF_EXPORT ExtensionSet {
// the number of elements is small enough that linear search is faster than
// binary search.
struct KeyValue {
struct FlatItem {
int first;
// flat_capacity and flat_size are only valid in the first element (index 0)
// of flat map array.
uint16_t flat_capacity;
uint16_t flat_size;
Extension second;
};
static void SetFlatCapacityAndSize(FlatItem& item, uint16_t flat_capacity,
uint16_t flat_size) {
item.flat_capacity = flat_capacity;
item.flat_size = flat_size;
}
// Constant to represent an empty ExtensionSet.
static const FlatItem kEmptyKeyValue;
using LargeMap = absl::btree_map<int, Extension>;
struct LargeRep {
int unused_padding;
uint16_t flat_capacity = ~uint16_t{};
uint16_t flat_size = ~uint16_t{};
LargeMap large;
};
static_assert(offsetof(FlatItem, flat_capacity) ==
offsetof(LargeRep, flat_capacity),
"KeyValue and LargeRep layout mismatch");
static_assert(offsetof(FlatItem, flat_size) == offsetof(LargeRep, flat_size),
"KeyValue and LargeRep layout mismatch");
// Wrapper API that switches between flat-map and LargeMap.
// Finds a key (if present) in the ExtensionSet.
@ -927,7 +954,7 @@ class PROTOBUF_EXPORT ExtensionSet {
void InternalReserveSmallCapacityFromEmpty(Arena* arena,
size_t minimum_new_capacity);
bool is_large() const { return static_cast<int16_t>(flat_size_) < 0; }
bool is_large() const { return static_cast<int16_t>(flat_size()) < 0; }
// Removes a key from the ExtensionSet.
void Erase(int key);
@ -935,7 +962,8 @@ class PROTOBUF_EXPORT ExtensionSet {
// Returns the number of elements in the ExtensionSet, including cleared
// extensions.
size_t Size() const {
return ABSL_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_;
return ABSL_PREDICT_FALSE(is_large()) ? map_.large->large.size()
: flat_size();
}
// For use as `PrefetchFunctor`s in `ForEach`.
@ -979,7 +1007,7 @@ class PROTOBUF_EXPORT ExtensionSet {
template <typename KeyValueFunctor, typename PrefetchFunctor>
void ForEach(KeyValueFunctor func, PrefetchFunctor prefetch_func) {
if (ABSL_PREDICT_FALSE(is_large())) {
ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
ForEachPrefetchImpl(map_.large->large.begin(), map_.large->large.end(),
std::move(func), std::move(prefetch_func));
return;
}
@ -990,7 +1018,7 @@ class PROTOBUF_EXPORT ExtensionSet {
template <typename KeyValueFunctor, typename PrefetchFunctor>
void ForEach(KeyValueFunctor func, PrefetchFunctor prefetch_func) const {
if (ABSL_PREDICT_FALSE(is_large())) {
ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
ForEachPrefetchImpl(map_.large->large.begin(), map_.large->large.end(),
std::move(func), std::move(prefetch_func));
return;
}
@ -1023,7 +1051,7 @@ class PROTOBUF_EXPORT ExtensionSet {
template <typename KeyValueFunctor>
void ForEachNoPrefetch(KeyValueFunctor func) {
if (ABSL_PREDICT_FALSE(is_large())) {
ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
ForEachNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
std::move(func));
return;
}
@ -1034,7 +1062,7 @@ class PROTOBUF_EXPORT ExtensionSet {
template <typename KeyValueFunctor>
void ForEachNoPrefetch(KeyValueFunctor func) const {
if (ABSL_PREDICT_FALSE(is_large())) {
ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
ForEachNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
std::move(func));
return;
}
@ -1047,16 +1075,14 @@ class PROTOBUF_EXPORT ExtensionSet {
template <typename KeyValueFunctor>
bool AnyOfNoPrefetch(KeyValueFunctor predicate) const {
if (ABSL_PREDICT_FALSE(is_large())) {
return AnyOfNoPrefetch(map_.large->begin(), map_.large->end(),
return AnyOfNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
std::move(predicate));
}
return AnyOfNoPrefetch(flat_begin(), flat_end(), std::move(predicate));
}
// Returns true if nothing is allocated in the ExtensionSet.
bool IsCompletelyEmpty() const {
return flat_size_ == 0 && flat_capacity_ == 0;
}
bool IsCompletelyEmpty() const { return flat_capacity() == 0; }
// Reduces the flat_capacity_ to the smallest power of 2 >= flat_size_.
void InternalReduceSmallCapacity(Arena* arena);
@ -1223,39 +1249,56 @@ class PROTOBUF_EXPORT ExtensionSet {
static inline size_t RepeatedMessage_SpaceUsedExcludingSelfLong(
RepeatedPtrFieldBase* field);
KeyValue* flat_begin() {
FlatItem* flat_begin() {
assert(!is_large());
return map_.flat;
}
const KeyValue* flat_begin() const {
const FlatItem* flat_begin() const {
assert(!is_large());
return map_.flat;
}
KeyValue* flat_end() {
FlatItem* flat_end() {
assert(!is_large());
return map_.flat + flat_size_;
return map_.flat + flat_size();
}
const KeyValue* flat_end() const {
const FlatItem* flat_end() const {
assert(!is_large());
return map_.flat + flat_size_;
return map_.flat + flat_size();
}
static KeyValue* AllocateFlatMap(Arena* arena,
static FlatItem* AllocateFlatMap(Arena* arena,
uint16_t powerof2_flat_capacity);
static void DeleteFlatMap(const KeyValue* flat, uint16_t flat_capacity);
static void DeleteFlatMap(const FlatItem* flat, uint16_t flat_capacity);
uint16_t flat_capacity() const {
ABSL_DCHECK(map_.flat != nullptr);
return map_.flat->flat_capacity;
}
uint16_t flat_size() const {
ABSL_DCHECK(map_.flat != nullptr);
return map_.flat->flat_size;
}
void set_flat_capacity_and_size(uint16_t capacity, uint16_t size) {
ABSL_DCHECK(map_.flat != &kEmptyKeyValue);
SetFlatCapacityAndSize(*map_.flat, capacity, size);
}
void set_flat_size(uint16_t size) {
ABSL_DCHECK(map_.flat != &kEmptyKeyValue);
map_.flat->flat_size = size;
}
// Manual memory-management:
// map_.flat is an allocated array of flat_capacity_ elements.
// [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix.
uint16_t flat_capacity_ = 0;
uint16_t flat_size_ = 0; // negative int16_t(flat_size_) indicates is_large()
// map_.flat is either pointer to kEmptyKeyValue or an allocated array of
// flat_capacity elements. [map_.flat, map_.flat + flat_size) is the
// currently-in-use prefix.
// flat_capacity and flat_size are stored in the first element of the array.
union AllocatedData {
KeyValue* flat;
FlatItem* flat;
// If flat_capacity_ > kMaximumFlatCapacity, switch to LargeMap,
// If flat_capacity > kMaximumFlatCapacity, switch to LargeMap,
// which guarantees O(n lg n) CPU but larger constant factors.
LargeMap* large;
} map_ = {nullptr};
LargeRep* large;
} map_ = {const_cast<FlatItem*>(&kEmptyKeyValue)};
};
// ===================================================================

View file

@ -371,8 +371,9 @@ int ExtensionSet::SpaceUsedExcludingSelf() const {
}
size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
size_t total_size =
(is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue);
size_t total_size = is_large() ? map_.large->large.size() * sizeof(FlatItem) +
sizeof(LargeRep)
: flat_capacity() * sizeof(FlatItem);
ForEach(
[&total_size](int /* number */, const Extension& ext) {
total_size += ext.SpaceUsedExcludingSelfLong();

View file

@ -525,8 +525,8 @@ TEST(ExtensionSetTest, ArenaMergeFromWithClearedExtensions) {
}
TEST(ExtensionSetTest, ArenaMergeFromWithClearedExtensionsReduceCapacity) {
if (sizeof(void*) != 8) {
GTEST_SKIP() << "This test is only correct on 64-bit systems.";
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
Arena arena;
auto* message = Arena::Create<unittest::TestAllExtensions>(&arena);
@ -2112,6 +2112,22 @@ TEST(ExtensionSetTest, MessageSetRecursionLimitIsConsistent) {
}
}
TEST(ExtensionSetTest, MergeLargeExtensionSetToEmpty) {
ExtensionSet src;
ExtensionSet dst;
constexpr int kNumExtensions = 70000; // > 2**16 (65536)
for (int i = 1; i <= kNumExtensions; ++i) {
src.Set<int32_t>(/*arena=*/nullptr, i, WireFormatLite::TYPE_INT32, i,
/*descriptor=*/nullptr);
}
dst.MergeFrom(/*arena=*/nullptr, /*extendee=*/nullptr, src,
/*other_arena=*/nullptr);
EXPECT_EQ(dst.NumExtensions(), kNumExtensions);
for (int i = 1; i <= kNumExtensions; ++i) {
EXPECT_EQ(dst.Get<int32_t>(i, 0), i);
}
}
} // namespace
} // namespace internal
} // namespace protobuf

View file

@ -845,8 +845,8 @@ TEST(CordInputStreamTest, SkipToEnd) {
}
TEST(CordInputStreamTest, HugeCordNodes) {
if (sizeof(void*) < 8) {
GTEST_SKIP() << "Not enough memory for test.";
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
std::string input_str;

View file

@ -1702,8 +1702,8 @@ TEST_P(JsonTest, OversizedStringRejected) {
GTEST_SKIP() << "Test is too slow in non-opt builds.";
#else
if (sizeof(void*) < 8) {
GTEST_SKIP() << "Test requires 64-bit environment.";
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
absl::Cord chunk(std::string(1024 * 1024, 'a'));

View file

@ -2731,7 +2731,7 @@ TEST(GeneratedMapFieldTest, SerializationToArray) {
}
TEST(GeneratedMapFieldTest, SerializeLargeString) {
if (sizeof(void*) < 8) {
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
UNITTEST::TestMap msg;

View file

@ -888,9 +888,8 @@ TEST(MicroStringTest, SetInChunksWontPreallocateForVeryLargeFakeSize) {
}
TEST(MicroStringTest, SetInChunksAllowsVeryLargeValues) {
if (sizeof(void*) < 8) {
GTEST_SKIP() << "Might not be possible to allocate that much memory on "
"this platform.";
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
std::string total(1'000'000'000, 0);

View file

@ -0,0 +1,36 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "google/protobuf/offset_ptr.h"
#include <cstddef>
#include "absl/log/absl_log.h"
namespace google {
namespace protobuf {
namespace internal {
void BasePointerInvalidSelfReference() noexcept {
ABSL_LOG(FATAL) << "Nullable base pointer can't self reference.";
}
void BasePointerNonnullFailure() noexcept {
ABSL_LOG(FATAL)
<< "Non-nullable base pointer constructed with a null pointer.";
}
void BasePointerOverflow(const void* ptr, const void* base) noexcept {
ptrdiff_t diff =
reinterpret_cast<const char*>(ptr) - reinterpret_cast<const char*>(base);
ABSL_LOG(FATAL) << "Pointer out of scope for offset pointer: ptr=" << ptr
<< " base=" << base << " diff=" << diff;
}
} // namespace internal
} // namespace protobuf
} // namespace google

View file

@ -0,0 +1,177 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef GOOGLE_PROTOBUF_OFFSET_PTR_H__
#define GOOGLE_PROTOBUF_OFFSET_PTR_H__
#include <cstddef>
#include <cstdint>
#include "absl/base/optimization.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace internal {
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void BasePointerOverflow(
const void* ptr, const void* base) noexcept;
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void
BasePointerInvalidSelfReference() noexcept;
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void
BasePointerNonnullFailure() noexcept;
// Offset based pointer-like class.
// It encodes its data relative to a `base` pointer.
// The caller must provide this pointer and it must be the same base pointer
// pass to `Resolve`.
// The offset is encoded in 32-bit and the caller must guarantee that.
//
// Is kAllowNull is false, then nullptr is not a valid input and will terminate
// the program. However, such mode is faster. The caller should choose the
// appropriate setting for the pointer in question.
template <typename T, bool kAllowNull>
class BasePointer {
// We must use 0 as the null pointer because some of these are initialized via
// memset.
static constexpr int32_t kNullOffset = 0;
public:
// Uninitialized.
BasePointer() = default;
// Trivial copy/assign.
BasePointer(const BasePointer&) = default;
BasePointer& operator=(const BasePointer&) = default;
BasePointer(T* ptr, const void* base) {
if constexpr (kAllowNull) {
if (ptr == nullptr) {
offset_ = kNullOffset;
return;
}
if (ABSL_PREDICT_FALSE(ptr == base)) {
BasePointerInvalidSelfReference();
}
} else {
if (ABSL_PREDICT_FALSE(ptr == nullptr)) {
BasePointerNonnullFailure();
}
}
ptrdiff_t diff = reinterpret_cast<const char*>(ptr) -
reinterpret_cast<const char*>(base);
if (ABSL_PREDICT_FALSE(static_cast<int32_t>(diff) != diff)) {
BasePointerOverflow(ptr, base);
}
offset_ = static_cast<int32_t>(diff);
}
// `base` must be the same `base` pointer as the one passed to the
// constructor.
T* Resolve(const void* base) const {
if constexpr (kAllowNull) {
if (offset_ == kNullOffset) return nullptr;
}
T* out = const_cast<T*>(reinterpret_cast<const T*>(
reinterpret_cast<const char*>(base) + offset_));
PROTOBUF_ASSUME(out != nullptr);
return out;
}
private:
int32_t offset_;
};
// Offset based pointer class.
// It uses its own address as the base pointer, which simplifies its use but
// restricts the input pointer to be in the same slab of memory as the
// `OffsetPtr` instance itself.
// kAllowNull follows the semantics of BasePointer.
template <typename T, bool kAllowNull>
class OffsetPtr {
public:
using value_type = T;
OffsetPtr() = default;
// Bit copy is wrong because we are relative to `this`.
OffsetPtr(const OffsetPtr&) = delete;
OffsetPtr& operator=(const OffsetPtr&) = delete;
// We can't have a conversion constructor because it would allow for
// temporaries to be made, which breaks the invariant of maximum distance.
T* get() const { return ptr_.Resolve(this); }
operator T*() const { return get(); } // NOLINT
T* operator->() const { return get(); }
OffsetPtr& operator=(T* value) {
ptr_ = BasePointer<T, kAllowNull>(value, this);
return *this;
}
OffsetPtr& operator=(std::nullptr_t) {
static_assert(kAllowNull, "Can't accept null.");
return *this = static_cast<T*>(nullptr);
}
private:
BasePointer<T, kAllowNull> ptr_;
};
template <typename T>
using NullableOffsetPtr = OffsetPtr<T, true>;
template <typename T>
using NonnullOffsetPtr = OffsetPtr<T, false>;
// Same as OffsetPtr, with a special case &T::default_instance.
// The pointer can be set to `&T::default_instance()` even though it is outside
// the range. It is handled specially.
// Null inputs are equivalent to the default instance.
template <typename T>
class OffsetProtoPtr {
public:
using value_type = T;
OffsetProtoPtr() = default;
// Bit copy is wrong because we are relative to `this`.
OffsetProtoPtr(const OffsetProtoPtr&) = delete;
OffsetProtoPtr& operator=(const OffsetProtoPtr&) = delete;
// We can't have a conversion constructor because it would allow for
// temporaries to be made, which breaks the invariant of maximum distance.
T* get() const {
T* value = ptr_.Resolve(this);
return value == nullptr ? &T::default_instance() : value;
}
operator T*() const { return get(); } // NOLINT
T* operator->() const { return get(); }
OffsetProtoPtr& operator=(T* value) {
ptr_ = BasePointer<T, true>(
value == &T::default_instance() ? nullptr : value, this);
return *this;
}
private:
BasePointer<T, true> ptr_;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_OFFSET_PTR_H__

View file

@ -0,0 +1,132 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "google/protobuf/offset_ptr.h"
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <gtest/gtest.h>
#include "google/protobuf/unittest.pb.h"
namespace google {
namespace protobuf {
namespace internal {
namespace {
int array[10];
TEST(BasePtrTest, Basic) {
BasePointer<int, false> b(&array[5], &array);
EXPECT_EQ(&array[5], b.Resolve(&array));
}
TEST(BasePtrTest, Copyable) {
EXPECT_TRUE(
(std::is_trivially_copy_constructible_v<BasePointer<int, false>>));
EXPECT_TRUE((std::is_trivially_copy_assignable_v<BasePointer<int, false>>));
EXPECT_TRUE((std::is_trivially_destructible_v<BasePointer<int, false>>));
BasePointer<int, false> b(&array[7], &array);
EXPECT_EQ(&array[7], b.Resolve(&array));
auto b2 = b;
EXPECT_EQ(&array[7], b2.Resolve(&array));
}
TEST(BasePtrTest, BaseCanBeOnEitherSide) {
EXPECT_EQ(&array[7],
(BasePointer<int, false>(&array[7], &array[3])).Resolve(&array[3]));
EXPECT_EQ(&array[4],
(BasePointer<int, false>(&array[4], &array[7])).Resolve(&array[7]));
}
TEST(BasePtrTest, BaseCanBeSameAsPointer) {
int var = 0;
EXPECT_EQ(&var, (BasePointer<int, false>(&var, &var)).Resolve(&var));
}
TEST(BasePtrTest, NullIsAllowed) {
bool dummy = false;
BasePointer<int, true> b(nullptr, &dummy);
EXPECT_EQ(nullptr, b.Resolve(&dummy));
int p = 0;
EXPECT_DEATH((BasePointer<int, true>(&p, &p)),
"Nullable base pointer can't self reference");
EXPECT_DEATH((BasePointer<int, false>(nullptr, &dummy)),
"Non-nullable base pointer constructed with a null pointer");
}
TEST(BasePtrTest, OutOfScopeFails) {
// For this one we manufacture pointers to make sure they trigger out of scope
// failures.
if (sizeof(void*) == 4) {
GTEST_SKIP() << "We need 64-bit to have out-of-scope pointers.";
}
void* base =
reinterpret_cast<void*>(static_cast<uintptr_t>(0x123457890abcdef));
const auto make_ptr = [&](ptrdiff_t diff) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base) + diff);
};
using T = BasePointer<void, false>;
// INT_MAX is fine.
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::max()), base).Resolve(base),
make_ptr(std::numeric_limits<int>::max()));
// INT_MAX+1 is too much.
EXPECT_DEATH(
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::max()} + 1), base),
"Pointer out of scope for offset pointer");
// INT_MIN is fine.
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::min()), base).Resolve(base),
make_ptr(std::numeric_limits<int>::min()));
// INT_MIN-1 is too much.
EXPECT_DEATH(
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::min()} - 1), base),
"Pointer out of scope for offset pointer");
}
TEST(OffsetPtrTest, Basic) {
struct Object {
int array[10];
OffsetPtr<int, false> ptr;
} object{};
object.ptr = object.array + 3;
EXPECT_EQ(object.ptr, object.array + 3);
}
TEST(OffsetProtoPtr, Basic) {
using P = proto2_unittest::TestAllTypes;
OffsetProtoPtr<const P> p;
p = nullptr;
EXPECT_EQ(&P::default_instance(), p);
P msg;
p = &msg;
EXPECT_EQ(&msg, p);
p = &P::default_instance();
EXPECT_EQ(&P::default_instance(), p);
}
} // namespace
} // namespace internal
} // namespace protobuf
} // namespace google

View file

@ -500,34 +500,7 @@ void OptionInterpreter::UpdateSourceCodeInfo(SourceCodeInfo* info) {
}
if (loc_matches) {
if (loc->path_size() == static_cast<int64_t>(match_src.size() + 1)) {
int uninterpreted_field = loc->path(match_src.size());
SourceCodeInfo_Location* mapped_loc = new_locs.Add();
*mapped_loc = *loc;
mapped_loc->mutable_path()->Assign(match_dest.begin(),
match_dest.end());
mapped_loc->add_path(uninterpreted_field);
if (uninterpreted_field ==
UninterpretedOption::kAggregateValueFieldNumber) {
auto it = agg_loc_map.find(loc->path());
if (it != agg_loc_map.end()) {
for (const AggregateFieldLocation* afl : it->second) {
SourceCodeInfo_Location* name_loc = new_locs.Add();
name_loc->mutable_path()->Assign(afl->field_dest_path.begin(),
afl->field_dest_path.end());
name_loc->add_path(UninterpretedOption::kNameFieldNumber);
SetSpan(name_loc, *loc, afl->name_range);
SourceCodeInfo_Location* val_loc = new_locs.Add();
val_loc->mutable_path()->Assign(afl->field_dest_path.begin(),
afl->field_dest_path.end());
val_loc->add_path(afl->value_marker);
SetSpan(val_loc, *loc, afl->val_range);
}
}
}
}
// TODO: b/168903973 - Remove once we update the format.
// don't copy this row since it is a sub-location that we're removing
// (or we already mapped it if it's a direct child)
continue;

View file

@ -320,6 +320,14 @@ constexpr bool HasAnySanitizer() {
#endif
}
constexpr bool RunLargeMemoryTests() {
// For tests that need a lot of memory, we check that we have a 64-bit
// platform.
// And we also check we are not using sanitizers. They increase memory
// requirements and can be too slow for those tests.
return sizeof(void*) == 8 && !HasAnySanitizer();
}
constexpr bool PerformDebugChecks() {
if (HasAnySanitizer()) return true;
#if defined(NDEBUG)

View file

@ -169,8 +169,8 @@ TEST(RepeatedField, Small) {
class RepeatedFieldIsFullTest : public testing::Test {
protected:
void SetUp() override {
if (sizeof(void*) == 4) {
GTEST_SKIP() << "Platform does not have enough memory for the test.";
if (!internal::RunLargeMemoryTests()) {
GTEST_SKIP() << "Not enough memory for this test.";
}
if (internal::GetBoundsCheckMode() != internal::BoundsCheckMode::kAbort) {
GTEST_SKIP() << "Preemtive abort is not enabled.";

View file

@ -233,11 +233,12 @@ TEST(RetentionTest, StripSourceRetentionOptionsWithSourceCodeInfo) {
compiler::StripSourceRetentionOptions(*interpreted_desc,
/*include_source_code_info=*/true);
EXPECT_EQ(interpreted_unstripped_file.source_code_info().location_size(), 92);
// TODO: b/168903973 - Remove once we update the format.
EXPECT_EQ(interpreted_unstripped_file.source_code_info().location_size(), 64);
// Stripping removes source-retention options (including some sub-fields),
// reducing the location count.
EXPECT_EQ(stripped_file.source_code_info().location_size(), 89);
EXPECT_EQ(stripped_file.source_code_info().location_size(), 63);
}
TEST(RetentionTest, RemoveEmptyOptions) {

View file

@ -188,6 +188,7 @@ upb_amalgamation(
"//upb/text:debug",
"//upb/text:internal",
"//upb/wire",
"//upb/wire:encode_extension",
"//upb/wire:back_alloc",
"//upb/wire:byte_size",
"//upb/wire:decoder",
@ -248,6 +249,7 @@ upb_amalgamation(
"//upb/reflection:json_enumvalue_options_upb_proto",
"//upb/reflection:internal",
"//upb/wire",
"//upb/wire:encode_extension",
"//upb/wire:back_alloc",
"//upb/wire:decoder",
"//upb/wire:encoder",
@ -307,6 +309,7 @@ upb_amalgamation(
"//upb/reflection:internal",
"//upb/util:def_to_proto",
"//upb/wire",
"//upb/wire:encode_extension",
"//upb/wire:back_alloc",
"//upb/wire:decoder",
"//upb/wire:encoder",

View file

@ -73,6 +73,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
/* Create lazily, since it's only needed for Any */
if (!e->arena) {
e->arena = upb_Arena_New();
if (!e->arena) {
jsonenc_err(e, "Out of memory");
}
}
return e->arena;
}
@ -390,6 +393,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
upb_Arena* arena = jsonenc_arena(e);
upb_Message* any = upb_Message_New(any_layout, arena);
if (!any) {
jsonenc_err(e, "Out of memory");
return;
}
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
kUpb_DecodeStatus_Ok) {

View file

@ -17,6 +17,7 @@
#include "upb/json/encode.h"
#include "upb/json/test.upb.h"
#include "upb/json/test.upbdefs.h"
#include "upb/mem/alloc.h"
#include "upb/mem/arena.h"
#include "upb/mem/arena.hpp"
#include "upb/reflection/def.hpp"
@ -50,6 +51,68 @@ void DecodeEncodeArbitraryJson(std::string_view json) {
size_t written = upb_JsonEncode(UPB_UPCAST(box), m.ptr(), defpool.ptr(),
options, json_buf, size + 1, status.ptr());
EXPECT_EQ(written, size);
if (upb_AllocationCount_IsAvailable()) {
auto RunJsonScenario = [&]() -> bool {
upb_Arena* local_arena = upb_Arena_New();
if (!local_arena) return false;
upb_test_Box* local_box = upb_test_Box_new(local_arena);
if (!local_box) {
upb_Arena_Free(local_arena);
return false;
}
upb::Status local_status;
bool local_ok = upb_JsonDecode(
json.data(), json.size(), UPB_UPCAST(local_box), m.ptr(),
defpool.ptr(), options, local_arena, local_status.ptr());
if (!local_ok) {
upb_Arena_Free(local_arena);
return false;
}
size_t local_sz =
upb_JsonEncode(UPB_UPCAST(local_box), m.ptr(), defpool.ptr(), options,
nullptr, 0, local_status.ptr());
if (local_sz == (size_t)-1 || !local_status.ok()) {
upb_Arena_Free(local_arena);
return false;
}
char* local_json_buf = (char*)upb_Arena_Malloc(local_arena, local_sz + 1);
if (!local_json_buf) {
upb_Arena_Free(local_arena);
return false;
}
size_t local_written =
upb_JsonEncode(UPB_UPCAST(local_box), m.ptr(), defpool.ptr(), options,
local_json_buf, local_sz + 1, local_status.ptr());
if (local_written == (size_t)-1 || !local_status.ok()) {
upb_Arena_Free(local_arena);
return false;
}
upb_Arena_Free(local_arena);
return true;
};
upb_AllocationCount_Reset();
if (RunJsonScenario()) {
size_t total_allocations = upb_AllocationCount_Get();
for (size_t i = 0; i < total_allocations; ++i) {
upb_AllocationCount_Reset();
upb_AllocationCount_FailOn(i);
bool success_with_fail = RunJsonScenario();
EXPECT_FALSE(success_with_fail)
<< "Fuzzed JSON scenario unexpectedly succeeded when allocation "
<< "number " << i << " was failed, with "
<< upb_AllocationCount_Get() << " total.";
}
}
upb_AllocationCount_Reset();
}
}
FUZZ_TEST(FuzzTest, DecodeEncodeArbitraryJson);

View file

@ -46,7 +46,6 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
":internal",
":message_unknowns",
":types",
"//upb/base",
"//upb/base:internal",
@ -70,6 +69,7 @@ cc_library(
features = UPB_DEFAULT_FEATURES,
visibility = [
"//hpb/internal:__pkg__",
"//multiplatform/elements/engine/imports/eml_operators:__pkg__",
"//pkg:__pkg__",
"//python:__pkg__",
"//third_party/cel/c/internal:__pkg__",
@ -527,6 +527,8 @@ cc_test(
deps = [
":internal",
":message",
":message_test_upb_minitable_proto",
":message_test_upb_proto",
":message_unknowns",
"//upb/base",
"//upb/mem",
@ -535,6 +537,7 @@ cc_test(
"//upb/test:test_proto_upb_minitable",
"//upb/test:test_upb_proto",
"//upb/wire",
"//upb/wire:encode_extension",
"@googletest//:gtest",
"@googletest//:gtest_main",
],

View file

@ -42,12 +42,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
upb_TaggedAuxType tag) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
// For Canonical Extensions, we check whether the extension has already been
// set. If we find an extension with the same pointer and tag, we reuse it to
// prevent duplicate entries for the same extension.
//
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
// accumulates.
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
upb_Extension* ext =
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
}
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
if (!ext) return NULL;
memset(ext, 0, sizeof(upb_Extension));
ext->ext = e;

Some files were not shown because too many files have changed in this diff Show more