Merge pull request #10268 from tonydnewell/bugfix/issue-8101
Bugfix/issue 8101
diff --git a/.gitignore b/.gitignore
index d8b0bd3..cc881f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,23 @@
m4/lt~obsolete.m4
autom4te.cache
+# CMake-generated files
+.ninja_deps
+.ninja_logs
+cmake/protobuf/*.cmake
+cmake_install.cmake
+CMakeCache.txt
+CTestTestfile.cmake
+CMakeFiles/*
+Testing/Temporary/*
+
+/core
+/protoc
+/test_plugin
+/tests
+/lite-test
+/protoc-*.*
+
# downloaded files
/gmock
@@ -41,6 +58,7 @@
*.la
src/.libs
*.so
+*.a
.dirstamp
diff --git a/BUILD.bazel b/BUILD.bazel
index 1a305e7..a14476a 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -266,7 +266,7 @@
alias(
name = "well_known_types_py_pb2",
actual = "//python:well_known_types_py_pb2",
- visibility = ["@upb//:__subpackages__"],
+ visibility = ["//visibility:public"],
)
alias(
diff --git a/CHANGES.txt b/CHANGES.txt
index 1b83184..a7d74a7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,18 +1,62 @@
2022-07-01 Unreleased version
+
C++
* Reduced .pb.o object file size slightly by explicitly instantiating
InternalMetadata templates in the runtime.
* Add C++20 keywords guarded by PROTOBUF_FUTURE_CPP20_KEYWORDS
* Fixed crash in ThreadLocalStorage for pre-C++17 compilers on 32-bit ARM.
* Clarified that JSON API non-OK statuses are not a stable API.
+ * Added a default implementation of MessageDifferencer::Reporter methods.
+ * proto2::MapPair is now an alias to std::pair.
+ * Hide C++ RepeatedField::UnsafeArenaSwap
Kotlin
* Kotlin generated code comments now use kdoc format instead of javadoc.
* Escape keywords in package names in proto generated code
+ * Add Kotlin enum int value getters and setters
Java
* Performance improvement for repeated use of FieldMaskUtil#merge by caching
constructed FieldMaskTrees.
+ * Optimized Java proto serialization gencode for protos having many extension ranges with few fields in between.
+
+ Python
+ * Changes ordering of printed fields in .pyi files from lexicographic to the same ordering found in the proto descriptor.
+
+ Compiler
+ * Print full path name of source .proto file on error
+
+
+2022-07-25 version 21.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
+
+ C++
+ * Reduce the required alignment of ArenaString from 8 to 4 (#10298)
+
+
+2022-07-19 version 21.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
+ C++
+ * Add header search paths to Protobuf-C++.podspec (#10024)
+ * Fixed Visual Studio constinit errors (#10232)
+ * Fix #9947: make the ABI compatible between debug and non-debug builds (#10271)
+
+ UPB
+ * Allow empty package names (fixes behavior regression in 4.21.0)
+ * Fix a SEGV bug when comparing a non-materialized sub-message (#10208)
+ * Fix several bugs in descriptor mapping containers (eg. descriptor.services_by_name)
+ * for x in mapping now yields keys rather than values, to match Python conventions and the behavior of the old library.
+ * Lookup operations now correctly reject unhashable types as map keys.
+ * We implement repr() to use the same format as dict.
+ * Fix maps to use the ScalarMapContainer class when appropriate
+ * Fix bug when parsing an unknown value in a proto2 enum extension (protocolbuffers/upb#717)
+
+ PHP
+ * Add "readonly" as a keyword for PHP and add previous classnames to descriptor pool (#10041)
+
+ Python
+ * Make //:protobuf_python and //:well_known_types_py_pb2 public (#10118)
+
+ Bazel
+ * Add back a filegroup for :well_known_protos (#10061)
2022-06-27 version 21.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
C++
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 04cb330..2ed5ca1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,9 +57,11 @@
option(protobuf_BUILD_TESTS "Build tests" ON)
option(protobuf_BUILD_CONFORMANCE "Build conformance tests" OFF)
option(protobuf_BUILD_EXAMPLES "Build examples" OFF)
+option(protobuf_BUILD_PROTOBUF_BINARIES "Build protobuf libraries and protoc compiler" ON)
option(protobuf_BUILD_PROTOC_BINARIES "Build libprotoc and protoc compiler" ON)
option(protobuf_BUILD_LIBPROTOC "Build libprotoc" OFF)
option(protobuf_DISABLE_RTTI "Remove runtime type information in the binaries" OFF)
+option(protobuf_TEST_XML_OUTDIR "Output directory for XML logs from tests." "")
if (BUILD_SHARED_LIBS)
set(protobuf_BUILD_SHARED_LIBS_DEFAULT ON)
else (BUILD_SHARED_LIBS)
@@ -81,6 +83,9 @@
if (protobuf_BUILD_PROTOC_BINARIES OR protobuf_BUILD_TESTS)
set(protobuf_BUILD_LIBPROTOC ON)
endif ()
+if (NOT protobuf_BUILD_PROTOBUF_BINARIES)
+ set(protobuf_INSTALL OFF)
+endif()
# Path to main configure script
set(protobuf_CONFIGURE_SCRIPT "${protobuf_SOURCE_DIR}/configure.ac")
@@ -242,12 +247,12 @@
if (MSVC)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Build with multiple processes
- add_definitions(/MP)
+ add_compile_options(/MP)
endif()
# Set source file and execution character sets to UTF-8
- add_definitions(/utf-8)
+ add_compile_options(/utf-8)
# MSVC warning suppressions
- add_definitions(
+ add_compile_options(
/wd4065 # switch statement contains 'default' but no 'case' labels
/wd4244 # 'conversion' conversion from 'type1' to 'type2', possible loss of data
/wd4251 # 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
@@ -262,23 +267,16 @@
/wd4996 # The compiler encountered a deprecated declaration.
)
# Allow big object
- add_definitions(/bigobj)
+ add_compile_options(/bigobj)
string(REPLACE "/" "\\" PROTOBUF_SOURCE_WIN32_PATH ${protobuf_SOURCE_DIR})
string(REPLACE "/" "\\" PROTOBUF_BINARY_WIN32_PATH ${protobuf_BINARY_DIR})
string(REPLACE "." "," protobuf_RC_FILEVERSION "${protobuf_VERSION}")
- configure_file(${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in extract_includes.bat)
# Suppress linker warnings about files with no symbols defined.
- set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
+ string(APPEND CMAKE_STATIC_LINKER_FLAGS " /ignore:4221")
- if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
- # Configure Resource Compiler
- enable_language(RC)
- # use English language (0x409) in resource compiler
- set(rc_flags "/l0x409")
- # fix rc.exe invocations because of usage of add_definitions()
- set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> ${rc_flags} <DEFINES> /fo<OBJECT> <SOURCE>")
- endif()
+ # use English language (0x409) in resource compiler
+ string(APPEND CMAKE_RC_FLAGS " -l0x409")
# Generate the version.rc file used elsewhere.
configure_file(${protobuf_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
@@ -304,28 +302,49 @@
add_definitions(-DUNICODE -D_UNICODE)
endif (protobuf_UNICODE)
-include(${protobuf_SOURCE_DIR}/cmake/libprotobuf-lite.cmake)
-include(${protobuf_SOURCE_DIR}/cmake/libprotobuf.cmake)
-if (protobuf_BUILD_LIBPROTOC)
- include(${protobuf_SOURCE_DIR}/cmake/libprotoc.cmake)
-endif (protobuf_BUILD_LIBPROTOC)
-if (protobuf_BUILD_PROTOC_BINARIES)
- include(${protobuf_SOURCE_DIR}/cmake/protoc.cmake)
- if (NOT DEFINED protobuf_PROTOC_EXE)
- set(protobuf_PROTOC_EXE protoc)
- endif (NOT DEFINED protobuf_PROTOC_EXE)
-endif (protobuf_BUILD_PROTOC_BINARIES)
+if (protobuf_BUILD_PROTOBUF_BINARIES)
+ include(${protobuf_SOURCE_DIR}/cmake/libprotobuf-lite.cmake)
+ if (NOT DEFINED protobuf_LIB_PROTOBUF_LITE)
+ set(protobuf_LIB_PROTOBUF_LITE libprotobuf-lite)
+ endif ()
+ include(${protobuf_SOURCE_DIR}/cmake/libprotobuf.cmake)
+ if (NOT DEFINED protobuf_LIB_PROTOBUF)
+ set(protobuf_LIB_PROTOBUF libprotobuf)
+ endif ()
+ if (protobuf_BUILD_LIBPROTOC)
+ include(${protobuf_SOURCE_DIR}/cmake/libprotoc.cmake)
+ if (NOT DEFINED protobuf_LIB_PROTOC)
+ set(protobuf_LIB_PROTOC libprotoc)
+ endif ()
+ endif ()
+ if (protobuf_BUILD_PROTOC_BINARIES)
+ include(${protobuf_SOURCE_DIR}/cmake/protoc.cmake)
+ if (NOT DEFINED protobuf_PROTOC_EXE)
+ set(protobuf_PROTOC_EXE protoc)
+ endif ()
+ endif ()
+else ()
+ find_package(protobuf)
+ if (protobuf_FOUND)
+ set(protobuf_PROTOC_EXE protobuf::protoc)
+ set(protobuf_LIB_PROTOC protobuf::libprotoc)
+ set(protobuf_LIB_PROTOBUF protobuf::libprotobuf)
+ set(protobuf_LIB_PROTOBUF_LITE protobuf::libprotobuf-lite)
+ message(STATUS "CMake installation of Protobuf found.")
+ endif ()
+endif ()
-# Ensure we have a protoc executable if we need one
+# Ensure we have a protoc executable and protobuf libraries if we need one
if (protobuf_BUILD_TESTS OR protobuf_BUILD_CONFORMANCE OR protobuf_BUILD_EXAMPLES)
if (NOT DEFINED protobuf_PROTOC_EXE)
- find_program(protobuf_PROTOC_EXE protoc)
- if (NOT protobuf_PROTOC_EXE)
- message(FATAL "Build requires 'protoc' but binary not found and not building protoc.")
- endif ()
+ find_program(protobuf_PROTOC_EXE protoc REQUIRED)
+ message(STATUS "Found system ${protobuf_PROTOC_EXE}.")
endif ()
if(protobuf_VERBOSE)
message(STATUS "Using protoc : ${protobuf_PROTOC_EXE}")
+ message(STATUS "Using libprotobuf : ${protobuf_LIB_PROTOBUF}")
+ message(STATUS "Using libprotobuf-lite : ${protobuf_LIB_PROTOBUF_LITE}")
+ message(STATUS "Using libprotoc : ${protobuf_LIB_PROTOC}")
endif(protobuf_VERBOSE)
endif ()
diff --git a/Makefile.am b/Makefile.am
index d35bcaf..acc72c2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -131,11 +131,13 @@
csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs \
csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj \
csharp/src/Google.Protobuf.Test/IssuesTest.cs \
+ csharp/src/Google.Protobuf.Test/JsonFormatterSettingsTest.cs \
csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs \
csharp/src/Google.Protobuf.Test/JsonParserTest.cs \
csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs \
csharp/src/Google.Protobuf.Test/LegacyGeneratedCodeTest.cs \
csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs \
+ csharp/src/Google.Protobuf.Test/ParsingPrimitivesTest.cs \
csharp/src/Google.Protobuf.Test/Proto3OptionalTest.cs \
csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs \
csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs \
@@ -174,6 +176,7 @@
csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs \
csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs \
csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs \
+ csharp/src/Google.Protobuf.Test/WritingPrimitivesTest.cs \
csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs \
csharp/src/Google.Protobuf.Test/testprotos.pb \
csharp/src/Google.Protobuf.sln \
@@ -958,6 +961,8 @@
php/tests/EncodeDecodeTest.php \
php/tests/force_c_ext.php \
php/tests/gdb_test.sh \
+ php/tests/generated_previous/GPBMetadata/ProtoPrevious/TestPreviouslyUnreservedMessage.php \
+ php/tests/generated_previous/Previous/readonly.php \
php/tests/GeneratedClassTest.php \
php/tests/GeneratedPhpdocTest.php \
php/tests/GeneratedServiceTest.php \
@@ -967,6 +972,7 @@
php/tests/multirequest.php \
php/tests/multirequest.sh \
php/tests/PhpImplementationTest.php \
+ php/tests/PreviouslyGeneratedClassTest.php \
php/tests/proto/empty/echo.proto \
php/tests/proto/test.proto \
php/tests/proto/test_descriptors.proto \
@@ -985,6 +991,7 @@
php/tests/proto/test_service.proto \
php/tests/proto/test_service_namespace.proto \
php/tests/proto/test_wrapper_type_setters.proto \
+ php/tests/proto_previous/test_previously_unreserved_message.proto \
php/tests/test_base.php \
php/tests/test_util.php \
php/tests/valgrind.supp \
@@ -1214,7 +1221,6 @@
cmake/README.md \
cmake/conformance.cmake \
cmake/examples.cmake \
- cmake/extract_includes.bat.in \
cmake/install.cmake \
cmake/libprotobuf-lite.cmake \
cmake/libprotobuf.cmake \
diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec
index c8a516b..858a861 100644
--- a/Protobuf-C++.podspec
+++ b/Protobuf-C++.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Protobuf-C++'
- s.version = '3.21.2'
+ s.version = '3.21.4'
s.summary = 'Protocol Buffers v3 runtime library for C++.'
s.homepage = 'https://github.com/google/protobuf'
s.license = 'BSD-3-Clause'
diff --git a/Protobuf.podspec b/Protobuf.podspec
index 85f1dc6..e41f39a 100644
--- a/Protobuf.podspec
+++ b/Protobuf.podspec
@@ -5,7 +5,7 @@
# dependent projects use the :git notation to refer to the library.
Pod::Spec.new do |s|
s.name = 'Protobuf'
- s.version = '3.21.2'
+ s.version = '3.21.4'
s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.'
s.homepage = 'https://github.com/protocolbuffers/protobuf'
s.license = 'BSD-3-Clause'
diff --git a/README.md b/README.md
index c2e6575..ae63158 100644
--- a/README.md
+++ b/README.md
@@ -82,3 +82,10 @@
web at:
https://developers.google.com/protocol-buffers/
+
+Developer Community
+-------------------
+
+To be alerted to upcoming changes in Protocol Buffers and connect with protobuf developers and users,
+[join the Google Group](https://groups.google.com/g/protobuf).
+
diff --git a/cmake/README.md b/cmake/README.md
index ce3e680..4a4259e 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -1,15 +1,19 @@
-This directory contains *CMake* files that can be used to build protobuf
-with *MSVC* on *Windows*. You can build the project from *Command Prompt*
-and using an *Visual Studio* IDE.
+This directory contains *CMake* files that can be used to build protobuf.
-You need to have [CMake](http://www.cmake.org), [Visual Studio](https://www.visualstudio.com)
-and optionally [Git](http://git-scm.com) installed on your computer before proceeding.
+You need to have [CMake](http://www.cmake.org) and
+[Git](http://git-scm.com) installed on your computer before proceeding.
-Most of the instructions will be given to the *Сommand Prompt*, but the same
-actions can be performed using appropriate GUI tools.
+Most of the instructions will be given using CMake's command-line interface, but
+the same actions can be performed using appropriate GUI tools.
-Environment Setup
-=================
+# Windows Builds
+
+On Windows, you can build the project from *Command Prompt* and using an
+*Visual Studio* IDE. You will also need to have
+[Visual Studio](https://www.visualstudio.com) installed on your computer before
+proceeding.
+
+## Environment Setup
Open the appropriate *Command Prompt* from the *Start* menu.
@@ -42,8 +46,7 @@
Good. Now you are ready to continue.
-Getting Sources
-===============
+## Getting Sources
You can get the latest stable source packages from the release page:
@@ -76,8 +79,7 @@
Good. Now you are ready for *CMake* configuration.
-CMake Configuration
-===================
+## CMake Configuration
*CMake* supports a lot of different
[generators](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html)
@@ -137,8 +139,7 @@
It will generate *Visual Studio* solution file *protobuf.sln* in current directory.
-Unit Tests
-----------
+### Unit Tests
Unit tests are being built along with the rest of protobuf. The unit tests require Google Mock (now a part of Google Test).
@@ -178,8 +179,7 @@
-Dprotobuf_BUILD_TESTS=OFF ^
C:\Path\to\src\protobuf
-Compiling
-=========
+## Compiling
The standard way to compile a *CMake* project is `cmake --build <directory>`.
@@ -206,8 +206,7 @@
And wait for the compilation to finish.
-Testing
-=======
+## Testing
To run unit-tests, first you must compile protobuf as described above.
Then run:
@@ -259,8 +258,7 @@
If all tests are passed, safely continue.
-Installing
-==========
+## Installing
To install protobuf to the *install* folder you've specified in the configuration step, you need to build the `install` target:
@@ -292,8 +290,7 @@
debug build of libprotobufd.lib with "d" postfix. Similarly, release builds should link against
release libprotobuf.lib library.
-DLLs vs. static linking
-=======================
+## DLLs vs. static linking
Static linking is now the default for the Protocol Buffer libraries. Due to
issues with Win32's use of a separate heap for each DLL, as well as binary
@@ -318,8 +315,7 @@
public interface, and that you statically link protocol buffers into your
library.
-ZLib support
-============
+## ZLib support
If you want to include GzipInputStream and GzipOutputStream
(google/protobuf/io/gzip_stream.h) in libprotobuf, you will need to do a few
@@ -369,8 +365,7 @@
Build and testing protobuf as usual.
-Notes on Compiler Warnings
-==========================
+## Notes on Compiler Warnings
The following warnings have been disabled while building the protobuf libraries
and compiler. You may have to disable some of them in your own project as
@@ -397,3 +392,23 @@
nevertheless. So, we disable it. Unfortunately, this warning will also be
produced when compiling code which merely uses protocol buffers, meaning you
may have to disable it in your code too.
+
+# Linux Builds
+
+Building with CMake works very similarly on Linux. Instead of Visual Studio,
+you will need to have gcc or clang installed to handle the C++ builds. CMake
+will generate Makefiles by default, but can also be configured to use Ninja. To
+build Protobuf, you will need to run (from the source directory):
+
+ cmake .
+ cmake --build . --parallel 10
+
+Protobuf can be tested and installed with CMake:
+
+ ctest --verbose
+ sudo cmake --install .
+
+or directly with the generated Makefiles:
+
+ make VERBOSE=1 test
+ sudo make install
diff --git a/cmake/conformance.cmake b/cmake/conformance.cmake
index d6c435a..338b275 100644
--- a/cmake/conformance.cmake
+++ b/cmake/conformance.cmake
@@ -24,6 +24,9 @@
${protobuf_SOURCE_DIR}/conformance/conformance.pb.cc
${protobuf_SOURCE_DIR}/conformance/conformance_test.cc
${protobuf_SOURCE_DIR}/conformance/conformance_test_runner.cc
+ ${protobuf_SOURCE_DIR}/conformance/conformance_test_main.cc
+ ${protobuf_SOURCE_DIR}/conformance/text_format_conformance_suite.cc
+ ${protobuf_SOURCE_DIR}/conformance/text_format_conformance_suite.h
${protobuf_SOURCE_DIR}/conformance/third_party/jsoncpp/json.h
${protobuf_SOURCE_DIR}/conformance/third_party/jsoncpp/jsoncpp.cpp
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.pb.cc
@@ -45,5 +48,13 @@
conformance_cpp
PUBLIC ${protobuf_SOURCE_DIR}/conformance)
-target_link_libraries(conformance_test_runner libprotobuf)
-target_link_libraries(conformance_cpp libprotobuf)
+target_link_libraries(conformance_test_runner ${protobuf_LIB_PROTOBUF})
+target_link_libraries(conformance_cpp ${protobuf_LIB_PROTOBUF})
+
+add_test(NAME conformance_cpp_test
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/conformance_test_runner
+ --failure_list ${protobuf_SOURCE_DIR}/conformance/failure_list_cpp.txt
+ --text_format_failure_list ${protobuf_SOURCE_DIR}/conformance/text_format_failure_list_cpp.txt
+ --output_dir ${protobuf_TEST_XML_OUTDIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/conformance_cpp
+ DEPENDS conformance_test_runner conformance_cpp)
diff --git a/cmake/examples.cmake b/cmake/examples.cmake
index 3b83d2b..07cfad2 100644
--- a/cmake/examples.cmake
+++ b/cmake/examples.cmake
@@ -30,7 +30,7 @@
# Add examples as an external project.
# sub_directory cannot be used because the find_package(protobuf) call would cause failures with redefined targets.
add_examples_build(examples "-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}")
-add_dependencies(examples libprotobuf protoc)
+add_dependencies(examples ${protobuf_LIB_PROTOBUF} ${protobuf_PROTOC_EXE})
option(protobuf_BUILD_EXAMPLES_MULTITEST "Build Examples in multiple configurations. Useful for testing." OFF)
mark_as_advanced(protobuf_BUILD_EXAMPLES_MULTITEST)
@@ -42,7 +42,7 @@
"-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}"
"-Dprotobuf_MODULE_COMPATIBLE:BOOL=TRUE"
)
- add_dependencies(examples-legacy libprotobuf protoc)
+ add_dependencies(examples-legacy ${protobuf_LIB_PROTOBUF} ${protobuf_PROTOC_EXE})
#Build using the installed library.
add_examples_build(examples-installed
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
deleted file mode 100644
index 1292829..0000000
--- a/cmake/extract_includes.bat.in
+++ /dev/null
@@ -1,144 +0,0 @@
-mkdir include
-mkdir include\google
-mkdir include\google\protobuf
-mkdir include\google\protobuf\compiler
-mkdir include\google\protobuf\compiler\cpp
-mkdir include\google\protobuf\compiler\csharp
-mkdir include\google\protobuf\compiler\java
-mkdir include\google\protobuf\compiler\objectivec
-mkdir include\google\protobuf\compiler\php
-mkdir include\google\protobuf\compiler\python
-mkdir include\google\protobuf\compiler\ruby
-mkdir include\google\protobuf\io
-mkdir include\google\protobuf\stubs
-mkdir include\google\protobuf\util
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.h" include\google\protobuf\any.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.pb.h" include\google\protobuf\any.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.pb.h" include\google\protobuf\api.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arena.h" include\google\protobuf\arena.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arena_impl.h" include\google\protobuf\arena_impl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arenastring.h" include\google\protobuf\arenastring.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arenaz_sampler.h" include\google\protobuf\arenaz_sampler.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\code_generator.h" include\google\protobuf\compiler\code_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\command_line_interface.h" include\google\protobuf\compiler\command_line_interface.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\file.h" include\google\protobuf\compiler\cpp\file.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\cpp_generator.h" include\google\protobuf\compiler\cpp\cpp_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\generator.h" include\google\protobuf\compiler\cpp\generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\helpers.h" include\google\protobuf\compiler\cpp\helpers.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\names.h" include\google\protobuf\compiler\cpp\names.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_doc_comment.h" include\google\protobuf\compiler\csharp\csharp_doc_comment.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_generator.h" include\google\protobuf\compiler\csharp\csharp_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h" include\google\protobuf\compiler\csharp\csharp_names.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_options.h" include\google\protobuf\compiler\csharp\csharp_options.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h" include\google\protobuf\compiler\importer.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\generator.h" include\google\protobuf\compiler\java\generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h" include\google\protobuf\compiler\java\java_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\kotlin_generator.h" include\google\protobuf\compiler\java\kotlin_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\names.h" include\google\protobuf\compiler\java\names.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_generator.h" include\google\protobuf\compiler\objectivec\objectivec_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_helpers.h" include\google\protobuf\compiler\objectivec\objectivec_helpers.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h" include\google\protobuf\compiler\parser.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\generator.h" include\google\protobuf\compiler\python\generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\pyi_generator.h" include\google\protobuf\compiler\python\pyi_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h" include\google\protobuf\compiler\python\python_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.pb.h" include\google\protobuf\descriptor.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor_database.h" include\google\protobuf\descriptor_database.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.pb.h" include\google\protobuf\duration.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\dynamic_message.h" include\google\protobuf\dynamic_message.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.pb.h" include\google\protobuf\empty.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\endian.h" include\google\protobuf\endian.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\explicitly_constructed.h" include\google\protobuf\explicitly_constructed.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set.h" include\google\protobuf\extension_set.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set_inl.h" include\google\protobuf\extension_set_inl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_access_listener.h" include\google\protobuf\field_access_listener.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.pb.h" include\google\protobuf\field_mask.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflection.h" include\google\protobuf\generated_enum_reflection.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h" include\google\protobuf\generated_enum_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_bases.h" include\google\protobuf\generated_message_bases.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h" include\google\protobuf\generated_message_reflection.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_tctable_decl.h" include\google\protobuf\generated_message_tctable_decl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_tctable_impl.h" include\google\protobuf\generated_message_tctable_impl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\inlined_string_field.h" include\google\protobuf\inlined_string_field.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h" include\google\protobuf\io\gzip_stream.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\io_win32.h" include\google\protobuf\io\io_win32.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\printer.h" include\google\protobuf\io\printer.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\strtod.h" include\google\protobuf\io\strtod.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\tokenizer.h" include\google\protobuf\io\tokenizer.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream.h" include\google\protobuf\io\zero_copy_stream.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl.h" include\google\protobuf\io\zero_copy_stream_impl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl_lite.h" include\google\protobuf\io\zero_copy_stream_impl_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map.h" include\google\protobuf\map.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry.h" include\google\protobuf\map_entry.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry_lite.h" include\google\protobuf\map_entry_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field.h" include\google\protobuf\map_field.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_inl.h" include\google\protobuf\map_field_inl.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_lite.h" include\google\protobuf\map_field_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_type_handler.h" include\google\protobuf\map_type_handler.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message.h" include\google\protobuf\message.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message_lite.h" include\google\protobuf\message_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata.h" include\google\protobuf\metadata.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata_lite.h" include\google\protobuf\metadata_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\parse_context.h" include\google\protobuf\parse_context.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port.h" include\google\protobuf\port.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_def.inc" include\google\protobuf\port_def.inc
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_undef.inc" include\google\protobuf\port_undef.inc
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\bytestream.h" include\google\protobuf\stubs\bytestream.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\callback.h" include\google\protobuf\stubs\callback.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\casts.h" include\google\protobuf\stubs\casts.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\common.h" include\google\protobuf\stubs\common.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\hash.h" include\google\protobuf\stubs\hash.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\logging.h" include\google\protobuf\stubs\logging.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\macros.h" include\google\protobuf\stubs\macros.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\map_util.h" include\google\protobuf\stubs\map_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\mutex.h" include\google\protobuf\stubs\mutex.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\once.h" include\google\protobuf\stubs\once.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros.h" include\google\protobuf\stubs\platform_macros.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\port.h" include\google\protobuf\stubs\port.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\status.h" include\google\protobuf\stubs\status.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stl_util.h" include\google\protobuf\stubs\stl_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stringpiece.h" include\google\protobuf\stubs\stringpiece.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\strutil.h" include\google\protobuf\stubs\strutil.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\template_util.h" include\google\protobuf\stubs\template_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\text_format.h" include\google\protobuf\text_format.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.pb.h" include\google\protobuf\timestamp.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.pb.h" include\google\protobuf\type.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\unknown_field_set.h" include\google\protobuf\unknown_field_set.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\delimited_message_util.h" include\google\protobuf\util\delimited_message_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_comparator.h" include\google\protobuf\util\field_comparator.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_mask_util.h" include\google\protobuf\util\field_mask_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\json_util.h" include\google\protobuf\util\json_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\message_differencer.h" include\google\protobuf\util\message_differencer.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\time_util.h" include\google\protobuf\util\time_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver.h" include\google\protobuf\util\type_resolver.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver_util.h" include\google\protobuf\util\type_resolver_util.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format.h" include\google\protobuf\wire_format.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite.h" include\google\protobuf\wire_format_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.pb.h" include\google\protobuf\wrappers.pb.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.proto" include\google\protobuf\any.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.proto" include\google\protobuf\api.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.proto" include\google\protobuf\compiler\plugin.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.proto" include\google\protobuf\descriptor.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.proto" include\google\protobuf\duration.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.proto" include\google\protobuf\empty.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.proto" include\google\protobuf\field_mask.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.proto" include\google\protobuf\source_context.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.proto" include\google\protobuf\struct.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.proto" include\google\protobuf\timestamp.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.proto" include\google\protobuf\type.proto
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.proto" include\google\protobuf\wrappers.proto
diff --git a/cmake/install.cmake b/cmake/install.cmake
index 2da8170..cf24e30 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -43,25 +43,23 @@
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/protobuf.pc ${CMAKE_CURRENT_BINARY_DIR}/protobuf-lite.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
-file(STRINGS ${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in _extract_strings
- REGEX "^copy")
-foreach(_extract_string ${_extract_strings})
- string(REGEX REPLACE "^.* .+ include\\\\(.+)$" "\\1"
- _header ${_extract_string})
- string(REPLACE "\\" "/" _header ${_header})
+include(${protobuf_SOURCE_DIR}/src/file_lists.cmake)
+set(protobuf_HEADERS
+ ${libprotobuf_hdrs}
+ ${libprotoc_hdrs}
+ ${wkt_protos_files}
+ ${descriptor_proto_proto_srcs}
+ ${plugin_proto_proto_srcs}
+)
+foreach(_header ${protobuf_HEADERS})
+ string(REPLACE "${protobuf_SOURCE_DIR}/src" "" _header ${_header})
get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/src/${_header}" ABSOLUTE)
get_filename_component(_extract_name ${_header} NAME)
get_filename_component(_extract_to "${CMAKE_INSTALL_INCLUDEDIR}/${_header}" DIRECTORY)
- if(EXISTS "${_extract_from}")
- install(FILES "${_extract_from}"
- DESTINATION "${_extract_to}"
- COMPONENT protobuf-headers
- RENAME "${_extract_name}")
- else()
- message(AUTHOR_WARNING "The file \"${_extract_from}\" is listed in "
- "\"${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in\" "
- "but there not exists. The file will not be installed.")
- endif()
+ install(FILES "${_extract_from}"
+ DESTINATION "${_extract_to}"
+ COMPONENT protobuf-headers
+ RENAME "${_extract_name}")
endforeach()
# Internal function for parsing auto tools scripts
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index be1d429..ce2a890 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -1,6 +1,7 @@
option(protobuf_USE_EXTERNAL_GTEST "Use external Google Test (i.e. not the one in third_party/googletest)" OFF)
-option(protobuf_TEST_XML_OUTDIR "Output directory for XML logs from tests." "")
+option(protobuf_REMOVE_INSTALLED_HEADERS
+ "Remove local headers so that installed ones are used instead" OFF)
option(protobuf_ABSOLUTE_TEST_PLUGIN_PATH
"Using absolute test_plugin path in tests" ON)
@@ -77,10 +78,9 @@
add_library(protobuf-lite-test-common STATIC
${lite_test_util_srcs} ${lite_test_proto_files})
-target_link_libraries(protobuf-lite-test-common libprotobuf-lite GTest::gmock)
+target_link_libraries(protobuf-lite-test-common ${protobuf_LIB_PROTOBUF_LITE} GTest::gmock)
set(common_test_files
- ${lite_test_util_srcs}
${test_util_hdrs}
${test_util_srcs}
${mock_code_generator_srcs}
@@ -89,7 +89,7 @@
add_library(protobuf-test-common STATIC
${common_test_files} ${tests_proto_files})
-target_link_libraries(protobuf-test-common libprotobuf GTest::gmock)
+target_link_libraries(protobuf-test-common ${protobuf_LIB_PROTOBUF} GTest::gmock)
set(tests_files
${protobuf_test_files}
@@ -130,7 +130,7 @@
/wd4146 # unary minus operator applied to unsigned type, result still unsigned
)
endif()
-target_link_libraries(tests protobuf-lite-test-common protobuf-test-common libprotoc libprotobuf GTest::gmock_main)
+target_link_libraries(tests protobuf-lite-test-common protobuf-test-common ${protobuf_LIB_PROTOC} ${protobuf_LIB_PROTOBUF_LITE} GTest::gmock_main)
set(test_plugin_files
${test_plugin_files}
@@ -139,19 +139,50 @@
)
add_executable(test_plugin ${test_plugin_files})
-target_link_libraries(test_plugin libprotoc libprotobuf GTest::gmock)
+target_link_libraries(test_plugin ${protobuf_LIB_PROTOC} ${protobuf_LIB_PROTOBUF} GTest::gmock)
add_executable(lite-test ${protobuf_lite_test_files})
-target_link_libraries(lite-test protobuf-lite-test-common libprotobuf-lite GTest::gmock_main)
+target_link_libraries(lite-test protobuf-lite-test-common ${protobuf_LIB_PROTOBUF_LITE} GTest::gmock_main)
add_test(NAME lite-test
COMMAND lite-test ${protobuf_GTEST_ARGS})
add_custom_target(check
COMMAND tests
- DEPENDS tests test_plugin
+ DEPENDS tests lite-test test_plugin
WORKING_DIRECTORY ${protobuf_SOURCE_DIR})
add_test(NAME check
- COMMAND tests ${protobuf_GTEST_ARGS}
- WORKING_DIRECTORY "${protobuf_SOURCE_DIR}")
+ COMMAND tests ${protobuf_GTEST_ARGS})
+
+# For test purposes, remove headers that should already be installed. This
+# prevents accidental conflicts and also version skew (since local headers take
+# precedence over installed headers).
+add_custom_target(save-installed-headers)
+add_custom_target(remove-installed-headers)
+add_custom_target(restore-installed-headers)
+
+# Explicitly skip the bootstrapping headers as it's directly used in tests
+set(_installed_hdrs ${libprotobuf_hdrs} ${libprotoc_hdrs})
+list(REMOVE_ITEM _installed_hdrs
+ "${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.h"
+ "${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h")
+
+foreach(_hdr ${_installed_hdrs})
+ string(REPLACE "${protobuf_SOURCE_DIR}/src" "" _file ${_hdr})
+ set(_tmp_file "${CMAKE_BINARY_DIR}/tmp-install-test/${_file}")
+ add_custom_command(TARGET remove-installed-headers PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E remove -f "${_hdr}")
+ add_custom_command(TARGET save-installed-headers PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E
+ copy "${_hdr}" "${_tmp_file}" || true)
+ add_custom_command(TARGET restore-installed-headers PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E
+ copy "${_tmp_file}" "${_hdr}")
+endforeach()
+
+add_dependencies(remove-installed-headers save-installed-headers)
+if(protobuf_REMOVE_INSTALLED_HEADERS)
+ add_dependencies(protobuf-lite-test-common remove-installed-headers)
+ add_dependencies(protobuf-test-common remove-installed-headers)
+endif()
diff --git a/configure.ac b/configure.ac
index c55a6a2..64ddb3d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
# In the SVN trunk, the version should always be the next anticipated release
# version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed
# the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[3.21.2],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.21.4],[protobuf@googlegroups.com],[protobuf])
AM_MAINTAINER_MODE([enable])
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index 9b1548d..3719a52 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -2724,6 +2724,12 @@
"DurationNull", REQUIRED,
R"({"optionalDuration": null})",
"");
+ RunValidJsonTest("DurationNegativeSeconds", REQUIRED,
+ R"({"optionalDuration": "-5s"})",
+ "optional_duration: {seconds: -5 nanos: 0}");
+ RunValidJsonTest("DurationNegativeNanos", REQUIRED,
+ R"({"optionalDuration": "-0.5s"})",
+ "optional_duration: {seconds: 0 nanos: -500000000}");
ExpectParseFailureForJson(
"DurationMissingS", REQUIRED,
diff --git a/conformance/failure_list_php.txt b/conformance/failure_list_php.txt
index 667f80c..3232047a 100644
--- a/conformance/failure_list_php.txt
+++ b/conformance/failure_list_php.txt
@@ -8,6 +8,8 @@
Recommended.Proto3.ProtobufInput.ValidDataOneofBinary.MESSAGE.Merge.ProtobufOutput
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
Required.Proto3.JsonInput.DoubleFieldTooSmall
+Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
+Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
Required.Proto3.JsonInput.FloatFieldTooLarge
Required.Proto3.JsonInput.FloatFieldTooSmall
Required.Proto3.JsonInput.Int32FieldNotInteger
diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt
index 63c7e8a..52ca454 100644
--- a/conformance/failure_list_php_c.txt
+++ b/conformance/failure_list_php_c.txt
@@ -1,2 +1,5 @@
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
+Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
+Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
+Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
index 4938202..ff230a2 100644
--- a/conformance/failure_list_ruby.txt
+++ b/conformance/failure_list_ruby.txt
@@ -56,3 +56,6 @@
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput
+Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
+Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
+Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput
diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec
index ea05597..90033cf 100644
--- a/csharp/Google.Protobuf.Tools.nuspec
+++ b/csharp/Google.Protobuf.Tools.nuspec
@@ -5,7 +5,7 @@
<title>Google Protocol Buffers tools</title>
<summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
<description>See project site for more info.</description>
- <version>3.21.2</version>
+ <version>3.21.4</version>
<authors>Google Inc.</authors>
<owners>protobuf-packages</owners>
<licenseUrl>https://github.com/protocolbuffers/protobuf/blob/main/LICENSE</licenseUrl>
diff --git a/csharp/README.md b/csharp/README.md
index df48499..02abb7c 100644
--- a/csharp/README.md
+++ b/csharp/README.md
@@ -16,18 +16,19 @@
Supported platforms
===================
-The runtime library is built as a portable class library, supporting:
+The runtime library is built as a class library, supporting targets of:
-- .NET 4.5
-- Windows 8
-- Windows Phone Silverlight 8
-- Windows Phone 8.1
-- .NET Core
-- .NET 5
+- .NET 4.5+ (`net45`)
+- .NET Standard 1.1 and 2.0 (`netstandard1.1` and `netstandard2.0`)
+- .NET 5+ (`net50`)
You should be able to use Protocol Buffers in Visual Studio 2012 and
all later versions. This includes all code generated by `protoc`,
-which only uses features from C# 3 and earlier.
+which only uses features from C# 3 and earlier. When compiling generated
+code with old compilers (before C# 7.2) you need to define the
+`GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE` symbol in your project
+so that the generated classes don't implement `IBufferMessage`, which uses
+`ref struct` types.
Building
========
@@ -42,12 +43,6 @@
have no impact when using the compiled code - they're only relevant
when building the `Google.Protobuf` assembly.
-In order to run and debug the AddressBook example in the IDE, you must
-install the optional component, ".Net Core 1.0 - 1.1 development tools
-for Web" (as it's labelled in current versions of the VS2017
-installer), above and beyond the main .NET Core cross-platform
-development feature.
-
Testing
=======
@@ -57,20 +52,11 @@
.NET 3.5
========
-We don't officially support .NET 3.5. However, there has been some effort
-to make enabling .NET 3.5 support relatively painless in case you require it.
-There's no guarantee that this will continue in the future, so rely on .NET
-3.5 support at your peril.
-
-To enable .NET 3.5 support, you must edit the `TargetFrameworks` elements of
-[src/Google.Protobuf/Google.Protobuf.csproj](src/Google.Protobuf/Google.Protobuf.csproj)
-(and [src/Google.Protobuf.Test/Google.Protobuf.Test.csproj](src/Google.Protobuf.Test/Google.Protobuf.Test.csproj)
-if you want to run the unit tests):
-
-Open the .csproj file in a text editor and simply add `net35` to the list of
-target frameworks, noting that the `TargetFrameworks` element appears twice in
-the file (once in the first `PropertyGroup` element, and again in the second
-`PropertyGroup` element, i.e., the one with the conditional).
+We don't support .NET 3.5. It *used* to be feasible to build this library
+targeting .NET 3.5, but a number of changes requiring newer runtime/framework
+features have been added over time. While it would no doubt be *possible* to
+rework the current implementation to allow most of the functionality to be built
+in .NET 3.5, this would create an undue maintenance burden.
History of C# protobufs
=======================
@@ -82,9 +68,9 @@
The previous project differs from this project in a number of ways:
-- The old code only supported proto2; the new code only supports
+- The old code only supported proto2; the new code initially only supported
proto3 (so no unknown fields, no required/optional distinction, no
-extensions)
+extensions); since then proto2 support has been added
- The old code was based on immutable message types and builders for
them
- The old code did not support maps or `oneof`
diff --git a/csharp/protos/unittest_issues.proto b/csharp/protos/unittest_issues.proto
index f46c20e..45df7a1 100644
--- a/csharp/protos/unittest_issues.proto
+++ b/csharp/protos/unittest_issues.proto
@@ -169,4 +169,20 @@
string x = 1;
string y = 2;
}
-}
\ No newline at end of file
+}
+
+// Issue 8810
+message DisambiguateCommonMembers {
+ int32 disambiguate_common_members = 1;
+ int32 types = 2;
+ int32 descriptor = 3;
+ int32 equals = 4;
+ int32 to_string = 5;
+ int32 get_hash_code = 6;
+ int32 write_to = 7;
+ int32 clone = 8;
+ int32 calculate_size = 9;
+ int32 merge_from = 10;
+ int32 on_construction = 11;
+ int32 parser = 12;
+}
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test.TestProtos/MapUnittestProto3.cs
index 57e59a9..d3284a4 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/MapUnittestProto3.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/MapUnittestProto3.cs
@@ -580,23 +580,23 @@
if (other == null) {
return;
}
- mapInt32Int32_.Add(other.mapInt32Int32_);
- mapInt64Int64_.Add(other.mapInt64Int64_);
- mapUint32Uint32_.Add(other.mapUint32Uint32_);
- mapUint64Uint64_.Add(other.mapUint64Uint64_);
- mapSint32Sint32_.Add(other.mapSint32Sint32_);
- mapSint64Sint64_.Add(other.mapSint64Sint64_);
- mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
- mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
- mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
- mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
- mapInt32Float_.Add(other.mapInt32Float_);
- mapInt32Double_.Add(other.mapInt32Double_);
- mapBoolBool_.Add(other.mapBoolBool_);
- mapStringString_.Add(other.mapStringString_);
- mapInt32Bytes_.Add(other.mapInt32Bytes_);
- mapInt32Enum_.Add(other.mapInt32Enum_);
- mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
+ mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
+ mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
+ mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
+ mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
+ mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
+ mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
+ mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
+ mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
+ mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
+ mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
+ mapInt32Float_.MergeFrom(other.mapInt32Float_);
+ mapInt32Double_.MergeFrom(other.mapInt32Double_);
+ mapBoolBool_.MergeFrom(other.mapBoolBool_);
+ mapStringString_.MergeFrom(other.mapStringString_);
+ mapInt32Bytes_.MergeFrom(other.mapInt32Bytes_);
+ mapInt32Enum_.MergeFrom(other.mapInt32Enum_);
+ mapInt32ForeignMessage_.MergeFrom(other.mapInt32ForeignMessage_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1100,7 +1100,7 @@
if (other == null) {
return;
}
- mapInt32Message_.Add(other.mapInt32Message_);
+ mapInt32Message_.MergeFrom(other.mapInt32Message_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1298,8 +1298,8 @@
if (other == null) {
return;
}
- map1_.Add(other.map1_);
- map2_.Add(other.map2_);
+ map1_.MergeFrom(other.map1_);
+ map2_.MergeFrom(other.map2_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1723,21 +1723,21 @@
if (other == null) {
return;
}
- mapInt32Int32_.Add(other.mapInt32Int32_);
- mapInt64Int64_.Add(other.mapInt64Int64_);
- mapUint32Uint32_.Add(other.mapUint32Uint32_);
- mapUint64Uint64_.Add(other.mapUint64Uint64_);
- mapSint32Sint32_.Add(other.mapSint32Sint32_);
- mapSint64Sint64_.Add(other.mapSint64Sint64_);
- mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
- mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
- mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
- mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
- mapInt32Float_.Add(other.mapInt32Float_);
- mapInt32Double_.Add(other.mapInt32Double_);
- mapBoolBool_.Add(other.mapBoolBool_);
- mapInt32Enum_.Add(other.mapInt32Enum_);
- mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
+ mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
+ mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
+ mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
+ mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
+ mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
+ mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
+ mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
+ mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
+ mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
+ mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
+ mapInt32Float_.MergeFrom(other.mapInt32Float_);
+ mapInt32Double_.MergeFrom(other.mapInt32Double_);
+ mapBoolBool_.MergeFrom(other.mapBoolBool_);
+ mapInt32Enum_.MergeFrom(other.mapInt32Enum_);
+ mapInt32ForeignMessage_.MergeFrom(other.mapInt32ForeignMessage_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -2031,7 +2031,7 @@
if (other == null) {
return;
}
- type_.Add(other.type_);
+ type_.MergeFrom(other.type_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -2224,7 +2224,7 @@
if (other == null) {
return;
}
- entry_.Add(other.entry_);
+ entry_.MergeFrom(other.entry_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
index 08b1aaf..d573455 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
@@ -4344,25 +4344,25 @@
unpackedDouble_.Add(other.unpackedDouble_);
unpackedBool_.Add(other.unpackedBool_);
unpackedNestedEnum_.Add(other.unpackedNestedEnum_);
- mapInt32Int32_.Add(other.mapInt32Int32_);
- mapInt64Int64_.Add(other.mapInt64Int64_);
- mapUint32Uint32_.Add(other.mapUint32Uint32_);
- mapUint64Uint64_.Add(other.mapUint64Uint64_);
- mapSint32Sint32_.Add(other.mapSint32Sint32_);
- mapSint64Sint64_.Add(other.mapSint64Sint64_);
- mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
- mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
- mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
- mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
- mapInt32Float_.Add(other.mapInt32Float_);
- mapInt32Double_.Add(other.mapInt32Double_);
- mapBoolBool_.Add(other.mapBoolBool_);
- mapStringString_.Add(other.mapStringString_);
- mapStringBytes_.Add(other.mapStringBytes_);
- mapStringNestedMessage_.Add(other.mapStringNestedMessage_);
- mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
- mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
- mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
+ mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
+ mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
+ mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
+ mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
+ mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
+ mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
+ mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
+ mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
+ mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
+ mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
+ mapInt32Float_.MergeFrom(other.mapInt32Float_);
+ mapInt32Double_.MergeFrom(other.mapInt32Double_);
+ mapBoolBool_.MergeFrom(other.mapBoolBool_);
+ mapStringString_.MergeFrom(other.mapStringString_);
+ mapStringBytes_.MergeFrom(other.mapStringBytes_);
+ mapStringNestedMessage_.MergeFrom(other.mapStringNestedMessage_);
+ mapStringForeignMessage_.MergeFrom(other.mapStringForeignMessage_);
+ mapStringNestedEnum_.MergeFrom(other.mapStringNestedEnum_);
+ mapStringForeignEnum_.MergeFrom(other.mapStringForeignEnum_);
if (other.HasData) {
if (!HasData) {
Data = new global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data();
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
index 520216f..74e2a57 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
@@ -3753,25 +3753,25 @@
unpackedDouble_.Add(other.unpackedDouble_);
unpackedBool_.Add(other.unpackedBool_);
unpackedNestedEnum_.Add(other.unpackedNestedEnum_);
- mapInt32Int32_.Add(other.mapInt32Int32_);
- mapInt64Int64_.Add(other.mapInt64Int64_);
- mapUint32Uint32_.Add(other.mapUint32Uint32_);
- mapUint64Uint64_.Add(other.mapUint64Uint64_);
- mapSint32Sint32_.Add(other.mapSint32Sint32_);
- mapSint64Sint64_.Add(other.mapSint64Sint64_);
- mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
- mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
- mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
- mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
- mapInt32Float_.Add(other.mapInt32Float_);
- mapInt32Double_.Add(other.mapInt32Double_);
- mapBoolBool_.Add(other.mapBoolBool_);
- mapStringString_.Add(other.mapStringString_);
- mapStringBytes_.Add(other.mapStringBytes_);
- mapStringNestedMessage_.Add(other.mapStringNestedMessage_);
- mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
- mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
- mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
+ mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
+ mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
+ mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
+ mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
+ mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
+ mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
+ mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
+ mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
+ mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
+ mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
+ mapInt32Float_.MergeFrom(other.mapInt32Float_);
+ mapInt32Double_.MergeFrom(other.mapInt32Double_);
+ mapBoolBool_.MergeFrom(other.mapBoolBool_);
+ mapStringString_.MergeFrom(other.mapStringString_);
+ mapStringBytes_.MergeFrom(other.mapStringBytes_);
+ mapStringNestedMessage_.MergeFrom(other.mapStringNestedMessage_);
+ mapStringForeignMessage_.MergeFrom(other.mapStringForeignMessage_);
+ mapStringNestedEnum_.MergeFrom(other.mapStringNestedEnum_);
+ mapStringForeignEnum_.MergeFrom(other.mapStringForeignEnum_);
if (other.optionalBoolWrapper_ != null) {
if (optionalBoolWrapper_ == null || other.OptionalBoolWrapper != false) {
OptionalBoolWrapper = other.OptionalBoolWrapper;
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Unittest.cs b/csharp/src/Google.Protobuf.Test.TestProtos/Unittest.cs
index c1f43ce..7f1aca1 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/Unittest.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/Unittest.cs
@@ -24112,7 +24112,7 @@
if (other == null) {
return;
}
- foo_.Add(other.foo_);
+ foo_.MergeFrom(other.foo_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -30708,7 +30708,7 @@
}
OptionalGroup.MergeFrom(other.OptionalGroup);
}
- stringStringMap_.Add(other.stringStringMap_);
+ stringStringMap_.MergeFrom(other.stringStringMap_);
switch (other.OneofFieldCase) {
case OneofFieldOneofCase.OneofUint32:
OneofUint32 = other.OneofUint32;
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs
index 3fe2dd6..d65a656 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs
@@ -56,11 +56,17 @@
"dWxhcl9maWVsZBgBIAEoCRIbCg5vcHRpb25hbF9maWVsZBgCIAEoCUgAiAEB",
"QhEKD19vcHRpb25hbF9maWVsZCI5ChJPbmVvZldpdGhOb25lRmllbGQSCwoB",
"eBgBIAEoCUgAEg4KBG5vbmUYAiABKAlIAEIGCgR0ZXN0IjUKEU9uZW9mV2l0",
- "aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSpV",
- "CgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJVkVfRU5VTV9aRVJPEAASFgoJRml2",
- "ZUJlbG93EPv//////////wESFQoITWludXNPbmUQ////////////ASouCg5E",
- "ZXByZWNhdGVkRW51bRITCg9ERVBSRUNBVEVEX1pFUk8QABIHCgNvbmUQAUId",
- "qgIaVW5pdFRlc3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw=="));
+ "aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSKT",
+ "AgoZRGlzYW1iaWd1YXRlQ29tbW9uTWVtYmVycxIjChtkaXNhbWJpZ3VhdGVf",
+ "Y29tbW9uX21lbWJlcnMYASABKAUSDQoFdHlwZXMYAiABKAUSEgoKZGVzY3Jp",
+ "cHRvchgDIAEoBRIOCgZlcXVhbHMYBCABKAUSEQoJdG9fc3RyaW5nGAUgASgF",
+ "EhUKDWdldF9oYXNoX2NvZGUYBiABKAUSEAoId3JpdGVfdG8YByABKAUSDQoF",
+ "Y2xvbmUYCCABKAUSFgoOY2FsY3VsYXRlX3NpemUYCSABKAUSEgoKbWVyZ2Vf",
+ "ZnJvbRgKIAEoBRIXCg9vbl9jb25zdHJ1Y3Rpb24YCyABKAUSDgoGcGFyc2Vy",
+ "GAwgASgFKlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8Q",
+ "ABIWCglGaXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD/////////",
+ "//8BKi4KDkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcK",
+ "A29uZRABQh2qAhpVbml0VGVzdC5Jc3N1ZXMuVGVzdFByb3Rvc2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
@@ -77,7 +83,8 @@
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NullValueNotInOneof), global::UnitTest.Issues.TestProtos.NullValueNotInOneof.Parser, new[]{ "NullValue" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.MixedRegularAndOptional), global::UnitTest.Issues.TestProtos.MixedRegularAndOptional.Parser, new[]{ "RegularField", "OptionalField" }, new[]{ "OptionalField" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneField), global::UnitTest.Issues.TestProtos.OneofWithNoneField.Parser, new[]{ "X", "None" }, new[]{ "Test" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers), global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers.Parser, new[]{ "DisambiguateCommonMembers_", "Types_", "Descriptor_", "Equals_", "ToString_", "GetHashCode_", "WriteTo_", "Clone_", "CalculateSize_", "MergeFrom_", "OnConstruction_", "Parser_" }, null, null, null, null)
}));
}
#endregion
@@ -4347,6 +4354,605 @@
}
+ /// <summary>
+ /// Issue 8810
+ /// </summary>
+ public sealed partial class DisambiguateCommonMembers : pb::IMessage<DisambiguateCommonMembers>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<DisambiguateCommonMembers> _parser = new pb::MessageParser<DisambiguateCommonMembers>(() => new DisambiguateCommonMembers());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<DisambiguateCommonMembers> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[14]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public DisambiguateCommonMembers() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public DisambiguateCommonMembers(DisambiguateCommonMembers other) : this() {
+ disambiguateCommonMembers_ = other.disambiguateCommonMembers_;
+ types_ = other.types_;
+ descriptor_ = other.descriptor_;
+ equals_ = other.equals_;
+ toString_ = other.toString_;
+ getHashCode_ = other.getHashCode_;
+ writeTo_ = other.writeTo_;
+ clone_ = other.clone_;
+ calculateSize_ = other.calculateSize_;
+ mergeFrom_ = other.mergeFrom_;
+ onConstruction_ = other.onConstruction_;
+ parser_ = other.parser_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public DisambiguateCommonMembers Clone() {
+ return new DisambiguateCommonMembers(this);
+ }
+
+ /// <summary>Field number for the "disambiguate_common_members" field.</summary>
+ public const int DisambiguateCommonMembers_FieldNumber = 1;
+ private int disambiguateCommonMembers_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int DisambiguateCommonMembers_ {
+ get { return disambiguateCommonMembers_; }
+ set {
+ disambiguateCommonMembers_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "types" field.</summary>
+ public const int Types_FieldNumber = 2;
+ private int types_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Types_ {
+ get { return types_; }
+ set {
+ types_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "descriptor" field.</summary>
+ public const int Descriptor_FieldNumber = 3;
+ private int descriptor_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Descriptor_ {
+ get { return descriptor_; }
+ set {
+ descriptor_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "equals" field.</summary>
+ public const int Equals_FieldNumber = 4;
+ private int equals_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Equals_ {
+ get { return equals_; }
+ set {
+ equals_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "to_string" field.</summary>
+ public const int ToString_FieldNumber = 5;
+ private int toString_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int ToString_ {
+ get { return toString_; }
+ set {
+ toString_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "get_hash_code" field.</summary>
+ public const int GetHashCode_FieldNumber = 6;
+ private int getHashCode_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int GetHashCode_ {
+ get { return getHashCode_; }
+ set {
+ getHashCode_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "write_to" field.</summary>
+ public const int WriteTo_FieldNumber = 7;
+ private int writeTo_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int WriteTo_ {
+ get { return writeTo_; }
+ set {
+ writeTo_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "clone" field.</summary>
+ public const int Clone_FieldNumber = 8;
+ private int clone_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Clone_ {
+ get { return clone_; }
+ set {
+ clone_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "calculate_size" field.</summary>
+ public const int CalculateSize_FieldNumber = 9;
+ private int calculateSize_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize_ {
+ get { return calculateSize_; }
+ set {
+ calculateSize_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "merge_from" field.</summary>
+ public const int MergeFrom_FieldNumber = 10;
+ private int mergeFrom_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int MergeFrom_ {
+ get { return mergeFrom_; }
+ set {
+ mergeFrom_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "on_construction" field.</summary>
+ public const int OnConstruction_FieldNumber = 11;
+ private int onConstruction_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int OnConstruction_ {
+ get { return onConstruction_; }
+ set {
+ onConstruction_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "parser" field.</summary>
+ public const int Parser_FieldNumber = 12;
+ private int parser_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Parser_ {
+ get { return parser_; }
+ set {
+ parser_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as DisambiguateCommonMembers);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(DisambiguateCommonMembers other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (DisambiguateCommonMembers_ != other.DisambiguateCommonMembers_) return false;
+ if (Types_ != other.Types_) return false;
+ if (Descriptor_ != other.Descriptor_) return false;
+ if (Equals_ != other.Equals_) return false;
+ if (ToString_ != other.ToString_) return false;
+ if (GetHashCode_ != other.GetHashCode_) return false;
+ if (WriteTo_ != other.WriteTo_) return false;
+ if (Clone_ != other.Clone_) return false;
+ if (CalculateSize_ != other.CalculateSize_) return false;
+ if (MergeFrom_ != other.MergeFrom_) return false;
+ if (OnConstruction_ != other.OnConstruction_) return false;
+ if (Parser_ != other.Parser_) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (DisambiguateCommonMembers_ != 0) hash ^= DisambiguateCommonMembers_.GetHashCode();
+ if (Types_ != 0) hash ^= Types_.GetHashCode();
+ if (Descriptor_ != 0) hash ^= Descriptor_.GetHashCode();
+ if (Equals_ != 0) hash ^= Equals_.GetHashCode();
+ if (ToString_ != 0) hash ^= ToString_.GetHashCode();
+ if (GetHashCode_ != 0) hash ^= GetHashCode_.GetHashCode();
+ if (WriteTo_ != 0) hash ^= WriteTo_.GetHashCode();
+ if (Clone_ != 0) hash ^= Clone_.GetHashCode();
+ if (CalculateSize_ != 0) hash ^= CalculateSize_.GetHashCode();
+ if (MergeFrom_ != 0) hash ^= MergeFrom_.GetHashCode();
+ if (OnConstruction_ != 0) hash ^= OnConstruction_.GetHashCode();
+ if (Parser_ != 0) hash ^= Parser_.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (DisambiguateCommonMembers_ != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(DisambiguateCommonMembers_);
+ }
+ if (Types_ != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(Types_);
+ }
+ if (Descriptor_ != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(Descriptor_);
+ }
+ if (Equals_ != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(Equals_);
+ }
+ if (ToString_ != 0) {
+ output.WriteRawTag(40);
+ output.WriteInt32(ToString_);
+ }
+ if (GetHashCode_ != 0) {
+ output.WriteRawTag(48);
+ output.WriteInt32(GetHashCode_);
+ }
+ if (WriteTo_ != 0) {
+ output.WriteRawTag(56);
+ output.WriteInt32(WriteTo_);
+ }
+ if (Clone_ != 0) {
+ output.WriteRawTag(64);
+ output.WriteInt32(Clone_);
+ }
+ if (CalculateSize_ != 0) {
+ output.WriteRawTag(72);
+ output.WriteInt32(CalculateSize_);
+ }
+ if (MergeFrom_ != 0) {
+ output.WriteRawTag(80);
+ output.WriteInt32(MergeFrom_);
+ }
+ if (OnConstruction_ != 0) {
+ output.WriteRawTag(88);
+ output.WriteInt32(OnConstruction_);
+ }
+ if (Parser_ != 0) {
+ output.WriteRawTag(96);
+ output.WriteInt32(Parser_);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (DisambiguateCommonMembers_ != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(DisambiguateCommonMembers_);
+ }
+ if (Types_ != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(Types_);
+ }
+ if (Descriptor_ != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(Descriptor_);
+ }
+ if (Equals_ != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(Equals_);
+ }
+ if (ToString_ != 0) {
+ output.WriteRawTag(40);
+ output.WriteInt32(ToString_);
+ }
+ if (GetHashCode_ != 0) {
+ output.WriteRawTag(48);
+ output.WriteInt32(GetHashCode_);
+ }
+ if (WriteTo_ != 0) {
+ output.WriteRawTag(56);
+ output.WriteInt32(WriteTo_);
+ }
+ if (Clone_ != 0) {
+ output.WriteRawTag(64);
+ output.WriteInt32(Clone_);
+ }
+ if (CalculateSize_ != 0) {
+ output.WriteRawTag(72);
+ output.WriteInt32(CalculateSize_);
+ }
+ if (MergeFrom_ != 0) {
+ output.WriteRawTag(80);
+ output.WriteInt32(MergeFrom_);
+ }
+ if (OnConstruction_ != 0) {
+ output.WriteRawTag(88);
+ output.WriteInt32(OnConstruction_);
+ }
+ if (Parser_ != 0) {
+ output.WriteRawTag(96);
+ output.WriteInt32(Parser_);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (DisambiguateCommonMembers_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(DisambiguateCommonMembers_);
+ }
+ if (Types_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Types_);
+ }
+ if (Descriptor_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Descriptor_);
+ }
+ if (Equals_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Equals_);
+ }
+ if (ToString_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ToString_);
+ }
+ if (GetHashCode_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(GetHashCode_);
+ }
+ if (WriteTo_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(WriteTo_);
+ }
+ if (Clone_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Clone_);
+ }
+ if (CalculateSize_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(CalculateSize_);
+ }
+ if (MergeFrom_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(MergeFrom_);
+ }
+ if (OnConstruction_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(OnConstruction_);
+ }
+ if (Parser_ != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Parser_);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(DisambiguateCommonMembers other) {
+ if (other == null) {
+ return;
+ }
+ if (other.DisambiguateCommonMembers_ != 0) {
+ DisambiguateCommonMembers_ = other.DisambiguateCommonMembers_;
+ }
+ if (other.Types_ != 0) {
+ Types_ = other.Types_;
+ }
+ if (other.Descriptor_ != 0) {
+ Descriptor_ = other.Descriptor_;
+ }
+ if (other.Equals_ != 0) {
+ Equals_ = other.Equals_;
+ }
+ if (other.ToString_ != 0) {
+ ToString_ = other.ToString_;
+ }
+ if (other.GetHashCode_ != 0) {
+ GetHashCode_ = other.GetHashCode_;
+ }
+ if (other.WriteTo_ != 0) {
+ WriteTo_ = other.WriteTo_;
+ }
+ if (other.Clone_ != 0) {
+ Clone_ = other.Clone_;
+ }
+ if (other.CalculateSize_ != 0) {
+ CalculateSize_ = other.CalculateSize_;
+ }
+ if (other.MergeFrom_ != 0) {
+ MergeFrom_ = other.MergeFrom_;
+ }
+ if (other.OnConstruction_ != 0) {
+ OnConstruction_ = other.OnConstruction_;
+ }
+ if (other.Parser_ != 0) {
+ Parser_ = other.Parser_;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 8: {
+ DisambiguateCommonMembers_ = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ Types_ = input.ReadInt32();
+ break;
+ }
+ case 24: {
+ Descriptor_ = input.ReadInt32();
+ break;
+ }
+ case 32: {
+ Equals_ = input.ReadInt32();
+ break;
+ }
+ case 40: {
+ ToString_ = input.ReadInt32();
+ break;
+ }
+ case 48: {
+ GetHashCode_ = input.ReadInt32();
+ break;
+ }
+ case 56: {
+ WriteTo_ = input.ReadInt32();
+ break;
+ }
+ case 64: {
+ Clone_ = input.ReadInt32();
+ break;
+ }
+ case 72: {
+ CalculateSize_ = input.ReadInt32();
+ break;
+ }
+ case 80: {
+ MergeFrom_ = input.ReadInt32();
+ break;
+ }
+ case 88: {
+ OnConstruction_ = input.ReadInt32();
+ break;
+ }
+ case 96: {
+ Parser_ = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 8: {
+ DisambiguateCommonMembers_ = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ Types_ = input.ReadInt32();
+ break;
+ }
+ case 24: {
+ Descriptor_ = input.ReadInt32();
+ break;
+ }
+ case 32: {
+ Equals_ = input.ReadInt32();
+ break;
+ }
+ case 40: {
+ ToString_ = input.ReadInt32();
+ break;
+ }
+ case 48: {
+ GetHashCode_ = input.ReadInt32();
+ break;
+ }
+ case 56: {
+ WriteTo_ = input.ReadInt32();
+ break;
+ }
+ case 64: {
+ Clone_ = input.ReadInt32();
+ break;
+ }
+ case 72: {
+ CalculateSize_ = input.ReadInt32();
+ break;
+ }
+ case 80: {
+ MergeFrom_ = input.ReadInt32();
+ break;
+ }
+ case 88: {
+ OnConstruction_ = input.ReadInt32();
+ break;
+ }
+ case 96: {
+ Parser_ = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
#endregion
}
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestWellKnownTypes.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestWellKnownTypes.cs
index 3ec8d35..50b9046 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestWellKnownTypes.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestWellKnownTypes.cs
@@ -3258,24 +3258,24 @@
if (other == null) {
return;
}
- anyField_.Add(other.anyField_);
- apiField_.Add(other.apiField_);
- durationField_.Add(other.durationField_);
- emptyField_.Add(other.emptyField_);
- fieldMaskField_.Add(other.fieldMaskField_);
- sourceContextField_.Add(other.sourceContextField_);
- structField_.Add(other.structField_);
- timestampField_.Add(other.timestampField_);
- typeField_.Add(other.typeField_);
- doubleField_.Add(other.doubleField_);
- floatField_.Add(other.floatField_);
- int64Field_.Add(other.int64Field_);
- uint64Field_.Add(other.uint64Field_);
- int32Field_.Add(other.int32Field_);
- uint32Field_.Add(other.uint32Field_);
- boolField_.Add(other.boolField_);
- stringField_.Add(other.stringField_);
- bytesField_.Add(other.bytesField_);
+ anyField_.MergeFrom(other.anyField_);
+ apiField_.MergeFrom(other.apiField_);
+ durationField_.MergeFrom(other.durationField_);
+ emptyField_.MergeFrom(other.emptyField_);
+ fieldMaskField_.MergeFrom(other.fieldMaskField_);
+ sourceContextField_.MergeFrom(other.sourceContextField_);
+ structField_.MergeFrom(other.structField_);
+ timestampField_.MergeFrom(other.timestampField_);
+ typeField_.MergeFrom(other.typeField_);
+ doubleField_.MergeFrom(other.doubleField_);
+ floatField_.MergeFrom(other.floatField_);
+ int64Field_.MergeFrom(other.int64Field_);
+ uint64Field_.MergeFrom(other.uint64Field_);
+ int32Field_.MergeFrom(other.int32Field_);
+ uint32Field_.MergeFrom(other.uint32Field_);
+ boolField_.MergeFrom(other.boolField_);
+ stringField_.MergeFrom(other.stringField_);
+ bytesField_.MergeFrom(other.bytesField_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
index 8387291..17c5249 100644
--- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -36,6 +36,7 @@
using NUnit.Framework;
using System.Linq;
using Google.Protobuf.WellKnownTypes;
+using Google.Protobuf.Collections;
namespace Google.Protobuf
{
@@ -795,5 +796,44 @@
EqualityTester.AssertInequality(message1, message2);
EqualityTester.AssertEquality(message1, message3);
}
+
+ [Test]
+ [TestCase(false)]
+ [TestCase(true)]
+ public void MapFieldMerging(bool direct)
+ {
+ var message1 = new TestMap
+ {
+ MapStringString =
+ {
+ { "x1", "y1" },
+ { "common", "message1" }
+ }
+ };
+ var message2 = new TestMap
+ {
+ MapStringString =
+ {
+ { "x2", "y2" },
+ { "common", "message2" }
+ }
+ };
+ if (direct)
+ {
+ message1.MergeFrom(message2);
+ }
+ else
+ {
+ message1.MergeFrom(message2.ToByteArray());
+ }
+
+ var expected = new MapField<string, string>
+ {
+ { "x1", "y1" },
+ { "x2", "y2" },
+ { "common", "message2" }
+ };
+ Assert.AreEqual(expected, message1.MapStringString);
+ }
}
}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterSettingsTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterSettingsTest.cs
new file mode 100644
index 0000000..f7ea97c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterSettingsTest.cs
@@ -0,0 +1,111 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.Protobuf.Reflection;
+using NUnit.Framework;
+
+// For WrapInQuotes
+
+namespace Google.Protobuf
+{
+ public class JsonFormatterSettingsTest
+ {
+ [Test]
+ public void WithIndentation()
+ {
+ var settings = JsonFormatter.Settings.Default.WithIndentation("\t");
+ Assert.AreEqual("\t", settings.Indentation);
+ }
+
+ [Test]
+ public void WithTypeRegistry()
+ {
+ var typeRegistry = TypeRegistry.Empty;
+ var settings = JsonFormatter.Settings.Default.WithTypeRegistry(typeRegistry);
+ Assert.AreEqual(typeRegistry, settings.TypeRegistry);
+ }
+
+ [Test]
+ public void WithFormatDefaultValues()
+ {
+ var settingsWith = JsonFormatter.Settings.Default.WithFormatDefaultValues(true);
+ Assert.AreEqual(true, settingsWith.FormatDefaultValues);
+
+ var settingsWithout = JsonFormatter.Settings.Default.WithFormatDefaultValues(false);
+ Assert.AreEqual(false, settingsWithout.FormatDefaultValues);
+ }
+
+ [Test]
+ public void WithFormatEnumsAsIntegers()
+ {
+ var settingsWith = JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true);
+ Assert.AreEqual(true, settingsWith.FormatEnumsAsIntegers);
+
+ var settingsWithout = JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(false);
+ Assert.AreEqual(false, settingsWithout.FormatEnumsAsIntegers);
+ }
+
+ [Test]
+ public void WithMethodsPreserveExistingSettings()
+ {
+ var typeRegistry = TypeRegistry.Empty;
+ var baseSettings = JsonFormatter.Settings.Default
+ .WithIndentation("\t")
+ .WithFormatDefaultValues(true)
+ .WithFormatEnumsAsIntegers(true)
+ .WithTypeRegistry(typeRegistry)
+ .WithPreserveProtoFieldNames(true);
+
+ var settings1 = baseSettings.WithIndentation("\t");
+ var settings2 = baseSettings.WithFormatDefaultValues(true);
+ var settings3 = baseSettings.WithFormatEnumsAsIntegers(true);
+ var settings4 = baseSettings.WithTypeRegistry(typeRegistry);
+ var settings5 = baseSettings.WithPreserveProtoFieldNames(true);
+
+ AssertAreEqual(baseSettings, settings1);
+ AssertAreEqual(baseSettings, settings2);
+ AssertAreEqual(baseSettings, settings3);
+ AssertAreEqual(baseSettings, settings4);
+ AssertAreEqual(baseSettings, settings5);
+ }
+
+ private static void AssertAreEqual(JsonFormatter.Settings settings, JsonFormatter.Settings other)
+ {
+ Assert.AreEqual(settings.Indentation, other.Indentation);
+ Assert.AreEqual(settings.FormatDefaultValues, other.FormatDefaultValues);
+ Assert.AreEqual(settings.FormatEnumsAsIntegers, other.FormatEnumsAsIntegers);
+ Assert.AreEqual(settings.TypeRegistry, other.TypeRegistry);
+ }
+ }
+}
diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
index 714c78c..f4dfde2 100644
--- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
@@ -675,6 +675,200 @@
}
[Test]
+ public void WriteValueWithIndentation_EmptyMessage()
+ {
+ var value = new TestEmptyMessage();
+
+ AssertWriteValue(value, "{}", JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_NestedTestAllTypes()
+ {
+ var value = new NestedTestAllTypes
+ {
+ Payload = new TestAllTypes
+ {
+ SingleBool = true,
+ SingleInt32 = 100,
+ SingleString = "multiple fields",
+ RepeatedString = { "string1", "string2" },
+ },
+ Child = new NestedTestAllTypes
+ {
+ Payload = new TestAllTypes
+ {
+ SingleString = "single field",
+ },
+ },
+ RepeatedChild =
+ {
+ new NestedTestAllTypes { Payload = new TestAllTypes { SingleString = "child 1", RepeatedString = { "string" } } },
+ new NestedTestAllTypes { Payload = new TestAllTypes { SingleString = "child 2" } },
+ },
+ };
+
+ const string expectedJson = @"
+{
+ 'child': {
+ 'payload': {
+ 'singleString': 'single field'
+ }
+ },
+ 'payload': {
+ 'singleInt32': 100,
+ 'singleBool': true,
+ 'singleString': 'multiple fields',
+ 'repeatedString': [
+ 'string1',
+ 'string2'
+ ]
+ },
+ 'repeatedChild': [
+ {
+ 'payload': {
+ 'singleString': 'child 1',
+ 'repeatedString': [
+ 'string'
+ ]
+ }
+ },
+ {
+ 'payload': {
+ 'singleString': 'child 2'
+ }
+ }
+ ]
+}";
+ AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_WellKnownTypes()
+ {
+ var value = new TestWellKnownTypes
+ {
+ StructField = new Struct
+ {
+ Fields =
+ {
+ { "string", Value.ForString("foo") },
+ { "numbers", Value.ForList(Value.ForNumber(1), Value.ForNumber(2), Value.ForNumber(3)) },
+ { "emptyList", Value.ForList() },
+ { "emptyStruct", Value.ForStruct(new Struct()) },
+ },
+ },
+ };
+
+ const string expectedJson = @"
+{
+ 'structField': {
+ 'string': 'foo',
+ 'numbers': [
+ 1,
+ 2,
+ 3
+ ],
+ 'emptyList': [],
+ 'emptyStruct': {}
+ }
+}";
+ AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_StructSingleField()
+ {
+ var value = new Struct { Fields = { { "structField1", Value.ForString("structFieldValue1") } } };
+
+ const string expectedJson = @"
+{
+ 'structField1': 'structFieldValue1'
+}";
+ AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_StructMultipleFields()
+ {
+ var value = new Struct
+ {
+ Fields =
+ {
+ { "structField1", Value.ForString("structFieldValue1") },
+ { "structField2", Value.ForString("structFieldValue2") },
+ { "structField3", Value.ForString("structFieldValue3") },
+ },
+ };
+
+ const string expectedJson = @"
+{
+ 'structField1': 'structFieldValue1',
+ 'structField2': 'structFieldValue2',
+ 'structField3': 'structFieldValue3'
+}";
+ AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void FormatWithIndentation_EmbeddedMessage()
+ {
+ var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L };
+ var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithIndentation());
+ var valueJson = formatter.Format(value, indentationLevel: 1);
+
+ var actualJson = $@"
+{{
+ ""data"": {valueJson}
+}}";
+ const string expectedJson = @"
+{
+ 'data': {
+ 'singleInt32': 100,
+ 'singleInt64': '3210987654321'
+ }
+}";
+ AssertJson(expectedJson, actualJson.Trim());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_Map()
+ {
+ var value = new TestMap
+ {
+ MapStringString =
+ {
+ { "key1", "value1" },
+ { "key2", "value2" },
+ },
+ };
+
+ const string expectedJson = @"
+{
+ 'mapStringString': {
+ 'key1': 'value1',
+ 'key2': 'value2'
+ }
+}";
+
+ AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_List()
+ {
+ var value = new RepeatedField<int> { 1, 2, 3 };
+ AssertWriteValue(value, "[\n 1,\n 2,\n 3\n]", JsonFormatter.Settings.Default.WithIndentation());
+ }
+
+ [Test]
+ public void WriteValueWithIndentation_CustomIndentation()
+ {
+ var value = new RepeatedField<int> { 1, 2, 3 };
+ AssertWriteValue(value, "[\n\t1,\n\t2,\n\t3\n]", JsonFormatter.Settings.Default.WithIndentation("\t"));
+ }
+
+ [Test]
public void Proto2_DefaultValuesWritten()
{
var value = new ProtobufTestMessages.Proto2.TestAllTypesProto2() { FieldName13 = 0 };
@@ -683,7 +877,7 @@
private static void AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null)
{
- var writer = new StringWriter();
+ var writer = new StringWriter { NewLine = "\n" };
new JsonFormatter(settings ?? JsonFormatter.Settings.Default).WriteValue(writer, value);
string actual = writer.ToString();
AssertJson(expectedJson, actual);
@@ -691,13 +885,17 @@
/// <summary>
/// Checks that the actual JSON is the same as the expected JSON - but after replacing
- /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier
- /// to read.
+ /// all apostrophes in the expected JSON with double quotes, trimming leading whitespace and normalizing new lines.
+ /// This basically makes the tests easier to read.
/// </summary>
+ /// <remarks>
+ /// Line endings are normalized because indented JSON strings are generated with system-specific line endings,
+ /// while line endings in the test cases are hard-coded, but may be converted during source checkout, depending
+ /// on git settings, causing unpredictability in the test results otherwise.</remarks>
private static void AssertJson(string expectedJsonWithApostrophes, string actualJson)
{
- var expectedJson = expectedJsonWithApostrophes.Replace("'", "\"");
- Assert.AreEqual(expectedJson, actualJson);
+ var expectedJson = expectedJsonWithApostrophes.Replace("'", "\"").Replace("\r\n", "\n").TrimStart();
+ Assert.AreEqual(expectedJson, actualJson.Replace("\r\n", "\n"));
}
}
}
diff --git a/csharp/src/Google.Protobuf.Test/ParsingPrimitivesTest.cs b/csharp/src/Google.Protobuf.Test/ParsingPrimitivesTest.cs
new file mode 100644
index 0000000..4d0aa9e
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/ParsingPrimitivesTest.cs
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2022 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System;
+using System.Linq;
+
+namespace Google.Protobuf.Test;
+
+internal class ParsingPrimitivesTest
+{
+ // Note: test cases use integers rather than bytes as they're easier
+ // to specify in attributes.
+
+ [Test]
+ [TestCase("\ufffd", 255)]
+ [TestCase("A\ufffd", 65, 255)]
+ [TestCase("A\ufffd\ufffdB", 65, 255, 255, 66)]
+ // Overlong form of "space"
+ [TestCase("\ufffd\ufffd", 0xc0, 0xa0)]
+ public void ReadRawString_NonUtf8(string expectedText, params int[] bytes)
+ {
+ var context = CreateContext(bytes);
+ string text = ParsingPrimitives.ReadRawString(ref context.buffer, ref context.state, bytes.Length);
+ Assert.AreEqual(expectedText, text);
+ }
+
+ private static ParseContext CreateContext(int[] bytes)
+ {
+ byte[] actualBytes = bytes.Select(b => (byte) b).ToArray();
+ ParseContext.Initialize(actualBytes.AsSpan(), out var context);
+ return context;
+ }
+}
diff --git a/csharp/src/Google.Protobuf.Test/WritingPrimitivesTest.cs b/csharp/src/Google.Protobuf.Test/WritingPrimitivesTest.cs
new file mode 100644
index 0000000..069df34
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WritingPrimitivesTest.cs
@@ -0,0 +1,61 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2022 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Google.Protobuf.Test;
+
+internal class WritingPrimitivesTest
+{
+ [Test]
+ public void WriteRawString_IllFormedUnicodeString()
+ {
+ // See https://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/
+ char c1 = '\u0058';
+ char c2 = '\ud800';
+ char c3 = '\u0059';
+ string text = new string(new[] { c1, c2, c3 });
+ Span<byte> buffer = new byte[10];
+ WriteContext.Initialize(ref buffer, out var context);
+ WritingPrimitives.WriteString(ref context.buffer, ref context.state, text);
+
+ // The high surrogate is written out in a "raw" form, surrounded by the ASCII
+ // characters.
+ byte[] expectedBytes = { 0x5, 0x58, 0xef, 0xbf, 0xbd, 0x59 };
+ Assert.AreEqual(expectedBytes, buffer.Slice(0, context.state.position).ToArray());
+ }
+}
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 5f41bc4..bdfe1cc 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index f0124ee..09afb75 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -238,6 +238,21 @@
}
/// <summary>
+ /// Adds the specified entries to the map, replacing any existing entries with the same keys.
+ /// The keys and values are not automatically cloned.
+ /// </summary>
+ /// <remarks>This method primarily exists to be called from MergeFrom methods in generated classes for messages.</remarks>
+ /// <param name="entries">The entries to add to the map.</param>
+ public void MergeFrom(IDictionary<TKey, TValue> entries)
+ {
+ ProtoPreconditions.CheckNotNull(entries, nameof(entries));
+ foreach (var pair in entries)
+ {
+ this[pair.Key] = pair.Value;
+ }
+ }
+
+ /// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index 37d86ce..c95ecad 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -4,7 +4,7 @@
<Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
<Copyright>Copyright 2015, Google Inc.</Copyright>
<AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
- <VersionPrefix>3.21.2</VersionPrefix>
+ <VersionPrefix>3.21.4</VersionPrefix>
<LangVersion>10.0</LangVersion>
<Authors>Google Inc.</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0;net45;net50</TargetFrameworks>
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index 2ef10ee..4482c87 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -63,7 +63,12 @@
internal const string AnyDiagnosticValueField = "@value";
internal const string AnyWellKnownTypeValueField = "value";
private const string NameValueSeparator = ": ";
- private const string PropertySeparator = ", ";
+ private const string ValueSeparator = ", ";
+ private const string MultilineValueSeparator = ",";
+ private const char ObjectOpenBracket = '{';
+ private const char ObjectCloseBracket = '}';
+ private const char ListBracketOpen = '[';
+ private const char ListBracketClose = ']';
/// <summary>
/// Returns a formatter using the default settings.
@@ -140,11 +145,26 @@
/// Formats the specified message as JSON.
/// </summary>
/// <param name="message">The message to format.</param>
+ /// <remarks>This method delegates to <c>Format(IMessage, int)</c> with <c>indentationLevel = 0</c>.</remarks>
/// <returns>The formatted message.</returns>
- public string Format(IMessage message)
+ public string Format(IMessage message) => Format(message, indentationLevel: 0);
+
+ /// <summary>
+ /// Formats the specified message as JSON.
+ /// </summary>
+ /// <param name="message">The message to format.</param>
+ /// <param name="indentationLevel">Indentation level to start at.</param>
+ /// <remarks>To keep consistent indentation when embedding a message inside another JSON string, set <see cref="indentationLevel"/>. E.g:
+ /// <code>
+ /// var response = $@"{{
+ /// ""data"": { Format(message, indentationLevel: 1) }
+ /// }}"</code>
+ /// </remarks>
+ /// <returns>The formatted message.</returns>
+ public string Format(IMessage message, int indentationLevel)
{
var writer = new StringWriter();
- Format(message, writer);
+ Format(message, writer, indentationLevel);
return writer.ToString();
}
@@ -153,19 +173,29 @@
/// </summary>
/// <param name="message">The message to format.</param>
/// <param name="writer">The TextWriter to write the formatted message to.</param>
+ /// <remarks>This method delegates to <c>Format(IMessage, TextWriter, int)</c> with <c>indentationLevel = 0</c>.</remarks>
/// <returns>The formatted message.</returns>
- public void Format(IMessage message, TextWriter writer)
+ public void Format(IMessage message, TextWriter writer) => Format(message, writer, indentationLevel: 0);
+
+ /// <summary>
+ /// Formats the specified message as JSON. When <see cref="Settings.Indentation"/> is not null, start indenting at the specified <see cref="indentationLevel"/>.
+ /// </summary>
+ /// <param name="message">The message to format.</param>
+ /// <param name="writer">The TextWriter to write the formatted message to.</param>
+ /// <param name="indentationLevel">Indentation level to start at.</param>
+ /// <remarks>To keep consistent indentation when embedding a message inside another JSON string, set <see cref="indentationLevel"/>.</remarks>
+ public void Format(IMessage message, TextWriter writer, int indentationLevel)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(writer, nameof(writer));
if (message.Descriptor.IsWellKnownType)
{
- WriteWellKnownTypeValue(writer, message.Descriptor, message);
+ WriteWellKnownTypeValue(writer, message.Descriptor, message, indentationLevel);
}
else
{
- WriteMessage(writer, message);
+ WriteMessage(writer, message, indentationLevel);
}
}
@@ -192,7 +222,7 @@
return diagnosticFormatter.Format(message);
}
- private void WriteMessage(TextWriter writer, IMessage message)
+ private void WriteMessage(TextWriter writer, IMessage message, int indentationLevel)
{
if (message == null)
{
@@ -207,12 +237,13 @@
return;
}
}
- writer.Write("{ ");
- bool writtenFields = WriteMessageFields(writer, message, false);
- writer.Write(writtenFields ? " }" : "}");
+
+ WriteBracketOpen(writer, ObjectOpenBracket);
+ bool writtenFields = WriteMessageFields(writer, message, false, indentationLevel + 1);
+ WriteBracketClose(writer, ObjectCloseBracket, writtenFields, indentationLevel);
}
- private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten)
+ private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten, int indentationLevel)
{
var fields = message.Descriptor.Fields;
bool first = !assumeFirstFieldWritten;
@@ -226,10 +257,8 @@
continue;
}
- if (!first)
- {
- writer.Write(PropertySeparator);
- }
+ MaybeWriteValueSeparator(writer, first);
+ MaybeWriteValueWhitespace(writer, indentationLevel);
if (settings.PreserveProtoFieldNames)
{
@@ -240,13 +269,23 @@
WriteString(writer, accessor.Descriptor.JsonName);
}
writer.Write(NameValueSeparator);
- WriteValue(writer, value);
+ WriteValue(writer, value, indentationLevel);
first = false;
}
return !first;
}
+ private void MaybeWriteValueSeparator(TextWriter writer, bool first)
+ {
+ if (first)
+ {
+ return;
+ }
+
+ writer.Write(settings.Indentation == null ? ValueSeparator : MultilineValueSeparator);
+ }
+
/// <summary>
/// Determines whether or not a field value should be serialized according to the field,
/// its value in the message, and the settings of this formatter.
@@ -342,7 +381,19 @@
/// </summary>
/// <param name="writer">The writer to write the value to. Must not be null.</param>
/// <param name="value">The value to write. May be null.</param>
- public void WriteValue(TextWriter writer, object value)
+ /// <remarks>Delegates to <c>WriteValue(TextWriter, object, int)</c> with <c>indentationLevel = 0</c>.</remarks>
+ public void WriteValue(TextWriter writer, object value) => WriteValue(writer, value, 0);
+
+ /// <summary>
+ /// Writes a single value to the given writer as JSON. Only types understood by
+ /// Protocol Buffers can be written in this way. This method is only exposed for
+ /// advanced use cases; most users should be using <see cref="Format(IMessage)"/>
+ /// or <see cref="Format(IMessage, TextWriter)"/>.
+ /// </summary>
+ /// <param name="writer">The writer to write the value to. Must not be null.</param>
+ /// <param name="value">The value to write. May be null.</param>
+ /// <param name="indentationLevel">The current indentationLevel. Not used when <see cref="Settings.Indentation"/> is null.</param>
+ public void WriteValue(TextWriter writer, object value, int indentationLevel)
{
if (value == null || value is NullValue)
{
@@ -365,11 +416,11 @@
}
else if (value is IDictionary dictionary)
{
- WriteDictionary(writer, dictionary);
+ WriteDictionary(writer, dictionary, indentationLevel);
}
else if (value is IList list)
{
- WriteList(writer, list);
+ WriteList(writer, list, indentationLevel);
}
else if (value is int || value is uint)
{
@@ -418,7 +469,7 @@
}
else if (value is IMessage message)
{
- Format(message, writer);
+ Format(message, writer, indentationLevel);
}
else
{
@@ -432,7 +483,7 @@
/// values are using the embedded well-known types, in order to allow for dynamic messages
/// in the future.
/// </summary>
- private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value)
+ private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value, int indentationLevel)
{
// Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
// this would do the right thing.
@@ -472,26 +523,26 @@
}
if (descriptor.FullName == Struct.Descriptor.FullName)
{
- WriteStruct(writer, (IMessage)value);
+ WriteStruct(writer, (IMessage)value, indentationLevel);
return;
}
if (descriptor.FullName == ListValue.Descriptor.FullName)
{
var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
- WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value));
+ WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value), indentationLevel);
return;
}
if (descriptor.FullName == Value.Descriptor.FullName)
{
- WriteStructFieldValue(writer, (IMessage)value);
+ WriteStructFieldValue(writer, (IMessage)value, indentationLevel);
return;
}
if (descriptor.FullName == Any.Descriptor.FullName)
{
- WriteAny(writer, (IMessage)value);
+ WriteAny(writer, (IMessage)value, indentationLevel);
return;
}
- WriteMessage(writer, (IMessage)value);
+ WriteMessage(writer, (IMessage)value, indentationLevel);
}
private void WriteTimestamp(TextWriter writer, IMessage value)
@@ -519,7 +570,7 @@
writer.Write(FieldMask.ToJson(paths, DiagnosticOnly));
}
- private void WriteAny(TextWriter writer, IMessage value)
+ private void WriteAny(TextWriter writer, IMessage value, int indentationLevel)
{
if (DiagnosticOnly)
{
@@ -536,23 +587,23 @@
throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
}
IMessage message = descriptor.Parser.ParseFrom(data);
- writer.Write("{ ");
+ WriteBracketOpen(writer, ObjectOpenBracket);
WriteString(writer, AnyTypeUrlField);
writer.Write(NameValueSeparator);
WriteString(writer, typeUrl);
if (descriptor.IsWellKnownType)
{
- writer.Write(PropertySeparator);
+ writer.Write(ValueSeparator);
WriteString(writer, AnyWellKnownTypeValueField);
writer.Write(NameValueSeparator);
- WriteWellKnownTypeValue(writer, descriptor, message);
+ WriteWellKnownTypeValue(writer, descriptor, message, indentationLevel);
}
else
{
- WriteMessageFields(writer, message, true);
+ WriteMessageFields(writer, message, true, indentationLevel);
}
- writer.Write(" }");
+ WriteBracketClose(writer, ObjectCloseBracket, true, indentationLevel);
}
private void WriteDiagnosticOnlyAny(TextWriter writer, IMessage value)
@@ -563,7 +614,7 @@
WriteString(writer, AnyTypeUrlField);
writer.Write(NameValueSeparator);
WriteString(writer, typeUrl);
- writer.Write(PropertySeparator);
+ writer.Write(ValueSeparator);
WriteString(writer, AnyDiagnosticValueField);
writer.Write(NameValueSeparator);
writer.Write('"');
@@ -572,9 +623,9 @@
writer.Write(" }");
}
- private void WriteStruct(TextWriter writer, IMessage message)
+ private void WriteStruct(TextWriter writer, IMessage message, int indentationLevel)
{
- writer.Write("{ ");
+ WriteBracketOpen(writer, ObjectOpenBracket);
IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
bool first = true;
foreach (DictionaryEntry entry in fields)
@@ -586,19 +637,17 @@
throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
}
- if (!first)
- {
- writer.Write(PropertySeparator);
- }
+ MaybeWriteValueSeparator(writer, first);
+ MaybeWriteValueWhitespace(writer, indentationLevel + 1);
WriteString(writer, key);
writer.Write(NameValueSeparator);
- WriteStructFieldValue(writer, value);
+ WriteStructFieldValue(writer, value, indentationLevel + 1);
first = false;
}
- writer.Write(first ? "}" : " }");
+ WriteBracketClose(writer, ObjectCloseBracket, !first, indentationLevel);
}
- private void WriteStructFieldValue(TextWriter writer, IMessage message)
+ private void WriteStructFieldValue(TextWriter writer, IMessage message, int indentationLevel)
{
var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
if (specifiedField == null)
@@ -619,7 +668,7 @@
case Value.ListValueFieldNumber:
// Structs and ListValues are nested messages, and already well-known types.
var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
- WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage);
+ WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage, indentationLevel);
return;
case Value.NullValueFieldNumber:
WriteNull(writer);
@@ -629,33 +678,30 @@
}
}
- internal void WriteList(TextWriter writer, IList list)
+ internal void WriteList(TextWriter writer, IList list, int indentationLevel = 0)
{
- writer.Write("[ ");
+ WriteBracketOpen(writer, ListBracketOpen);
+
bool first = true;
foreach (var value in list)
{
- if (!first)
- {
- writer.Write(PropertySeparator);
- }
- WriteValue(writer, value);
+ MaybeWriteValueSeparator(writer, first);
+ MaybeWriteValueWhitespace(writer, indentationLevel + 1);
+ WriteValue(writer, value, indentationLevel + 1);
first = false;
}
- writer.Write(first ? "]" : " ]");
+
+ WriteBracketClose(writer, ListBracketClose, !first, indentationLevel);
}
- internal void WriteDictionary(TextWriter writer, IDictionary dictionary)
+ internal void WriteDictionary(TextWriter writer, IDictionary dictionary, int indentationLevel = 0)
{
- writer.Write("{ ");
+ WriteBracketOpen(writer, ObjectOpenBracket);
+
bool first = true;
// This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
foreach (DictionaryEntry pair in dictionary)
{
- if (!first)
- {
- writer.Write(PropertySeparator);
- }
string keyText;
if (pair.Key is string s)
{
@@ -677,12 +723,16 @@
}
throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
}
+
+ MaybeWriteValueSeparator(writer, first);
+ MaybeWriteValueWhitespace(writer, indentationLevel + 1);
WriteString(writer, keyText);
writer.Write(NameValueSeparator);
WriteValue(writer, pair.Value);
first = false;
}
- writer.Write(first ? "}" : " }");
+
+ WriteBracketClose(writer, ObjectCloseBracket, !first, indentationLevel);
}
/// <summary>
@@ -766,6 +816,49 @@
writer.Write(Hex[(c >> 0) & 0xf]);
}
+ private void WriteBracketOpen(TextWriter writer, char openChar)
+ {
+ writer.Write(openChar);
+ if (settings.Indentation == null)
+ {
+ writer.Write(' ');
+ }
+ }
+
+ private void WriteBracketClose(TextWriter writer, char closeChar, bool hasFields, int indentationLevel)
+ {
+ if (hasFields)
+ {
+ if (settings.Indentation != null)
+ {
+ writer.WriteLine();
+ WriteIndentation(writer, indentationLevel);
+ }
+ else
+ {
+ writer.Write(" ");
+ }
+ }
+
+ writer.Write(closeChar);
+ }
+
+ private void MaybeWriteValueWhitespace(TextWriter writer, int indentationLevel)
+ {
+ if (settings.Indentation != null) {
+ writer.WriteLine();
+ WriteIndentation(writer, indentationLevel);
+ }
+ }
+
+ private void WriteIndentation(TextWriter writer, int indentationLevel)
+ {
+ for (int i = 0; i < indentationLevel; i++)
+ {
+ writer.Write(settings.Indentation);
+ }
+ }
+
/// <summary>
/// Settings controlling JSON formatting.
/// </summary>
@@ -806,6 +899,10 @@
/// </summary>
public bool PreserveProtoFieldNames { get; }
+ /// <summary>
+ /// Indentation string, used for formatting. Setting null disables indentation.
+ /// </summary>
+ public string Indentation { get; }
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values
@@ -833,40 +930,54 @@
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages. TypeRegistry.Empty will be used if it is null.</param>
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
/// <param name="preserveProtoFieldNames"><c>true</c> to preserve proto field names; <c>false</c> to convert them to lowerCamelCase.</param>
+ /// <param name="indentation">The indentation string to use for multi-line formatting. <c>null</c> to disable multi-line format.</param>
private Settings(bool formatDefaultValues,
TypeRegistry typeRegistry,
bool formatEnumsAsIntegers,
- bool preserveProtoFieldNames)
+ bool preserveProtoFieldNames,
+ string indentation = null)
{
FormatDefaultValues = formatDefaultValues;
TypeRegistry = typeRegistry ?? TypeRegistry.Empty;
FormatEnumsAsIntegers = formatEnumsAsIntegers;
PreserveProtoFieldNames = preserveProtoFieldNames;
+ Indentation = indentation;
}
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values and the current settings.
/// </summary>
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
- public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames);
+ public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified type registry and the current settings.
/// </summary>
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
- public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames);
+ public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified enums formatting option and the current settings.
/// </summary>
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
- public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames);
+ public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified field name formatting option and the current settings.
/// </summary>
/// <param name="preserveProtoFieldNames"><c>true</c> to preserve proto field names; <c>false</c> to convert them to lowerCamelCase.</param>
- public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames) => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames);
+ public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames) => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames, Indentation);
+
+ /// <summary>
+ /// Creates a new <see cref="Settings"/> object with the specified indentation and the current settings.
+ /// </summary>
+ /// <param name="indentation">The string to output for each level of indentation (nesting). The default is two spaces per level. Use null to disable indentation entirely.</param>
+ /// <remarks>A non-null value for <see cref="Indentation"/> will insert additional line-breaks to the JSON output.
+ /// Each line will contain either a single value, or braces. The default line-break is determined by <see cref="Environment.NewLine"/>,
+ /// which is <c>"\n"</c> on Unix platforms, and <c>"\r\n"</c> on Windows. If <see cref="JsonFormatter"/> seems to produce empty lines,
+ /// you need to pass a <see cref="TextWriter"/> that uses a <c>"\n"</c> newline. See <see cref="JsonFormatter.Format(Google.Protobuf.IMessage, TextWriter)"/>.
+ /// </remarks>
+ public Settings WithIndentation(string indentation = " ") => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, indentation);
}
// Effectively a cache of mapping from enum values to the original name as specified in the proto file,
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
index 66907d4..5710292 100644
--- a/csharp/src/Google.Protobuf/MessageParser.cs
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -171,6 +171,10 @@
/// <summary>
/// Parses a message from the given JSON.
/// </summary>
+ /// <remarks>This method always uses the default JSON parser; it is not affected by <see cref="WithDiscardUnknownFields(bool)"/>.
+ /// To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
+ /// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.
+ /// </remarks>
/// <param name="json">The JSON to parse.</param>
/// <returns>The parsed message.</returns>
/// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
@@ -203,6 +207,9 @@
/// <summary>
/// Creates a new message parser which optionally discards unknown fields when parsing.
/// </summary>
+ /// <remarks>Note that this does not affect the behavior of <see cref="ParseJson(string)"/>
+ /// at all. To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
+ /// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.</remarks>
/// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
/// <returns>A newly configured message parser.</returns>
public MessageParser WithDiscardUnknownFields(bool discardUnknownFields) =>
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
index 8c1eec5..aa25686 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -212,7 +212,7 @@
if (other == null) {
return;
}
- fields_.Add(other.fields_);
+ fields_.MergeFrom(other.fields_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
diff --git a/java/README.md b/java/README.md
index 7e71e66..5e3ded4 100644
--- a/java/README.md
+++ b/java/README.md
@@ -23,7 +23,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</dependency>
```
@@ -37,7 +37,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</dependency>
```
@@ -45,7 +45,7 @@
If you are using Gradle, add the following to your `build.gradle` file's dependencies:
```
- implementation 'com.google.protobuf:protobuf-java:3.21.2'
+ implementation 'com.google.protobuf:protobuf-java:3.21.4'
```
Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using.
diff --git a/java/bom/pom.xml b/java/bom/pom.xml
index b4c3465..4cccfb3 100644
--- a/java/bom/pom.xml
+++ b/java/bom/pom.xml
@@ -4,7 +4,7 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-bom</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
<packaging>pom</packaging>
<name>Protocol Buffers [BOM]</name>
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 845ff88..d5eacd6 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</parent>
<artifactId>protobuf-java</artifactId>
diff --git a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
index cf394e3..66cf51d 100644
--- a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
+++ b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
@@ -209,7 +209,7 @@
}
}
- private final void writeInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
+ private void writeInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
@@ -227,7 +227,7 @@
}
}
- private final void writeInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
+ private void writeInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
@@ -255,7 +255,7 @@
}
}
- private final void writeFixed32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
+ private void writeFixed32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
@@ -273,7 +273,7 @@
}
}
- private final void writeFixed32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
+ private void writeFixed32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
@@ -307,7 +307,7 @@
}
}
- private final void writeUInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
+ private void writeUInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
@@ -325,7 +325,7 @@
}
}
- private final void writeUInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
+ private void writeUInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
@@ -353,7 +353,7 @@
}
}
- private final void writeFixed64List_Internal(int fieldNumber, List<Long> list, boolean packed)
+ private void writeFixed64List_Internal(int fieldNumber, List<Long> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
@@ -371,7 +371,7 @@
}
}
- private final void writeFixed64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
+ private void writeFixed64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
@@ -399,7 +399,7 @@
}
}
- private final void writeFloatList_Internal(int fieldNumber, List<Float> list, boolean packed)
+ private void writeFloatList_Internal(int fieldNumber, List<Float> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
@@ -417,7 +417,7 @@
}
}
- private final void writeFloatList_Internal(int fieldNumber, FloatArrayList list, boolean packed)
+ private void writeFloatList_Internal(int fieldNumber, FloatArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
@@ -445,7 +445,7 @@
}
}
- private final void writeDoubleList_Internal(int fieldNumber, List<Double> list, boolean packed)
+ private void writeDoubleList_Internal(int fieldNumber, List<Double> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
@@ -463,7 +463,7 @@
}
}
- private final void writeDoubleList_Internal(int fieldNumber, DoubleArrayList list, boolean packed)
+ private void writeDoubleList_Internal(int fieldNumber, DoubleArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
@@ -497,7 +497,7 @@
}
}
- private final void writeBoolList_Internal(int fieldNumber, List<Boolean> list, boolean packed)
+ private void writeBoolList_Internal(int fieldNumber, List<Boolean> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
@@ -515,7 +515,7 @@
}
}
- private final void writeBoolList_Internal(int fieldNumber, BooleanArrayList list, boolean packed)
+ private void writeBoolList_Internal(int fieldNumber, BooleanArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
@@ -572,7 +572,7 @@
}
}
- private final void writeUInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
+ private void writeUInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
@@ -590,7 +590,7 @@
}
}
- private final void writeUInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
+ private void writeUInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
@@ -630,7 +630,7 @@
}
}
- private final void writeSInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
+ private void writeSInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
@@ -648,7 +648,7 @@
}
}
- private final void writeSInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
+ private void writeSInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
@@ -759,7 +759,7 @@
}
}
- private final void writeSInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
+ private void writeSInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
@@ -777,7 +777,7 @@
}
}
- private final void writeSInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
+ private void writeSInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
throws IOException {
if (packed) {
requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index 8ba1f9b..91c9b19 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -1788,6 +1788,27 @@
return Collections.unmodifiableList(Arrays.asList(values));
}
+ /** Determines if the given field number is reserved. */
+ public boolean isReservedNumber(final int number) {
+ for (final EnumDescriptorProto.EnumReservedRange range : proto.getReservedRangeList()) {
+ if (range.getStart() <= number && number <= range.getEnd()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Determines if the given field name is reserved. */
+ public boolean isReservedName(final String name) {
+ checkNotNull(name);
+ for (final String reservedName : proto.getReservedNameList()) {
+ if (reservedName.equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Find an enum value by name.
*
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index e212ab5..0c16000 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -137,7 +137,7 @@
// any unnecessary intermediary allocations while reducing the generated code size.
/** Lazily initializes unknown fields. */
- private final void ensureUnknownFieldsInitialized() {
+ private void ensureUnknownFieldsInitialized() {
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
unknownFields = UnknownFieldSetLite.newInstance();
}
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index 49a71dc..7988e7c 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -61,6 +61,7 @@
import protobuf_unittest.UnittestProto.TestJsonName;
import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestReservedEnumFields;
import protobuf_unittest.UnittestProto.TestReservedFields;
import protobuf_unittest.UnittestProto.TestService;
import java.util.Collections;
@@ -797,6 +798,20 @@
}
@Test
+ public void testReservedEnumFields() {
+ EnumDescriptor d = TestReservedEnumFields.getDescriptor();
+ assertThat(d.isReservedNumber(2)).isTrue();
+ assertThat(d.isReservedNumber(8)).isFalse();
+ assertThat(d.isReservedNumber(9)).isTrue();
+ assertThat(d.isReservedNumber(10)).isTrue();
+ assertThat(d.isReservedNumber(11)).isTrue();
+ assertThat(d.isReservedNumber(12)).isFalse();
+ assertThat(d.isReservedName("foo")).isFalse();
+ assertThat(d.isReservedName("bar")).isTrue();
+ assertThat(d.isReservedName("baz")).isTrue();
+ }
+
+ @Test
public void testToString() {
assertThat(
UnittestProto.TestAllTypes.getDescriptor()
diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml
index 3fec5ec..2dc4309 100644
--- a/java/kotlin-lite/pom.xml
+++ b/java/kotlin-lite/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</parent>
<artifactId>protobuf-kotlin-lite</artifactId>
diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml
index 43debaf..7a350f7 100644
--- a/java/kotlin/pom.xml
+++ b/java/kotlin/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</parent>
<artifactId>protobuf-kotlin</artifactId>
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
index 1645cfb..8ce0094 100644
--- a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
@@ -66,6 +66,11 @@
assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
optionalNestedEnum = NestedEnum.BAZ
assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ assertThat(optionalNestedEnumValue).isEqualTo(3)
+ optionalNestedEnumValue = 1
+ assertThat(optionalNestedEnumValue).isEqualTo(1)
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.FOO)
+
oneofUint32 = 601
assertThat(oneofUint32).isEqualTo(601)
}
diff --git a/java/lite.md b/java/lite.md
index 1ad0019..d4b4fc8 100644
--- a/java/lite.md
+++ b/java/lite.md
@@ -29,7 +29,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-javalite</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</dependency>
```
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index 7c635ec..20381c6 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</parent>
<artifactId>protobuf-javalite</artifactId>
diff --git a/java/pom.xml b/java/pom.xml
index 34475a4..99abcf8 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -4,7 +4,7 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
<packaging>pom</packaging>
<name>Protocol Buffers [Parent]</name>
diff --git a/java/protoc/pom.xml b/java/protoc/pom.xml
index aa6bc58..b2cd0d5 100644
--- a/java/protoc/pom.xml
+++ b/java/protoc/pom.xml
@@ -4,11 +4,11 @@
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
- <version>1</version>
+ <version>5</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
- <version>3.21.2</version>
+ <version>3.21.3</version>
<packaging>pom</packaging>
<name>Protobuf Compiler</name>
<description>
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 53f90ce..f634047 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</parent>
<artifactId>protobuf-java-util</artifactId>
diff --git a/kokoro/linux/bazel_distcheck/build.sh b/kokoro/linux/bazel_distcheck/build.sh
deleted file mode 100755
index a50b175..0000000
--- a/kokoro/linux/bazel_distcheck/build.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests using bazel-build dist archive
-#
-# Note that the builds use WORKSPACE to fetch external sources, not
-# git submodules.
-
-set -eu
-
-use_bazel.sh 5.0.0 || true
-bazel version
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Get kokoro scripts from repo root by default.
-: ${SCRIPT_ROOT:=$(pwd)}
-source ${SCRIPT_ROOT}/kokoro/common/pyenv.sh
-
-# Build distribution archive
-echo "============================================================"
-echo -e "[[ $(date) ]] Building distribution archive...\n"
-${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh build //pkg:dist_all_tar
-DIST_ARCHIVE=$(readlink $(bazel info bazel-bin)/pkg/dist_all_tar.tar.gz)
-bazel shutdown
-
-# Extract the dist archive.
-echo "============================================================"
-echo -e "[[ $(date) ]] Extracting distribution archive...\n"
-
-# Construct temp directory for running the dist build.
-# If you want to run locally and keep the build dir, create a directory
-# and pass it in the DIST_WORK_ROOT env var.
-if [[ -z ${DIST_WORK_ROOT:-} ]]; then
- : ${DIST_WORK_ROOT:=$(mktemp -d)}
- function dist_cleanup() {
- (( $BASH_SUBSHELL == 0 )) && rm -rf ${DIST_WORK_ROOT}
- }
- trap dist_cleanup EXIT
-fi
-
-DIST_WORKSPACE=${DIST_WORK_ROOT}/protobuf
-mkdir -p ${DIST_WORKSPACE}
-tar -C ${DIST_WORKSPACE} --strip-components=1 -axf bazel-bin/pkg/dist_all_tar.tar.gz
-
-echo "============================================================"
-echo -e "[[ $(date) ]] Building extracted archive...\n"
-
-cd ${DIST_WORKSPACE}
-
-bazel_args=(
- test
- --keep_going
- --test_output=errors
- --
- //...
- -//objectivec/... # only works on macOS
- -//csharp/... # release builds require external dependencies
- @com_google_protobuf_examples//...
-)
-${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh "${bazel_args[@]}"
diff --git a/kokoro/linux/bazel_distcheck/common.cfg b/kokoro/linux/bazel_distcheck/common.cfg
deleted file mode 100644
index 6b18488..0000000
--- a/kokoro/linux/bazel_distcheck/common.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-# Common config shared by presubmit and continuous.
-
-bazel_setting: {
- project_id: "protobuf-build"
- bes_backend_address: "buildeventservice.googleapis.com"
- foundry_backend_address: "remotebuildexecution.googleapis.com"
- upsalite_frontend_address: "https://source.cloud.google.com"
- local_execution: true
-}
diff --git a/kokoro/linux/bazel_distcheck/continuous.cfg b/kokoro/linux/bazel_distcheck/continuous.cfg
deleted file mode 100644
index 4ea8b21..0000000
--- a/kokoro/linux/bazel_distcheck/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/bazel_distcheck/build.sh"
-timeout_mins: 15
diff --git a/kokoro/linux/bazel_distcheck/presubmit.cfg b/kokoro/linux/bazel_distcheck/presubmit.cfg
deleted file mode 100644
index 4ea8b21..0000000
--- a/kokoro/linux/bazel_distcheck/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/bazel_distcheck/build.sh"
-timeout_mins: 15
diff --git a/kokoro/linux/cmake/build.sh b/kokoro/linux/cmake/build.sh
new file mode 100755
index 0000000..523253d
--- /dev/null
+++ b/kokoro/linux/cmake/build.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Build file to set up and run tests using CMake
+
+set -eux
+
+# Change to repo root
+cd $(dirname $0)/../../..
+GIT_REPO_ROOT=`pwd`
+
+CONTAINER_IMAGE=gcr.io/protobuf-build/cmake/linux@sha256:79e6ed9d7f3f8e56167a3309a521e5b7e6a212bfb19855c65ee1cbb6f9099671
+
+# Update git submodules
+git submodule update --init --recursive
+
+tmpfile=$(mktemp -u)
+
+docker run \
+ --cidfile $tmpfile \
+ -v $GIT_REPO_ROOT:/workspace \
+ $CONTAINER_IMAGE \
+ /test.sh -Dprotobuf_BUILD_CONFORMANCE=ON
+
+# Save logs for Kokoro
+docker cp \
+ `cat $tmpfile`:/workspace/logs $KOKORO_ARTIFACTS_DIR
diff --git a/kokoro/linux/cmake/continuous.cfg b/kokoro/linux/cmake/continuous.cfg
new file mode 100644
index 0000000..f03bd39
--- /dev/null
+++ b/kokoro/linux/cmake/continuous.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake/presubmit.cfg b/kokoro/linux/cmake/presubmit.cfg
new file mode 100644
index 0000000..f03bd39
--- /dev/null
+++ b/kokoro/linux/cmake/presubmit.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_distcheck/build.sh b/kokoro/linux/cmake_distcheck/build.sh
deleted file mode 100755
index 116e40b..0000000
--- a/kokoro/linux/cmake_distcheck/build.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests based on distribution archive
-
-set -eux
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-#
-# Update git submodules
-#
-git submodule update --init --recursive
-
-#
-# Build distribution archive
-#
-# TODO: this should use Bazel-built dist archives.
-date ; ./autogen.sh
-date ; ./configure
-date ; make dist
-date
-
-DIST_ARCHIVE=( $(ls protobuf-*.tar.gz) )
-if (( ${#DIST_ARCHIVE[@]} != 1 )); then
- echo >&2 "Distribution archive not found. ${#DIST_ARCHIVE[@]} matches:"
- echo >&2 "${DIST_ARCHIVE[@]}"
- exit 1
-fi
-
-#
-# Check for all expected files
-#
-kokoro/common/check_missing_dist_files.sh ${DIST_ARCHIVE}
-
-#
-# Extract to a temporary directory
-#
-if [[ -z ${DIST_WORK_ROOT:-} ]]; then
- # If you want to preserve the extracted sources, set the DIST_WORK_ROOT
- # environment variable to an existing directory that should be used.
- DIST_WORK_ROOT=$(mktemp -d)
- function cleanup_work_root() {
- echo "Cleaning up temporary directory ${DIST_WORK_ROOT}..."
- rm -rf ${DIST_WORK_ROOT}
- }
- trap cleanup_work_root EXIT
-fi
-
-tar -C ${DIST_WORK_ROOT} --strip-components=1 -axf ${DIST_ARCHIVE}
-
-#
-# Run tests using extracted sources
-#
-SOURCE_DIR=${DIST_WORK_ROOT} \
-CMAKE_GENERATOR=Ninja \
-CTEST_PARALLEL_LEVEL=$(nproc) \
-kokoro/common/cmake.sh
-
-echo "PASS"
diff --git a/kokoro/linux/cmake_distcheck/continuous.cfg b/kokoro/linux/cmake_distcheck/continuous.cfg
deleted file mode 100644
index 6ef4c89..0000000
--- a/kokoro/linux/cmake_distcheck/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/cmake_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/linux/cmake_distcheck/presubmit.cfg b/kokoro/linux/cmake_distcheck/presubmit.cfg
deleted file mode 100644
index 6ef4c89..0000000
--- a/kokoro/linux/cmake_distcheck/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/cmake_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/linux/cmake_install/build.sh b/kokoro/linux/cmake_install/build.sh
new file mode 100755
index 0000000..7fdf267
--- /dev/null
+++ b/kokoro/linux/cmake_install/build.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Build file to build, install, and test using CMake.
+
+set -eux
+
+# Change to repo root
+cd $(dirname $0)/../../..
+GIT_REPO_ROOT=`pwd`
+
+CONTAINER_IMAGE=gcr.io/protobuf-build/cmake/linux@sha256:79e6ed9d7f3f8e56167a3309a521e5b7e6a212bfb19855c65ee1cbb6f9099671
+
+# Update git submodules
+git submodule update --init --recursive
+
+tmpfile=$(mktemp -u)
+
+docker run \
+ --cidfile $tmpfile \
+ -v $GIT_REPO_ROOT:/workspace \
+ $CONTAINER_IMAGE \
+ "/install.sh && /test.sh \
+ -Dprotobuf_REMOVE_INSTALLED_HEADERS=ON \
+ -Dprotobuf_BUILD_PROTOBUF_BINARIES=OFF \
+ -Dprotobuf_BUILD_CONFORMANCE=ON"
+
+
+# Save logs for Kokoro
+docker cp \
+ `cat $tmpfile`:/workspace/logs $KOKORO_ARTIFACTS_DIR
diff --git a/kokoro/linux/cmake_install/continuous.cfg b/kokoro/linux/cmake_install/continuous.cfg
new file mode 100644
index 0000000..f1ae0b3
--- /dev/null
+++ b/kokoro/linux/cmake_install/continuous.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake_install/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_install/presubmit.cfg b/kokoro/linux/cmake_install/presubmit.cfg
new file mode 100644
index 0000000..f1ae0b3
--- /dev/null
+++ b/kokoro/linux/cmake_install/presubmit.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake_install/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_ninja/build.sh b/kokoro/linux/cmake_ninja/build.sh
new file mode 100755
index 0000000..21cc01e
--- /dev/null
+++ b/kokoro/linux/cmake_ninja/build.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Build file to set up and run tests using CMake with the Ninja generator.
+
+set -eux
+
+# Change to repo root
+cd $(dirname $0)/../../..
+GIT_REPO_ROOT=`pwd`
+
+CONTAINER_IMAGE=gcr.io/protobuf-build/cmake/linux@sha256:79e6ed9d7f3f8e56167a3309a521e5b7e6a212bfb19855c65ee1cbb6f9099671
+
+# Update git submodules
+git submodule update --init --recursive
+
+tmpfile=$(mktemp -u)
+
+docker run \
+ --cidfile $tmpfile \
+ -v $GIT_REPO_ROOT:/workspace \
+ $CONTAINER_IMAGE \
+ /test.sh -G Ninja -Dprotobuf_BUILD_CONFORMANCE=ON
+
+# Save logs for Kokoro
+docker cp \
+ `cat $tmpfile`:/workspace/logs $KOKORO_ARTIFACTS_DIR
diff --git a/kokoro/linux/cmake_ninja/continuous.cfg b/kokoro/linux/cmake_ninja/continuous.cfg
new file mode 100644
index 0000000..144fc90
--- /dev/null
+++ b/kokoro/linux/cmake_ninja/continuous.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake_ninja/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_ninja/presubmit.cfg b/kokoro/linux/cmake_ninja/presubmit.cfg
new file mode 100644
index 0000000..144fc90
--- /dev/null
+++ b/kokoro/linux/cmake_ninja/presubmit.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake_ninja/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_shared/build.sh b/kokoro/linux/cmake_shared/build.sh
new file mode 100755
index 0000000..87dde41
--- /dev/null
+++ b/kokoro/linux/cmake_shared/build.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+#
+# Build file to set up and run tests via CMake using shared libraries
+
+set -eux
+
+# TODO(mkruskal) Implement this.
\ No newline at end of file
diff --git a/kokoro/linux/cmake_shared/continuous.cfg b/kokoro/linux/cmake_shared/continuous.cfg
new file mode 100644
index 0000000..f03bd39
--- /dev/null
+++ b/kokoro/linux/cmake_shared/continuous.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cmake_shared/presubmit.cfg b/kokoro/linux/cmake_shared/presubmit.cfg
new file mode 100644
index 0000000..f03bd39
--- /dev/null
+++ b/kokoro/linux/cmake_shared/presubmit.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cmake/build.sh"
+timeout_mins: 1440
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.*"
+ }
+}
diff --git a/kokoro/linux/cpp_distcheck/build.sh b/kokoro/linux/cpp_distcheck/build.sh
deleted file mode 100755
index a28843e..0000000
--- a/kokoro/linux/cpp_distcheck/build.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-set -ex # exit immediately on error
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-./tests.sh cpp_distcheck
-
-# Run tests under release docker image.
-DOCKER_IMAGE_NAME=protobuf/protoc_$(sha1sum protoc-artifacts/Dockerfile | cut -f1 -d " ")
-until docker pull $DOCKER_IMAGE_NAME; do sleep 10; done
-
-docker run -v $(pwd):/var/local/protobuf --rm $DOCKER_IMAGE_NAME \
- bash -l /var/local/protobuf/tests.sh cpp || FAILED="true"
-
-# This directory is owned by root. We need to delete it, because otherwise
-# Kokoro will attempt to rsync it and fail with a permission error.
-rm -rf src/core
-
-if [ "$FAILED" = "true" ]; then
- exit 1
-fi
diff --git a/kokoro/linux/cpp_distcheck/continuous.cfg b/kokoro/linux/cpp_distcheck/continuous.cfg
deleted file mode 100644
index 4289f6a..0000000
--- a/kokoro/linux/cpp_distcheck/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/cpp_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/linux/cpp_distcheck/presubmit.cfg b/kokoro/linux/cpp_distcheck/presubmit.cfg
deleted file mode 100644
index 4289f6a..0000000
--- a/kokoro/linux/cpp_distcheck/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/cpp_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/linux/dist_install/build.sh b/kokoro/linux/dist_install/build.sh
deleted file mode 100755
index c456ee8..0000000
--- a/kokoro/linux/dist_install/build.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-set -ex # exit immediately on error
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/java_stretch
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="dist_install"
-./kokoro/linux/build_and_run_docker.sh
diff --git a/kokoro/linux/dist_install/continuous.cfg b/kokoro/linux/dist_install/continuous.cfg
deleted file mode 100644
index b1e0b20..0000000
--- a/kokoro/linux/dist_install/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/dist_install/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/linux/dist_install/presubmit.cfg b/kokoro/linux/dist_install/presubmit.cfg
deleted file mode 100644
index b1e0b20..0000000
--- a/kokoro/linux/dist_install/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/dist_install/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/cpp_distcheck/build.sh b/kokoro/macos/cpp_distcheck/build.sh
deleted file mode 100755
index d729b63..0000000
--- a/kokoro/macos/cpp_distcheck/build.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-source kokoro/macos/prepare_build_macos_rc
-
-./tests.sh cpp_distcheck
diff --git a/kokoro/macos/cpp_distcheck/continuous.cfg b/kokoro/macos/cpp_distcheck/continuous.cfg
deleted file mode 100644
index 89441bc..0000000
--- a/kokoro/macos/cpp_distcheck/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/cpp_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/cpp_distcheck/presubmit.cfg b/kokoro/macos/cpp_distcheck/presubmit.cfg
deleted file mode 100644
index 89441bc..0000000
--- a/kokoro/macos/cpp_distcheck/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/cpp_distcheck/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/php7.0_mac/build.sh b/kokoro/macos/php7.0_mac/build.sh
deleted file mode 100755
index c6717e0..0000000
--- a/kokoro/macos/php7.0_mac/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-source kokoro/macos/prepare_build_macos_rc
-
-# TODO(mkruskal) Re-enable this once we can get a working PHP 7.0 installed.
-#./tests.sh php7.0_mac
diff --git a/kokoro/macos/php7.0_mac/continuous.cfg b/kokoro/macos/php7.0_mac/continuous.cfg
deleted file mode 100644
index c2c1811..0000000
--- a/kokoro/macos/php7.0_mac/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.0_mac/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/php7.0_mac/presubmit.cfg b/kokoro/macos/php7.0_mac/presubmit.cfg
deleted file mode 100644
index c2c1811..0000000
--- a/kokoro/macos/php7.0_mac/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.0_mac/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/build.sh b/kokoro/macos/php7.3_mac/build.sh
deleted file mode 100755
index 2688ddb..0000000
--- a/kokoro/macos/php7.3_mac/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-source kokoro/macos/prepare_build_macos_rc
-
-# TODO(mkruskal) Re-enable this once we can get a working PHP 7.0 installed.
-#./tests.sh php7.3_mac
diff --git a/kokoro/macos/php74/build.sh b/kokoro/macos/php74/build.sh
new file mode 100755
index 0000000..ff39657
--- /dev/null
+++ b/kokoro/macos/php74/build.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Build file to set up and run tests
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+# Prepare worker environment to run tests
+source kokoro/macos/prepare_build_macos_rc
+
+# Install Dependencies
+brew install coreutils php@7.4
+
+# Configure path
+PHP_FOLDER=$(find $HOMEBREW_PREFIX -type d -regex ".*php.*/7.4.[0-9]*")
+test ! -z "$PHP_FOLDER"
+export PATH="$PHP_FOLDER/bin:$PATH"
+
+# Test
+./tests.sh php_mac
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/macos/php74/continuous.cfg
similarity index 65%
rename from kokoro/macos/php7.3_mac/continuous.cfg
rename to kokoro/macos/php74/continuous.cfg
index 9a71745..cf7e80b 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/macos/php74/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/macos/php74/build.sh"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/macos/php74/presubmit.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/macos/php74/presubmit.cfg
index 9a71745..cf7e80b 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/macos/php74/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/macos/php74/build.sh"
timeout_mins: 1440
diff --git a/kokoro/macos/php80/build.sh b/kokoro/macos/php80/build.sh
new file mode 100755
index 0000000..84e2c46
--- /dev/null
+++ b/kokoro/macos/php80/build.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Build file to set up and run tests
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+# Prepare worker environment to run tests
+source kokoro/macos/prepare_build_macos_rc
+
+# Install Dependencies
+brew install coreutils php@8.0
+
+# Configure path
+PHP_FOLDER=$(find $HOMEBREW_PREFIX -type d -regex ".*php.*/8.0.[0-9]*")
+test ! -z "$PHP_FOLDER"
+export PATH="$PHP_FOLDER/bin:$PATH"
+
+# Test
+./tests.sh php_mac
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/macos/php80/continuous.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/macos/php80/continuous.cfg
index 9a71745..ded43e6 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/macos/php80/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/macos/php80/build.sh"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/macos/php80/presubmit.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/macos/php80/presubmit.cfg
index 9a71745..ded43e6 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/macos/php80/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/macos/php80/build.sh"
timeout_mins: 1440
diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc
index 8e0a87e..7ec2832 100755
--- a/kokoro/macos/prepare_build_macos_rc
+++ b/kokoro/macos/prepare_build_macos_rc
@@ -4,20 +4,16 @@
set -eux
+export HOMEBREW_PREFIX=$(brew --prefix)
+
##
# Select Xcode version
-
-# Remember to update the Xcode version when Xcode_11.3.app is not available.
-# If xcode is not available, it will probably encounter the failure for
-# "autom4te: need GNU m4 1.4 or later: /usr/bin/m4"
-# go/kokoro/userdocs/macos/selecting_xcode.md for more information.
-export DEVELOPER_DIR=/Applications/Xcode_11.3.app/Contents/Developer
+export DEVELOPER_DIR=/Applications/Xcode_13.3.1.app/Contents/Developer
+sudo xcode-select -s "${DEVELOPER_DIR}"
##
-# Select C/C++ compilers
-
-export CC=gcc
-export CXX=g++
+# Use Python 2 by default (for googletest)
+pyenv global 2.7.18
##
# Install Tox
@@ -27,14 +23,18 @@
fi
##
-# Install RVM
-
+# Setup RVM
if [[ "${KOKORO_INSTALL_RVM:-}" == "yes" ]] ; then
- curl -sSL https://rvm.io/mpapis.asc | gpg --import -
- curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
+ git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-cask
+ git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-core
+ git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-services
+ sudo chown -R $(whoami) $HOME/.rvm/
+fi
- # Old OpenSSL versions cannot handle the SSL certificate used by
- # https://get.rvm.io, so as a workaround we download RVM directly from
- # GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133
- curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby
+# "Install" valgrind if it doesn't exist
+##
+if [ ! -x "$(command -v valgrind)" ]; then
+ echo "#! /bin/bash" > valgrind
+ chmod ug+x valgrind
+ sudo mv valgrind /usr/local/bin/valgrind
fi
diff --git a/kokoro/release/ruby/macos/build_artifacts.sh b/kokoro/release/ruby/macos/build_artifacts.sh
index c68b63c..a109d45 100755
--- a/kokoro/release/ruby/macos/build_artifacts.sh
+++ b/kokoro/release/ruby/macos/build_artifacts.sh
@@ -12,8 +12,5 @@
# ruby environment
bash kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
-gem install rubygems-update
-update_rubygems
-
# build artifacts
bash kokoro/release/ruby/macos/ruby/ruby_build.sh
diff --git a/kokoro/release/ruby/macos/ruby/ruby_build.sh b/kokoro/release/ruby/macos/ruby/ruby_build.sh
index 55773b2..bbfc631 100755
--- a/kokoro/release/ruby/macos/ruby/ruby_build.sh
+++ b/kokoro/release/ruby/macos/ruby/ruby_build.sh
@@ -3,7 +3,6 @@
set -ex
# Build protoc
-use_bazel.sh 5.1.1
bazel build //:protoc
export PROTOC=$PWD/bazel-bin/protoc
diff --git a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
index 2a9cb16..ae973fc 100755
--- a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
+++ b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
@@ -4,13 +4,9 @@
set +ex # rvm script is very verbose and exits with errorcode
-curl -sSL https://rvm.io/mpapis.asc | gpg --import -
-curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
-
-# Old OpenSSL versions cannot handle the SSL certificate used by
-# https://get.rvm.io, so as a workaround we download RVM directly from
-# GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133
-curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby
+# Fix permissions
+sudo chown -R $(whoami) $HOME/.rvm/
+sudo chown -R $(whoami) /Library/Ruby/
source $HOME/.rvm/scripts/rvm
set -e # rvm commands are very verbose
diff --git a/kokoro/windows/bazel/build.bat b/kokoro/windows/bazel/build.bat
new file mode 100644
index 0000000..52b83f4
--- /dev/null
+++ b/kokoro/windows/bazel/build.bat
@@ -0,0 +1,4 @@
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+@rem TODO(mkruskal) Implement tests
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/bazel/continuous.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/bazel/continuous.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/bazel/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/bazel/presubmit.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/bazel/presubmit.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/bazel/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/windows/cmake/build.bat b/kokoro/windows/cmake/build.bat
new file mode 100644
index 0000000..52b83f4
--- /dev/null
+++ b/kokoro/windows/cmake/build.bat
@@ -0,0 +1,4 @@
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+@rem TODO(mkruskal) Implement tests
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake/continuous.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake/continuous.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake/presubmit.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake/presubmit.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/windows/cmake_install/build.bat b/kokoro/windows/cmake_install/build.bat
new file mode 100644
index 0000000..52b83f4
--- /dev/null
+++ b/kokoro/windows/cmake_install/build.bat
@@ -0,0 +1,4 @@
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+@rem TODO(mkruskal) Implement tests
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake_install/continuous.cfg
similarity index 63%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake_install/continuous.cfg
index 9a71745..2efc0dc 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake_install/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake_install/build.bat"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/presubmit.cfg b/kokoro/windows/cmake_install/presubmit.cfg
similarity index 63%
rename from kokoro/macos/php7.3_mac/presubmit.cfg
rename to kokoro/windows/cmake_install/presubmit.cfg
index 9a71745..2efc0dc 100644
--- a/kokoro/macos/php7.3_mac/presubmit.cfg
+++ b/kokoro/windows/cmake_install/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake_install/build.bat"
timeout_mins: 1440
diff --git a/kokoro/windows/cmake_nmake/build.bat b/kokoro/windows/cmake_nmake/build.bat
new file mode 100644
index 0000000..52b83f4
--- /dev/null
+++ b/kokoro/windows/cmake_nmake/build.bat
@@ -0,0 +1,4 @@
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+@rem TODO(mkruskal) Implement tests
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake_nmake/continuous.cfg
similarity index 63%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake_nmake/continuous.cfg
index 9a71745..3c279fe 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake_nmake/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake_nmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake_nmake/presubmit.cfg
similarity index 63%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake_nmake/presubmit.cfg
index 9a71745..3c279fe 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake_nmake/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake_nmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/windows/cmake_shared/build.bat b/kokoro/windows/cmake_shared/build.bat
new file mode 100644
index 0000000..52b83f4
--- /dev/null
+++ b/kokoro/windows/cmake_shared/build.bat
@@ -0,0 +1,4 @@
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+@rem TODO(mkruskal) Implement tests
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake_shared/continuous.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake_shared/continuous.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake_shared/continuous.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/kokoro/macos/php7.3_mac/continuous.cfg b/kokoro/windows/cmake_shared/presubmit.cfg
similarity index 65%
copy from kokoro/macos/php7.3_mac/continuous.cfg
copy to kokoro/windows/cmake_shared/presubmit.cfg
index 9a71745..37e89e0 100644
--- a/kokoro/macos/php7.3_mac/continuous.cfg
+++ b/kokoro/windows/cmake_shared/presubmit.cfg
@@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
+build_file: "protobuf/kokoro/windows/cmake/build.bat"
timeout_mins: 1440
diff --git a/objectivec/GPBApi.pbobjc.h b/objectivec/GPBApi.pbobjc.h
index 871e908..1848aa6 100644
--- a/objectivec/GPBApi.pbobjc.h
+++ b/objectivec/GPBApi.pbobjc.h
@@ -74,12 +74,12 @@
/** The methods of this interface, in unspecified order. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethod*> *methodsArray;
-/** The number of items in @c methodsArray without causing the array to be created. */
+/** The number of items in @c methodsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger methodsArray_Count;
/** Any metadata attached to the interface. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/**
@@ -115,7 +115,7 @@
/** Included interfaces. See [Mixin][]. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMixin*> *mixinsArray;
-/** The number of items in @c mixinsArray without causing the array to be created. */
+/** The number of items in @c mixinsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger mixinsArray_Count;
/** The source syntax of the service. */
@@ -169,7 +169,7 @@
/** Any metadata attached to the method. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source syntax of this method. */
diff --git a/objectivec/GPBFieldMask.pbobjc.h b/objectivec/GPBFieldMask.pbobjc.h
index c4667b4..b7eccff 100644
--- a/objectivec/GPBFieldMask.pbobjc.h
+++ b/objectivec/GPBFieldMask.pbobjc.h
@@ -247,7 +247,7 @@
/** The set of field mask paths. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *pathsArray;
-/** The number of items in @c pathsArray without causing the array to be created. */
+/** The number of items in @c pathsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger pathsArray_Count;
@end
diff --git a/objectivec/GPBStruct.pbobjc.h b/objectivec/GPBStruct.pbobjc.h
index dd6ab28..ff4eefd 100644
--- a/objectivec/GPBStruct.pbobjc.h
+++ b/objectivec/GPBStruct.pbobjc.h
@@ -87,7 +87,7 @@
/** Unordered map of dynamically typed values. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, GPBValue*> *fields;
-/** The number of items in @c fields without causing the array to be created. */
+/** The number of items in @c fields without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger fields_Count;
@end
@@ -178,7 +178,7 @@
/** Repeated field of dynamically typed values. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBValue*> *valuesArray;
-/** The number of items in @c valuesArray without causing the array to be created. */
+/** The number of items in @c valuesArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger valuesArray_Count;
@end
diff --git a/objectivec/GPBType.pbobjc.h b/objectivec/GPBType.pbobjc.h
index b023050..969219f 100644
--- a/objectivec/GPBType.pbobjc.h
+++ b/objectivec/GPBType.pbobjc.h
@@ -195,17 +195,17 @@
/** The list of fields. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBField*> *fieldsArray;
-/** The number of items in @c fieldsArray without causing the array to be created. */
+/** The number of items in @c fieldsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger fieldsArray_Count;
/** The list of types appearing in `oneof` definitions in this type. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *oneofsArray;
-/** The number of items in @c oneofsArray without causing the array to be created. */
+/** The number of items in @c oneofsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger oneofsArray_Count;
/** The protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source context. */
@@ -279,7 +279,7 @@
/** The protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The field JSON name. */
@@ -334,12 +334,12 @@
/** Enum value definitions. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValue*> *enumvalueArray;
-/** The number of items in @c enumvalueArray without causing the array to be created. */
+/** The number of items in @c enumvalueArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
/** Protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source context. */
@@ -385,7 +385,7 @@
/** Protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/** The number of items in @c optionsArray without causing the array to be created. */
+/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
@end
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index b72d0e2..cd0910c 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -2248,7 +2248,7 @@
NSCAssert([[self descriptor] oneofWithName:oneof.name] == oneof,
@"OneofDescriptor %@ doesn't appear to be for %@ messages.",
oneof.name, [self class]);
- GPBFieldDescriptor *firstField = oneof->fields_[0];
+ GPBFieldDescriptor *firstField __unused = oneof->fields_[0];
NSCAssert(firstField->description_->hasIndex == oneofHasIndex,
@"Internal error, oneofHasIndex (%d) doesn't match (%d).",
firstField->description_->hasIndex, oneofHasIndex);
diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh
index 1b9de6e..e6c9b04 100755
--- a/objectivec/generate_well_known_types.sh
+++ b/objectivec/generate_well_known_types.sh
@@ -73,6 +73,7 @@
if ! diff "${ObjCDir}/GPB${OBJC_NAME}${EXT}" "${TMP_DIR}/${DIR}/${OBJC_NAME}${EXT}" > /dev/null 2>&1 ; then
if [[ "${CHECK_ONLY}" == 1 ]] ; then
echo "ERROR: The WKTs need to be regenerated! Run $0"
+ diff -u "${ObjCDir}/GPB${OBJC_NAME}${EXT}" "${TMP_DIR}/${DIR}/${OBJC_NAME}${EXT}"
exit 1
fi
diff --git a/php/BUILD.bazel b/php/BUILD.bazel
index 3460959..dfb0976 100644
--- a/php/BUILD.bazel
+++ b/php/BUILD.bazel
@@ -12,7 +12,9 @@
"src/Google/Protobuf/**/*.php",
"tests/*.php",
"tests/*.sh",
+ "tests/generated_previous/**/*.php",
"tests/proto/**/*.proto",
+ "tests/proto_previous/*.proto",
]) + [
"BUILD.bazel",
"README.md",
diff --git a/php/composer.json b/php/composer.json
index 756704f..436142f 100644
--- a/php/composer.json
+++ b/php/composer.json
@@ -20,7 +20,10 @@
"autoload-dev": {
"psr-4": {
"": "tmp"
- }
+ },
+ "classmap": [
+ "tests/generated_previous"
+ ]
},
"scripts": {
"test_c": "./generate_test_protos.sh && ./tests/compile_extension.sh && php -dextension=ext/google/protobuf/modules/protobuf.so vendor/bin/phpunit --bootstrap tests/force_c_ext.php tests",
diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c
index dfb96f2..018dac1 100644
--- a/php/ext/google/protobuf/def.c
+++ b/php/ext/google/protobuf/def.c
@@ -162,7 +162,7 @@
ZVAL_NULL(val);
} else {
char *classname =
- GetPhpClassname(upb_EnumDef_File(m), upb_EnumDef_FullName(m));
+ GetPhpClassname(upb_EnumDef_File(m), upb_EnumDef_FullName(m), false);
zend_string *str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
@@ -499,19 +499,23 @@
}
static zend_class_entry *Descriptor_GetGeneratedClass(const upb_MessageDef *m) {
- char *classname =
- GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m));
- zend_string *str = zend_string_init(classname, strlen(classname), 0);
- zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
+ for (int i = 0; i < 2; ++i) {
+ char *classname =
+ GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), (bool)i);
+ zend_string *str = zend_string_init(classname, strlen(classname), 0);
+ zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
- zend_string_release (str);
+ zend_string_release (str);
+ free(classname);
- if (!ce) {
- zend_error(E_ERROR, "Couldn't load generated class %s", classname);
+ if (ce) {
+ return ce;
+ }
}
- free(classname);
- return ce;
+ char *classname =
+ GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), false);
+ zend_error(E_ERROR, "Couldn't load generated class %s", classname);
}
void Descriptor_FromMessageDef(zval *val, const upb_MessageDef *m) {
diff --git a/php/ext/google/protobuf/names.c b/php/ext/google/protobuf/names.c
index 5d7b68a..e359d01 100644
--- a/php/ext/google/protobuf/names.c
+++ b/php/ext/google/protobuf/names.c
@@ -82,12 +82,15 @@
"global", "goto", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "object",
"or", "parent", "print", "private", "protected",
- "public", "require", "require_once", "return", "self",
- "static", "switch", "throw", "trait", "try",
- "unset", "use", "var", "while", "xor",
- "yield", "int", "float", "bool", "string",
- "true", "false", "null", "void", "iterable",
- NULL};
+ "public", "readonly", "require", "require_once", "return",
+ "self", "static", "switch", "throw", "trait",
+ "try", "unset", "use", "var", "while",
+ "xor", "yield", "int", "float", "bool",
+ "string", "true", "false", "null", "void",
+ "iterable", NULL};
+
+const char *const kPreviouslyUnreservedNames[] = {
+ "readonly", NULL};
bool is_reserved_name(const char* name) {
int i;
@@ -99,6 +102,15 @@
return false;
}
+bool is_previously_unreserved_name(const char* name) {
+ for (int i = 0; kPreviouslyUnreservedNames[i]; i++) {
+ if (strcmp(kPreviouslyUnreservedNames[i], name) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
static char nolocale_tolower(char ch) {
if (ch >= 'A' && ch <= 'Z') {
return ch - ('A' - 'a');
@@ -115,17 +127,22 @@
}
}
-static bool is_reserved(const char *segment, int length) {
- bool result;
- char* lower = calloc(1, length + 1);
- memcpy(lower, segment, length);
- int i = 0;
- while(lower[i]) {
- lower[i] = nolocale_tolower(lower[i]);
- i++;
+static char *strdup_nolocale_lower(char *str, int length) {
+ char* lower = malloc(length + 1);
+ lower[length] = '\0';
+ for(int i = 0; i < length; ++i) {
+ lower[i] = nolocale_tolower(str[i]);
}
- lower[length] = 0;
+ return lower;
+}
+
+static bool is_reserved(const char *segment, int length, bool previous) {
+ bool result;
+ char* lower = strdup_nolocale_lower(segment, length);
result = is_reserved_name(lower);
+ if (result && previous && is_previously_unreserved_name(lower)) {
+ result = false;
+ }
free(lower);
return result;
}
@@ -133,11 +150,12 @@
static void fill_prefix(const char *segment, int length,
const char *prefix_given,
const char *package_name,
- stringsink *classname) {
+ stringsink *classname,
+ bool previous) {
if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
stringsink_string(classname, prefix_given, strlen(prefix_given));
} else {
- if (is_reserved(segment, length)) {
+ if (is_reserved(segment, length, previous)) {
if (package_name != NULL &&
strcmp("google.protobuf", package_name) == 0) {
stringsink_string(classname, "GPB", 3);
@@ -160,7 +178,7 @@
}
static void fill_namespace(const char *package, const char *php_namespace,
- stringsink *classname) {
+ stringsink *classname, bool previous) {
if (php_namespace != NULL) {
if (strlen(php_namespace) != 0) {
stringsink_string(classname, php_namespace, strlen(php_namespace));
@@ -174,7 +192,7 @@
while (j < package_len && package[j] != '.') {
j++;
}
- fill_prefix(package + i, j - i, "", package, classname);
+ fill_prefix(package + i, j - i, "", package, classname, previous);
fill_segment(package + i, j - i, classname, true);
stringsink_string(classname, "\\", 1);
i = j + 1;
@@ -185,7 +203,8 @@
static void fill_classname(const char *fullname,
const char *package,
const char *prefix,
- stringsink *classname) {
+ stringsink *classname,
+ bool previous) {
int classname_start = 0;
if (package != NULL) {
size_t package_len = strlen(package);
@@ -199,7 +218,7 @@
while (j < fullname_len && fullname[j] != '.') {
j++;
}
- fill_prefix(fullname + i, j - i, prefix, package, classname);
+ fill_prefix(fullname + i, j - i, prefix, package, classname, previous);
fill_segment(fullname + i, j - i, classname, false);
if (j != fullname_len) {
stringsink_string(classname, "\\", 1);
@@ -215,7 +234,7 @@
return ret;
}
-char *GetPhpClassname(const upb_FileDef *file, const char *fullname) {
+char *GetPhpClassname(const upb_FileDef *file, const char *fullname, bool previous) {
// Prepend '.' to package name to make it absolute. In the 5 additional
// bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if
// given message is google.protobuf.Empty.
@@ -234,8 +253,8 @@
stringsink namesink;
stringsink_init(&namesink);
- fill_namespace(package, php_namespace, &namesink);
- fill_classname(fullname, package, prefix, &namesink);
+ fill_namespace(package, php_namespace, &namesink, previous);
+ fill_classname(fullname, package, prefix, &namesink, previous);
stringsink_string(&namesink, "\0", 1);
ret = strdup(namesink.ptr);
stringsink_uninit(&namesink);
@@ -243,3 +262,26 @@
free(prefix);
return ret;
}
+
+bool IsPreviouslyUnreservedClassName(const char* fullname) {
+ const char *classname = strrchr(fullname, '\\');
+ if (classname) {
+ classname += 1;
+ } else {
+ classname = fullname;
+ }
+ if (strncmp(classname, "PB", 2) != 0) {
+ return false;
+ }
+ classname += 2;
+ int length = strlen(classname);
+ char* lower = strdup_nolocale_lower(classname, length);
+ for (int j = 0; kPreviouslyUnreservedNames[j]; j++) {
+ if (strcmp(kPreviouslyUnreservedNames[j], lower) == 0) {
+ free(lower);
+ return true;
+ }
+ }
+ free(lower);
+ return false;
+}
diff --git a/php/ext/google/protobuf/names.h b/php/ext/google/protobuf/names.h
index 86af799..cc42dc8 100644
--- a/php/ext/google/protobuf/names.h
+++ b/php/ext/google/protobuf/names.h
@@ -35,6 +35,7 @@
// Translates a protobuf symbol name (eg. foo.bar.Baz) into a PHP class name
// (eg. \Foo\Bar\Baz).
-char *GetPhpClassname(const upb_FileDef *file, const char *fullname);
+char *GetPhpClassname(const upb_FileDef *file, const char *fullname, bool previous);
+bool IsPreviouslyUnreservedClassName(const char* fullname);
#endif // PHP_PROTOBUF_NAMES_H_
diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml
index bf3d90e..c291714 100644
--- a/php/ext/google/protobuf/package.xml
+++ b/php/ext/google/protobuf/package.xml
@@ -5,16 +5,16 @@
<summary>Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.</summary>
<description>https://developers.google.com/protocol-buffers/</description>
<lead>
- <name>Bo Yang</name>
- <user>stanleycheung</user>
- <email>protobuf-opensource@google.com</email>
+ <name>Protobuf Team</name>
+ <user>protobufpackages</user>
+ <email>protobuf-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2022-06-23</date>
- <time>12:12:44</time>
+ <date>2022-07-25</date>
+ <time>13:21:48</time>
<version>
- <release>3.21.2</release>
- <api>3.21.2</api>
+ <release>3.21.4</release>
+ <api>3.21.4</api>
</version>
<stability>
<release>stable</release>
@@ -1358,5 +1358,35 @@
<notes>
</notes>
</release>
+ <release>
+ <version>
+ <release>3.21.3</release>
+ <api>3.21.3</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2022-07-21</date>
+ <time>10:19:47</time>
+ <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+ <notes>
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>3.21.4</release>
+ <api>3.21.4</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2022-07-25</date>
+ <time>13:21:48</time>
+ <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+ <notes>
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c
index c786b6e..a5aba23 100644
--- a/php/ext/google/protobuf/protobuf.c
+++ b/php/ext/google/protobuf/protobuf.c
@@ -242,13 +242,19 @@
// -----------------------------------------------------------------------------
void NameMap_AddMessage(const upb_MessageDef *m) {
- char *k = GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m));
- zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
- free(k);
+ for (int i = 0; i < 2; ++i) {
+ char *k = GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), (bool)i);
+ zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
+ if (!IsPreviouslyUnreservedClassName(k)) {
+ free(k);
+ return;
+ }
+ free(k);
+ }
}
void NameMap_AddEnum(const upb_EnumDef *e) {
- char *k = GetPhpClassname(upb_EnumDef_File(e), upb_EnumDef_FullName(e));
+ char *k = GetPhpClassname(upb_EnumDef_File(e), upb_EnumDef_FullName(e), false);
zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e);
free(k);
}
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index c5dac32..e63e9e8 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -127,7 +127,7 @@
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
-#define PHP_PROTOBUF_VERSION "3.21.2"
+#define PHP_PROTOBUF_VERSION "3.21.4"
// ptr -> PHP object cache. This is a weak map that caches lazily-created
// wrapper objects around upb types:
diff --git a/php/src/Google/Protobuf/Internal/Descriptor.php b/php/src/Google/Protobuf/Internal/Descriptor.php
index a7f80d5..51a34d6 100644
--- a/php/src/Google/Protobuf/Internal/Descriptor.php
+++ b/php/src/Google/Protobuf/Internal/Descriptor.php
@@ -45,6 +45,7 @@
private $enum_type = [];
private $klass;
private $legacy_klass;
+ private $previous_klass;
private $options;
private $oneof_decl = [];
@@ -162,6 +163,16 @@
return $this->legacy_klass;
}
+ public function setPreviouslyUnreservedClass($klass)
+ {
+ $this->previous_klass = $klass;
+ }
+
+ public function getPreviouslyUnreservedClass()
+ {
+ return $this->previous_klass;
+ }
+
public function setOptions($options)
{
$this->options = $options;
@@ -179,6 +190,7 @@
$message_name_without_package = "";
$classname = "";
$legacy_classname = "";
+ $previous_classname = "";
$fullname = "";
GPBUtil::getFullClassName(
$proto,
@@ -187,10 +199,12 @@
$message_name_without_package,
$classname,
$legacy_classname,
- $fullname);
+ $fullname,
+ $previous_classname);
$desc->setFullName($fullname);
$desc->setClass($classname);
$desc->setLegacyClass($legacy_classname);
+ $desc->setPreviouslyUnreservedClass($previous_classname);
$desc->setOptions($proto->getOptions());
foreach ($proto->getField() as $field_proto) {
diff --git a/php/src/Google/Protobuf/Internal/DescriptorPool.php b/php/src/Google/Protobuf/Internal/DescriptorPool.php
index 1468a02..1be00e2 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorPool.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorPool.php
@@ -96,6 +96,7 @@
$descriptor->getClass();
$this->class_to_desc[$descriptor->getClass()] = $descriptor;
$this->class_to_desc[$descriptor->getLegacyClass()] = $descriptor;
+ $this->class_to_desc[$descriptor->getPreviouslyUnreservedClass()] = $descriptor;
foreach ($descriptor->getNestedType() as $nested_type) {
$this->addDescriptor($nested_type);
}
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptor.php b/php/src/Google/Protobuf/Internal/EnumDescriptor.php
index 7af4f84..383f53b 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptor.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptor.php
@@ -101,7 +101,8 @@
$enum_name_without_package,
$classname,
$legacy_classname,
- $fullname);
+ $fullname,
+ $unused_previous_classname);
$desc->setFullName($fullname);
$desc->setClass($classname);
$desc->setLegacyClass($legacy_classname);
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 4b15283..ffea900 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -285,11 +285,12 @@
"include"=>0, "include_once"=>0, "instanceof"=>0, "insteadof"=>0,
"interface"=>0, "isset"=>0, "list"=>0, "match"=>0, "namespace"=>0,
"new"=>0, "or"=>0, "parent"=>0, "print"=>0, "private"=>0,
- "protected"=>0,"public"=>0, "require"=>0, "require_once"=>0,
- "return"=>0, "self"=>0, "static"=>0, "switch"=>0, "throw"=>0,
- "trait"=>0, "try"=>0,"unset"=>0, "use"=>0, "var"=>0, "while"=>0,
- "xor"=>0, "yield"=>0, "int"=>0, "float"=>0, "bool"=>0, "string"=>0,
- "true"=>0, "false"=>0, "null"=>0, "void"=>0, "iterable"=>0
+ "protected"=>0,"public"=>0, "readonly" => 0,"require"=>0,
+ "require_once"=>0,"return"=>0, "self"=>0, "static"=>0, "switch"=>0,
+ "throw"=>0,"trait"=>0, "try"=>0,"unset"=>0, "use"=>0, "var"=>0,
+ "while"=>0,"xor"=>0, "yield"=>0, "int"=>0, "float"=>0, "bool"=>0,
+ "string"=>0,"true"=>0, "false"=>0, "null"=>0, "void"=>0,
+ "iterable"=>0
);
if (array_key_exists(strtolower($classname), $reserved_words)) {
@@ -303,6 +304,27 @@
return "";
}
+ private static function getPreviouslyUnreservedClassNamePrefix(
+ $classname,
+ $file_proto)
+ {
+ $previously_unreserved_words = array(
+ "readonly"=>0
+ );
+
+ if (array_key_exists(strtolower($classname), $previously_unreserved_words)) {
+ $option = $file_proto->getOptions();
+ $prefix = is_null($option) ? "" : $option->getPhpClassPrefix();
+ if ($prefix !== "") {
+ return $prefix;
+ }
+
+ return "";
+ }
+
+ return self::getClassNamePrefix($classname, $file_proto);
+ }
+
public static function getLegacyClassNameWithoutPackage(
$name,
$file_proto)
@@ -322,6 +344,17 @@
return implode('\\', $parts);
}
+ private static function getPreviouslyUnreservedClassNameWithoutPackage(
+ $name,
+ $file_proto)
+ {
+ $parts = explode('.', $name);
+ foreach ($parts as $i => $part) {
+ $parts[$i] = static::getPreviouslyUnreservedClassNamePrefix($parts[$i], $file_proto) . $parts[$i];
+ }
+ return implode('\\', $parts);
+ }
+
public static function getFullClassName(
$proto,
$containing,
@@ -329,7 +362,8 @@
&$message_name_without_package,
&$classname,
&$legacy_classname,
- &$fullname)
+ &$fullname,
+ &$previous_classname)
{
// Full name needs to start with '.'.
$message_name_without_package = $proto->getName();
@@ -350,6 +384,9 @@
$legacy_class_name_without_package =
static::getLegacyClassNameWithoutPackage(
$message_name_without_package, $file_proto);
+ $previous_class_name_without_package =
+ static::getPreviouslyUnreservedClassNameWithoutPackage(
+ $message_name_without_package, $file_proto);
$option = $file_proto->getOptions();
if (!is_null($option) && $option->hasPhpNamespace()) {
@@ -358,10 +395,13 @@
$classname = $namespace . "\\" . $class_name_without_package;
$legacy_classname =
$namespace . "\\" . $legacy_class_name_without_package;
+ $previous_classname =
+ $namespace . "\\" . $previous_class_name_without_package;
return;
} else {
$classname = $class_name_without_package;
$legacy_classname = $legacy_class_name_without_package;
+ $previous_classname = $previous_class_name_without_package;
return;
}
}
@@ -369,6 +409,7 @@
if ($package === "") {
$classname = $class_name_without_package;
$legacy_classname = $legacy_class_name_without_package;
+ $previous_classname = $previous_class_name_without_package;
} else {
$parts = array_map('ucwords', explode('.', $package));
foreach ($parts as $i => $part) {
@@ -381,6 +422,11 @@
$legacy_classname =
implode('\\', array_map('ucwords', explode('.', $package))).
"\\".$legacy_class_name_without_package;
+ $previous_classname =
+ implode('\\', array_map('ucwords', explode('.', $package))).
+ "\\".self::getPreviouslyUnreservedClassNamePrefix(
+ $previous_class_name_without_package, $file_proto).
+ $previous_class_name_without_package;
}
}
diff --git a/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php
index 8a89973..37c33df 100644
--- a/php/tests/GeneratedClassTest.php
+++ b/php/tests/GeneratedClassTest.php
@@ -334,6 +334,18 @@
$this->legacyEnum(new TestLegacyMessage\NestedEnum);
}
+ public function testLegacyReadOnlyMessage()
+ {
+ $this->assertTrue(class_exists('\Upper\READONLY'));
+ $this->assertTrue(class_exists('\Lower\readonly'));
+ }
+
+ public function testLegacyReadOnlyEnum()
+ {
+ $this->assertTrue(class_exists('\Upper_enum\READONLY'));
+ $this->assertTrue(class_exists('\Lower_enum\readonly'));
+ }
+
private function legacyEnum(TestLegacyMessage_NestedEnum $enum)
{
// If we made it here without a PHP Fatal error, the typehint worked
@@ -943,6 +955,7 @@
$m = new \Lower\PBprivate();
$m = new \Lower\PBprotected();
$m = new \Lower\PBpublic();
+ $m = new \Lower\PBreadonly();
$m = new \Lower\PBrequire();
$m = new \Lower\PBrequire_once();
$m = new \Lower\PBreturn();
@@ -1023,6 +1036,7 @@
$m = new \Upper\PBPRIVATE();
$m = new \Upper\PBPROTECTED();
$m = new \Upper\PBPUBLIC();
+ $m = new \Upper\PBREADONLY();
$m = new \Upper\PBREQUIRE();
$m = new \Upper\PBREQUIRE_ONCE();
$m = new \Upper\PBRETURN();
@@ -1104,6 +1118,7 @@
$m = new \Lower_enum\PBprotected();
$m = new \Lower_enum\PBpublic();
$m = new \Lower_enum\PBrequire();
+ $m = new \Lower_enum\PBreadonly();
$m = new \Lower_enum\PBrequire_once();
$m = new \Lower_enum\PBreturn();
$m = new \Lower_enum\PBself();
@@ -1183,6 +1198,7 @@
$m = new \Upper_enum\PBPRIVATE();
$m = new \Upper_enum\PBPROTECTED();
$m = new \Upper_enum\PBPUBLIC();
+ $m = new \Upper_enum\PBREADONLY();
$m = new \Upper_enum\PBREQUIRE();
$m = new \Upper_enum\PBREQUIRE_ONCE();
$m = new \Upper_enum\PBRETURN();
@@ -1287,6 +1303,7 @@
$m = \Lower_enum_value\NotAllowed::iterable;
$m = \Lower_enum_value\NotAllowed::parent;
$m = \Lower_enum_value\NotAllowed::self;
+ $m = \Lower_enum_value\NotAllowed::readonly;
$m = \Upper_enum_value\NotAllowed::PBABSTRACT;
$m = \Upper_enum_value\NotAllowed::PBAND;
@@ -1367,6 +1384,7 @@
$m = \Upper_enum_value\NotAllowed::ITERABLE;
$m = \Upper_enum_value\NotAllowed::PARENT;
$m = \Upper_enum_value\NotAllowed::SELF;
+ $m = \Upper_enum_value\NotAllowed::READONLY;
$this->assertTrue(true);
}
diff --git a/php/tests/PreviouslyGeneratedClassTest.php b/php/tests/PreviouslyGeneratedClassTest.php
new file mode 100644
index 0000000..077c84f
--- /dev/null
+++ b/php/tests/PreviouslyGeneratedClassTest.php
@@ -0,0 +1,18 @@
+<?php
+
+require_once('test_base.php');
+require_once('test_util.php');
+
+class PreviouslyGeneratedClassTest extends TestBase
+{
+ #########################################################
+ # Test compatibility for previously unreserved words.
+ #########################################################
+
+ public function testPrefixForReservedWords()
+ {
+ $m = new \Previous\readonly();
+
+ $this->assertTrue(true);
+ }
+}
diff --git a/php/tests/generated_previous/GPBMetadata/ProtoPrevious/TestPreviouslyUnreservedMessage.php b/php/tests/generated_previous/GPBMetadata/ProtoPrevious/TestPreviouslyUnreservedMessage.php
new file mode 100644
index 0000000..d2120f9
--- /dev/null
+++ b/php/tests/generated_previous/GPBMetadata/ProtoPrevious/TestPreviouslyUnreservedMessage.php
@@ -0,0 +1,28 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: proto_previous/test_previously_unreserved_message.proto
+
+namespace GPBMetadata\ProtoPrevious;
+
+class TestPreviouslyUnreservedMessage
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ $pool->internalAddGeneratedFile(
+ '
+W
+7proto_previous/test_previously_unreserved_message.protoprevious"
+
+readonlybproto3'
+ , true);
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/php/tests/generated_previous/Previous/readonly.php b/php/tests/generated_previous/Previous/readonly.php
new file mode 100644
index 0000000..013f293
--- /dev/null
+++ b/php/tests/generated_previous/Previous/readonly.php
@@ -0,0 +1,31 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: proto_previous/test_previously_unreserved_message.proto
+
+namespace Previous;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>previous.readonly</code>
+ */
+class readonly extends \Google\Protobuf\Internal\Message
+{
+
+ /**
+ * Constructor.
+ *
+ * @param array $data {
+ * Optional. Data for populating the Message object.
+ *
+ * }
+ */
+ public function __construct($data = NULL) {
+ \GPBMetadata\ProtoPrevious\TestPreviouslyUnreservedMessage::initOnce();
+ parent::__construct($data);
+ }
+
+}
+
diff --git a/php/tests/proto/test_reserved_enum_lower.proto b/php/tests/proto/test_reserved_enum_lower.proto
index f8557d2..1f96ac6 100644
--- a/php/tests/proto/test_reserved_enum_lower.proto
+++ b/php/tests/proto/test_reserved_enum_lower.proto
@@ -57,6 +57,7 @@
enum private { ZERO52 = 0; }
enum protected { ZERO53 = 0; }
enum public { ZERO54 = 0; }
+enum readonly { ZERO80 = 0; }
enum require { ZERO55 = 0; }
enum require_once { ZERO56 = 0; }
enum return { ZERO57 = 0; }
diff --git a/php/tests/proto/test_reserved_enum_upper.proto b/php/tests/proto/test_reserved_enum_upper.proto
index 8d382ab..c5e7e99 100644
--- a/php/tests/proto/test_reserved_enum_upper.proto
+++ b/php/tests/proto/test_reserved_enum_upper.proto
@@ -57,6 +57,7 @@
enum PRIVATE { ZERO52 = 0; }
enum PROTECTED { ZERO53 = 0; }
enum PUBLIC { ZERO54 = 0; }
+enum READONLY { ZERO80 = 0; }
enum REQUIRE { ZERO55 = 0; }
enum REQUIRE_ONCE { ZERO56 = 0; }
enum RETURN { ZERO57 = 0; }
diff --git a/php/tests/proto/test_reserved_enum_value_lower.proto b/php/tests/proto/test_reserved_enum_value_lower.proto
index ca5a7c7..86c6877 100644
--- a/php/tests/proto/test_reserved_enum_value_lower.proto
+++ b/php/tests/proto/test_reserved_enum_value_lower.proto
@@ -58,6 +58,7 @@
private = 51;
protected = 52;
public = 53;
+ readonly = 79;
require = 54;
require_once = 55;
return = 56;
diff --git a/php/tests/proto/test_reserved_enum_value_upper.proto b/php/tests/proto/test_reserved_enum_value_upper.proto
index 6b4040d..ac0beda 100644
--- a/php/tests/proto/test_reserved_enum_value_upper.proto
+++ b/php/tests/proto/test_reserved_enum_value_upper.proto
@@ -58,6 +58,7 @@
PRIVATE = 51;
PROTECTED = 52;
PUBLIC = 53;
+ READONLY = 79;
REQUIRE = 54;
REQUIRE_ONCE = 55;
RETURN = 56;
diff --git a/php/tests/proto/test_reserved_message_lower.proto b/php/tests/proto/test_reserved_message_lower.proto
index 2390a87..551ed7a 100644
--- a/php/tests/proto/test_reserved_message_lower.proto
+++ b/php/tests/proto/test_reserved_message_lower.proto
@@ -57,6 +57,7 @@
message private {}
message protected {}
message public {}
+message readonly {}
message require {}
message require_once {}
message return {}
diff --git a/php/tests/proto/test_reserved_message_upper.proto b/php/tests/proto/test_reserved_message_upper.proto
index 9f55330..96995c9 100644
--- a/php/tests/proto/test_reserved_message_upper.proto
+++ b/php/tests/proto/test_reserved_message_upper.proto
@@ -57,6 +57,7 @@
message PRIVATE {}
message PROTECTED {}
message PUBLIC {}
+message READONLY {}
message REQUIRE {}
message REQUIRE_ONCE {}
message RETURN {}
diff --git a/php/tests/proto_previous/test_previously_unreserved_message.proto b/php/tests/proto_previous/test_previously_unreserved_message.proto
new file mode 100644
index 0000000..1b4b0b7
--- /dev/null
+++ b/php/tests/proto_previous/test_previously_unreserved_message.proto
@@ -0,0 +1,5 @@
+syntax = "proto3";
+
+package previous;
+
+message readonly {}
\ No newline at end of file
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index e952643..0d2611f 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -114,6 +114,6 @@
_github_archive(
name = "upb",
repo = "https://github.com/protocolbuffers/upb",
- commit = "04cb5af6b67c80db61f0aee76dcb6d233e51795c",
- sha256 = "62d3519a7b65d6695e011f2733bfc5d7c6ab77f2bd83cdd2dca449da2e739c7f",
+ commit = "17b6451684ffcf6e77d10a5def9bf19af57eccd3",
+ sha256 = "655c30a01c8ab56680c154baded548c5df8f726305d3338d0885cbb1f700ec10",
)
diff --git a/protobuf_version.bzl b/protobuf_version.bzl
index b6c35f3..edac503 100644
--- a/protobuf_version.bzl
+++ b/protobuf_version.bzl
@@ -1,3 +1,3 @@
-PROTOC_VERSION = '21.2'
-PROTOBUF_JAVA_VERSION = '3.21.2'
-PROTOBUF_PYTHON_VERSION = '4.21.2'
+PROTOC_VERSION = '21.4'
+PROTOBUF_JAVA_VERSION = '3.21.4'
+PROTOBUF_PYTHON_VERSION = '4.21.4'
diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml
index bce8121..d816174 100644
--- a/protoc-artifacts/pom.xml
+++ b/protoc-artifacts/pom.xml
@@ -4,11 +4,11 @@
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
- <version>1</version>
+ <version>5</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
<packaging>pom</packaging>
<name>Protobuf Compiler</name>
<description>
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index 2c3e06c..b01d870 100644
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -30,4 +30,4 @@
# Copyright 2007 Google Inc. All Rights Reserved.
-__version__ = '4.21.2'
+__version__ = '4.21.4'
diff --git a/python/release.sh b/python/release.sh
index 15a70db..87fcf8c 100755
--- a/python/release.sh
+++ b/python/release.sh
@@ -19,11 +19,24 @@
chmod +x test-venv/bin/protoc
source test-venv/bin/activate
- pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir
+ (pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir) || (retry_pip_install ${PYPI} ${VERSION})
deactivate
rm -fr test-venv
}
+function retry_pip_install() {
+ local PYPI=$1
+ local VERSION=$2
+
+ read -p "pip install failed, possibly due to delay between upload and availability on pip. Retry? [y/n]" -r
+ echo
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+ exit 1
+ fi
+
+ (pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir) || (retry_pip_install ${PYPI} ${VERSION})
+}
+
[ $# -lt 1 ] && {
echo "Usage: $0 VERSION ["
@@ -86,13 +99,16 @@
python3 setup.py sdist
twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/*
-# Test locally with different python versions.
+# Sleep to allow time for distribution to be available on pip.
+sleep 5m
+
+# Test locally.
run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple
# Deploy egg/wheel packages to testing PyPI and test again.
python3 setup.py clean build bdist_wheel
twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/*
-
+sleep 5m
run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple
echo "All install tests have passed using testing PyPI."
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index e7aa377..e43665d 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "google-protobuf"
- s.version = "3.21.2"
+ s.version = "3.21.4"
git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag
s.licenses = ["BSD-3-Clause"]
s.summary = "Protocol Buffers"
diff --git a/ruby/pom.xml b/ruby/pom.xml
index f1bdbf1..4264172 100644
--- a/ruby/pom.xml
+++ b/ruby/pom.xml
@@ -9,7 +9,7 @@
<groupId>com.google.protobuf.jruby</groupId>
<artifactId>protobuf-jruby</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
<name>Protocol Buffer JRuby native extension</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
@@ -76,7 +76,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
- <version>3.21.2</version>
+ <version>3.21.4</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
diff --git a/src/Makefile.am b/src/Makefile.am
index 9875b1c..15f7aa4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@
PTHREAD_DEF =
endif
-PROTOBUF_VERSION = 32:2:0
+PROTOBUF_VERSION = 32:4:0
if GCC
# Turn on all warnings except for sign comparison (we ignore sign comparison
@@ -774,6 +774,7 @@
google/protobuf/compiler/csharp/csharp_generator_unittest.cc \
google/protobuf/compiler/importer_unittest.cc \
google/protobuf/compiler/java/doc_comment_unittest.cc \
+ google/protobuf/compiler/java/message_serialization_unittest.cc \
google/protobuf/compiler/java/plugin_unittest.cc \
google/protobuf/compiler/mock_code_generator.cc \
google/protobuf/compiler/mock_code_generator.h \
diff --git a/src/file_lists.cmake b/src/file_lists.cmake
index 32f10b2..67092cc 100644
--- a/src/file_lists.cmake
+++ b/src/file_lists.cmake
@@ -771,6 +771,7 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment_unittest.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/plugin_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 2368446..0a9ee26 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index ac80560..4903294 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 0987c99..1466376 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -1419,7 +1419,7 @@
ASSERT_GT(arena.SpaceAllocated(), first_block_size);
auto second_block_size = (arena.SpaceAllocated() - first_block_size);
- EXPECT_EQ(second_block_size, 2*first_block_size);
+ EXPECT_GE(second_block_size, 2*first_block_size);
}
TEST(ArenaTest, Alignment) {
diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc
index 03b1438..8d7e6ff 100644
--- a/src/google/protobuf/arenastring.cc
+++ b/src/google/protobuf/arenastring.cc
@@ -50,7 +50,8 @@
namespace {
-// Enforce that allocated data aligns to at least 8 bytes, and that
+// TaggedStringPtr::Flags uses the lower 2 bits as tags.
+// Enforce that allocated data aligns to at least 4 bytes, and that
// the alignment of the global const string value does as well.
// The alignment guaranteed by `new std::string` depends on both:
// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
@@ -64,8 +65,8 @@
#endif
constexpr size_t kStringAlign = alignof(std::string);
-static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 8, "");
-static_assert(alignof(ExplicitlyConstructedArenaString) >= 8, "");
+static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, "");
+static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, "");
} // namespace
diff --git a/src/google/protobuf/arenaz_sampler.cc b/src/google/protobuf/arenaz_sampler.cc
index 6ad3a36..ab524fb 100644
--- a/src/google/protobuf/arenaz_sampler.cc
+++ b/src/google/protobuf/arenaz_sampler.cc
@@ -72,7 +72,7 @@
bytes_used.store(0, std::memory_order_relaxed);
bytes_allocated.store(0, std::memory_order_relaxed);
bytes_wasted.store(0, std::memory_order_relaxed);
- max_bytes_allocated.store(0, std::memory_order_relaxed);
+ max_block_size.store(0, std::memory_order_relaxed);
thread_ids.store(0, std::memory_order_relaxed);
weight = stride;
// The inliner makes hardcoded skip_count difficult (especially when combined
@@ -87,6 +87,9 @@
info->bytes_used.fetch_add(used, std::memory_order_relaxed);
info->bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
info->bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
+ if (info->max_block_size.load(std::memory_order_relaxed) < allocated) {
+ info->max_block_size.store(allocated, std::memory_order_relaxed);
+ }
const uint64_t tid = 1ULL << (GetCachedTID() % 63);
info->thread_ids.fetch_or(tid, std::memory_order_relaxed);
}
diff --git a/src/google/protobuf/arenaz_sampler.h b/src/google/protobuf/arenaz_sampler.h
index 4a04c6a..e9a4dec 100644
--- a/src/google/protobuf/arenaz_sampler.h
+++ b/src/google/protobuf/arenaz_sampler.h
@@ -69,8 +69,8 @@
std::atomic<size_t> bytes_used;
std::atomic<size_t> bytes_allocated;
std::atomic<size_t> bytes_wasted;
- // Records the largest size an arena ever had.
- std::atomic<size_t> max_bytes_allocated;
+ // Records the largest block allocated for the arena.
+ std::atomic<size_t> max_block_size;
// Bit `i` is set to 1 indicates that a thread with `tid % 63 = i` accessed
// the underlying arena. We use `% 63` as a rudimentary hash to ensure some
// bit mixing for thread-ids; `% 64` would only grab the low bits and might
diff --git a/src/google/protobuf/arenaz_sampler_test.cc b/src/google/protobuf/arenaz_sampler_test.cc
index 7bac100..1b73938 100644
--- a/src/google/protobuf/arenaz_sampler_test.cc
+++ b/src/google/protobuf/arenaz_sampler_test.cc
@@ -89,21 +89,21 @@
EXPECT_EQ(info.bytes_used.load(), 0);
EXPECT_EQ(info.bytes_allocated.load(), 0);
EXPECT_EQ(info.bytes_wasted.load(), 0);
- EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+ EXPECT_EQ(info.max_block_size.load(), 0);
EXPECT_EQ(info.weight, kTestStride);
info.num_allocations.store(1, std::memory_order_relaxed);
info.bytes_used.store(1, std::memory_order_relaxed);
info.bytes_allocated.store(1, std::memory_order_relaxed);
info.bytes_wasted.store(1, std::memory_order_relaxed);
- info.max_bytes_allocated.store(1, std::memory_order_relaxed);
+ info.max_block_size.store(1, std::memory_order_relaxed);
info.PrepareForSampling(2 * kTestStride);
EXPECT_EQ(info.num_allocations.load(), 0);
EXPECT_EQ(info.bytes_used.load(), 0);
EXPECT_EQ(info.bytes_allocated.load(), 0);
EXPECT_EQ(info.bytes_wasted.load(), 0);
- EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+ EXPECT_EQ(info.max_block_size.load(), 0);
EXPECT_EQ(info.weight, 2 * kTestStride);
}
@@ -117,14 +117,29 @@
EXPECT_EQ(info.bytes_used.load(), 100);
EXPECT_EQ(info.bytes_allocated.load(), 128);
EXPECT_EQ(info.bytes_wasted.load(), 0);
- EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+ EXPECT_EQ(info.max_block_size.load(), 128);
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
/*wasted=*/28);
EXPECT_EQ(info.num_allocations.load(), 2);
EXPECT_EQ(info.bytes_used.load(), 200);
EXPECT_EQ(info.bytes_allocated.load(), 384);
EXPECT_EQ(info.bytes_wasted.load(), 28);
- EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+ EXPECT_EQ(info.max_block_size.load(), 256);
+}
+
+TEST(ThreadSafeArenaStatsTest, RecordAllocateSlowMaxBlockSizeTest) {
+ ThreadSafeArenaStats info;
+ constexpr int64_t kTestStride = 458;
+ MutexLock l(&info.init_mu);
+ info.PrepareForSampling(kTestStride);
+ RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
+ EXPECT_EQ(info.max_block_size.load(), 128);
+ RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
+ /*wasted=*/28);
+ EXPECT_EQ(info.max_block_size.load(), 256);
+ RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128,
+ /*wasted=*/28);
+ EXPECT_EQ(info.max_block_size.load(), 256);
}
TEST(ThreadSafeArenazSamplerTest, SamplingCorrectness) {
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 0a0c7e3..7491046 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -339,9 +339,12 @@
void AddErrorOrWarning(const std::string& filename, int line, int column,
const std::string& message, const std::string& type,
std::ostream& out) {
- // Print full path when running under MSVS
std::string dfile;
- if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
+ if (
+#ifndef PROTOBUF_OPENSOURCE
+ // Print full path when running under MSVS
+ format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
+#endif // !PROTOBUF_OPENSOURCE
tree_ != nullptr && tree_->VirtualFileToDiskFile(filename, &dfile)) {
out << dfile;
} else {
@@ -398,7 +401,6 @@
// Get name of all output files.
void GetOutputFilenames(std::vector<std::string>* output_filenames);
-
// implements GeneratorContext --------------------------------------
io::ZeroCopyOutputStream* Open(const std::string& filename) override;
io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename) override;
@@ -963,6 +965,7 @@
int CommandLineInterface::Run(int argc, const char* const argv[]) {
Clear();
+
switch (ParseArguments(argc, argv)) {
case PARSE_ARGUMENT_DONE_AND_EXIT:
return 0;
@@ -1076,7 +1079,6 @@
}
}
- // Write all output to disk.
for (const auto& pair : output_directories) {
const std::string& location = pair.first;
GeneratorContextImpl* directory = pair.second.get();
@@ -1151,7 +1153,6 @@
// Do not add a default case.
}
}
-
return 0;
}
diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc
index cf4f14e..90d2084 100644
--- a/src/google/protobuf/compiler/cpp/field.cc
+++ b/src/google/protobuf/compiler/cpp/field.cc
@@ -330,7 +330,6 @@
}
}
-
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
diff --git a/src/google/protobuf/compiler/cpp/field.h b/src/google/protobuf/compiler/cpp/field.h
index 3903e79..3fcbda3 100644
--- a/src/google/protobuf/compiler/cpp/field.h
+++ b/src/google/protobuf/compiler/cpp/field.h
@@ -208,7 +208,6 @@
virtual bool IsInlined() const { return false; }
-
virtual ArenaDtorNeeds NeedsArenaDestructor() const {
return ArenaDtorNeeds::kNone;
}
diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc
index 838e0ab..502d8c0 100644
--- a/src/google/protobuf/compiler/cpp/file.cc
+++ b/src/google/protobuf/compiler/cpp/file.cc
@@ -495,12 +495,10 @@
generator->GenerateInitDefaultSplitInstance(printer);
format(
"} {}\n"
- " ~$1$() {}\n"
" union {\n"
- " $2$ _instance;\n"
+ " $1$ _instance;\n"
" };\n"
"};\n",
- DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
StrCat(generator->classname_, "::Impl_::Split"));
// NO_DESTROY is not necessary for correctness. The empty destructor is
// enough. However, the empty destructor fails to be elided in some
@@ -508,7 +506,7 @@
// there just to improve performance and binary size in these builds.
format(
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
- "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
+ "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const $1$ $2$;\n",
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
DefaultInstanceName(generator->descriptor_, options_, /*split=*/true));
}
@@ -999,7 +997,7 @@
const Descriptor* class_desc = p.second;
format(
"struct $1$;\n"
- "$dllexport_decl $extern $1$ $2$;\n",
+ "$dllexport_decl $extern const $1$ $2$;\n",
DefaultInstanceType(class_desc, options, /*split=*/true),
DefaultInstanceName(class_desc, options, /*split=*/true));
}
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index 4939aa5..d182c86 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -176,7 +176,6 @@
#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES
};
-
static std::unordered_set<std::string>* MakeKeywordsMap() {
auto* result = new std::unordered_set<std::string>();
for (const auto keyword : kKeywordList) {
@@ -525,7 +524,6 @@
return result;
}
-
std::string FieldMemberName(const FieldDescriptor* field, bool split) {
StringPiece prefix =
IsMapEntryMessage(field->containing_type()) ? "" : "_impl_.";
@@ -876,8 +874,6 @@
bool IsProfileDriven(const Options& options) {
return options.access_info_map != nullptr;
}
-
-
bool IsStringInlined(const FieldDescriptor* descriptor,
const Options& options) {
(void)descriptor;
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 3ca5315..51a3e65 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -828,7 +828,6 @@
// Generate type-specific accessor declarations.
field_generators_.get(field).GenerateAccessorDeclarations(printer);
-
format("\n");
}
@@ -1238,41 +1237,41 @@
Formatter::SaveState saver(&format);
format.AddMap(vars);
- // Generate has_$name$() or $name$_size().
- if (field->is_repeated()) {
- if (IsFieldStripped(field, options_)) {
- format(
- "inline int $classname$::$name$_size() const { "
- "__builtin_trap(); }\n");
- } else {
- format(
- "inline int $classname$::_internal_$name$_size() const {\n"
- " return $field$$1$.size();\n"
- "}\n"
- "inline int $classname$::$name$_size() const {\n"
- "$annotate_size$"
- " return _internal_$name$_size();\n"
- "}\n",
- IsImplicitWeakField(field, options_, scc_analyzer_) &&
- field->message_type()
- ? ".weak"
- : "");
- }
- } else if (field->real_containing_oneof()) {
- format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
- format.Set("oneof_name", field->containing_oneof()->name());
- format.Set("oneof_index",
- StrCat(field->containing_oneof()->index()));
- GenerateOneofMemberHasBits(field, format);
+
+ // Generate has_$name$() or $name$_size().
+ if (field->is_repeated()) {
+ if (IsFieldStripped(field, options_)) {
+ format(
+ "inline int $classname$::$name$_size() const { "
+ "__builtin_trap(); }\n");
} else {
- // Singular field.
- GenerateSingularFieldHasBits(field, format);
+ format(
+ "inline int $classname$::_internal_$name$_size() const {\n"
+ " return $field$$1$.size();\n"
+ "}\n"
+ "inline int $classname$::$name$_size() const {\n"
+ "$annotate_size$"
+ " return _internal_$name$_size();\n"
+ "}\n",
+ IsImplicitWeakField(field, options_, scc_analyzer_) &&
+ field->message_type()
+ ? ".weak"
+ : "");
}
+ } else if (field->real_containing_oneof()) {
+ format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
+ format.Set("oneof_name", field->containing_oneof()->name());
+ format.Set("oneof_index",
+ StrCat(field->containing_oneof()->index()));
+ GenerateOneofMemberHasBits(field, format);
+ } else {
+ // Singular field.
+ GenerateSingularFieldHasBits(field, format);
+ }
if (!IsCrossFileMaybeMap(field)) {
GenerateFieldClear(field, true, format);
}
-
// Generate type-specific accessors.
if (!IsFieldStripped(field, options_)) {
field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
@@ -1760,7 +1759,7 @@
format(
"private:\n"
"inline bool IsSplitMessageDefault() const {\n"
- " return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n"
+ " return $split$ == reinterpret_cast<const Impl_::Split*>(&$1$);\n"
"}\n"
"PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n"
"public:\n",
@@ -1928,6 +1927,8 @@
" typedef void InternalArenaConstructable_;\n"
" typedef void DestructorSkippable_;\n"
"};\n"
+ "static_assert(std::is_trivially_copy_constructible<Split>::value);\n"
+ "static_assert(std::is_trivially_destructible<Split>::value);\n"
"Split* _split_;\n");
}
@@ -2421,8 +2422,15 @@
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
- format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
- DefaultInstanceName(descriptor_, options_, /*split=*/true));
+ // We can't assign the default split to this->split without the const_cast
+ // because the former is a const. The const_cast is safe because we don't
+ // intend to modify the default split through this pointer, and we also
+ // expect the default split to be in the rodata section which is protected
+ // from mutation.
+ format(
+ "decltype($split$){const_cast<Impl_::Split*>"
+ "(reinterpret_cast<const Impl_::Split*>(&$1$))}",
+ DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
for (auto oneof : OneOfRange(descriptor_)) {
put_sep();
@@ -2681,7 +2689,7 @@
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
- format("/*decltype($split$)*/&$1$._instance",
+ format("/*decltype($split$)*/const_cast<Impl_::Split*>(&$1$._instance)",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
@@ -2866,8 +2874,10 @@
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
- format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
- DefaultInstanceName(descriptor_, options_, /*split=*/true));
+ format(
+ "decltype($split$){const_cast<Impl_::Split*>"
+ "(reinterpret_cast<const Impl_::Split*>(&$1$))}",
+ DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
for (auto oneof : OneOfRange(descriptor_)) {
put_sep();
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
index 8045f48..30b0fd4 100644
--- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
@@ -83,7 +83,8 @@
return 2;
}
-void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
+void PopulateFastFieldEntry(const Descriptor* descriptor,
+ const TailCallTableInfo::FieldEntryInfo& entry,
const Options& options,
TailCallTableInfo::FastFieldInfo& info);
@@ -158,6 +159,7 @@
}
std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize(
+ const Descriptor* descriptor,
const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries,
int table_size_log2, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
@@ -200,7 +202,7 @@
GOOGLE_CHECK(info.func_name.empty()) << info.func_name;
info.field = field;
info.coded_tag = tag;
- PopulateFastFieldEntry(entry, options, info);
+ PopulateFastFieldEntry(descriptor, entry, options, info);
// If this field does not have presence, then it can set an out-of-bounds
// bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32).
info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63;
@@ -412,8 +414,8 @@
int num_fast_fields = -1;
for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) {
size_t try_size = 1 << try_size_log2;
- auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2,
- options, scc_analyzer);
+ auto split_fields = SplitFastFieldsForSize(
+ descriptor, field_entries, try_size_log2, options, scc_analyzer);
GOOGLE_CHECK_EQ(split_fields.size(), try_size);
int try_num_fast_fields = 0;
for (const auto& info : split_fields) {
@@ -1667,11 +1669,12 @@
namespace {
-void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
+void PopulateFastFieldEntry(const Descriptor* descriptor,
+ const TailCallTableInfo::FieldEntryInfo& entry,
const Options& options,
TailCallTableInfo::FastFieldInfo& info) {
const FieldDescriptor* field = entry.field;
- std::string name = "::_pbi::TcParser::Fast";
+ std::string name;
uint8_t aux_idx = static_cast<uint8_t>(entry.aux_idx);
switch (field->type()) {
@@ -1784,7 +1787,36 @@
// Append the tag length. Fast parsing only handles 1- or 2-byte tags.
name.append(TagSize(field->number()) == 1 ? "1" : "2");
- info.func_name = std::move(name);
+ if (name == "V8S1") {
+ info.func_name = StrCat(
+ "::_pbi::TcParser::SingularVarintNoZag1<bool, offsetof(", //
+ ClassName(descriptor), //
+ ", ", //
+ FieldMemberName(field, /*split=*/false), //
+ "), ", //
+ HasHasbit(field) ? entry.hasbit_idx : 63, //
+ ">()");
+ } else if (name == "V32S1") {
+ info.func_name = StrCat(
+ "::_pbi::TcParser::SingularVarintNoZag1<uint32_t, offsetof(", //
+ ClassName(descriptor), //
+ ", ", //
+ FieldMemberName(field, /*split=*/false), //
+ "), ", //
+ HasHasbit(field) ? entry.hasbit_idx : 63, //
+ ">()");
+ } else if (name == "V64S1") {
+ info.func_name = StrCat(
+ "::_pbi::TcParser::SingularVarintNoZag1<uint64_t, offsetof(", //
+ ClassName(descriptor), //
+ ", ", //
+ FieldMemberName(field, /*split=*/false), //
+ "), ", //
+ HasHasbit(field) ? entry.hasbit_idx : 63, //
+ ">()");
+ } else {
+ info.func_name = StrCat("::_pbi::TcParser::Fast", name);
+ }
info.aux_idx = aux_idx;
}
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
index d40c9d3..1b58b95 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -397,15 +397,30 @@
}
std::string GetPropertyName(const FieldDescriptor* descriptor) {
+ // Names of members declared or overridden in the message.
+ static const auto& reserved_member_names = *new std::unordered_set<std::string>({
+ "Types",
+ "Descriptor",
+ "Equals",
+ "ToString",
+ "GetHashCode",
+ "WriteTo",
+ "Clone",
+ "CalculateSize",
+ "MergeFrom",
+ "OnConstruction",
+ "Parser"
+ });
+
// TODO(jtattermusch): consider introducing csharp_property_name field option
std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor));
- // Avoid either our own type name or reserved names. Note that not all names
- // are reserved - a field called to_string, write_to etc would still cause a problem.
+ // Avoid either our own type name or reserved names.
// There are various ways of ending up with naming collisions, but we try to avoid obvious
- // ones.
+ // ones. In particular, we avoid the names of all the members we generate.
+ // Note that we *don't* add an underscore for MemberwiseClone or GetType. Those generate
+ // warnings, but not errors; changing the name now could be a breaking change.
if (property_name == descriptor->containing_type()->name()
- || property_name == "Types"
- || property_name == "Descriptor") {
+ || reserved_member_names.find(property_name) != reserved_member_names.end()) {
property_name += "_";
}
return property_name;
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
index a13b995..9efd3d5 100644
--- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -90,7 +90,7 @@
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(
variables_,
- "$name$_.Add(other.$name$_);\n");
+ "$name$_.MergeFrom(other.$name$_);\n");
}
void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {
diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc
index b82d147..aa3a51f 100644
--- a/src/google/protobuf/compiler/java/enum_field.cc
+++ b/src/google/protobuf/compiler/java/enum_field.cc
@@ -281,6 +281,18 @@
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ var $kt_name$Value: kotlin.Int\n"
+ " @JvmName(\"${$get$kt_capitalized_name$Value$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$Value$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$Value$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$Value$}$(value)\n"
+ " }\n");
+ }
+
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
/* builder */ false, /* kdoc */ true);
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc
index caa215b..a256824 100644
--- a/src/google/protobuf/compiler/java/enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/enum_field_lite.cc
@@ -296,6 +296,18 @@
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ var $kt_name$Value: kotlin.Int\n"
+ " @JvmName(\"${$get$kt_capitalized_name$Value$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$Value$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$Value$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$Value$}$(value)\n"
+ " }\n");
+ }
+
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
/* builder */ false, /* kdoc */ true);
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/generator.h b/src/google/protobuf/compiler/java/generator.h
index bbc7170..39d2445 100644
--- a/src/google/protobuf/compiler/java/generator.h
+++ b/src/google/protobuf/compiler/java/generator.h
@@ -63,7 +63,12 @@
uint64_t GetSupportedFeatures() const override;
+ void set_opensource_runtime(bool opensource) {
+ opensource_runtime_ = opensource;
+ }
+
private:
+ bool opensource_runtime_ = true;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator);
};
diff --git a/src/google/protobuf/compiler/java/message_serialization.h b/src/google/protobuf/compiler/java/message_serialization.h
index 6145392..15dc515 100644
--- a/src/google/protobuf/compiler/java/message_serialization.h
+++ b/src/google/protobuf/compiler/java/message_serialization.h
@@ -32,6 +32,7 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_SERIALIZATION_H__
#include <algorithm>
+#include <cstddef>
#include <vector>
#include <google/protobuf/io/printer.h>
@@ -66,20 +67,31 @@
std::sort(sorted_extensions.begin(), sorted_extensions.end(),
ExtensionRangeOrdering());
+ std::size_t range_idx = 0;
+
// Merge the fields and the extension ranges, both sorted by field number.
- for (int i = 0, j = 0;
- i < descriptor->field_count() || j < sorted_extensions.size();) {
- if (i == descriptor->field_count()) {
- GenerateSerializeExtensionRange(printer, sorted_extensions[j++]);
- } else if (j == sorted_extensions.size()) {
- field_generators.get(sorted_fields[i++])
- .GenerateSerializationCode(printer);
- } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) {
- field_generators.get(sorted_fields[i++])
- .GenerateSerializationCode(printer);
- } else {
- GenerateSerializeExtensionRange(printer, sorted_extensions[j++]);
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* field = sorted_fields[i];
+
+ // Collapse all extension ranges up until the next field. This leads to
+ // shorter and more efficient codegen for messages containing a large
+ // number of extension ranges without fields in between them.
+ const Descriptor::ExtensionRange* range = nullptr;
+ while (range_idx < sorted_extensions.size() &&
+ sorted_extensions[range_idx]->end <= field->number()) {
+ range = sorted_extensions[range_idx++];
}
+
+ if (range != nullptr) {
+ GenerateSerializeExtensionRange(printer, range);
+ }
+ field_generators.get(field).GenerateSerializationCode(printer);
+ }
+
+ // After serializing all fields, serialize any remaining extensions via a
+ // single writeUntil call.
+ if (range_idx < sorted_extensions.size()) {
+ GenerateSerializeExtensionRange(printer, sorted_extensions.back());
}
}
diff --git a/src/google/protobuf/compiler/java/message_serialization_unittest.cc b/src/google/protobuf/compiler/java/message_serialization_unittest.cc
new file mode 100644
index 0000000..b2e1fca
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_serialization_unittest.cc
@@ -0,0 +1,124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/java/generator.h>
+#include <google/protobuf/test_util2.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+namespace {
+
+using ::testing::ElementsAre;
+
+// Generates Java code for the specified Java proto, returning the compiler's
+// exit status.
+int CompileJavaProto(std::string proto_file_name) {
+ JavaGenerator java_generator;
+
+ CommandLineInterface cli;
+ cli.RegisterGenerator("--java_out", &java_generator, /*help_text=*/"");
+
+ std::string proto_path = StrCat(
+ "--proto_path=",
+ TestUtil::GetTestDataPath("third_party/protobuf/compiler/java"));
+ std::string java_out = StrCat("--java_out=", TestTempDir());
+
+ const char* argv[] = {
+ "protoc",
+ proto_path.c_str(),
+ java_out.c_str(),
+ proto_file_name.c_str(),
+ };
+
+ // Open-source codebase does not support ABSL_ARRAYSIZE.
+ return cli.Run(sizeof(argv) / sizeof(*argv), argv);
+}
+
+TEST(MessageSerializationTest, CollapseAdjacentExtensionRanges) {
+ GOOGLE_CHECK_EQ(CompileJavaProto("message_serialization_unittest.proto"), 0);
+
+ std::string java_source;
+ GOOGLE_CHECK_OK(File::GetContents(
+ // Open-source codebase does not support file::JoinPath, so we manually
+ // concatenate instead.
+ StrCat(TestTempDir(),
+ "/TestMessageWithManyExtensionRanges.java"),
+ &java_source, true));
+
+ // Open-source codebase does not support constexpr StringPiece.
+ static constexpr const char kWriteUntilCall[] = "extensionWriter.writeUntil(";
+
+ std::vector<std::string> range_ends;
+
+ // Open-source codebase does not have Split overload taking a single
+ // char delimiter.
+ //
+ // NOLINTNEXTLINE(abseil-faster-strsplit-delimiter)
+ for (const auto& line : Split(java_source, "\n")) {
+ // Extract end position from writeUntil call. (Open-source codebase does not
+ // support RE2.)
+ std::size_t write_until_pos = line.find(kWriteUntilCall);
+ if (write_until_pos == std::string::npos) {
+ continue;
+ }
+ write_until_pos += (sizeof(kWriteUntilCall) - 1);
+
+ std::size_t comma_pos = line.find(',', write_until_pos);
+ if (comma_pos == std::string::npos) {
+ continue;
+ }
+
+ range_ends.push_back(
+ std::string(line.substr(write_until_pos, comma_pos - write_until_pos)));
+ }
+
+ EXPECT_THAT(range_ends, ElementsAre("3", "13", "43"));
+}
+
+} // namespace
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/message_serialization_unittest.proto b/src/google/protobuf/compiler/java/message_serialization_unittest.proto
new file mode 100644
index 0000000..9cfdf42
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_serialization_unittest.proto
@@ -0,0 +1,56 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_package = "";
+
+// Each batch of extension ranges not separated by a non-extension field should
+// be serialized using a single ExtensionWriter#writeUntil call.
+message TestMessageWithManyExtensionRanges {
+ // First extension range: ends at field number 3 (exclusive)
+ extensions 1 to 2;
+
+ optional int32 foo = 3;
+ optional int32 bar = 5;
+
+ // Second extension range: ends at field number 13 (exclusive)
+ extensions 6;
+ extensions 8;
+ extensions 10 to 12;
+
+ optional int32 baz = 23;
+
+ // Third extension range: ends at field number 43 (exclusive)
+ extensions 42;
+}
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 3960946..15b6591 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -66,6 +66,10 @@
cli.RegisterGenerator("--java_out", "--java_opt", &java_generator,
"Generate Java source file.");
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+ java_generator.set_opensource_runtime(true);
+#endif
+
// Proto2 Kotlin
java::KotlinGenerator kt_generator;
cli.RegisterGenerator("--kotlin_out", "--kotlin_opt", &kt_generator,
@@ -76,6 +80,11 @@
python::Generator py_generator;
cli.RegisterGenerator("--python_out", "--python_opt", &py_generator,
"Generate Python source file.");
+
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+ py_generator.set_opensource_runtime(true);
+#endif
+
// Python pyi
python::PyiGenerator pyi_generator;
cli.RegisterGenerator("--pyi_out", &pyi_generator,
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
index 004ea19..a9e6517 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -388,7 +388,7 @@
"$comments$"
"$array_comment$"
"@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
- "/** The number of items in @c $name$ without causing the array to be created. */\n"
+ "/** The number of items in @c $name$ without causing the container to be created. */\n"
"@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
if (IsInitName(variables_.find("name")->second)) {
// If property name starts with init we need to annotate it to get past ARC.
diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc
index 7c9a3e3..6c824e3 100644
--- a/src/google/protobuf/compiler/php/php_generator.cc
+++ b/src/google/protobuf/compiler/php/php_generator.cc
@@ -48,29 +48,29 @@
const std::string kDescriptorDirName = "Google/Protobuf/Internal";
const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
const char* const kReservedNames[] = {
- "abstract", "and", "array", "as", "break",
- "callable", "case", "catch", "class", "clone",
- "const", "continue", "declare", "default", "die",
- "do", "echo", "else", "elseif", "empty",
- "enddeclare", "endfor", "endforeach", "endif", "endswitch",
- "endwhile", "eval", "exit", "extends", "final",
- "finally", "fn", "for", "foreach", "function",
- "global", "goto", "if", "implements", "include",
- "include_once", "instanceof", "insteadof", "interface", "isset",
- "list", "match", "namespace", "new", "or",
- "parent", "print", "private", "protected", "public",
- "require", "require_once", "return", "self", "static",
- "switch", "throw", "trait", "try", "unset",
- "use", "var", "while", "xor", "yield",
- "int", "float", "bool", "string", "true",
- "false", "null", "void", "iterable"};
+ "abstract", "and", "array", "as", "break",
+ "callable", "case", "catch", "class", "clone",
+ "const", "continue", "declare", "default", "die",
+ "do", "echo", "else", "elseif", "empty",
+ "enddeclare", "endfor", "endforeach", "endif", "endswitch",
+ "endwhile", "eval", "exit", "extends", "final",
+ "finally", "fn", "for", "foreach", "function",
+ "global", "goto", "if", "implements", "include",
+ "include_once", "instanceof", "insteadof", "interface", "isset",
+ "list", "match", "namespace", "new", "or",
+ "parent", "print", "private", "protected", "public",
+ "readonly", "require", "require_once", "return", "self",
+ "static", "switch", "throw", "trait", "try",
+ "unset", "use", "var", "while", "xor",
+ "yield", "int", "float", "bool", "string",
+ "true", "false", "null", "void", "iterable"};
const char* const kValidConstantNames[] = {
"int", "float", "bool", "string", "true",
"false", "null", "void", "iterable", "parent",
- "self"
+ "self", "readonly"
};
-const int kReservedNamesSize = 79;
-const int kValidConstantNamesSize = 11;
+const int kReservedNamesSize = 80;
+const int kValidConstantNamesSize = 12;
const int kFieldSetter = 1;
const int kFieldGetter = 2;
const int kFieldProperty = 3;
@@ -407,6 +407,29 @@
return result + ".php";
}
+template <typename DescriptorType>
+std::string LegacyGeneratedClassFileName(const DescriptorType* desc,
+ const Options& options) {
+ std::string result = LegacyFullClassName(desc, options);
+
+ for (int i = 0; i < result.size(); i++) {
+ if (result[i] == '\\') {
+ result[i] = '/';
+ }
+ }
+ return result + ".php";
+}
+
+template <typename DescriptorType>
+std::string LegacyReadOnlyGeneratedClassFileName(const DescriptorType* desc,
+ const Options& options) {
+ std::string php_namespace = RootPhpNamespace(desc, options);
+ if (!php_namespace.empty()) {
+ return php_namespace + "/" + desc->name() + ".php";
+ }
+ return desc->name() + ".php";
+}
+
std::string GeneratedServiceFileName(const ServiceDescriptor* service,
const Options& options) {
std::string result = FullClassName(service, options) + "Interface";
@@ -1252,6 +1275,70 @@
printer.Print("}\n\n");
}
+template <typename DescriptorType>
+void LegacyGenerateClassFile(const FileDescriptor* file,
+ const DescriptorType* desc, const Options& options,
+ GeneratorContext* generator_context) {
+ std::string filename = LegacyGeneratedClassFileName(desc, options);
+ std::unique_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
+ io::Printer printer(output.get(), '^');
+
+ GenerateHead(file, &printer);
+
+ std::string php_namespace = RootPhpNamespace(desc, options);
+ if (!php_namespace.empty()) {
+ printer.Print(
+ "namespace ^name^;\n\n",
+ "name", php_namespace);
+ }
+ std::string newname = FullClassName(desc, options);
+ printer.Print("if (false) {\n");
+ Indent(&printer);
+ printer.Print("/**\n");
+ printer.Print(" * This class is deprecated. Use ^new^ instead.\n",
+ "new", newname);
+ printer.Print(" * @deprecated\n");
+ printer.Print(" */\n");
+ printer.Print("class ^old^ {}\n",
+ "old", LegacyGeneratedClassName(desc));
+ Outdent(&printer);
+ printer.Print("}\n");
+ printer.Print("class_exists(^new^::class);\n",
+ "new", GeneratedClassNameImpl(desc));
+ printer.Print("@trigger_error('^old^ is deprecated and will be removed in "
+ "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
+ "old", LegacyFullClassName(desc, options),
+ "fullname", newname);
+}
+
+template <typename DescriptorType>
+void LegacyReadOnlyGenerateClassFile(const FileDescriptor* file,
+ const DescriptorType* desc, const Options& options,
+ GeneratorContext* generator_context) {
+ std::string filename = LegacyReadOnlyGeneratedClassFileName(desc, options);
+ std::unique_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
+ io::Printer printer(output.get(), '^');
+
+ GenerateHead(file, &printer);
+
+ std::string php_namespace = RootPhpNamespace(desc, options);
+ if (!php_namespace.empty()) {
+ printer.Print(
+ "namespace ^name^;\n\n",
+ "name", php_namespace);
+ }
+ std::string newname = FullClassName(desc, options);
+ printer.Print("class_exists(^new^::class); // autoload the new class, which "
+ "will also create an alias to the deprecated class\n",
+ "new", GeneratedClassNameImpl(desc));
+ printer.Print("@trigger_error(__NAMESPACE__ . '\\^old^ is deprecated and will be removed in "
+ "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
+ "old", desc->name(),
+ "fullname", newname);
+}
+
void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
const Options& options,
GeneratorContext* generator_context) {
@@ -1372,6 +1459,19 @@
"new", fullname,
"old", LegacyFullClassName(en, options));
}
+
+ // Write legacy file for backwards compatibility with "readonly" keywword
+ std::string lower = en->name();
+ std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+ if (lower == "readonly") {
+ printer.Print(
+ "// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
+ printer.Print(
+ "class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
+ "new", fullname,
+ "old", en->name());
+ LegacyReadOnlyGenerateClassFile(file, en, options, generator_context);
+ }
}
void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
@@ -1487,6 +1587,19 @@
"old", LegacyFullClassName(message, options));
}
+ // Write legacy file for backwards compatibility with "readonly" keywword
+ std::string lower = message->name();
+ std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+ if (lower == "readonly") {
+ printer.Print(
+ "// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
+ printer.Print(
+ "class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
+ "new", fullname,
+ "old", message->name());
+ LegacyReadOnlyGenerateClassFile(file, message, options, generator_context);
+ }
+
// Nested messages and enums.
for (int i = 0; i < message->nested_type_count(); i++) {
GenerateMessageFile(file, message->nested_type(i), options,
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index b73c9de..51152e6 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/compiler/python/generator.h b/src/google/protobuf/compiler/python/generator.h
index f1fecbc..0b8d56d 100644
--- a/src/google/protobuf/compiler/python/generator.h
+++ b/src/google/protobuf/compiler/python/generator.h
@@ -76,6 +76,10 @@
uint64_t GetSupportedFeatures() const override;
+ void set_opensource_runtime(bool opensource) {
+ opensource_runtime_ = opensource;
+ }
+
private:
void PrintImports() const;
void PrintFileDescriptor() const;
@@ -172,6 +176,8 @@
mutable io::Printer* printer_; // Set in Generate(). Under mutex_.
mutable bool pure_python_workable_;
+ bool opensource_runtime_ = true;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
};
diff --git a/src/google/protobuf/compiler/python/pyi_generator.cc b/src/google/protobuf/compiler/python/pyi_generator.cc
index 1ccc9a2..e954fd3 100644
--- a/src/google/protobuf/compiler/python/pyi_generator.cc
+++ b/src/google/protobuf/compiler/python/pyi_generator.cc
@@ -44,39 +44,22 @@
namespace compiler {
namespace python {
-template <typename DescriptorT>
-struct SortByName {
- bool operator()(const DescriptorT* l, const DescriptorT* r) const {
- return l->name() < r->name();
- }
-};
-
PyiGenerator::PyiGenerator() : file_(nullptr) {}
PyiGenerator::~PyiGenerator() {}
-void PyiGenerator::PrintItemMap(
- const std::map<std::string, std::string>& item_map) const {
- for (const auto& entry : item_map) {
- printer_->Print("$key$: $value$\n", "key", entry.first, "value",
- entry.second);
- }
-}
-
template <typename DescriptorT>
-std::string PyiGenerator::ModuleLevelName(
- const DescriptorT& descriptor,
- const std::map<std::string, std::string>& import_map) const {
+std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
if (descriptor.file() != file_) {
std::string module_alias;
std::string filename = descriptor.file()->name();
- if (import_map.find(filename) == import_map.end()) {
+ if (import_map_.find(filename) == import_map_.end()) {
std::string module_name = ModuleName(descriptor.file()->name());
std::vector<std::string> tokens = Split(module_name, ".");
module_alias = "_" + tokens.back();
} else {
- module_alias = import_map.at(filename);
+ module_alias = import_map_.at(filename);
}
name = module_alias + "." + name;
}
@@ -156,7 +139,6 @@
void PyiGenerator::PrintImportForDescriptor(
const FileDescriptor& desc,
- std::map<std::string, std::string>* import_map,
std::set<std::string>* seen_aliases) const {
const std::string& filename = desc.name();
std::string module_name = StrippedModuleName(filename);
@@ -176,21 +158,19 @@
}
printer_->Print("$statement$ as $alias$\n", "statement",
import_statement, "alias", alias);
- (*import_map)[filename] = alias;
+ import_map_[filename] = alias;
seen_aliases->insert(alias);
}
-void PyiGenerator::PrintImports(
- std::map<std::string, std::string>* item_map,
- std::map<std::string, std::string>* import_map) const {
+void PyiGenerator::PrintImports() const {
// Prints imported dependent _pb2 files.
std::set<std::string> seen_aliases;
for (int i = 0; i < file_->dependency_count(); ++i) {
const FileDescriptor* dep = file_->dependency(i);
- PrintImportForDescriptor(*dep, import_map, &seen_aliases);
+ PrintImportForDescriptor(*dep, &seen_aliases);
for (int j = 0; j < dep->public_dependency_count(); ++j) {
PrintImportForDescriptor(
- *dep->public_dependency(j), import_map, &seen_aliases);
+ *dep->public_dependency(j), &seen_aliases);
}
}
@@ -254,7 +234,7 @@
if (import_modules.has_union) {
printer_->Print(", Union as _Union");
}
- printer_->Print("\n\n");
+ printer_->Print("\n");
// Public imports
for (int i = 0; i < file_->public_dependency_count(); ++i) {
@@ -272,17 +252,8 @@
module_name, "enum_class",
public_dep->enum_type(i)->name());
}
- // Enum values for public imports
- for (int i = 0; i < public_dep->enum_type_count(); ++i) {
- const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
- for (int j = 0; j < enum_descriptor->value_count(); ++j) {
- (*item_map)[enum_descriptor->value(j)->name()] =
- ModuleLevelName(*enum_descriptor, *import_map);
- }
- }
- // Top level extensions for public imports
- AddExtensions(*public_dep, item_map);
}
+printer_->Print("\n");
}
void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
@@ -293,20 +264,18 @@
"enum_name", enum_name);
}
-// Adds enum value to item map which will be ordered and printed later.
-void PyiGenerator::AddEnumValue(
- const EnumDescriptor& enum_descriptor,
- std::map<std::string, std::string>* item_map,
- const std::map<std::string, std::string>& import_map) const {
+void PyiGenerator::PrintEnumValues(
+ const EnumDescriptor& enum_descriptor) const {
// enum values
- std::string module_enum_name = ModuleLevelName(enum_descriptor, import_map);
+ std::string module_enum_name = ModuleLevelName(enum_descriptor);
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j);
- (*item_map)[value_descriptor->name()] = module_enum_name;
+ printer_->Print("$name$: $module_enum_name$\n",
+ "name", value_descriptor->name(),
+ "module_enum_name", module_enum_name);
}
}
-// Prints top level enums
void PyiGenerator::PrintTopLevelEnums() const {
for (int i = 0; i < file_->enum_type_count(); ++i) {
printer_->Print("\n");
@@ -314,25 +283,22 @@
}
}
-// Add top level extensions to item_map which will be ordered and
-// printed later.
template <typename DescriptorT>
-void PyiGenerator::AddExtensions(
- const DescriptorT& descriptor,
- std::map<std::string, std::string>* item_map) const {
+void PyiGenerator::PrintExtensions(const DescriptorT& descriptor) const {
for (int i = 0; i < descriptor.extension_count(); ++i) {
const FieldDescriptor* extension_field = descriptor.extension(i);
std::string constant_name = extension_field->name() + "_FIELD_NUMBER";
ToUpper(&constant_name);
- (*item_map)[constant_name] = "_ClassVar[int]";
- (*item_map)[extension_field->name()] = "_descriptor.FieldDescriptor";
+ printer_->Print("$constant_name$: _ClassVar[int]\n",
+ "constant_name", constant_name);
+ printer_->Print("$name$: _descriptor.FieldDescriptor\n",
+ "name", extension_field->name());
}
}
// Returns the string format of a field's cpp_type
std::string PyiGenerator::GetFieldType(
- const FieldDescriptor& field_des, const Descriptor& containing_des,
- const std::map<std::string, std::string>& import_map) const {
+ const FieldDescriptor& field_des, const Descriptor& containing_des) const {
switch (field_des.cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
case FieldDescriptor::CPPTYPE_UINT32:
@@ -345,7 +311,7 @@
case FieldDescriptor::CPPTYPE_BOOL:
return "bool";
case FieldDescriptor::CPPTYPE_ENUM:
- return ModuleLevelName(*field_des.enum_type(), import_map);
+ return ModuleLevelName(*field_des.enum_type());
case FieldDescriptor::CPPTYPE_STRING:
if (field_des.type() == FieldDescriptor::TYPE_STRING) {
return "str";
@@ -356,7 +322,7 @@
// If the field is inside a nested message and the nested message has the
// same name as a top-level message, then we need to prefix the field type
// with the module name for disambiguation.
- std::string name = ModuleLevelName(*field_des.message_type(), import_map);
+ 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());
@@ -371,8 +337,7 @@
}
void PyiGenerator::PrintMessage(
- const Descriptor& message_descriptor, bool is_nested,
- const std::map<std::string, std::string>& import_map) const {
+ const Descriptor& message_descriptor, bool is_nested) const {
if (!is_nested) {
printer_->Print("\n");
}
@@ -390,17 +355,11 @@
printer_->Indent();
printer_->Indent();
- std::vector<const FieldDescriptor*> fields;
- fields.reserve(message_descriptor.field_count());
- for (int i = 0; i < message_descriptor.field_count(); ++i) {
- fields.push_back(message_descriptor.field(i));
- }
- std::sort(fields.begin(), fields.end(), SortByName<FieldDescriptor>());
-
// Prints slots
printer_->Print("__slots__ = [", "class_name", class_name);
bool first_item = true;
- for (const auto& field_des : fields) {
+ for (int i = 0; i < message_descriptor.field_count(); ++i) {
+ const FieldDescriptor* field_des = message_descriptor.field(i);
if (IsPythonKeyword(field_des->name())) {
continue;
}
@@ -413,48 +372,34 @@
}
printer_->Print("]\n");
- std::map<std::string, std::string> item_map;
// Prints Extensions for extendable messages
if (message_descriptor.extension_range_count() > 0) {
- item_map["Extensions"] = "_python_message._ExtensionDict";
+ printer_->Print("Extensions: _python_message._ExtensionDict\n");
}
// Prints nested enums
- std::vector<const EnumDescriptor*> nested_enums;
- nested_enums.reserve(message_descriptor.enum_type_count());
for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
- nested_enums.push_back(message_descriptor.enum_type(i));
- }
- std::sort(nested_enums.begin(), nested_enums.end(),
- SortByName<EnumDescriptor>());
-
- for (const auto& entry : nested_enums) {
- PrintEnum(*entry);
- // Adds enum value to item_map which will be ordered and printed later
- AddEnumValue(*entry, &item_map, import_map);
+ PrintEnum(*message_descriptor.enum_type(i));
+ PrintEnumValues(*message_descriptor.enum_type(i));
}
// Prints nested messages
- std::vector<const Descriptor*> nested_messages;
- nested_messages.reserve(message_descriptor.nested_type_count());
for (int i = 0; i < message_descriptor.nested_type_count(); ++i) {
- nested_messages.push_back(message_descriptor.nested_type(i));
- }
- std::sort(nested_messages.begin(), nested_messages.end(),
- SortByName<Descriptor>());
-
- for (const auto& entry : nested_messages) {
- PrintMessage(*entry, true, import_map);
+ PrintMessage(*message_descriptor.nested_type(i), true);
}
- // Adds extensions to item_map which will be ordered and printed later
- AddExtensions(message_descriptor, &item_map);
+ PrintExtensions(message_descriptor);
- // Adds field number and field descriptor to item_map
+ // Prints field number
for (int i = 0; i < message_descriptor.field_count(); ++i) {
const FieldDescriptor& field_des = *message_descriptor.field(i);
- item_map[ToUpper(field_des.name()) + "_FIELD_NUMBER"] =
- "_ClassVar[int]";
+ printer_->Print(
+ "$field_number_name$: _ClassVar[int]\n", "field_number_name",
+ ToUpper(field_des.name()) + "_FIELD_NUMBER");
+ }
+ // Prints field name and type
+ for (int i = 0; i < message_descriptor.field_count(); ++i) {
+ const FieldDescriptor& field_des = *message_descriptor.field(i);
if (IsPythonKeyword(field_des.name())) {
continue;
}
@@ -465,27 +410,25 @@
field_type = (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
? "_containers.MessageMap["
: "_containers.ScalarMap[");
- field_type += GetFieldType(*key_des, message_descriptor, import_map);
+ field_type += GetFieldType(*key_des, message_descriptor);
field_type += ", ";
- field_type += GetFieldType(*value_des, message_descriptor, import_map);
+ field_type += GetFieldType(*value_des, message_descriptor);
} else {
if (field_des.is_repeated()) {
field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
? "_containers.RepeatedCompositeFieldContainer["
: "_containers.RepeatedScalarFieldContainer[");
}
- field_type += GetFieldType(field_des, message_descriptor, import_map);
+ field_type += GetFieldType(field_des, message_descriptor);
}
if (field_des.is_repeated()) {
field_type += "]";
}
- item_map[field_des.name()] = field_type;
+ printer_->Print("$name$: $type$\n",
+ "name", field_des.name(), "type", field_type);
}
- // Prints all items in item_map
- PrintItemMap(item_map);
-
// Prints __init__
printer_->Print("def __init__(self");
bool has_key_words = false;
@@ -513,9 +456,9 @@
const Descriptor* map_entry = field_des->message_type();
printer_->Print(
"_Mapping[$key_type$, $value_type$]", "key_type",
- GetFieldType(*map_entry->field(0), message_descriptor, import_map),
+ GetFieldType(*map_entry->field(0), message_descriptor),
"value_type",
- GetFieldType(*map_entry->field(1), message_descriptor, import_map));
+ GetFieldType(*map_entry->field(1), message_descriptor));
} else {
if (field_des->is_repeated()) {
printer_->Print("_Iterable[");
@@ -523,15 +466,15 @@
if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer_->Print(
"_Union[$type_name$, _Mapping]", "type_name",
- GetFieldType(*field_des, message_descriptor, import_map));
+ GetFieldType(*field_des, message_descriptor));
} else {
if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer_->Print("_Union[$type_name$, str]", "type_name",
- ModuleLevelName(*field_des->enum_type(), import_map));
+ ModuleLevelName(*field_des->enum_type()));
} else {
printer_->Print(
"$type_name$", "type_name",
- GetFieldType(*field_des, message_descriptor, import_map));
+ GetFieldType(*field_des, message_descriptor));
}
}
if (field_des->is_repeated()) {
@@ -553,36 +496,21 @@
printer_->Outdent();
}
-void PyiGenerator::PrintMessages(
- const std::map<std::string, std::string>& import_map) const {
+void PyiGenerator::PrintMessages() const {
// Deterministically order the descriptors.
- std::vector<const Descriptor*> messages;
- messages.reserve(file_->message_type_count());
for (int i = 0; i < file_->message_type_count(); ++i) {
- messages.push_back(file_->message_type(i));
- }
- std::sort(messages.begin(), messages.end(), SortByName<Descriptor>());
-
- for (const auto& entry : messages) {
- PrintMessage(*entry, false, import_map);
+ PrintMessage(*file_->message_type(i), false);
}
}
void PyiGenerator::PrintServices() const {
- std::vector<const ServiceDescriptor*> services;
- services.reserve(file_->service_count());
- for (int i = 0; i < file_->service_count(); ++i) {
- services.push_back(file_->service(i));
- }
- std::sort(services.begin(), services.end(), SortByName<ServiceDescriptor>());
-
// Prints $Service$ and $Service$_Stub classes
- for (const auto& entry : services) {
+ for (int i = 0; i < file_->service_count(); ++i) {
printer_->Print("\n");
printer_->Print(
"class $service_name$(_service.service): ...\n\n"
"class $service_name$_Stub($service_name$): ...\n",
- "service_name", entry->name());
+ "service_name", file_->service(i)->name());
}
}
@@ -591,6 +519,7 @@
GeneratorContext* context,
std::string* error) const {
MutexLock lock(&mutex_);
+ import_map_.clear();
// Calculate file name.
file_ = file;
std::string filename =
@@ -601,29 +530,28 @@
io::Printer printer(output.get(), '$');
printer_ = &printer;
- // item map will store "DESCRIPTOR", top level extensions, top level enum
- // values. The items will be sorted and printed later.
- std::map<std::string, std::string> item_map;
+ PrintImports();
+ printer_->Print("DESCRIPTOR: _descriptor.FileDescriptor\n");
- // Adds "DESCRIPTOR" into item_map.
- item_map["DESCRIPTOR"] = "_descriptor.FileDescriptor";
-
- // import_map will be a mapping from filename to module alias, e.g.
- // "google3/foo/bar.py" -> "_bar"
- std::map<std::string, std::string> import_map;
-
- PrintImports(&item_map, &import_map);
- // Adds top level enum values to item_map.
- for (int i = 0; i < file_->enum_type_count(); ++i) {
- AddEnumValue(*file_->enum_type(i), &item_map, import_map);
+ // Prints extensions and enums from imports.
+ for (int i = 0; i < file_->public_dependency_count(); ++i) {
+ const FileDescriptor* public_dep = file_->public_dependency(i);
+ PrintExtensions(*public_dep);
+ for (int i = 0; i < public_dep->enum_type_count(); ++i) {
+ const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
+ PrintEnumValues(*enum_descriptor);
+ }
}
- // Adds top level extensions to item_map.
- AddExtensions(*file_, &item_map);
- // Prints item map
- PrintItemMap(item_map);
- PrintMessages(import_map);
PrintTopLevelEnums();
+ // Prints top level enum values
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ PrintEnumValues(*file_->enum_type(i));
+ }
+ // Prints top level Extensions
+ PrintExtensions(*file_);
+ PrintMessages();
+
if (HasGenericServices(file)) {
PrintServices();
}
diff --git a/src/google/protobuf/compiler/python/pyi_generator.h b/src/google/protobuf/compiler/python/pyi_generator.h
index 9611ed4..40741e1 100644
--- a/src/google/protobuf/compiler/python/pyi_generator.h
+++ b/src/google/protobuf/compiler/python/pyi_generator.h
@@ -76,37 +76,29 @@
private:
void PrintImportForDescriptor(const FileDescriptor& desc,
- std::map<std::string, std::string>* import_map,
std::set<std::string>* seen_aliases) const;
- void PrintImports(std::map<std::string, std::string>* item_map,
- std::map<std::string, std::string>* import_map) const;
- void PrintEnum(const EnumDescriptor& enum_descriptor) const;
- void AddEnumValue(const EnumDescriptor& enum_descriptor,
- std::map<std::string, std::string>* item_map,
- const std::map<std::string, std::string>& import_map) const;
+ void PrintImports() const;
void PrintTopLevelEnums() const;
+ void PrintEnum(const EnumDescriptor& enum_descriptor) const;
+ void PrintEnumValues(const EnumDescriptor& enum_descriptor) const;
template <typename DescriptorT>
- void AddExtensions(const DescriptorT& descriptor,
- std::map<std::string, std::string>* item_map) const;
- void PrintMessages(
- const std::map<std::string, std::string>& import_map) const;
- void PrintMessage(const Descriptor& message_descriptor, bool is_nested,
- const std::map<std::string, std::string>& import_map) const;
+ void PrintExtensions(const DescriptorT& descriptor) const;
+ void PrintMessages() const;
+ void PrintMessage(const Descriptor& message_descriptor, bool is_nested) const;
void PrintServices() const;
- void PrintItemMap(const std::map<std::string, std::string>& item_map) const;
std::string GetFieldType(
- const FieldDescriptor& field_des, const Descriptor& containing_des,
- const std::map<std::string, std::string>& import_map) const;
+ const FieldDescriptor& field_des, const Descriptor& containing_des) const;
template <typename DescriptorT>
- std::string ModuleLevelName(
- const DescriptorT& descriptor,
- const std::map<std::string, std::string>& import_map) const;
+ std::string ModuleLevelName(const DescriptorT& descriptor) const;
// Very coarse-grained lock to ensure that Generate() is reentrant.
- // Guards file_ and printer_.
+ // Guards file_, printer_, and import_map_.
mutable Mutex mutex_;
mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_.
mutable io::Printer* printer_; // Set in Generate(). Under mutex_.
+ // import_map will be a mapping from filename to module alias, e.g.
+ // "google3/foo/bar.py" -> "_bar"
+ mutable std::map<std::string, std::string> import_map_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PyiGenerator);
};
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index f6f5da5..439db9f 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 87729c4..1e4a3e1 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index fdc398c..c5f528b 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index fd75b88..01ecfac 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index 67349b4..3fad18c 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -38,7 +38,6 @@
#include <google/protobuf/port.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_tctable_decl.h>
-#include <google/protobuf/message_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/wire_format_lite.h>
@@ -257,16 +256,6 @@
// clang-format on
} // namespace field_layout
-// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
-// defined in port_def.inc.
-//
-// Note that this is performance sensitive: changing the parameters will change
-// the registers used by the ABI calling convention, which subsequently affects
-// register selection logic inside the function.
-
-// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
-#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
-
#ifndef NDEBUG
template <size_t align>
void AlignFail(uintptr_t address) {
@@ -349,6 +338,28 @@
static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
+ // Manually unrolled and specialized Varint parsing.
+ template <typename FieldType, int data_offset, int hasbit_idx>
+ static const char* SpecializedUnrolledVImpl1(PROTOBUF_TC_PARAM_DECL);
+
+ template <typename FieldType, int data_offset, int hasbit_idx>
+ static constexpr TailCallParseFunc SingularVarintNoZag1() {
+ if (data_offset < 100) {
+ return &SpecializedUnrolledVImpl1<FieldType, data_offset, hasbit_idx>;
+ } else if (sizeof(FieldType) == 1) {
+ return &FastV8S1;
+ } else if (sizeof(FieldType) == 4) {
+ return &FastV32S1;
+ } else if (sizeof(FieldType) == 8) {
+ return &FastV64S1;
+ } else {
+ static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
+ sizeof(FieldType) == 8,
+ "");
+ return nullptr;
+ }
+ }
+
// Functions referenced by generated fast tables (closed enum):
// E: closed enum (N.B.: open enums use V32, above)
// r: enum range v: enum validator (_IsValid function)
@@ -600,6 +611,135 @@
static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
};
+template <typename FieldType, int data_offset, int hasbit_idx>
+const char* TcParser::SpecializedUnrolledVImpl1(PROTOBUF_TC_PARAM_DECL) {
+ using TagType = uint8_t;
+ // super-early success test...
+ if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
+ ptr += sizeof(TagType); // Consume tag
+ if (hasbit_idx < 32) {
+ hasbits |= (uint64_t{1} << hasbit_idx);
+ }
+ uint8_t value = data.data >> 8;
+ RefAt<FieldType>(msg, data_offset) = value;
+ ptr += 1;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ }
+ ptr += sizeof(TagType); // Consume tag
+ if (hasbit_idx < 32) {
+ hasbits |= (uint64_t{1} << hasbit_idx);
+ }
+
+ // Few registers
+ auto* out = &RefAt<FieldType>(msg, data_offset);
+ uint64_t res = 0xFF & (data.data >> 8);
+ /* if (PROTOBUF_PREDICT_FALSE(res & 0x80)) */ {
+ res = RotRight7AndReplaceLowByte(res, ptr[1]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[2]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[3]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[4]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[5]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[6]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[7]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ res = RotRight7AndReplaceLowByte(res, ptr[8]);
+ if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+ if (ptr[9] & 0xFE) return nullptr;
+ res = RotateLeft(res, -7) & ~1;
+ res += ptr[9] & 1;
+ *out = RotateLeft(res, 63);
+ ptr += 10;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 56);
+ ptr += 9;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 49);
+ ptr += 8;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 42);
+ ptr += 7;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 35);
+ ptr += 6;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 28);
+ ptr += 5;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 21);
+ ptr += 4;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 14);
+ ptr += 3;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = RotateLeft(res, 7);
+ ptr += 2;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+ *out = res;
+ ptr += 1;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+// Dispatch to the designated parse function
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
+ PROTOBUF_TC_PARAM_DECL) {
+ const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
+ const size_t idx = coded_tag & table->fast_idx_mask;
+ PROTOBUF_ASSUME((idx & 7) == 0);
+ auto* fast_entry = table->fast_entry(idx >> 3);
+ data = fast_entry->bits;
+ data.data ^= coded_tag;
+ PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
+}
+
+// We can only safely call from field to next field if the call is optimized
+// to a proper tail call. Otherwise we blow through stack. Clang and gcc
+// reliably do this optimization in opt mode, but do not perform this in debug
+// mode. Luckily the structure of the algorithm is such that it's always
+// possible to just return and use the enclosing parse loop as a trampoline.
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
+ PROTOBUF_TC_PARAM_DECL) {
+ constexpr bool always_return = !PROTOBUF_TAILCALL;
+ if (always_return || !ctx->DataAvailable(ptr)) {
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ }
+ PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
+ PROTOBUF_TC_PARAM_DECL) {
+ (void)data;
+ (void)ctx;
+ SyncHasbits(msg, hasbits, table);
+ return ptr;
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
+ PROTOBUF_TC_PARAM_DECL) {
+ (void)data;
+ (void)ctx;
+ (void)ptr;
+ SyncHasbits(msg, hasbits, table);
+ return nullptr;
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index aef780f..f9fb6cc 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -30,6 +30,7 @@
#include <cstdint>
#include <numeric>
+#include <type_traits>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_tctable_decl.h>
@@ -84,56 +85,13 @@
// TODO(b/64614992): remove this asm
asm("" : "+r"(table));
#endif
- ptr = TagDispatch(msg, ptr, ctx, table - 1, 0, {});
+ ptr = TagDispatch(msg, ptr, ctx, {}, table - 1, 0);
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
return ptr;
}
- // Dispatch to the designated parse function
-inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
- const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
- const size_t idx = coded_tag & table->fast_idx_mask;
- PROTOBUF_ASSUME((idx & 7) == 0);
- auto* fast_entry = table->fast_entry(idx >> 3);
- data = fast_entry->bits;
- data.data ^= coded_tag;
- PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
-}
-
-// We can only safely call from field to next field if the call is optimized
-// to a proper tail call. Otherwise we blow through stack. Clang and gcc
-// reliably do this optimization in opt mode, but do not perform this in debug
-// mode. Luckily the structure of the algorithm is such that it's always
-// possible to just return and use the enclosing parse loop as a trampoline.
-inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
- constexpr bool always_return = !PROTOBUF_TAILCALL;
- if (always_return || !ctx->DataAvailable(ptr)) {
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
- }
- PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
-inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
- (void)ctx;
- SyncHasbits(msg, hasbits, table);
- return ptr;
-}
-
-inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
- (void)ctx;
- (void)ptr;
- SyncHasbits(msg, hasbits, table);
- return nullptr;
-}
-
// On the fast path, a (matching) 1-byte tag already has the decoded value.
static uint32_t FastDecodeTag(uint8_t coded_tag) {
return coded_tag;
@@ -875,8 +833,31 @@
}
const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return SingularVarint<bool, uint8_t>(
- PROTOBUF_TC_PARAM_PASS);
+ // Special case for a varint bool field with a tag of 1 byte:
+ // The coded_tag() field will actually contain the value too and we can check
+ // both at the same time.
+ auto coded_tag = data.coded_tag<uint16_t>();
+ if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
+ auto& field = RefAt<bool>(msg, data.offset());
+ // Note: we use `data.data` because Clang generates suboptimal code when
+ // using coded_tag.
+ // In x86_64 this uses the CH register to read the second byte out of
+ // `data`.
+ uint8_t value = data.data >> 8;
+ // The assume allows using a mov instead of test+setne.
+ PROTOBUF_ASSUME(value <= 1);
+ field = static_cast<bool>(value);
+
+ ptr += 2; // Consume the tag and the value.
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ }
+
+ // If it didn't match above either the tag is wrong, or the value is encoded
+ // non-canonically.
+ // Jump to MiniParse as wrong tag is the most probable reason.
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
}
const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index e30bfa6..aa507cb 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -251,7 +251,8 @@
template <typename... Args>
void Print(const char* text, const Args&... args) {
std::map<std::string, std::string> vars;
- PrintInternal(&vars, text, args...);
+ FillMap(&vars, args...);
+ Print(vars, text);
}
// Indent text by two spaces. After calling Indent(), two spaces will be
@@ -299,18 +300,13 @@
void Annotate(const char* begin_varname, const char* end_varname,
const std::string& file_path, const std::vector<int>& path);
- // Base case
- void PrintInternal(std::map<std::string, std::string>* vars,
- const char* text) {
- Print(*vars, text);
- }
+ void FillMap(std::map<std::string, std::string>* vars) {}
template <typename... Args>
- void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
- const char* key, const std::string& value,
- const Args&... args) {
+ void FillMap(std::map<std::string, std::string>* vars, const std::string& key,
+ const std::string& value, const Args&... args) {
(*vars)[key] = value;
- PrintInternal(vars, text, args...);
+ FillMap(vars, args...);
}
// Copy size worth of bytes from data to buffer_.
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index d0aa010..a3f79f1 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -333,6 +333,11 @@
} // namespace internal
+#ifdef PROTOBUF_FUTURE_MAP_PAIR_UPGRADE
+// This is the class for Map's internal value_type.
+template <typename Key, typename T>
+using MapPair = std::pair<const Key, T>;
+#else
// This is the class for Map's internal value_type. Instead of using
// std::pair as value_type, we use this class which provides us more control of
// its process of construction and destruction.
@@ -363,6 +368,7 @@
friend class Arena;
friend class Map<Key, T>;
};
+#endif
// Map is an associative container type used to store protobuf map
// fields. Each Map instance may or may not use a different hash function, a
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index f7c024c..fd89524 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -84,3 +84,5 @@
} // namespace internal
} // namespace protobuf
} // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
index 041ac82..1d55dd5 100644
--- a/src/google/protobuf/map_test.inc
+++ b/src/google/protobuf/map_test.inc
@@ -810,6 +810,8 @@
m, UnorderedElementsAre(Pair(1, "one"), Pair(2, "two"), Pair(42, "aaa")));
}
+#ifndef PROTOBUF_FUTURE_MAP_PAIR_UPGRADE
+
TEST_F(MapImplTest, EmplaceKeyOnly) {
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
@@ -824,6 +826,43 @@
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, ""), Pair(42, "")));
}
+#else
+
+TEST_F(MapImplTest, ValueTypeNoImplicitConversion) {
+ using vt = typename Map<const char*, int>::value_type;
+
+ EXPECT_FALSE((std::is_convertible<
+ vt, std::pair<std::string, std::vector<std::string>>>::value));
+}
+
+enum class ConstructorType {
+ kDefault,
+ kCopy,
+ kMove,
+};
+
+struct ConstructorTag {
+ ConstructorTag() : invoked_constructor(ConstructorType::kDefault) {}
+ ConstructorTag(const ConstructorTag&)
+ : invoked_constructor(ConstructorType::kCopy) {}
+ ConstructorTag(ConstructorTag&&)
+ : invoked_constructor(ConstructorType::kMove) {}
+
+ ConstructorType invoked_constructor;
+};
+
+TEST_F(MapImplTest, ValueTypeHasMoveConstructor) {
+ using vt = typename Map<ConstructorTag, ConstructorTag>::value_type;
+ ConstructorTag l, r;
+
+ vt pair(l, std::move(r));
+
+ EXPECT_EQ(pair.first.invoked_constructor, ConstructorType::kCopy);
+ EXPECT_EQ(pair.second.invoked_constructor, ConstructorType::kMove);
+}
+
+#endif // !PROTOBUF_FUTURE_MAP_PAIR_UPGRADE
+
struct CountedInstance {
CountedInstance() { ++num_created; }
CountedInstance(const CountedInstance&) : CountedInstance() {}
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 724a622..1279164 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -214,7 +214,7 @@
}
namespace internal {
-void* CreateSplitMessageGeneric(Arena* arena, void* default_split,
+void* CreateSplitMessageGeneric(Arena* arena, const void* default_split,
size_t size) {
void* split =
(arena == nullptr) ? ::operator new(size) : arena->AllocateAligned(size);
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 7042a13..b61fafb 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -411,7 +411,8 @@
namespace internal {
// Creates and returns an allocation for a split message.
-void* CreateSplitMessageGeneric(Arena* arena, void* default_split, size_t size);
+void* CreateSplitMessageGeneric(Arena* arena, const void* default_split,
+ size_t size);
// Forward-declare interfaces used to implement RepeatedFieldRef.
// These are protobuf internals that users shouldn't care about.
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 27a8b38..2674b26 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -521,18 +521,14 @@
*to = from;
}
-// Non-inline implementations of InternalMetadata routines
-#if defined(NDEBUG) || defined(_MSC_VER)
-// for opt and MSVC builds, the destructor is defined in the header.
-#else
+// Non-inline implementations of InternalMetadata destructor
// This is moved out of the header because the GOOGLE_DCHECK produces a lot of code.
-InternalMetadata::~InternalMetadata() {
+void InternalMetadata::CheckedDestruct() {
if (HasMessageOwnedArenaTag()) {
GOOGLE_DCHECK(!HasUnknownFieldsTag());
delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
}
}
-#endif
// Non-inline variants of std::string specializations for
// various InternalMetadata routines.
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
index 44e3b31..a1b9202 100644
--- a/src/google/protobuf/message_unittest.inc
+++ b/src/google/protobuf/message_unittest.inc
@@ -1174,11 +1174,12 @@
std::signbit(out_message.optional_double()));
}
-std::string EncodeEnumValue(int number, int value, int non_canonical_bytes) {
- uint8_t buf[100];
- uint8_t* p = buf;
-
- p = internal::WireFormatLite::WriteEnumToArray(number, value, p);
+// Adds `non_canonical_bytes` bytes to the varint representation at the tail of
+// the buffer.
+// `buf` points to the start of the buffer, `p` points to one-past-the-end.
+// Returns the new one-past-the-end pointer.
+uint8_t* AddNonCanonicalBytes(const uint8_t* buf, uint8_t* p,
+ int non_canonical_bytes) {
// varint can have a max of 10 bytes.
while (non_canonical_bytes-- > 0 && p - buf < 10) {
// Add a dummy byte at the end.
@@ -1186,7 +1187,15 @@
p[0] = 0;
++p;
}
+ return p;
+}
+std::string EncodeEnumValue(int number, int value, int non_canonical_bytes) {
+ uint8_t buf[100];
+ uint8_t* p = buf;
+
+ p = internal::WireFormatLite::WriteEnumToArray(number, value, p);
+ p = AddNonCanonicalBytes(buf, p, non_canonical_bytes);
return std::string(buf, p);
}
@@ -1201,6 +1210,16 @@
const auto other_field = EncodeOtherField();
+ // Encode a boolean field for many different cases and verify that it can be
+ // parsed as expected.
+ // There are:
+ // - optional/repeated/packed fields
+ // - field tags that encode in 1/2/3 bytes
+ // - canonical and non-canonical encodings of the varint
+ // - last vs not last field
+ // - label combinations to trigger different parsers: sequential, small
+ // sequential, non-validated.
+
constexpr int kInvalidValue = 0x900913;
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
@@ -1226,6 +1245,8 @@
auto encoded = EncodeEnumValue(field->number(), value_desc->number(),
non_canonical_bytes);
if (use_tail_field) {
+ // Make sure that fields after this one can be parsed too. ie test
+ // that the "next" jump is correct too.
encoded += other_field;
}
@@ -1263,5 +1284,64 @@
}
}
+std::string EncodeBoolValue(int number, bool value, int non_canonical_bytes) {
+ uint8_t buf[100];
+ uint8_t* p = buf;
+
+ p = internal::WireFormatLite::WriteBoolToArray(number, value, p);
+ p = AddNonCanonicalBytes(buf, p, non_canonical_bytes);
+ return std::string(buf, p);
+}
+
+TEST(MESSAGE_TEST_NAME, TestBoolParsers) {
+ UNITTEST::BoolParseTester obj;
+
+ const auto other_field = EncodeOtherField();
+
+ // Encode a boolean field for many different cases and verify that it can be
+ // parsed as expected.
+ // There are:
+ // - optional/repeated/packed fields
+ // - field tags that encode in 1/2/3 bytes
+ // - canonical and non-canonical encodings of the varint
+ // - last vs not last field
+
+ auto* ref = obj.GetReflection();
+ auto* descriptor = obj.descriptor();
+ for (bool use_tail_field : {false, true}) {
+ SCOPED_TRACE(use_tail_field);
+ for (int non_canonical_bytes = 0; non_canonical_bytes < 10;
+ ++non_canonical_bytes) {
+ SCOPED_TRACE(non_canonical_bytes);
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const auto* field = descriptor->field(i);
+ if (field->name() == "other_field") continue;
+ SCOPED_TRACE(field->full_name());
+ for (bool value : {false, true}) {
+ SCOPED_TRACE(value);
+ auto encoded =
+ EncodeBoolValue(field->number(), value, non_canonical_bytes);
+ if (use_tail_field) {
+ // Make sure that fields after this one can be parsed too. ie test
+ // that the "next" jump is correct too.
+ encoded += other_field;
+ }
+
+ EXPECT_TRUE(obj.ParseFromString(encoded));
+ if (field->is_repeated()) {
+ ASSERT_EQ(ref->FieldSize(obj, field), 1);
+ EXPECT_EQ(ref->GetRepeatedBool(obj, field, 0), value);
+ } else {
+ EXPECT_TRUE(ref->HasField(obj, field));
+ EXPECT_EQ(ref->GetBool(obj, field), value);
+ }
+ auto& unknown = ref->GetUnknownFields(obj);
+ ASSERT_EQ(unknown.field_count(), 0);
+ }
+ }
+ }
+ }
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/metadata_lite.h b/src/google/protobuf/metadata_lite.h
index af840e5..d015dc2 100644
--- a/src/google/protobuf/metadata_lite.h
+++ b/src/google/protobuf/metadata_lite.h
@@ -77,15 +77,19 @@
GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
}
-#if defined(NDEBUG) || defined(_MSC_VER)
+ // To keep the ABI identical between debug and non-debug builds,
+ // the destructor is always defined here even though it may delegate
+ // to a non-inline private method.
+ // (see https://github.com/protocolbuffers/protobuf/issues/9947)
~InternalMetadata() {
+#if defined(NDEBUG) || defined(_MSC_VER)
if (HasMessageOwnedArenaTag()) {
delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
}
- }
#else
- ~InternalMetadata();
+ CheckedDestruct();
#endif
+ }
template <typename T>
void Delete() {
@@ -264,6 +268,9 @@
PROTOBUF_NOINLINE void DoSwap(T* other) {
mutable_unknown_fields<T>()->Swap(other);
}
+
+ // Private helper with debug checks for ~InternalMetadata()
+ void CheckedDestruct();
};
// String Template specializations.
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index a7baf4d..c72e19f 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -617,6 +617,7 @@
PROTOBUF_NODISCARD inline PROTOBUF_ALWAYS_INLINE uint64_t
RotRight7AndReplaceLowByte(uint64_t res, const char& byte) {
+ // TODO(b/239808098): remove the inline assembly
#if defined(__x86_64__) && defined(__GNUC__)
// This will only use one register for `res`.
// `byte` comes as a reference to allow the compiler to generate code like:
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 2e861d2..ea3d682 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -154,6 +154,13 @@
# define PROTOBUF_GNUC_MIN(x, y) 0
#endif
+#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
+#define PROTOBUF_CLANG_MIN(x, y) \
+ (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
+#else
+#define PROTOBUF_CLANG_MIN(x, y) 0
+#endif
+
// Portable check for MSVC minimum version:
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#if defined(_MSC_VER)
@@ -174,11 +181,15 @@
// Future versions of protobuf will include breaking changes to some APIs.
// This macro can be set to enable these API changes ahead of time, so that
// user code can be updated before upgrading versions of protobuf.
-// PROTOBUF_FUTURE_FINAL is used on classes that are historically not marked as
-// final, but that may be marked final in future (breaking) releases.
#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
-// Used on classes that are historically not marked as final.
+
+// Used to upgrade google::protobuf::MapPair<K, V> to std::pair<const K, V>.
+// Owner: mordberg@
+#define PROTOBUF_FUTURE_MAP_PAIR_UPGRADE 1
+
+// Used on classes that are historically not marked as final, but that may be
+// marked final in future (breaking) releases.
// Owner: kfm@
#define PROTOBUF_FUTURE_FINAL final
@@ -201,7 +212,7 @@
#ifdef PROTOBUF_VERSION
#error PROTOBUF_VERSION was previously defined
#endif
-#define PROTOBUF_VERSION 3021002
+#define PROTOBUF_VERSION 3021004
#ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
#error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined
@@ -666,30 +677,39 @@
// This experiment is purely for the purpose of gathering data. All code guarded
// by this flag is supposed to be removed after this experiment.
#define PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
+
#ifdef PROTOBUF_CONSTINIT
#error PROTOBUF_CONSTINIT was previously defined
#endif
-#if defined(__cpp_constinit) && !defined(_MSC_VER)
-#define PROTOBUF_CONSTINIT constinit
-#define PROTOBUF_CONSTEXPR constexpr
+
+// Lexan sets both MSV_VER and clang, so handle it with the clang path.
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC 17 currently seems to raise an error about constant-initialized pointers.
+# if PROTOBUF_MSC_VER_MIN(1930)
+# define PROTOBUF_CONSTINIT
+# define PROTOBUF_CONSTEXPR constexpr
+# endif
+#else
+# if defined(__cpp_constinit) && !defined(__CYGWIN__)
+# define PROTOBUF_CONSTINIT constinit
+# define PROTOBUF_CONSTEXPR constexpr
// Some older Clang versions incorrectly raise an error about
// constant-initializing weak default instance pointers. Versions 12.0 and
// higher seem to work, except that XCode 12.5.1 shows the error even though it
// uses Clang 12.0.5.
-// Clang-cl on Windows raises error also.
-#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization) && \
- ((defined(__APPLE__) && __clang_major__ >= 13) || \
- (!defined(__APPLE__) && __clang_major__ >= 12))
-#define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
-#define PROTOBUF_CONSTEXPR constexpr
-#elif PROTOBUF_GNUC_MIN(12, 2)
-#define PROTOBUF_CONSTINIT __constinit
-#define PROTOBUF_CONSTEXPR constexpr
-// MSVC 17 currently seems to raise an error about constant-initialized pointers.
-#elif defined(_MSC_VER) && _MSC_VER >= 1930
-#define PROTOBUF_CONSTINIT
-#define PROTOBUF_CONSTEXPR constexpr
-#else
+# elif !defined(__CYGWIN__) && \
+ __has_cpp_attribute(clang::require_constant_initialization) && \
+ ((defined(__APPLE__) && PROTOBUF_CLANG_MIN(13, 0)) || \
+ (!defined(__APPLE__) && PROTOBUF_CLANG_MIN(12, 0)))
+# define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
+# define PROTOBUF_CONSTEXPR constexpr
+# elif PROTOBUF_GNUC_MIN(12, 2)
+# define PROTOBUF_CONSTINIT __constinit
+# define PROTOBUF_CONSTEXPR constexpr
+# endif
+#endif
+
+#ifndef PROTOBUF_CONSTINIT
#define PROTOBUF_CONSTINIT
#define PROTOBUF_CONSTEXPR
#endif
@@ -812,11 +832,22 @@
#define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1
#endif
-#define PROTOBUF_TC_PARAM_DECL \
- ::google::protobuf::MessageLite *msg, const char *ptr, \
- ::google::protobuf::internal::ParseContext *ctx, \
- const ::google::protobuf::internal::TcParseTableBase *table, \
- uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
+// Note that this is performance sensitive: changing the parameters will change
+// the registers used by the ABI calling convention, which subsequently affects
+// register selection logic inside the function.
+// Arguments `msg`, `ptr` and `ctx` are the 1st/2nd/3rd argument to match the
+// signature of ParseLoop.
+//
+// Note for x86_64: `data` must be the third or fourth argument for performance
+// reasons. In order to efficiently read the second byte of `data` we need it to
+// be passed in RDX or RCX.
+#define PROTOBUF_TC_PARAM_DECL \
+ ::google::protobuf::MessageLite *msg, const char *ptr, \
+ ::google::protobuf::internal::ParseContext *ctx, \
+ ::google::protobuf::internal::TcFieldData data, \
+ const ::google::protobuf::internal::TcParseTableBase *table, uint64_t hasbits
+// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
+#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, data, table, hasbits
#ifdef PROTOBUF_UNUSED
#error PROTOBUF_UNUSED was previously defined
@@ -938,6 +969,21 @@
#pragma warning(disable: 4125)
#endif
+#if PROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII
+#define PROTOBUF_DEBUG true
+#else
+#define PROTOBUF_DEBUG false
+#endif
+
+// This `for` allows us to condition the `GOOGLE_LOG` on the define above, so that
+// code can write `PROTOBUF_DLOG(INFO) << ...;` and have it turned off when
+// debug logging is off.
+//
+// This is a `for`, not and `if`, to avoid it accidentally chaining with an
+// `else` below it.
+#define PROTOBUF_DLOG(x) \
+ for (bool b = PROTOBUF_DEBUG; b; b = false) GOOGLE_LOG(x)
+
// We don't want code outside port_def doing complex testing, so
// remove our portable condition test macros to nudge folks away from
// using it themselves.
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index 4ad9d33..23eb789 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -40,6 +40,7 @@
#undef PROTOBUF_BUILTIN_BSWAP64
#undef PROTOBUF_BUILTIN_ATOMIC
#undef PROTOBUF_GNUC_MIN
+#undef PROTOBUF_CLANG_MIN
#undef PROTOBUF_MSC_VER_MIN
#undef PROTOBUF_CPLUSPLUS_MIN
#undef PROTOBUF_NAMESPACE
@@ -107,9 +108,12 @@
#undef PROTOBUF_LOCKS_EXCLUDED
#undef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
#undef PROTOBUF_GUARDED_BY
+#undef PROTOBUF_DEBUG
+#undef PROTOBUF_DLOG
#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
#undef PROTOBUF_FUTURE_BREAKING_CHANGES
+#undef PROTOBUF_FUTURE_MAP_PAIR_UPGRADE
#undef PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR
#undef PROTOBUF_FUTURE_REMOVE_CLEARED_API
#endif
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index e504274..b4e4416 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -233,12 +233,6 @@
// copies data between each other.
void Swap(RepeatedField* other);
- // Swaps entire contents with "other". Should be called only if the caller can
- // guarantee that both repeated fields are on the same arena or are on the
- // heap. Swapping between different arenas is disallowed and caught by a
- // GOOGLE_DCHECK (see API docs for details).
- void UnsafeArenaSwap(RepeatedField* other);
-
// Swaps two elements.
void SwapElements(int index1, int index2);
@@ -321,6 +315,12 @@
: rep()->arena;
}
+ // Swaps entire contents with "other". Should be called only if the caller can
+ // guarantee that both repeated fields are on the same arena or are on the
+ // heap. Swapping between different arenas is disallowed and caught by a
+ // GOOGLE_DCHECK (see API docs for details).
+ void UnsafeArenaSwap(RepeatedField* other);
+
static constexpr int kInitialSize = 0;
// A note on the representation here (see also comment below for
// RepeatedPtrFieldBase's struct Rep):
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index fb2e29f..899cfb0 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 7a0805d..154ea45 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 9d90305..c4d2636 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -82,7 +82,7 @@
// The current version, represented as a single integer to make comparison
// easier: major * 10^6 + minor * 10^3 + micro
-#define GOOGLE_PROTOBUF_VERSION 3021002
+#define GOOGLE_PROTOBUF_VERSION 3021004
// A suffix string for alpha, beta or rc releases. Empty for stable releases.
#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 3b5a469..771216e 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index bcf1a44..2555602 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 4d08b44..7176f09 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -221,6 +221,12 @@
reserved "bar", "baz";
}
+enum TestReservedEnumFields {
+ UNKNOWN = 0;
+ reserved 2, 15, 9 to 11;
+ reserved "bar", "baz";
+}
+
message TestAllExtensions {
extensions 1 to max;
}
@@ -1521,3 +1527,20 @@
optional int32 other_field = 99;
};
+// This message contains different kind of bool fields to exercise the different
+// parsers in table-drived.
+message BoolParseTester {
+ optional bool optional_bool_lowfield = 1;
+ optional bool optional_bool_midfield = 1001;
+ optional bool optional_bool_hifield = 1000001;
+ repeated bool repeated_bool_lowfield = 2;
+ repeated bool repeated_bool_midfield = 1002;
+ repeated bool repeated_bool_hifield = 1000002;
+ repeated bool packed_bool_lowfield = 3 [packed = true];
+ repeated bool packed_bool_midfield = 1003 [packed = true];
+ repeated bool packed_bool_hifield = 1000003 [packed = true];
+
+ // An arbitrary field we can append to to break the runs of repeated fields.
+ optional int32 other_field = 99;
+};
+
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 9c59d39..04cab9c 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -48,10 +48,12 @@
#include <google/protobuf/util/zero_copy_sink.h>
#include <google/protobuf/stubs/status_macros.h>
+
// clang-format off
#include <google/protobuf/port_def.inc>
// clang-format on
+
namespace google {
namespace protobuf {
namespace util {
@@ -62,6 +64,7 @@
io::ZeroCopyInputStream* binary_input,
io::ZeroCopyOutputStream* json_output,
const JsonPrintOptions& options) {
+
io::CodedInputStream in_stream(binary_input);
google::protobuf::Type type;
RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
@@ -152,6 +155,7 @@
io::ZeroCopyInputStream* json_input,
io::ZeroCopyOutputStream* binary_output,
const JsonParseOptions& options) {
+
google::protobuf::Type type;
RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
ZeroCopyStreamByteSink sink(binary_output);
@@ -219,6 +223,7 @@
util::Status MessageToJsonString(const Message& message, std::string* output,
const JsonOptions& options) {
+
const DescriptorPool* pool = message.GetDescriptor()->file()->pool();
TypeResolver* resolver =
pool == DescriptorPool::generated_pool()
@@ -235,6 +240,7 @@
util::Status JsonStringToMessage(StringPiece input, Message* message,
const JsonParseOptions& options) {
+
const DescriptorPool* pool = message->GetDescriptor()->file()->pool();
TypeResolver* resolver =
pool == DescriptorPool::generated_pool()
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index 8fbab5a..6a5a448 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -33,6 +33,7 @@
#ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
#define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
+
#include <google/protobuf/stubs/bytestream.h>
#include <google/protobuf/stubs/status.h>
#include <google/protobuf/stubs/strutil.h>
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index 1c72072..be0d39e 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -42,6 +42,7 @@
#include <google/protobuf/struct.pb.h>
#include <google/protobuf/timestamp.pb.h>
#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/unittest.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <google/protobuf/stubs/status.h>
@@ -155,7 +156,7 @@
util::StatusOr<Proto> ToProto(StringPiece json,
JsonParseOptions options = {}) {
Proto proto;
- RETURN_IF_ERROR(JsonStringToMessage(json, &proto, options));
+ RETURN_IF_ERROR(ToProto(proto, json, options));
return proto;
}
@@ -270,13 +271,26 @@
R"("defaultString":"hello","defaultBytes":"d29ybGQ=","defaultNestedEnum":"BAR",)"
R"("defaultForeignEnum":"FOREIGN_BAR","defaultImportEnum":"IMPORT_BAR",)"
R"("defaultStringPiece":"abc","defaultCord":"123"})"));
+
+ // The ESF parser actually gets this wrong, and serializes floats whose
+ // default value is non-finite as 0. We make sure to reproduce this bug.
+ EXPECT_THAT(
+ ToJson(protobuf_unittest::TestExtremeDefaultValues(), options),
+ IsOkAndHolds(
+ R"({"escapedBytes":"XDAwMFwwMDFcMDA3XDAxMFwwMTRcblxyXHRcMDEzXFxcJ1wiXDM3Ng==")"
+ R"(,"largeUint32":4294967295,"largeUint64":"18446744073709551615",)"
+ R"("smallInt32":-2147483647,"smallInt64":"-9223372036854775807")"
+ R"(,"reallySmallInt32":-2147483648,"reallySmallInt64":"-9223372036854775808",)"
+ R"("utf8String":"ሴ","zeroFloat":0,"oneFloat":1,"smallFloat":1.5,)"
+ R"("negativeOneFloat":-1,"negativeFloat":-1.5,"largeFloat":2e+08,)"
+ R"("smallNegativeFloat":-8e-28,"infDouble":0,"negInfDouble":0)"
+ R"(,"nanDouble":0,"infFloat":0,"negInfFloat":0,"nanFloat":0)"
+ R"(,"cppTrigraph":"? ? ?? ?? ??? ??/ ??-","stringWithZero":"hel\u0000lo")"
+ R"(,"bytesWithZero":"d29yXDAwMGxk","stringPieceWithZero":"ab\u0000c")"
+ R"(,"cordWithZero":"12\u00003","replacementString":"${unknown}"})"));
}
TEST_P(JsonTest, TestPreserveProtoFieldNames) {
- if (GetParam() == Codec::kResolver) {
- GTEST_SKIP();
- }
-
TestMessage m;
m.mutable_message_value();
@@ -286,6 +300,22 @@
}
+TEST_P(JsonTest, Camels) {
+ protobuf_unittest::TestCamelCaseFieldNames m;
+ m.set_stringfield("sTRINGfIELD");
+
+ EXPECT_THAT(ToJson(m), IsOkAndHolds(R"({"StringField":"sTRINGfIELD"})"));
+}
+
+TEST_P(JsonTest, EvilString) {
+ auto m = ToProto<TestMessage>(R"json(
+ {"string_value": ")json"
+ "\n\r\b\f\1\2\3"
+ "\"}");
+ ASSERT_OK(m);
+ EXPECT_EQ(m->string_value(), "\n\r\b\f\1\2\3");
+}
+
TEST_P(JsonTest, TestAlwaysPrintEnumsAsInts) {
TestMessage orig;
orig.set_enum_value(proto3::BAR);
@@ -378,6 +408,7 @@
"repeatedEnumValue": [1, "FOO"],
"repeatedMessageValue": [
{"value": 40},
+ {},
{"value": 96}
]
}
@@ -406,9 +437,10 @@
EXPECT_THAT(m->repeated_string_value(), ElementsAre("foo", "bar ", ""));
EXPECT_THAT(m->repeated_enum_value(), ElementsAre(proto3::BAR, proto3::FOO));
- ASSERT_THAT(m->repeated_message_value(), SizeIs(2));
+ ASSERT_THAT(m->repeated_message_value(), SizeIs(3));
EXPECT_EQ(m->repeated_message_value(0).value(), 40);
- EXPECT_EQ(m->repeated_message_value(1).value(), 96);
+ EXPECT_EQ(m->repeated_message_value(1).value(), 0);
+ EXPECT_EQ(m->repeated_message_value(2).value(), 96);
EXPECT_THAT(
ToJson(*m),
@@ -419,7 +451,7 @@
R"("messageValue":{"value":2048},"repeatedBoolValue":[true],"repeatedInt32Value":[0,-42])"
R"(,"repeatedUint64Value":["1","2"],"repeatedDoubleValue":[1.5,-2],)"
R"("repeatedStringValue":["foo","bar ",""],"repeatedEnumValue":["BAR","FOO"],)"
- R"("repeatedMessageValue":[{"value":40},{"value":96}]})"));
+ R"("repeatedMessageValue":[{"value":40},{},{"value":96}]})"));
}
TEST_P(JsonTest, CurseOfAtob) {
@@ -434,6 +466,15 @@
false, true));
}
+TEST_P(JsonTest, FloatPrecision) {
+ google::protobuf::Value v;
+ v.mutable_list_value()->add_values()->set_number_value(0.9900000095367432);
+ v.mutable_list_value()->add_values()->set_number_value(0.8799999952316284);
+
+ EXPECT_THAT(ToJson(v),
+ IsOkAndHolds("[0.99000000953674316,0.87999999523162842]"));
+}
+
TEST_P(JsonTest, ParseLegacySingleRepeatedField) {
auto m = ToProto<TestMessage>(R"json({
"repeatedInt32Value": 1997,
@@ -470,8 +511,10 @@
TEST_P(JsonTest, RepeatedMapKey) {
EXPECT_THAT(ToProto<TestMap>(R"json({
- "twiceKey": 0,
- "twiceKey": 1
+ "string_map": {
+ "twiceKey": 0,
+ "twiceKey": 1
+ }
})json"), StatusIs(util::StatusCode::kInvalidArgument));
}
@@ -700,6 +743,55 @@
R"("int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}}})"));
}
+TEST_P(JsonTest, TestParsingBrokenAny) {
+ auto m = ToProto<TestAny>(R"json(
+ {
+ "value": {}
+ }
+ )json");
+ ASSERT_OK(m);
+ EXPECT_EQ(m->value().type_url(), "");
+ EXPECT_EQ(m->value().value(), "");
+
+ EXPECT_THAT(ToProto<TestAny>(R"json(
+ {
+ "value": {
+ "type_url": "garbage",
+ "value": "bW9yZSBnYXJiYWdl"
+ }
+ }
+ )json"),
+ StatusIs(util::StatusCode::kInvalidArgument));
+}
+
+TEST_P(JsonTest, TestFlatList) {
+ auto m = ToProto<TestMessage>(R"json(
+ {
+ "repeatedInt32Value": [[[5]], [6]]
+ }
+ )json");
+ ASSERT_OK(m);
+ EXPECT_THAT(m->repeated_int32_value(), ElementsAre(5, 6));
+
+ // The above flatteing behavior is suppressed for google::protobuf::ListValue.
+ auto m2 = ToProto<google::protobuf::Value>(R"json(
+ {
+ "repeatedInt32Value": [[[5]], [6]]
+ }
+ )json");
+ ASSERT_OK(m2);
+ auto fields = m2->struct_value().fields();
+ auto list = fields["repeatedInt32Value"].list_value();
+ EXPECT_EQ(list.values(0)
+ .list_value()
+ .values(0)
+ .list_value()
+ .values(0)
+ .number_value(),
+ 5);
+ EXPECT_EQ(list.values(1).list_value().values(0).number_value(), 6);
+}
+
TEST_P(JsonTest, ParseWrappers) {
auto m = ToProto<TestWrapper>(R"json(
{
@@ -757,6 +849,14 @@
EXPECT_EQ(t.string_value(), "expected_value");
}
+TEST_P(JsonTest, TestHugeBareString) {
+ auto m = ToProto<TestMessage>(R"json({
+ "int64Value": 6009652459062546621
+ })json");
+ ASSERT_OK(m);
+ EXPECT_EQ(m->int64_value(), 6009652459062546621);
+}
+
TEST_P(JsonTest, TestParsingUnknownEnumsProto2) {
StringPiece input = R"json({"ayuLmao": "UNKNOWN_VALUE"})json";
@@ -895,6 +995,39 @@
EXPECT_EQ(m2->value().seconds(), 4);
EXPECT_EQ(m2->value().nanos(), 5);
+
+ // Negative duration with zero seconds.
+ auto m3 = ToProto<proto3::TestDuration>(R"json(
+ {
+ "value": {"nanos": -5},
+ }
+ )json");
+ ASSERT_OK(m3);
+ EXPECT_EQ(m3->value().seconds(), 0);
+ EXPECT_EQ(m3->value().nanos(), -5);
+ EXPECT_THAT(ToJson(m3->value()), IsOkAndHolds("\"-0.000000005s\""));
+
+ // Negative duration with zero nanos.
+ auto m4 = ToProto<proto3::TestDuration>(R"json(
+ {
+ "value": {"seconds": -5},
+ }
+ )json");
+ ASSERT_OK(m4);
+ EXPECT_EQ(m4->value().seconds(), -5);
+ EXPECT_EQ(m4->value().nanos(), 0);
+ EXPECT_THAT(ToJson(m4->value()), IsOkAndHolds("\"-5s\""));
+
+ // Parse "0.5s" as a JSON string.
+ auto m5 = ToProto<proto3::TestDuration>(R"json(
+ {
+ "value": "0.5s",
+ }
+ )json");
+ ASSERT_OK(m5);
+ EXPECT_EQ(m5->value().seconds(), 0);
+ EXPECT_EQ(m5->value().nanos(), 500000000);
+ EXPECT_THAT(ToJson(m5->value()), IsOkAndHolds("\"0.500s\""));
}
// These tests are not exhaustive; tests in //third_party/protobuf/conformance
@@ -991,13 +1124,40 @@
ASSERT_THAT(m2->repeated_value(), SizeIs(1));
EXPECT_TRUE(m2->repeated_value(0).has_null_value());
+
+ m2->Clear();
+ m2->mutable_repeated_value(); // Materialize an empty singular Value.
+ m2->add_repeated_value();
+ m2->add_repeated_value()->set_string_value("solitude");
+ m2->add_repeated_value();
+ EXPECT_THAT(ToJson(*m2), IsOkAndHolds(R"({"repeatedValue":["solitude"]})"));
}
-TEST_P(JsonTest, DISABLED_HtmlEscape) {
+TEST_P(JsonTest, ListList) {
+ auto m = ToProto<proto3::TestListValue>(R"json({
+ "repeated_value": [["ayy", "lmao"]]
+ })json");
+ ASSERT_OK(m);
+
+ EXPECT_EQ(m->repeated_value(0).values(0).string_value(), "ayy");
+ EXPECT_EQ(m->repeated_value(0).values(1).string_value(), "lmao");
+
+ m = ToProto<proto3::TestListValue>(R"json({
+ "repeated_value": [{
+ "values": ["ayy", "lmao"]
+ }]
+ })json");
+ ASSERT_OK(m);
+
+ EXPECT_EQ(m->repeated_value(0).values(0).string_value(), "ayy");
+ EXPECT_EQ(m->repeated_value(0).values(1).string_value(), "lmao");
+}
+
+TEST_P(JsonTest, HtmlEscape) {
TestMessage m;
m.set_string_value("</script>");
EXPECT_THAT(ToJson(m),
- IsOkAndHolds("{\"stringValue\":\"\\u003c/script\\u003e\"}"));
+ IsOkAndHolds(R"({"stringValue":"\u003c/script\u003e"})"));
}
} // namespace
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 4df3152..c8291c1 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -242,17 +242,17 @@
// Reports that a field has been added into Message2.
virtual void ReportAdded(const Message& message1, const Message& message2,
- const std::vector<SpecificField>& field_path) = 0;
+ const std::vector<SpecificField>& field_path) {}
// Reports that a field has been deleted from Message1.
virtual void ReportDeleted(
const Message& message1, const Message& message2,
- const std::vector<SpecificField>& field_path) = 0;
+ const std::vector<SpecificField>& field_path) {}
// Reports that the value of a field has been modified.
virtual void ReportModified(
const Message& message1, const Message& message2,
- const std::vector<SpecificField>& field_path) = 0;
+ const std::vector<SpecificField>& field_path) {}
// Reports that a repeated field has been moved to another location. This
// only applies when using TreatAsSet or TreatAsMap() -- see below. Also
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index a7e64bf..8f38f7c 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -53,7 +53,6 @@
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
-// Do UTF-8 validation on string type in Debug build only
#ifndef NDEBUG
#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
#endif
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 72304a5..f629e5e 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
+#if 3021004 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
diff --git a/tests.sh b/tests.sh
index f2b481c..6508674 100755
--- a/tests.sh
+++ b/tests.sh
@@ -45,44 +45,6 @@
PPROF_PATH=/usr/bin/google-pprof HEAPCHECK=strict ./protobuf-test
}
-build_cpp_distcheck() {
- grep -q -- "-Og" src/Makefile.am &&
- echo "The -Og flag is incompatible with Clang versions older than 4.0." &&
- exit 1
-
- # Initialize any submodules.
- git submodule update --init --recursive
- ./autogen.sh
- ./configure
- make dist
-
- # List all files that should be included in the distribution package.
- git ls-files | grep "^\(java\|python\|objectivec\|csharp\|ruby\|php\|cmake\|examples\|src/google/protobuf/.*\.proto\)" |\
- grep -v ".gitignore" | grep -v "java/lite/proguard.pgcfg" |\
- grep -v "python/compatibility_tests" | grep -v "python/docs" | grep -v "python/.repo-metadata.json" |\
- grep -v "python/protobuf_distutils" | grep -v "csharp/compatibility_tests" > dist.lst
- # Unzip the dist tar file.
- DIST=`ls *.tar.gz`
- tar -xf $DIST
- cd ${DIST//.tar.gz}
- # Check if every file exists in the dist tar file.
- FILES_MISSING=""
- for FILE in $(<../dist.lst); do
- [ -f "$FILE" ] || {
- echo "$FILE is not found!"
- FILES_MISSING="$FILE $FILES_MISSING"
- }
- done
- cd ..
- if [ ! -z "$FILES_MISSING" ]; then
- echo "Missing files in EXTRA_DIST: $FILES_MISSING"
- exit 1
- fi
-
- # Do the regular dist-check for C++.
- make distcheck -j$(nproc)
-}
-
build_dist_install() {
# Create a symlink pointing to python2 and put it at the beginning of $PATH.
# This is necessary because the googletest build system involves a Python
@@ -490,47 +452,8 @@
test_php_c
}
-build_php7.0_mac() {
+build_php_mac() {
internal_build_cpp
- # Install PHP
- curl -s https://php-osx.liip.ch/install.sh | bash -s 7.0
- PHP_FOLDER=`find /usr/local -type d -name "php5-7.0*"` # The folder name may change upon time
- test ! -z "$PHP_FOLDER"
- export PATH="$PHP_FOLDER/bin:$PATH"
-
- # Install Composer
- wget https://getcomposer.org/download/2.0.13/composer.phar --progress=dot:mega -O /usr/local/bin/composer
- chmod a+x /usr/local/bin/composer
-
- # Install valgrind
- echo "#! /bin/bash" > valgrind
- chmod ug+x valgrind
- sudo mv valgrind /usr/local/bin/valgrind
-
- # Test
- test_php_c
-}
-
-build_php7.3_mac() {
- internal_build_cpp
- # Install PHP
- # We can't test PHP 7.4 with these binaries yet:
- # https://github.com/liip/php-osx/issues/276
- curl -s https://php-osx.liip.ch/install.sh | bash -s 7.3
- PHP_FOLDER=`find /usr/local -type d -name "php5-7.3*"` # The folder name may change upon time
- test ! -z "$PHP_FOLDER"
- export PATH="$PHP_FOLDER/bin:$PATH"
-
- # Install Composer
- wget https://getcomposer.org/download/2.0.13/composer.phar --progress=dot:mega -O /usr/local/bin/composer
- chmod a+x /usr/local/bin/composer
-
- # Install valgrind
- echo "#! /bin/bash" > valgrind
- chmod ug+x valgrind
- sudo mv valgrind /usr/local/bin/valgrind
-
- # Test
test_php_c
}
@@ -578,7 +501,6 @@
if [ "$#" -ne 1 ]; then
echo "
Usage: $0 { cpp |
- cpp_distcheck |
csharp |
java_jdk7 |
java_oracle7 |
diff --git a/version.json b/version.json
index e50d633..4244127 100644
--- a/version.json
+++ b/version.json
@@ -1,17 +1,17 @@
{
"main": {
- "protoc_version": "21-dev",
+ "protoc_version": "22-dev",
"lts": false,
- "date": "2022-04-22",
+ "date": "2022-07-21",
"languages": {
- "cpp": "3.21-dev",
- "csharp": "3.21-dev",
- "java": "3.21-dev",
- "javascript": "3.21-dev",
- "objectivec": "3.21-dev",
- "php": "3.21-dev",
- "python": "4.21-dev",
- "ruby": "3.21-dev"
+ "cpp": "3.22-dev",
+ "csharp": "3.22-dev",
+ "java": "3.22-dev",
+ "javascript": "3.22-dev",
+ "objectivec": "3.22-dev",
+ "php": "3.22-dev",
+ "python": "4.22-dev",
+ "ruby": "3.22-dev"
}
}
}